]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
d73f37656f94ff7e7d2ee2c9166d86ee41b1be97
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.common.authorization_mgt;
25
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;
32
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;
40
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;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 // TODO: Auto-generated Javadoc
57 /**
58  * The Class PermissionRoleUtil.
59  *
60  * @author
61  */
62 public class PermissionRoleUtil {
63
64     static final Logger logger = LoggerFactory.getLogger(PermissionRoleUtil.class);
65
66     /**
67      * Gets the relation subject.
68      *
69      * @param ctx the ctx
70      * @return the relation subject
71      */
72     static public SubjectType getRelationSubject(ServiceContext ctx) {
73         Object o = ctx.getProperty(ServiceContextProperties.SUBJECT);
74         if (o == null) {
75             throw new IllegalArgumentException(ServiceContextProperties.SUBJECT
76                     + " property is missing in context "
77                     + ctx.toString());
78         }
79         return (SubjectType) o;
80     }
81
82     /**
83      * Gets the relation subject.
84      *
85      * @param ctx the ctx
86      * @param pr the pr
87      * @return the relation subject
88      */
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);
94         }
95         return subject;
96     }
97
98     /**
99      * buildPermissionRoleRel builds persistent relationship entities from given
100      * permissionrole.
101      *
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
106      */
107     static public void buildPermissionRoleRel(JPATransactionContext jpaTransactionContext, 
108                 PermissionRole pr,
109                 SubjectType subject,
110                 List<PermissionRoleRel> prrl,
111                 boolean handleDelete,
112                 String tenantId) throws Exception {
113         
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);
120                         prrl.add(prr);
121                     }
122                 }
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);
129                         prrl.add(prr);
130                     }
131                 }
132         }
133     }
134     
135     static public void buildPermissionRoleRel(
136                 ServiceContext ctx,
137                 PermissionRole pr,
138                 SubjectType subject,
139                 List<PermissionRoleRel> prrl,
140                 boolean handleDelete,
141                 String tenantId) throws Exception {
142         
143         JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection();
144         try {
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);
152             }
153             throw e;
154         } finally {
155             ctx.closeConnection();
156         }
157     }    
158
159     /*
160      * Try to find a persisted Permission record using a PermissionValue instance.
161      *
162      */
163     static private Permission lookupPermission(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, String tenantId) throws TransactionException {
164         Permission result = null;
165         
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;
169         //
170         // If we have a permission ID, use it to try to lookup the persisted permission
171         //
172         if (permissionId != null && !permissionId.isEmpty()) {
173                 try {
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'.",
177                                         permissionId);
178                         logger.trace(msg);
179                 }
180         } else if ((resourceName != null && !resourceName.isEmpty()) && 
181                         (actionGroup != null && !actionGroup.isEmpty())) {
182                 //
183                 // If there was no permission ID, then we can try to find the permission with the resource name and action group tuple
184                 //
185                 try {
186                         result = (Permission)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext, 
187                                         Permission.class.getName(),
188                                         PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(), 
189                                         PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(),
190                                         tenantId);
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);
194                         logger.trace(msg);
195                 }
196         } else {
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);
199                 logger.warn(errMsg);
200         }
201         
202         return result;
203     }
204     
205     /**
206      * Builds a permisson role relationship for either 'create' or 'delete'
207      *
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 
213      */
214     static private PermissionRoleRel buildPermissonRoleRel(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue,
215                 RoleValue roleValue,
216                 SubjectType subject,
217                 boolean handleDelete,  // if 'true' then we're deleting not building a permission-role record
218                 String tenantId) throws DocumentException {
219
220         PermissionRoleRel result = null;
221         Permission permission = lookupPermission(jpaTransactionContext, permissionValue, tenantId);
222         
223         //
224         // If we couldn't find an existing permission and we're not processing a DELETE request, we need to create
225         // a new permission.
226         //
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);
238                 }
239         }
240         
241         //
242         // Since our permissionValue may not have been supplied by the client with an ID, we need
243         // to add it now.
244         //
245         if (permissionValue.getPermissionId() == null || permissionValue.getPermissionId().trim().isEmpty()) {
246                 permissionValue.setPermissionId(permission.getCsid());
247         }
248         
249         //
250         // Create the permission-role to persist
251         //
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());
258         
259         //
260         // For 'delete' we need to set the hjid of the existing relstionship
261         //
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();
267         }
268         if (relationshipId != null && handleDelete == true) {
269                 result.setHjid(Long.parseLong(relationshipId));  // set this so we can convince JPA to del the relation
270         }
271         
272         return result;
273     }
274
275     private static Permission createPermission(JPATransactionContext jpaTransactionContext, Permission permission) {
276                 Permission result = null;
277                 
278                 PermissionResource permissionResource = new PermissionResource();  // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton)
279                 result = permissionResource.createPermissionFromInstance(jpaTransactionContext, permission);
280                 
281                 return result;
282         }
283
284         private static List<PermissionAction> createPermActionList(String actionGroup) throws DocumentException {
285         ArrayList<PermissionAction> result = new ArrayList<PermissionAction>();
286         
287         for (char c : actionGroup.toUpperCase().toCharArray()) {
288                 PermissionAction permAction = new PermissionAction();
289                 switch (c) {
290                         case 'C':
291                                 permAction.setName(ActionType.CREATE);
292                                 break;
293                                 
294                         case 'R':
295                                 permAction.setName(ActionType.READ);
296                                 break;
297                                 
298                         case 'U':
299                                 permAction.setName(ActionType.UPDATE);
300                                 break;
301                                 
302                         case 'D':
303                                 permAction.setName(ActionType.DELETE);
304                                 break;
305                                 
306                         case 'L':
307                                 permAction.setName(ActionType.SEARCH);
308                                 break;
309                                 
310                         default:
311                                 String errMsg = String.format("Illegal action group token '%c' in permission action group '%s'.",
312                                                 c, actionGroup);
313                                 throw new DocumentException(errMsg);
314                 }
315                 
316                 if (result.add(permAction) == false) {
317                         String warnMsg = String.format("Illegal or duplicate action group token '%c' in permission action group '%s'.",
318                                         c, actionGroup);
319                         logger.warn(warnMsg);
320                 }
321         }
322         
323                 return result;
324         }
325
326         /**
327      * Checks if is invalid tenant.
328      *
329      * @param tenantId the tenant id
330      * @param msgBldr the msg bldr
331      * @return true, if is invalid tenant
332      */
333     static boolean isInvalidTenant(String tenantId, StringBuilder msgBldr) {
334         boolean invalid = false;
335
336         if (tenantId == null || tenantId.isEmpty()) {
337             invalid = true;
338             msgBldr.append("\n tenant : tenantId is missing");
339         }
340         String whereClause = "where id = :id";
341         HashMap<String, Object> params = new HashMap<String, Object>();
342         params.put("id", tenantId);
343
344         Object tenantFound = JpaStorageUtils.getEntity(
345                 "org.collectionspace.services.account.Tenant", whereClause, params);
346         if (tenantFound == null) {
347             invalid = true;
348             msgBldr.append("\n tenant : tenantId=" + tenantId
349                     + " not found");
350         }
351         return invalid;
352     }
353 }