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.authorization.storage;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.UUID;
30 import org.collectionspace.services.authorization.PermissionRole;
31 import org.collectionspace.services.authorization.PermissionRoleSubResource;
32 import org.collectionspace.services.authorization.PermissionValue;
33 import org.collectionspace.services.authorization.Role;
34 import org.collectionspace.services.authorization.RoleValue;
35 import org.collectionspace.services.authorization.RolesList;
36 import org.collectionspace.services.authorization.SubjectType;
38 import org.collectionspace.services.client.PermissionRoleFactory;
39 import org.collectionspace.services.client.RoleClient;
40 import org.collectionspace.services.client.RoleFactory;
41 import org.collectionspace.services.common.api.Tools;
42 import org.collectionspace.services.common.context.ServiceContext;
43 import org.collectionspace.services.common.document.BadRequestException;
44 import org.collectionspace.services.common.document.DocumentFilter;
45 import org.collectionspace.services.common.document.DocumentWrapper;
46 import org.collectionspace.services.common.document.JaxbUtils;
47 import org.collectionspace.services.common.security.SecurityUtils;
48 import org.collectionspace.services.common.storage.TransactionContext;
49 import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 * Document handler for Role
58 @SuppressWarnings("unchecked")
59 public class RoleDocumentHandler
60 extends JpaDocumentHandler<Role, RolesList, Role, List<Role>> {
61 private final Logger logger = LoggerFactory.getLogger(RoleDocumentHandler.class);
63 private RolesList rolesList;
66 public void handleCreate(DocumentWrapper<Role> wrapDoc) throws Exception {
67 String id = UUID.randomUUID().toString();
68 Role role = wrapDoc.getWrappedObject();
70 // Synthesize the display name if it was not passed in.
71 String displayName = role.getDisplayName();
72 boolean displayNameEmpty = true;
73 if (displayName != null) {
74 displayNameEmpty = displayName.trim().isEmpty();
76 if (displayNameEmpty == true) {
77 role.setDisplayName(role.getRoleName());
81 role.setRoleName(RoleClient.getBackendRoleName(role.getRoleName(), role.getTenantId()));
83 // We do not allow creation of locked roles through the services.
84 role.setMetadataProtection(null);
85 role.setPermsProtection(null);
88 @SuppressWarnings("rawtypes")
90 public void handleUpdate(DocumentWrapper<Role> wrapDoc) throws Exception {
91 Role roleFound = wrapDoc.getWrappedObject();
92 Role roleReceived = getCommonPart();
93 // If marked as metadata immutable, do not do update
94 if (!RoleClient.IMMUTABLE.equals(roleFound.getMetadataProtection())) {
96 .setRoleName(RoleClient.getBackendRoleName(roleReceived.getRoleName(), roleFound.getTenantId()));
97 merge(roleReceived, roleFound);
100 // Update perms is supplied.
102 ServiceContext ctx = this.getServiceContext();
103 List<PermissionValue> permValueList = roleReceived.getPermission();
104 if (permValueList != null && permValueList.size() > 0) {
105 PermissionRoleSubResource subResource =
106 new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
108 // First, delete the existing permroles
110 subResource.deletePermissionRole(ctx, roleFound.getCsid(), SubjectType.PERMISSION);
112 // Next, create the new permroles
114 RoleValue roleValue = RoleFactory.createRoleValueInstance(roleFound);
115 PermissionRole permRole = PermissionRoleFactory.createPermissionRoleInstance(SubjectType.PERMISSION, roleValue,
116 permValueList, true, true);
117 subResource.createPermissionRole(ctx, permRole, SubjectType.PERMISSION);
119 // Finally, set the updated perm list in the result
121 PermissionRole newPermRole = subResource.getPermissionRole(ctx, roleFound.getCsid(), SubjectType.PERMISSION);
122 roleFound.setPermission(newPermRole.getPermission());
127 * Merge fields manually from 'from' to the 'to' role
128 * -this method is created due to inefficiency of JPA EM merge
131 * @return merged role
133 private Role merge(Role from, Role to) throws Exception {
134 // A role's name cannot be changed
135 if (!(from.getRoleName().equalsIgnoreCase(to.getRoleName()))) {
136 String msg = "Role name cannot be changed " + to.getRoleName();
138 throw new BadRequestException(msg);
141 if (from.getDisplayName() != null && !from.getDisplayName().trim().isEmpty() ) {
142 to.setDisplayName(from.getDisplayName());
144 if (from.getRoleGroup() != null && !from.getRoleGroup().trim().isEmpty()) {
145 to.setRoleGroup(from.getRoleGroup());
147 if (from.getDescription() != null && !from.getDescription().trim().isEmpty()) {
148 to.setDescription(from.getDescription());
151 if (logger.isDebugEnabled()) {
152 org.collectionspace.services.authorization.ObjectFactory objectFactory =
153 new org.collectionspace.services.authorization.ObjectFactory();
154 logger.debug("Merged role on update=" + JaxbUtils.toString(objectFactory.createRole(to), Role.class));
161 public void completeCreate(DocumentWrapper<Role> wrapDoc) throws Exception {
162 Role role = wrapDoc.getWrappedObject();
164 // If there are perms in the payload, create the required role/perm relationships.
166 List<PermissionValue> permValueList = role.getPermission();
167 if (permValueList != null && permValueList.size() > 0) {
169 // To prevent new Permissions being created (especially low-level Spring Security perms), we'll first flush the current
170 // JPA context to ensure our Role can be successfully persisted.
172 TransactionContext jpaTransactionContext = this.getServiceContext().getCurrentTransactionContext();
173 jpaTransactionContext.flush();
175 // create and persist a permrole instance
176 // The caller of this method needs to ensure a valid and active EM (EntityManager) instance is in the Service context
177 RoleValue roleValue = RoleFactory.createRoleValueInstance(role);
178 PermissionRole permRole = PermissionRoleFactory.createPermissionRoleInstance(SubjectType.PERMISSION, roleValue,
179 permValueList, true, true);
180 PermissionRoleSubResource subResource =
181 new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
182 subResource.createPermissionRole(getServiceContext(), permRole, SubjectType.PERMISSION);
188 public void completeUpdate(DocumentWrapper<Role> wrapDoc) throws Exception {
189 Role updatedRole = wrapDoc.getWrappedObject();
190 getServiceContext().setOutput(updatedRole);
191 sanitize(updatedRole);
195 public void handleGet(DocumentWrapper<Role> wrapDoc) throws Exception {
196 setCommonPart(extractCommonPart(wrapDoc));
197 sanitize(getCommonPart());
198 getServiceContext().setOutput(role);
202 public void handleGetAll(DocumentWrapper<List<Role>> wrapDoc) throws Exception {
203 RolesList rolesList = extractCommonPartList(wrapDoc);
204 setCommonPartList(rolesList);
205 getServiceContext().setOutput(getCommonPartList());
209 public Role extractCommonPart(
210 DocumentWrapper<Role> wrapDoc)
212 Role role = wrapDoc.getWrappedObject();
214 String includePermsQueryParamValue = (String) getServiceContext().getQueryParams().getFirst(RoleClient.INCLUDE_PERMS_QP);
215 boolean includePerms = Tools.isTrue(includePermsQueryParamValue);
217 PermissionRoleSubResource permRoleResource =
218 new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
219 PermissionRole permRole = permRoleResource.getPermissionRole(getServiceContext(), role.getCsid(), SubjectType.PERMISSION);
220 role.setPermission(permRole.getPermission());
227 public void fillCommonPart(Role obj, DocumentWrapper<Role> wrapDoc)
229 throw new UnsupportedOperationException("operation not relevant for AccountDocumentHandler");
233 * See https://issues.collectionspace.org/browse/DRYD-181
235 * For backward compatibility, we could not change the role list to be a child class of AbstractCommonList. This
236 * would have change the result payload and would break existing API clients. So the best we can do, it treat
237 * the role list payload as a special case and return the paging information.
240 protected RolesList extractPagingInfoForRoles(RolesList roleList, DocumentWrapper<List<Role>> wrapDoc)
243 DocumentFilter docFilter = this.getDocumentFilter();
244 long pageSize = docFilter.getPageSize();
245 long pageNum = pageSize != 0 ? docFilter.getOffset() / pageSize : pageSize;
246 // set the page size and page number
247 roleList.setPageNum(pageNum);
248 roleList.setPageSize(pageSize);
249 List<Role> docList = wrapDoc.getWrappedObject();
250 // Set num of items in list. this is useful to our testing framework.
251 roleList.setItemsInPage(docList.size());
252 // set the total result size
253 roleList.setTotalItems(docFilter.getTotalItemsResult());
259 public RolesList extractCommonPartList(
260 DocumentWrapper<List<Role>> wrapDoc) throws Exception {
262 RolesList rolesList = extractPagingInfoForRoles(new RolesList(), wrapDoc);
263 List<Role> list = new ArrayList<Role>();
264 rolesList.setRole(list);
265 for (Role role : wrapDoc.getWrappedObject()) {
274 public Role getCommonPart() {
279 public void setCommonPart(Role role) {
284 public RolesList getCommonPartList() {
289 public void setCommonPartList(RolesList rolesList) {
290 this.rolesList = rolesList;
294 public String getQProperty(
300 public DocumentFilter createDocumentFilter() {
301 DocumentFilter filter = new RoleJpaFilter(this.getServiceContext());
306 * sanitize removes data not needed to be sent to the consumer
309 private void sanitize(Role role) {
310 if (!SecurityUtils.isCSpaceAdmin()) {
311 // role.setTenantId(null); // REM - There's no reason for hiding the tenant ID is there?
315 private void setTenant(Role role) {
316 //set tenant only if not available from input
317 if (role.getTenantId() == null || role.getTenantId().isEmpty()) {
318 role.setTenantId(getServiceContext().getTenantId());