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.context.ServiceContext;
36 import org.collectionspace.services.common.context.ServiceContextProperties;
37 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
39 import org.collectionspace.services.authorization.perms.ActionType;
40 import org.collectionspace.services.authorization.perms.EffectType;
41 import org.collectionspace.services.authorization.perms.Permission;
42 import org.collectionspace.services.authorization.perms.PermissionAction;
43 import org.collectionspace.services.authorization.storage.PermissionStorageConstants;
44 import org.collectionspace.services.authorization.PermissionResource;
45 import org.collectionspace.services.authorization.PermissionRole;
46 import org.collectionspace.services.authorization.PermissionRoleRel;
47 import org.collectionspace.services.authorization.PermissionValue;
48 import org.collectionspace.services.authorization.RoleValue;
49 import org.collectionspace.services.authorization.SubjectType;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
54 // TODO: Auto-generated Javadoc
56 * The Class PermissionRoleUtil.
60 public class PermissionRoleUtil {
62 static final Logger logger = LoggerFactory.getLogger(PermissionRoleUtil.class);
65 * Gets the relation subject.
68 * @return the relation subject
70 static public SubjectType getRelationSubject(ServiceContext ctx) {
71 Object o = ctx.getProperty(ServiceContextProperties.SUBJECT);
73 throw new IllegalArgumentException(ServiceContextProperties.SUBJECT
74 + " property is missing in context "
77 return (SubjectType) o;
81 * Gets the relation subject.
85 * @return the relation subject
87 static public SubjectType getRelationSubject(ServiceContext ctx, PermissionRole pr) {
88 SubjectType subject = pr.getSubject();
89 if (subject == null) {
90 //it is not required to give subject as URI determines the subject
91 subject = getRelationSubject(ctx);
97 * buildPermissionRoleRel builds persistent relationship entities from given
100 * @param pr permissionrole
101 * @param subject the subject
102 * @param prrl persistent entities built are inserted into this list
103 * @param toDelete the to delete
105 static public void buildPermissionRoleRel(EntityManager em,
108 List<PermissionRoleRel> prrl,
109 boolean handleDelete,
110 String tenantId) throws Exception {
112 if (subject.equals(SubjectType.ROLE)) {
113 List<PermissionValue> permissionValues = pr.getPermission();
114 if (permissionValues != null && permissionValues.size() > 0) {
115 PermissionValue pv = permissionValues.get(0);
116 for (RoleValue rv : pr.getRole()) {
117 PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId);
121 } else if (subject.equals(SubjectType.PERMISSION)) {
122 List<RoleValue> roleValues = pr.getRole();
123 if (roleValues != null && roleValues.size() > 0) {
124 RoleValue rv = roleValues.get(0);
125 for (PermissionValue pv : pr.getPermission()) {
126 PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId);
133 static public void buildPermissionRoleRel(
136 List<PermissionRoleRel> prrl,
137 boolean handleDelete,
138 String tenantId) throws Exception {
139 EntityManagerFactory emf = null;
140 EntityManager em = null;
142 emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);
143 em = emf.createEntityManager();
144 em.getTransaction().begin();
146 buildPermissionRoleRel(em, pr, subject, prrl, handleDelete, tenantId);
148 em.getTransaction().commit();
150 } catch (Exception e) {
151 if (em != null && em.getTransaction().isActive()) {
152 em.getTransaction().rollback();
154 if (logger.isDebugEnabled()) {
155 logger.debug("Caught exception ", e);
160 JpaStorageUtils.releaseEntityManagerFactory(emf);
166 * Try to find a persisted Permission record using a PermissionValue instance.
169 static private Permission lookupPermission(EntityManager em, PermissionValue permissionValue, String tenantId) {
170 Permission result = null;
172 String actionGroup = permissionValue.getActionGroup() != null ? permissionValue.getActionGroup().trim() : null;
173 String resourceName = permissionValue.getResourceName() != null ? permissionValue.getResourceName().trim() : null;
174 String permissionId = permissionValue.getPermissionId() != null ? permissionValue.getPermissionId().trim() : null;
176 // If we have a permission ID, use it to try to lookup the persisted permission
178 if (permissionId != null && !permissionId.isEmpty()) {
180 result = (Permission)JpaStorageUtils.getEntity(em, permissionId, Permission.class);
181 } catch (Throwable e) {
182 String msg = String.format("Searched for but couldn't find a permission with CSID='%s'.",
186 } else if ((resourceName != null && !resourceName.isEmpty()) &&
187 (actionGroup != null && !actionGroup.isEmpty())) {
189 // If there was no permission ID, then we can try to find the permission with the resource name and action group tuple
192 result = (Permission)JpaStorageUtils.getEntityByDualKeys(em,
193 Permission.class.getName(),
194 PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(),
195 PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(),
197 } catch (NoResultException e) {
198 String msg = String.format("Searched for but couldn't find a permission for resource='%s', action group='%s', and tenant ID='%s'.",
199 permissionValue.getResourceName(), permissionValue.getActionGroup(), tenantId);
203 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'.",
204 permissionId, resourceName, actionGroup);
212 * Builds a permisson role relationship for either 'create' or 'delete'
214 * @param pv the pv (currently using only the ID)
215 * @param rv the rv (currently using only the ID)
216 * @param handleDelete the handle delete
217 * @return the permission role rel
218 * @throws DocumentException
220 static private PermissionRoleRel buildPermissonRoleRel(EntityManager em, PermissionValue permissionValue,
223 boolean handleDelete, // if 'true' then we're deleting not building a permission-role record
224 String tenantId) throws DocumentException {
226 PermissionRoleRel result = null;
227 Permission permission = lookupPermission(em, permissionValue, tenantId);
230 // If we couldn't find an existing permission and we're not processing a DELETE request, we need to create
233 if (permission == null && handleDelete == false) {
234 permission = new Permission();
235 permission.setResourceName(permissionValue.getResourceName());
236 permission.setActionGroup(permissionValue.getActionGroup());
237 permission.setEffect(EffectType.PERMIT); // By default, CollectionSpace currently (11/2017) supports only PERMIT
238 List<PermissionAction> actionList = createPermActionList(permissionValue.getActionGroup());
239 permission.setAction(actionList);
240 permission = createPermission(permission);
241 if (permission == null) {
242 String errMsg = "Could not create new permission for new permission-role relationship.";
243 throw new DocumentException(errMsg);
248 // Since our permissionValue may not have been supplied by the client with an ID, we need
251 if (permissionValue.getPermissionId() == null || permissionValue.getPermissionId().trim().isEmpty()) {
252 permissionValue.setPermissionId(permission.getCsid());
256 // Create the permission-role to persist
258 result = new PermissionRoleRel();
259 result.setPermissionId(permission.getCsid());
260 result.setPermissionResource(permission.getResourceName());
261 result.setActionGroup(permission.getActionGroup());
262 result.setRoleId(roleValue.getRoleId());
263 result.setRoleName(roleValue.getRoleName());
266 // For 'delete' we need to set the hjid of the existing relstionship
268 String relationshipId = null;
269 if (subject.equals(SubjectType.ROLE) == true) {
270 relationshipId = roleValue.getRoleRelationshipId();
271 } else if (subject.equals(SubjectType.PERMISSION) == true) {
272 relationshipId = permissionValue.getPermRelationshipId();
274 if (relationshipId != null && handleDelete == true) {
275 result.setHjid(Long.parseLong(relationshipId)); // set this so we can convince JPA to del the relation
281 private static Permission createPermission(Permission permission) {
282 Permission result = null;
284 PermissionResource permissionResource = new PermissionResource(); // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton)
285 result = permissionResource.createPermissionFromInstance(permission);
290 private static List<PermissionAction> createPermActionList(String actionGroup) throws DocumentException {
291 ArrayList<PermissionAction> result = new ArrayList<PermissionAction>();
293 for (char c : actionGroup.toUpperCase().toCharArray()) {
294 PermissionAction permAction = new PermissionAction();
297 permAction.setName(ActionType.CREATE);
301 permAction.setName(ActionType.READ);
305 permAction.setName(ActionType.UPDATE);
309 permAction.setName(ActionType.DELETE);
313 permAction.setName(ActionType.SEARCH);
317 String errMsg = String.format("Illegal action group token '%c' in permission action group '%s'.",
319 throw new DocumentException(errMsg);
322 if (result.add(permAction) == false) {
323 String warnMsg = String.format("Illegal or duplicate action group token '%c' in permission action group '%s'.",
325 logger.warn(warnMsg);
333 * Checks if is invalid tenant.
335 * @param tenantId the tenant id
336 * @param msgBldr the msg bldr
337 * @return true, if is invalid tenant
339 static boolean isInvalidTenant(String tenantId, StringBuilder msgBldr) {
340 boolean invalid = false;
342 if (tenantId == null || tenantId.isEmpty()) {
344 msgBldr.append("\n tenant : tenantId is missing");
346 String whereClause = "where id = :id";
347 HashMap<String, Object> params = new HashMap<String, Object>();
348 params.put("id", tenantId);
350 Object tenantFound = JpaStorageUtils.getEntity(
351 "org.collectionspace.services.account.Tenant", whereClause, params);
352 if (tenantFound == null) {
354 msgBldr.append("\n tenant : tenantId=" + tenantId