]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
156ad27f6e592d188523fb34ab2b2b2af057361f
[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.authorization.storage;
25
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.UUID;
29
30 import javax.persistence.EntityExistsException;
31 import javax.persistence.EntityManager;
32 import javax.persistence.NoResultException;
33
34 import org.collectionspace.services.authorization.perms.ActionType;
35 import org.collectionspace.services.authorization.CSpaceAction;
36 import org.collectionspace.services.authorization.RolesList;
37 import org.collectionspace.services.authorization.perms.Permission;
38 import org.collectionspace.services.authorization.perms.PermissionAction;
39 import org.collectionspace.services.authorization.perms.PermissionsList;
40 import org.collectionspace.services.client.PermissionClient;
41 import org.collectionspace.services.client.PermissionClient.ActionCompare;
42 import org.collectionspace.services.authorization.URIResourceImpl;
43 import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
44 import org.collectionspace.services.common.document.BadRequestException;
45 import org.collectionspace.services.common.document.DocumentException;
46 import org.collectionspace.services.common.document.DocumentFilter;
47 import org.collectionspace.services.common.document.DocumentWrapper;
48 import org.collectionspace.services.common.document.JaxbUtils;
49 import org.collectionspace.services.common.security.SecurityUtils;
50 import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
51 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * Document handler for Permission
58  * @author 
59  */
60 public class PermissionDocumentHandler
61                 extends JpaDocumentHandler<Permission, PermissionsList, Permission, List<Permission>> {
62
63     private final Logger logger = LoggerFactory.getLogger(PermissionDocumentHandler.class);
64     private Permission permission;
65     private PermissionsList permissionsList;
66     
67     public CSpaceAction getAction(ActionType action) {
68         if (ActionType.CREATE.name().equals(action.name())) {
69             return CSpaceAction.CREATE;
70         } else if (ActionType.READ.equals(action)) {
71             return CSpaceAction.READ;
72         } else if (ActionType.UPDATE.equals(action)) {
73             return CSpaceAction.UPDATE;
74         } else if (ActionType.DELETE.equals(action)) {
75             return CSpaceAction.DELETE;
76         } else if (ActionType.SEARCH.equals(action)) {
77             return CSpaceAction.SEARCH;
78         } else if (ActionType.ADMIN.equals(action)) {
79             return CSpaceAction.ADMIN;
80         } else if (ActionType.START.equals(action)) {
81             return CSpaceAction.START;
82         } else if (ActionType.STOP.equals(action)) {
83             return CSpaceAction.STOP;
84         }
85         //
86         // We could not find a match, so we need to throw an exception.
87         //
88         throw new IllegalArgumentException("action = " + action.toString());
89     }
90     
91     /*
92      * Add the ACE hashed ID to the permission action so we can map the permission to the Spring Security
93      * tables.
94      */
95     private void handlePermissionActions(Permission perm) throws DocumentException {
96         //
97         // Verify the permission actions.  If the action group is missing, create it from the action list and vice versa.
98         //
99         ActionCompare compareResult = PermissionClient.validatePermActions(perm);
100         switch (compareResult) {
101                 case ACTIONS_MISSING:
102                         String msg = "Permission resource encountered with missing action group and action list.";
103                         throw new DocumentException(msg);
104                         
105                         case ACTION_GROUP_EMPTY:
106                                 String actionGroup = PermissionClient.getActionGroup(perm.getAction());
107                                 perm.setActionGroup(actionGroup);
108                                 break;
109                                 
110                         case ACTION_LIST_EMPTY:
111                                 List<PermissionAction> actionList = PermissionClient.getActionList(perm.getActionGroup());
112                                 perm.setAction(actionList);
113                                 break;
114                                 
115                         case MATCHES:
116                                 // all good
117                                 break;
118                                 
119                         case MISMATCHES:
120                                 msg = String.format("Permission has mismatching action group and action list.  Action group='%s' and Action list = '%s'.",
121                                                 perm.getActionGroup(), PermissionClient.getActionGroup(perm.getAction()));
122                                 throw new DocumentException(msg);
123         }
124         
125         List<PermissionAction> permActions = perm.getAction();
126         for (PermissionAction permAction : permActions) {
127             CSpaceAction action = getAction(permAction.getName());
128             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), perm.getResourceName(), action);
129             permAction.setObjectIdentity(uriRes.getHashedId().toString());
130             permAction.setObjectIdentityResource(uriRes.getId());
131             //PermissionActionUtil.update(perm, permAction);
132         }
133     }
134     
135     private Permission findExistingPermission(EntityManager em, Permission perm) {
136         Permission result = null;
137                 String tenantId = getServiceContext().getTenantId(); // we need a tenant ID 
138         
139                 try {
140                 result = (Permission)JpaStorageUtils.getEntityByDualKeys(em, 
141                                 Permission.class.getName(),
142                                 PermissionStorageConstants.RESOURCE_NAME, perm.getResourceName(), 
143                                 PermissionStorageConstants.ACTION_GROUP, perm.getActionGroup(),
144                                 tenantId);
145                 } catch (NoResultException e) {
146                         if (logger.isTraceEnabled()) {
147                                 String msg = String.format("Looked for but could not find permission with resource name = '%s', action group = '%s', tenat ID = '%s'.",
148                                                 perm.getResourceName(), perm.getActionGroup(), tenantId);
149                                 logger.trace(msg);
150                         }
151                 }
152
153         return result;
154     }
155
156     @Override
157     public void handleCreate(DocumentWrapper<Permission> wrapDoc) throws EntityExistsException, DocumentException {
158         //
159         // First check to see if an equivalent permission exists
160         //
161         Permission permission = wrapDoc.getWrappedObject();
162         
163         EntityManager em = (EntityManager) this.getServiceContext().getProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY);
164         Permission existingPermission = findExistingPermission(em, permission);
165
166         if (existingPermission == null) {
167                 String id = UUID.randomUUID().toString();        
168                 permission.setCsid(id);
169                 setTenant(permission);
170                 handlePermissionActions(permission);
171         } else {
172                 String msg = String.format("Found existing permission with resource name = '%s', action group = '%s', and tenant ID = '%s'.",
173                                 existingPermission.getResourceName(), existingPermission.getActionGroup(), existingPermission.getTenantId());
174                 wrapDoc.resetWrapperObject(existingPermission); // update the wrapped document with the existing permission instance
175                 throw new EntityExistsException(msg);
176         }
177     }
178
179     @Override
180     public void completeCreate(DocumentWrapper<Permission> wrapDoc) throws Exception {
181     }
182
183     @Override
184     public void handleUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
185         Permission permissionFound = wrapDoc.getWrappedObject();
186         Permission permissionReceived = getCommonPart();
187         merge(permissionReceived, permissionFound);
188     }
189
190     /**
191      * merge manually merges the from from to the to permission
192      * -this method is created due to inefficiency of JPA EM merge
193      * @param from
194      * @param to
195      * @return merged permission
196      */
197     private Permission merge(Permission from, Permission to) throws Exception {
198         if (!(from.getResourceName().equalsIgnoreCase(to.getResourceName()))) {
199             String msg = "Resource name cannot be changed " + to.getResourceName();
200             logger.error(msg);
201             throw new BadRequestException(msg);
202         }
203         //resource name, attribute  cannot be changed
204
205         if (from.getDescription() != null) {
206             to.setDescription(from.getDescription());
207         }
208         if (from.getEffect() != null) {
209             to.setEffect(from.getEffect());
210         }
211         List<PermissionAction> fromActions = from.getAction();
212         if (!fromActions.isEmpty()) {
213             // Override the whole list, no reconciliation by design
214             to.setAction(fromActions);
215             // Update the actionGroup field to reflect the new action list
216             to.setActionGroup(PermissionClient.getActionGroup(fromActions));
217         }
218
219         if (logger.isDebugEnabled()) {
220             logger.debug("merged permission=" + JaxbUtils.toString(to, Permission.class));
221         }
222
223         handlePermissionActions(to);
224         return to;
225     }
226
227     @Override
228     public void completeUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
229         Permission upAcc = wrapDoc.getWrappedObject();
230         getServiceContext().setOutput(upAcc);
231         sanitize(upAcc);
232         //FIXME update lower-layer authorization (acls)
233         //will require deleting old permissions for this resource and adding
234         //new based on new actions and effect
235     }
236
237     @Override
238     public void handleGet(DocumentWrapper<Permission> wrapDoc) throws Exception {
239         setCommonPart(extractCommonPart(wrapDoc));
240         sanitize(getCommonPart());
241         getServiceContext().setOutput(permission);
242     }
243
244     @Override
245     public void handleGetAll(DocumentWrapper<List<Permission>> wrapDoc) throws Exception {
246         PermissionsList permissionsList = extractCommonPartList(wrapDoc);
247         setCommonPartList(permissionsList);
248         getServiceContext().setOutput(getCommonPartList());
249     }
250
251     @Override
252     public void completeDelete(DocumentWrapper<Permission> wrapDoc) throws Exception {
253     }
254
255     /*
256      * See https://issues.collectionspace.org/browse/DRYD-181
257      * 
258      * For backward compatibility, we could not change the permission list to be a child class of AbstractCommonList.  This
259      * would have change the result payload and would break existing API clients.  So the best we can do, it treat
260      * the role list payload as a special case and return the paging information.
261      * 
262      */
263         protected PermissionsList extractPagingInfoForPerms(PermissionsList permList, DocumentWrapper<List<Permission>> wrapDoc)
264             throws Exception {
265
266         DocumentFilter docFilter = this.getDocumentFilter();
267         long pageSize = docFilter.getPageSize();
268         long pageNum = pageSize != 0 ? docFilter.getOffset() / pageSize : pageSize;
269         // set the page size and page number
270         permList.setPageNum(pageNum);
271         permList.setPageSize(pageSize);
272         List<Permission> docList = wrapDoc.getWrappedObject();
273         // Set num of items in list. this is useful to our testing framework.
274         permList.setItemsInPage(docList.size());
275         // set the total result size
276         permList.setTotalItems(docFilter.getTotalItemsResult());
277
278         return permList;
279     }
280         
281     @Override
282     public Permission extractCommonPart(
283             DocumentWrapper<Permission> wrapDoc)
284             throws Exception {
285         return wrapDoc.getWrappedObject();
286     }
287
288     @Override
289     public void fillCommonPart(Permission obj, DocumentWrapper<Permission> wrapDoc)
290             throws Exception {
291         throw new UnsupportedOperationException("operation not relevant for AccountDocumentHandler");
292     }
293
294     @Override
295     public PermissionsList extractCommonPartList(
296             DocumentWrapper<List<Permission>> wrapDoc)
297             throws Exception {
298
299         PermissionsList permissionsList = extractPagingInfoForPerms(new PermissionsList(), wrapDoc);
300         List<Permission> list = new ArrayList<Permission>();
301         permissionsList.setPermission(list);
302         for (Object obj : wrapDoc.getWrappedObject()) {
303             Permission permission = (Permission) obj;
304             sanitize(permission);
305             list.add(permission);
306         }
307         
308         return permissionsList;
309     }
310
311     @Override
312     public Permission getCommonPart() {
313         return permission;
314     }
315
316     @Override
317     public void setCommonPart(Permission permission) {
318         this.permission = permission;
319     }
320
321     @Override
322     public PermissionsList getCommonPartList() {
323         return permissionsList;
324     }
325
326     @Override
327     public void setCommonPartList(PermissionsList permissionsList) {
328         this.permissionsList = permissionsList;
329     }
330
331     @Override
332     public String getQProperty(
333             String prop) {
334         return null;
335     }
336
337     @Override
338     public DocumentFilter createDocumentFilter() {
339         DocumentFilter filter = new PermissionJpaFilter(this.getServiceContext());
340         return filter;
341     }
342
343     /**
344      * Sanitize removes data not needed to be sent to the consumer
345      * @param permission
346      */
347     private void sanitize(Permission permission) {
348         if (!SecurityUtils.isCSpaceAdmin()) {
349             // permission.setTenantId(null); // REM - Why are we removing the tenant ID from the payload? Commenting out this line for now.
350         }
351     }
352
353     private void setTenant(Permission permission) {
354         //set tenant only if not available from input
355         if (permission.getTenantId() == null || permission.getTenantId().isEmpty()) {
356             permission.setTenantId(getServiceContext().getTenantId());
357         }
358     }
359 }