2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.common.authorization_mgt;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import javax.persistence.EntityManager;
30 import javax.persistence.EntityManagerFactory;
31 import javax.persistence.NoResultException;
33 import org.collectionspace.services.common.document.DocumentException;
34 import org.collectionspace.services.common.document.DocumentNotFoundException;
35 import org.collectionspace.services.common.document.TransactionException;
36 import org.collectionspace.services.common.context.ServiceContext;
37 import org.collectionspace.services.common.context.ServiceContextProperties;
38 import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
39 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
41 import org.collectionspace.services.authorization.perms.ActionType;
42 import org.collectionspace.services.authorization.perms.EffectType;
43 import org.collectionspace.services.authorization.perms.Permission;
44 import org.collectionspace.services.authorization.perms.PermissionAction;
45 import org.collectionspace.services.authorization.storage.PermissionStorageConstants;
46 import org.collectionspace.services.authorization.PermissionResource;
47 import org.collectionspace.services.authorization.PermissionRole;
48 import org.collectionspace.services.authorization.PermissionRoleRel;
49 import org.collectionspace.services.authorization.PermissionValue;
50 import org.collectionspace.services.authorization.RoleValue;
51 import org.collectionspace.services.authorization.SubjectType;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 // TODO: Auto-generated Javadoc
58 * The Class PermissionRoleUtil.
62 public class PermissionRoleUtil {
64 static final Logger logger = LoggerFactory.getLogger(PermissionRoleUtil.class);
67 * Gets the relation subject.
70 * @return the relation subject
72 static public SubjectType getRelationSubject(ServiceContext ctx) {
73 Object o = ctx.getProperty(ServiceContextProperties.SUBJECT);
75 throw new IllegalArgumentException(ServiceContextProperties.SUBJECT
76 + " property is missing in context "
79 return (SubjectType) o;
83 * Gets the relation subject.
87 * @return the relation subject
89 static public SubjectType getRelationSubject(ServiceContext ctx, PermissionRole pr) {
90 SubjectType subject = pr.getSubject();
91 if (subject == null) {
92 //it is not required to give subject as URI determines the subject
93 subject = getRelationSubject(ctx);
99 * buildPermissionRoleRel builds persistent relationship entities from given
102 * @param pr permissionrole
103 * @param subject the subject
104 * @param prrl persistent entities built are inserted into this list
105 * @param toDelete the to delete
107 static public void buildPermissionRoleRel(JPATransactionContext jpaTransactionContext,
110 List<PermissionRoleRel> prrl,
111 boolean handleDelete,
112 String tenantId) throws Exception {
114 if (subject.equals(SubjectType.ROLE)) {
115 List<PermissionValue> permissionValues = pr.getPermission();
116 if (permissionValues != null && permissionValues.size() > 0) {
117 PermissionValue pv = permissionValues.get(0);
118 for (RoleValue rv : pr.getRole()) {
119 PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId);
123 } else if (subject.equals(SubjectType.PERMISSION)) {
124 List<RoleValue> roleValues = pr.getRole();
125 if (roleValues != null && roleValues.size() > 0) {
126 RoleValue rv = roleValues.get(0);
127 for (PermissionValue pv : pr.getPermission()) {
128 PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId);
135 static public void buildPermissionRoleRel(
139 List<PermissionRoleRel> prrl,
140 boolean handleDelete,
141 String tenantId) throws Exception {
143 JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection();
145 jpaTransactionContext.beginTransaction();
146 buildPermissionRoleRel(jpaTransactionContext, pr, subject, prrl, handleDelete, tenantId);
147 jpaTransactionContext.commitTransaction();
148 } catch (Exception e) {
149 jpaTransactionContext.markForRollback();
150 if (logger.isDebugEnabled()) {
151 logger.debug("Caught exception ", e);
155 ctx.closeConnection();
160 * Try to find a persisted Permission record using a PermissionValue instance.
163 static private Permission lookupPermission(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, String tenantId) throws TransactionException {
164 Permission result = null;
166 String actionGroup = permissionValue.getActionGroup() != null ? permissionValue.getActionGroup().trim() : null;
167 String resourceName = permissionValue.getResourceName() != null ? permissionValue.getResourceName().trim() : null;
168 String permissionId = permissionValue.getPermissionId() != null ? permissionValue.getPermissionId().trim() : null;
170 // If we have a permission ID, use it to try to lookup the persisted permission
172 if (permissionId != null && !permissionId.isEmpty()) {
174 result = (Permission)JpaStorageUtils.getEntity(jpaTransactionContext, permissionId, Permission.class);
175 } catch (Throwable e) {
176 String msg = String.format("Searched for but couldn't find a permission with CSID='%s'.",
180 } else if ((resourceName != null && !resourceName.isEmpty()) &&
181 (actionGroup != null && !actionGroup.isEmpty())) {
183 // If there was no permission ID, then we can try to find the permission with the resource name and action group tuple
186 result = (Permission)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext,
187 Permission.class.getName(),
188 PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(),
189 PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(),
191 } catch (NoResultException e) {
192 String msg = String.format("Searched for but couldn't find a permission for resource='%s', action group='%s', and tenant ID='%s'.",
193 permissionValue.getResourceName(), permissionValue.getActionGroup(), tenantId);
197 String errMsg = String.format("Couldn't perform lookup of permission. Not enough information provided. Lookups requires a permission CSID or a resource name and action group tuple. The provided information was permission ID='%s', resourceName='%s', and actionGroup='%s'.",
198 permissionId, resourceName, actionGroup);
206 * Builds a permisson role relationship for either 'create' or 'delete'
208 * @param pv the pv (currently using only the ID)
209 * @param rv the rv (currently using only the ID)
210 * @param handleDelete the handle delete
211 * @return the permission role rel
212 * @throws DocumentException
214 static private PermissionRoleRel buildPermissonRoleRel(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue,
217 boolean handleDelete, // if 'true' then we're deleting not building a permission-role record
218 String tenantId) throws DocumentException {
220 PermissionRoleRel result = null;
221 Permission permission = lookupPermission(jpaTransactionContext, permissionValue, tenantId);
224 // If we couldn't find an existing permission and we're not processing a DELETE request, we need to create
227 if (permission == null && handleDelete == false) {
228 permission = new Permission();
229 permission.setResourceName(permissionValue.getResourceName());
230 permission.setActionGroup(permissionValue.getActionGroup());
231 permission.setEffect(EffectType.PERMIT); // By default, CollectionSpace currently (11/2017) supports only PERMIT
232 List<PermissionAction> actionList = createPermActionList(permissionValue.getActionGroup());
233 permission.setAction(actionList);
234 permission = createPermission(jpaTransactionContext, permission);
235 if (permission == null) {
236 String errMsg = "Could not create new permission for new permission-role relationship.";
237 throw new DocumentException(errMsg);
242 // Since our permissionValue may not have been supplied by the client with an ID, we need
245 if (permissionValue.getPermissionId() == null || permissionValue.getPermissionId().trim().isEmpty()) {
246 permissionValue.setPermissionId(permission.getCsid());
250 // Create the permission-role to persist
252 result = new PermissionRoleRel();
253 result.setPermissionId(permission.getCsid());
254 result.setPermissionResource(permission.getResourceName());
255 result.setActionGroup(permission.getActionGroup());
256 result.setRoleId(roleValue.getRoleId());
257 result.setRoleName(roleValue.getRoleName());
260 // For 'delete' we need to set the hjid of the existing relstionship
262 String relationshipId = null;
263 if (subject.equals(SubjectType.ROLE) == true) {
264 relationshipId = roleValue.getRoleRelationshipId();
265 } else if (subject.equals(SubjectType.PERMISSION) == true) {
266 relationshipId = permissionValue.getPermRelationshipId();
268 if (relationshipId != null && handleDelete == true) {
269 result.setHjid(Long.parseLong(relationshipId)); // set this so we can convince JPA to del the relation
275 private static Permission createPermission(JPATransactionContext jpaTransactionContext, Permission permission) {
276 Permission result = null;
278 PermissionResource permissionResource = new PermissionResource(); // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton)
279 result = permissionResource.createPermissionFromInstance(jpaTransactionContext, permission);
284 private static List<PermissionAction> createPermActionList(String actionGroup) throws DocumentException {
285 ArrayList<PermissionAction> result = new ArrayList<PermissionAction>();
287 for (char c : actionGroup.toUpperCase().toCharArray()) {
288 PermissionAction permAction = new PermissionAction();
291 permAction.setName(ActionType.CREATE);
295 permAction.setName(ActionType.READ);
299 permAction.setName(ActionType.UPDATE);
303 permAction.setName(ActionType.DELETE);
307 permAction.setName(ActionType.SEARCH);
311 String errMsg = String.format("Illegal action group token '%c' in permission action group '%s'.",
313 throw new DocumentException(errMsg);
316 if (result.add(permAction) == false) {
317 String warnMsg = String.format("Illegal or duplicate action group token '%c' in permission action group '%s'.",
319 logger.warn(warnMsg);
327 * Checks if is invalid tenant.
329 * @param tenantId the tenant id
330 * @param msgBldr the msg bldr
331 * @return true, if is invalid tenant
333 static boolean isInvalidTenant(String tenantId, StringBuilder msgBldr) {
334 boolean invalid = false;
336 if (tenantId == null || tenantId.isEmpty()) {
338 msgBldr.append("\n tenant : tenantId is missing");
340 String whereClause = "where id = :id";
341 HashMap<String, Object> params = new HashMap<String, Object>();
342 params.put("id", tenantId);
344 Object tenantFound = JpaStorageUtils.getEntity(
345 "org.collectionspace.services.account.Tenant", whereClause, params);
346 if (tenantFound == null) {
348 msgBldr.append("\n tenant : tenantId=" + tenantId