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