import org.collectionspace.services.exhibition.ExhibitionResource;
import org.collectionspace.services.conditioncheck.ConditioncheckResource;
import org.collectionspace.services.conservation.ConservationResource;
+import org.collectionspace.services.authorization.PermissionResource;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
//import org.collectionspace.services.common.FileUtils;
-import org.collectionspace.services.authorization.PermissionResource;
import org.collectionspace.services.authorization.RoleResource;
import org.collectionspace.services.common.NuxeoBasedResource;
import org.collectionspace.services.common.ResourceMap;
final Logger logger = LoggerFactory.getLogger(AccountResource.class);
final StorageClient storageClient = new AccountStorageClient();
- private static final String PASSWORD_RESET_PATH = "requestpasswordreset";
- private static final String PROCESS_PASSWORD_RESET_PATH = "processpasswordreset";
+ private static final String PASSWORD_RESET_PATH = "/requestpasswordreset";
+ private static final String PROCESS_PASSWORD_RESET_PATH = "/processpasswordreset";
@Override
protected String getVersionString() {
--- /dev/null
+package org.collectionspace.services.client;
+
+import org.collectionspace.services.authorization.perms.ActionType;
+import org.collectionspace.services.authorization.perms.PermissionAction;
+
+public class PermissionActionFactory {
+ public static PermissionAction create(ActionType actionType) {
+ PermissionAction result = new PermissionAction();
+ result.setName(actionType);
+ return result;
+ }
+}
*/
package org.collectionspace.services.client;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
import javax.ws.rs.core.Response;
import org.apache.http.HttpStatus;
+import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionAction;
import org.collectionspace.services.authorization.perms.PermissionsList;
import org.collectionspace.services.description.ServiceDescription;
public static final String SERVICE_NAME = "authorization/permissions";
public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME;
public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT;
- public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/";
+ public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/";
+
+ public enum ActionCompare {
+ ACTION_GROUP_EMPTY, ACTION_LIST_EMPTY, ACTIONS_MISSING, MATCHES, MISMATCHES
+ }
public PermissionClient() throws Exception {
super();
return result;
}
+
+ public static String getActionGroup(List<PermissionAction> actionList) {
+ String result = null;
+ HashMap<ActionType, String> actionMap = getEmptyActionMap();
+
+ for (PermissionAction permAction : actionList) {
+ switch (permAction.getName()) {
+ case CREATE:
+ actionMap.put(ActionType.CREATE, "C");
+ break;
+ case READ:
+ actionMap.put(ActionType.READ, "R");
+ break;
+ case UPDATE:
+ actionMap.put(ActionType.UPDATE, "U");
+ break;
+ case DELETE:
+ actionMap.put(ActionType.DELETE, "D");
+ break;
+ case SEARCH:
+ actionMap.put(ActionType.SEARCH, "L");
+ break;
+ default:
+ String msg = String.format("Unknown permission action '%s'.", permAction.getName().value());
+ logger.error(null);
+ return result;
+ }
+ }
+
+ result = String.format("%s%s%s%s%s",
+ actionMap.get(ActionType.CREATE),
+ actionMap.get(ActionType.READ),
+ actionMap.get(ActionType.UPDATE),
+ actionMap.get(ActionType.DELETE),
+ actionMap.get(ActionType.SEARCH));
+
+ return result;
+ }
+
+ private static HashMap<ActionType, String> getEmptyActionMap() {
+ HashMap<ActionType, String> emptyActionMap = new HashMap<ActionType, String>();
+
+ emptyActionMap.put(ActionType.CREATE, "");
+ emptyActionMap.put(ActionType.READ, "");
+ emptyActionMap.put(ActionType.UPDATE, "");
+ emptyActionMap.put(ActionType.DELETE, "");
+ emptyActionMap.put(ActionType.SEARCH, "");
+
+ return emptyActionMap;
+ }
+
+ public static List<PermissionAction> getActionList(String actionGroup) {
+ if (actionGroup == null || actionGroup.trim().isEmpty()) {
+ return null;
+ }
+
+ List<PermissionAction> result = new ArrayList<PermissionAction>();
+ for (char c : actionGroup.toUpperCase().toCharArray()) {
+ switch (c) {
+ case 'C':
+ result.add(PermissionActionFactory.create(ActionType.CREATE));
+ break;
+ case 'R':
+ result.add(PermissionActionFactory.create(ActionType.READ));
+ break;
+ case 'U':
+ result.add(PermissionActionFactory.create(ActionType.UPDATE));
+ break;
+ case 'D':
+ result.add(PermissionActionFactory.create(ActionType.DELETE));
+ break;
+ case 'L':
+ result.add(PermissionActionFactory.create(ActionType.SEARCH));
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /*
+ * Validate that the permission's action group and action list are non-null, non-empty, and equivalent.
+ * Returns:
+ * -1 - Permission action group is empty or null
+ */
+ public static ActionCompare validatePermActions(Permission permission) {
+ String actionGroup = permission.getActionGroup();
+ List<PermissionAction> actionList = permission.getAction();
+
+ if ((actionGroup == null || actionGroup.trim().isEmpty() == true) && (actionList == null || actionList.size() < 1)) {
+ return ActionCompare.ACTIONS_MISSING;
+ }
+
+ if (actionGroup == null || actionGroup.trim().isEmpty() == true) {
+ return ActionCompare.ACTION_GROUP_EMPTY;
+ }
+
+ if (actionList == null || actionList.size() < 1) {
+ return ActionCompare.ACTION_LIST_EMPTY;
+ }
+
+ String actionGroupFromActionList = getActionGroup(permission.getAction());
+ if (actionGroupFromActionList == null || !actionGroupFromActionList.equalsIgnoreCase(actionGroup)) {
+ return ActionCompare.MISMATCHES;
+ }
+
+ return ActionCompare.MATCHES;
+ }
}
package org.collectionspace.services.client;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.authorization.perms.EffectType;
boolean useEffect) {
Permission permission = new Permission();
+
if (useResourceName) {
permission.setResourceName(resourceName);
}
if (useAction) {
permission.setAction(actionList);
+ String actionGroup = PermissionClient.getActionGroup(actionList);
+ permission.setActionGroup(actionGroup);
}
if (useEffect) {
permission.setEffect(effect);
return permission;
}
+ public static String createDefaultActionGroup() {
+ return "CRUDL";
+ }
public static List<PermissionAction> createDefaultActions() {
List<PermissionAction> actions = new ArrayList<PermissionAction>();
- PermissionAction create = new PermissionAction();
- create.setName(ActionType.CREATE);
- actions.add(create);
-
- PermissionAction read = new PermissionAction();
- read.setName(ActionType.READ);
- actions.add(read);
-
- PermissionAction update = new PermissionAction();
- update.setName(ActionType.UPDATE);
- actions.add(update);
-
- PermissionAction delete = new PermissionAction();
- delete.setName(ActionType.DELETE);
- actions.add(delete);
-
- PermissionAction search = new PermissionAction();
- search.setName(ActionType.SEARCH);
- actions.add(search);
+
+ actions.add(PermissionActionFactory.create(ActionType.CREATE));
+ actions.add(PermissionActionFactory.create(ActionType.READ));
+ actions.add(PermissionActionFactory.create(ActionType.UPDATE));
+ actions.add(PermissionActionFactory.create(ActionType.DELETE));
+ actions.add(PermissionActionFactory.create(ActionType.SEARCH));
return actions;
}
*/
@BeforeClass(alwaysRun = true)
public void seedData() throws Exception {
-
String rn1 = getRoleName();
String r1RoleId = createRole(rn1);
RoleValue rv1 = new RoleValue();
rv2.setRoleName(rn2);
roleValues.put(rv2.getRoleName(), rv2);
- String ra1 = "fooService" + TEST_MARKER;
- String permId1 = createPermission(ra1, EffectType.PERMIT);
+ String permId1 = createPermission("fooService" + TEST_MARKER);
+ Permission persistedPerm = readPermission(permId1);
PermissionValue pva1 = new PermissionValue();
- pva1.setResourceName(ra1);
+ pva1.setResourceName(persistedPerm.getResourceName());
+ pva1.setActionGroup(persistedPerm.getActionGroup());
+ pva1.setTenantId(persistedPerm.getTenantId());
pva1.setPermissionId(permId1);
permValues.put(pva1.getResourceName(), pva1);
- String ra2 = "barService" + TEST_MARKER;
- String permId2 = createPermission(ra1, EffectType.PERMIT);
+ String permId2 = createPermission("barService" + TEST_MARKER);
+ persistedPerm = readPermission(permId2);
PermissionValue pva2 = new PermissionValue();
- pva2.setResourceName(ra2);
+ pva2.setResourceName(persistedPerm.getResourceName());
+ pva2.setActionGroup(persistedPerm.getActionGroup());
+ pva2.setTenantId(persistedPerm.getTenantId());
pva2.setPermissionId(permId2);
permValues.put(pva2.getResourceName(), pva2);
}
* @return the string
* @throws Exception
*/
- private String createPermission(String resName, EffectType effect) throws Exception {
+ private String createPermission(String resName) throws Exception {
setupCreate();
PermissionClient permClient = new PermissionClient();
List<PermissionAction> actions = PermissionFactory.createDefaultActions();
Permission permission = PermissionFactory.createPermissionInstance(resName,
"default permissions for " + resName,
- actions, effect, true, true, true);
+ actions, EffectType.PERMIT, true, true, true);
Response res = null;
String id = null;
try {
}
return id;
}
+
+ private Permission readPermission(String csid) throws Exception {
+ Permission result = null;
+
+ setupRead();
+ PermissionClient permClient = new PermissionClient();
+ Response res = null;
+
+ try {
+ res = permClient.read(csid);
+ int statusCode = res.getStatus();
+ if (logger.isDebugEnabled()) {
+ logger.debug("readPermission: csid=" + csid
+ + " status = " + statusCode);
+ }
+ Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
+ invalidStatusCodeMessage(testRequestType, statusCode));
+ Assert.assertEquals(statusCode, testExpectedStatusCode);
+ result = (Permission) res.readEntity(Permission.class);
+ } finally {
+ if (res != null) {
+ res.close();
+ }
+ }
+ return result;
+ }
/**
* Delete permission.
import org.collectionspace.services.authorization.SubjectType;
import org.collectionspace.services.authorization.importer.AuthorizationGen;
import org.collectionspace.services.authorization.importer.AuthorizationSeed;
+import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon;
import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
logger.info("Seeding Permissions/Roles relationships metadata to database.");
List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
for (PermissionRole pr : authzGen.getDefaultPermissionRoles()) {
- PermissionRoleUtil.buildPermissionRoleRel(em, pr, SubjectType.ROLE, permRoleRels, false /*not for delete*/);
+ String tenantId = getTenantId(pr);
+ PermissionRoleUtil.buildPermissionRoleRel(em, pr, SubjectType.ROLE, permRoleRels, false /*not for delete*/, tenantId);
}
for (PermissionRoleRel permRoleRel : permRoleRels) {
authzStore.store(em, permRoleRel);
}
}
- private TransactionStatus beginTransaction(String name) {
+ /*
+ * Find the associated tenant ID for this permission role instance. Uses the tenant ID found in the first role.
+ */
+ private String getTenantId(PermissionRole pr) {
+ String result = null;
+
+ // Since all the role and permission values in a PermissionRole instance *must* have the same tenant ID, we
+ // can just get the tenant ID from the 0th (first) role.
+ result = pr.getRole().get(0).getTenantId();
+
+ return result;
+ }
+
+ private TransactionStatus beginTransaction(String name) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName(name);
public void associateDefaultPermissionsRoles() {
for (Permission p : adminPermList) {
- PermissionRole permAdmRole = associatePermissionRoles(p, adminRoles, true);
+ PermissionRole permAdmRole = associatePermissionToRoles(p, adminRoles, true);
adminPermRoleList.add(permAdmRole);
}
for (Permission p : readerPermList) {
- PermissionRole permRdrRole = associatePermissionRoles(p, readerRoles, true);
+ PermissionRole permRdrRole = associatePermissionToRoles(p, readerRoles, true);
readerPermRoleList.add(permRdrRole);
}
// Now associate the tenant management perms to the role
for (Permission p : tenantMgmntPermList) {
// Note we enforce tenant, as should all be tenant 0 (the special one)
- PermissionRole permTMRole = associatePermissionRoles(p, roles, true);
+ PermissionRole permTMRole = associatePermissionToRoles(p, roles, true);
tenantMgmntPermRoleList.add(permTMRole);
}
}
+ @Deprecated
public List<PermissionRole> associatePermissionsRoles(List<Permission> perms, List<Role> roles, boolean enforceTenancy) {
List<PermissionRole> result = null;
List<PermissionRole> permRoles = new ArrayList<PermissionRole>();
for (Permission perm : perms) {
- PermissionRole permRole = associatePermissionRoles(perm, roles, enforceTenancy);
+ PermissionRole permRole = associatePermissionToRoles(perm, roles, enforceTenancy);
if (permRole != null) {
permRoles.add(permRole);
}
return result;
}
- private PermissionRole associatePermissionRoles(Permission perm,
+ private PermissionRole associatePermissionToRoles(Permission perm,
List<Role> roles, boolean enforceTenancy) {
PermissionRole result = null;
PermissionRole pr = new PermissionRole();
pr.setSubject(SubjectType.ROLE);
- List<PermissionValue> permValues = new ArrayList<PermissionValue>();
- pr.setPermission(permValues);
+ List<PermissionValue> permValueList = new ArrayList<PermissionValue>();
+ pr.setPermission(permValueList);
+
PermissionValue permValue = new PermissionValue();
permValue.setPermissionId(perm.getCsid());
permValue.setResourceName(perm.getResourceName().toLowerCase());
permValue.setActionGroup(perm.getActionGroup());
- permValues.add(permValue);
+ permValue.setTenantId(perm.getTenantId());
+ permValueList.add(permValue);
List<RoleValue> roleValues = new ArrayList<RoleValue>();
for (Role role : roles) {
// This needs to use the qualified name, not the display name
rv.setRoleName(role.getRoleName().toUpperCase());
rv.setRoleId(role.getCsid());
+ rv.setTenantId(role.getTenantId());
roleValues.add(rv);
} else {
if (logger.isTraceEnabled() == true) {
<dependency>
<groupId>org.collectionspace.services</groupId>
<artifactId>org.collectionspace.services.common</artifactId>
- </dependency>
+ </dependency>
</dependencies>
<build>
--- /dev/null
+/**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.collectionspace.services.authorization;
+
+import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionsList;
+import org.collectionspace.services.authorization.storage.AuthorizationDelegate;
+import org.collectionspace.services.client.CollectionSpaceClientUtils;
+import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.PermissionClient;
+import org.collectionspace.services.common.SecurityResourceBase;
+import org.collectionspace.services.common.ServiceMessages;
+import org.collectionspace.services.common.context.RemoteServiceContextFactory;
+import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.common.context.ServiceContextFactory;
+import org.collectionspace.services.common.storage.StorageClient;
+import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
+import org.jboss.resteasy.util.HttpResponseCodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+@Path(PermissionClient.SERVICE_PATH)
+@Consumes("application/xml")
+@Produces("application/xml")
+public class PermissionResource extends SecurityResourceBase {
+
+ final Logger logger = LoggerFactory.getLogger(PermissionResource.class);
+ final StorageClient storageClient = new JpaStorageClientImpl();
+
+ @Override
+ protected String getVersionString() {
+ return "$LastChangedRevision: 1165 $";
+ }
+
+ @Override
+ public String getServiceName() {
+ return PermissionClient.SERVICE_NAME;
+ }
+
+ @Override
+ public Class<Permission> getCommonPartClass() {
+ return Permission.class;
+ }
+
+ @Override
+ public ServiceContextFactory<Permission, Permission> getServiceContextFactory() {
+ return RemoteServiceContextFactory.get();
+ }
+
+ @Override
+ public StorageClient getStorageClient(ServiceContext ctx) {
+ //FIXME use ctx to identify storage client
+ return storageClient;
+ }
+
+ @POST
+ public Response createPermission(Permission input) {
+ return create(input);
+ }
+
+ public Permission createPermissionFromInstance(Permission input) {
+ Permission result = null;
+
+ String permCsid = null;
+ Response response = createPermission(input);
+ if (response.getStatus() == Response.Status.CREATED.getStatusCode()) {
+ permCsid = CollectionSpaceClientUtils.extractId(response);
+ result = getPermission(permCsid);
+ }
+
+ return result;
+ }
+
+ @GET
+ @Path("{csid}")
+ public Permission getPermission(@PathParam("csid") String csid) {
+ return (Permission)get(csid, Permission.class);
+ }
+
+ @GET
+ @Produces("application/xml")
+ public PermissionsList getPermissionList(@Context UriInfo ui) {
+ PermissionsList result = (PermissionsList)getList(ui, Permission.class);
+ if(logger.isTraceEnabled()) {
+ PayloadOutputPart ppo = new PayloadOutputPart(PermissionsList.class.getName(), result);
+ System.out.println(ppo.asXML());
+ }
+
+ return result;
+ }
+
+ @PUT
+ @Path("{csid}")
+ public Permission updatePermission(@PathParam("csid") String csid,Permission theUpdate) {
+ return (Permission)update(csid, theUpdate, Permission.class);
+ }
+
+ @DELETE
+ @Path("{csid}")
+ public Response deletePermission(@PathParam("csid") String csid) {
+ logger.debug("deletePermission with csid=" + csid);
+ ensureCSID(csid, ServiceMessages.DELETE_FAILED + "permission ");
+ try {
+ //FIXME ideally the following two ops should be in the same tx CSPACE-658
+ //delete all relationships for this permission
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ subResource.deletePermissionRole(csid, SubjectType.ROLE);
+ //NOTE for delete permissions in the authz provider
+ //at the PermissionRoleSubResource/DocHandler level, there is no visibility
+ //if permission is deleted, so do it here, however,
+ //this is a very dangerous operation as it deletes the Spring ACL instead of ACE(s)
+ //the ACL might be needed for other ACEs roles...
+ AuthorizationDelegate.deletePermissions(csid);
+
+ ServiceContext<Permission, Permission> ctx = createServiceContext((Permission) null, Permission.class);
+ getStorageClient(ctx).delete(ctx, csid);
+ return Response.status(HttpResponseCodes.SC_OK).build();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.DELETE_FAILED, csid);
+ }
+ }
+
+ @POST
+ @Path("{csid}/permroles")
+ public Response createPermissionRole(@QueryParam("_method") String method,
+ @PathParam("csid") String permCsid,
+ PermissionRole input) {
+ if (method != null) {
+ if ("delete".equalsIgnoreCase(method)) {
+ return deletePermissionRole(permCsid, input);
+ }
+ }
+ logger.debug("createPermissionRole with permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.POST_FAILED + "permroles permission ");
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ String permrolecsid = subResource.createPermissionRole(input, SubjectType.ROLE);
+ UriBuilder path = UriBuilder.fromResource(PermissionResource.class);
+ path.path(permCsid + "/permroles/" + permrolecsid);
+ Response response = Response.created(path.build()).build();
+ return response;
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.POST_FAILED, permCsid);
+ }
+ }
+
+ @GET
+ @Path("{csid}/permroles/{id}")
+ public PermissionRoleRel getPermissionRole(
+ @PathParam("csid") String permCsid,
+ @PathParam("id") String permrolecsid) {
+ logger.debug("getPermissionRole with permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.GET_FAILED + "permroles permission ");
+ PermissionRoleRel result = null;
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ //get relationships for a permission
+ result = subResource.getPermissionRoleRel(permCsid, SubjectType.ROLE, permrolecsid);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.GET_FAILED, permCsid);
+ }
+ checkResult(result, permCsid, ServiceMessages.GET_FAILED);
+ return result;
+ }
+
+ @GET
+ @Path("{csid}/permroles")
+ public PermissionRole getPermissionRole(
+ @PathParam("csid") String permCsid) {
+ logger.debug("getPermissionRole with permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.GET_FAILED + "permroles permission ");
+ PermissionRole result = null;
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ //get relationships for a permission
+ result = subResource.getPermissionRole(permCsid, SubjectType.ROLE);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.GET_FAILED, permCsid);
+ }
+ checkResult(result, permCsid, ServiceMessages.GET_FAILED);
+ return result;
+ }
+
+ public Response deletePermissionRole(String permCsid, PermissionRole input) {
+ logger.debug("Delete payload of permrole relationships with permission permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.DELETE_FAILED + "permroles permission ");
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ //delete all relationships for a permission
+ subResource.deletePermissionRole(permCsid, SubjectType.ROLE, input);
+ return Response.status(HttpResponseCodes.SC_OK).build();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.DELETE_FAILED, permCsid);
+ }
+ }
+
+ @DELETE
+ @Path("{csid}/permroles")
+ public Response deletePermissionRole(
+ @PathParam("csid") String permCsid) {
+ logger.debug("Delete all the role relationships of the permissions with permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.DELETE_FAILED + "permroles permission ");
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ //delete all relationships for a permission
+ subResource.deletePermissionRole(permCsid, SubjectType.ROLE);
+ return Response.status(HttpResponseCodes.SC_OK).build();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.DELETE_FAILED, permCsid);
+ }
+ }
+
+}
package org.collectionspace.services.authorization.storage;
+import java.util.List;
+
import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionAction;
+import org.collectionspace.services.client.PermissionClient;
import org.collectionspace.services.common.ServiceMessages;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentHandler.Action;
boolean invalid = false;
if (action.equals(Action.CREATE)) {
-
//create specific validation here
if (permission.getResourceName() == null || permission.getResourceName().isEmpty()) {
invalid = true;
- msgBldr.append("\nresourceName : missing or empty");
+ msgBldr.append("\nThe resource name for creating a new permission resource is missing or empty.");
+ } else {
+ invalid = !validateActionFields(permission);
}
} else if (action.equals(Action.UPDATE)) {
//update specific validation here
if (permission.getResourceName() == null || permission.getResourceName().isEmpty()) {
invalid = true;
- msgBldr.append("\nresourceName : cannot be missing or empty");
+ msgBldr.append("\nThe resource name for updating an existing permission is missing or empty.");
+ } else {
+ invalid = !validateActionFields(permission);
}
}
+
if (invalid) {
String msg = msgBldr.toString();
logger.error(msg);
}
}
+ private boolean validateActionFields(Permission permission) {
+ boolean result = true;
+
+ List<PermissionAction> permActionList = permission.getAction();
+ boolean isPermActionListSet = (permActionList != null && permActionList.size() > 0);
+
+ String permActionGroup = permission.getActionGroup();
+ boolean isPermActionGroupSet = (permActionGroup != null && !permActionGroup.trim().isEmpty());
+
+ if (isPermActionListSet && isPermActionGroupSet) {
+ // the two action fields need to match
+ String derivedActionGroup = PermissionClient.getActionGroup(permActionList);
+ result = derivedActionGroup.equalsIgnoreCase(permActionGroup);
+ } else if (isPermActionListSet && !isPermActionGroupSet) {
+ // if Action list field is set but actionGroup field is not set then set the actionGroup by deriving it from the Action list
+ permission.setActionGroup(PermissionClient.getActionGroup(permActionList));
+ } else if (!isPermActionListSet && isPermActionGroupSet) {
+ // if the action list field is not set, but the action group is set then set the action actionL
+ permission.setAction(PermissionClient.getActionList(permActionGroup));
+ } else {
+ // both action fields are not set, we don't care.
+ }
+
+ return result;
+ }
+
}
}
/**
- * merge manually merges the from from to the to role
+ * Merge fields manually from 'from' to the 'to' role
* -this method is created due to inefficiency of JPA EM merge
* @param from
* @param to
* @return merged role
*/
private Role merge(Role from, Role to) throws Exception {
- //role name cannot be changed
+ // A role's name cannot be changed
if (!(from.getRoleName().equalsIgnoreCase(to.getRoleName()))) {
String msg = "Role name cannot be changed " + to.getRoleName();
logger.error(msg);
throw new BadRequestException(msg);
}
- if (from.getDisplayName() != null) {
+
+ if (from.getDisplayName() != null && !from.getDisplayName().trim().isEmpty() ) {
to.setDisplayName(from.getDisplayName());
}
- if (from.getRoleGroup() != null) {
+ if (from.getRoleGroup() != null && !from.getRoleGroup().trim().isEmpty()) {
to.setRoleGroup(from.getRoleGroup());
}
- if (from.getDescription() != null) {
+ if (from.getDescription() != null && !from.getDescription().trim().isEmpty()) {
to.setDescription(from.getDescription());
}
- // Note that we do not allow update of locks
+
if (logger.isDebugEnabled()) {
org.collectionspace.services.authorization.ObjectFactory objectFactory =
new org.collectionspace.services.authorization.ObjectFactory();
- logger.debug("merged role=" + JaxbUtils.toString(objectFactory.createRole(to) ,Role.class));
+ logger.debug("Merged role on update=" + JaxbUtils.toString(objectFactory.createRole(to), Role.class));
}
+
return to;
}
*/
private void sanitize(Role role) {
if (!SecurityUtils.isCSpaceAdmin()) {
- role.setTenantId(null);
+ role.setTenantId(null); // REM - See no reason for hiding the tenant ID?
}
}
import java.util.ArrayList;
import java.util.List;
+
import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter;
-import org.collectionspace.services.common.authorization_mgt.RoleStorageConstants;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.security.SecurityUtils;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
<xs:element name="roleId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="roleName" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="displayName" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="tenantId" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:element name="permissionId" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="resourceName" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="actionGroup" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="tenantId" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
DROP TABLE IF EXISTS roles CASCADE;
DROP SEQUENCE IF EXISTS hibernate_sequence;
create table accounts_roles (HJID int8 not null, account_id varchar(128) not null, created_at timestamp not null, role_id varchar(128) not null, role_name varchar(255), screen_name varchar(255), user_id varchar(128) not null, primary key (HJID), unique (account_id, role_id));
-create table permissions (csid varchar(128) not null, action_group varchar(128), attribute_name varchar(128), created_at timestamp not null, description varchar(255), effect varchar(32) not null, resource_name varchar(128) not null, tenant_id varchar(128) not null, updated_at timestamp, primary key (csid));
+create table permissions (csid varchar(128) not null, action_group varchar(128), attribute_name varchar(128), created_at timestamp not null, description varchar(255), effect varchar(32) not null, resource_name varchar(128) not null, tenant_id varchar(128) not null, updated_at timestamp, primary key (csid), unique (resource_name, action_group, tenant_id));
create table permissions_actions (HJID int8 not null, name varchar(128) not null, objectIdentity varchar(128) not null, objectIdentityResource varchar(128) not null, ACTION__PERMISSION_CSID varchar(128), primary key (HJID));
create table permissions_roles (HJID int8 not null, actionGroup varchar(255), created_at timestamp not null, permission_id varchar(128) not null, permission_resource varchar(255), role_id varchar(128) not null, role_name varchar(255), primary key (HJID), unique (permission_id, role_id));
create table roles (csid varchar(128) not null, created_at timestamp not null, description varchar(255), displayname varchar(200) not null, rolegroup varchar(255), rolename varchar(200) not null, tenant_id varchar(128) not null, metadata_protection varchar(255), perms_protection varchar(255), updated_at timestamp, primary key (csid), unique (rolename, tenant_id), unique (displayname, tenant_id));
<artifactId>org.collectionspace.services.authorization.service</artifactId>
<version>${project.version}</version>
</dependency>
+<!--
+ <dependency>
+ <groupId>org.collectionspace.services</groupId>
+ <artifactId>org.collectionspace.services.authorization-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ -->
<!-- Utilities -->
<!-- For NuxeoRESTClient.java class -->
*/
package org.collectionspace.services.authorization;
+import org.collectionspace.services.authorization.PermissionRole;
+import org.collectionspace.services.authorization.PermissionRoleRel;
+import org.collectionspace.services.authorization.SubjectType;
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.perms.PermissionsList;
import org.collectionspace.services.authorization.storage.AuthorizationDelegate;
+import org.collectionspace.services.client.CollectionSpaceClientUtils;
import org.collectionspace.services.client.PayloadOutputPart;
import org.collectionspace.services.client.PermissionClient;
import org.collectionspace.services.common.SecurityResourceBase;
public Response createPermission(Permission input) {
return create(input);
}
+
+ public Permission createPermissionFromInstance(Permission input) {
+ Permission result = null;
+
+ String permCsid = null;
+ Response response = createPermission(input);
+ if (response.getStatus() == Response.Status.CREATED.getStatusCode()) {
+ permCsid = CollectionSpaceClientUtils.extractId(response);
+ result = getPermission(permCsid);
+ }
+
+ return result;
+ }
@GET
@Path("{csid}")
*/
package org.collectionspace.services.authorization;
+import org.collectionspace.services.authorization.PermissionRole;
+import org.collectionspace.services.authorization.PermissionRoleRel;
+import org.collectionspace.services.authorization.Role;
+import org.collectionspace.services.authorization.SubjectType;
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.storage.PermissionRoleDocumentHandler;
-
import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
import org.collectionspace.services.common.context.RemoteServiceContextFactory;
import org.collectionspace.services.common.context.ServiceContext;
* @throws Exception
* @see PermissionRole
*/
- static void addPermissions(ServiceContext ctx, PermissionRole pr) throws Exception {
+ public static void addPermissions(ServiceContext ctx, PermissionRole pr) throws Exception {
SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr);
AuthZ authz = AuthZ.get();
if (subject.equals(SubjectType.ROLE)) {
* @param pr permissionrole
* @throws Exception
*/
- static void deletePermissions(ServiceContext ctx, PermissionRole pr)
+ public static void deletePermissions(ServiceContext ctx, PermissionRole pr)
throws Exception {
SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr);
AuthZ authz = AuthZ.get();
* @see PermissionValue
* @see CSpaceResource
*/
- private static CSpaceResource[] getResources(Permission p) {
+ private static CSpaceResource[] getResources(Permission p) { // REM - We could use PermissionValue instead -would save the caller from needing to go to the DB for the Permission instance
List<CSpaceResource> rl = new ArrayList<CSpaceResource>();
for (PermissionAction pa : p.getAction()) {
--- /dev/null
+/**
+ * This document is a part of the source code and related artifacts
+ * for CollectionSpace, an open source collections management system
+ * for museums and related institutions:
+
+ * http://www.collectionspace.org
+ * http://wiki.collectionspace.org
+
+ * Copyright 2009 University of California at Berkeley
+
+ * Licensed under the Educational Community License (ECL), Version 2.0.
+ * You may not use this file except in compliance with this License.
+
+ * You may obtain a copy of the ECL 2.0 License at
+
+ * https://source.collectionspace.org/collection-space/LICENSE.txt
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.collectionspace.services.authorization.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.persistence.EntityExistsException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.NoResultException;
+
+import org.collectionspace.services.authorization.perms.ActionType;
+import org.collectionspace.services.authorization.CSpaceAction;
+import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionAction;
+import org.collectionspace.services.authorization.perms.PermissionsList;
+import org.collectionspace.services.client.PermissionClient;
+import org.collectionspace.services.client.PermissionClient.ActionCompare;
+import org.collectionspace.services.authorization.URIResourceImpl;
+import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
+import org.collectionspace.services.common.document.BadRequestException;
+import org.collectionspace.services.common.document.DocumentException;
+import org.collectionspace.services.common.document.DocumentFilter;
+import org.collectionspace.services.common.document.DocumentWrapper;
+import org.collectionspace.services.common.document.JaxbUtils;
+import org.collectionspace.services.common.security.SecurityUtils;
+import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
+import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Document handler for Permission
+ * @author
+ */
+public class PermissionDocumentHandler
+ extends JpaDocumentHandler<Permission, PermissionsList, Permission, List> {
+
+ private final Logger logger = LoggerFactory.getLogger(PermissionDocumentHandler.class);
+ private Permission permission;
+ private PermissionsList permissionsList;
+
+ public CSpaceAction getAction(ActionType action) {
+ if (ActionType.CREATE.name().equals(action.name())) {
+ return CSpaceAction.CREATE;
+ } else if (ActionType.READ.equals(action)) {
+ return CSpaceAction.READ;
+ } else if (ActionType.UPDATE.equals(action)) {
+ return CSpaceAction.UPDATE;
+ } else if (ActionType.DELETE.equals(action)) {
+ return CSpaceAction.DELETE;
+ } else if (ActionType.SEARCH.equals(action)) {
+ return CSpaceAction.SEARCH;
+ } else if (ActionType.ADMIN.equals(action)) {
+ return CSpaceAction.ADMIN;
+ } else if (ActionType.START.equals(action)) {
+ return CSpaceAction.START;
+ } else if (ActionType.STOP.equals(action)) {
+ return CSpaceAction.STOP;
+ }
+ //
+ // We could not find a match, so we need to throw an exception.
+ //
+ throw new IllegalArgumentException("action = " + action.toString());
+ }
+
+ /*
+ * Add the ACE hashed ID to the permission action so we can map the permission to the Spring Security
+ * tables.
+ */
+ private void handlePermissionActions(Permission perm) throws DocumentException {
+ //
+ // Verify the permission actions. If the action group is missing, create it from the action list and vice versa.
+ //
+ ActionCompare compareResult = PermissionClient.validatePermActions(perm);
+ switch (compareResult) {
+ case ACTIONS_MISSING:
+ String msg = "Permission resource encountered with missing action group and action list.";
+ throw new DocumentException(msg);
+
+ case ACTION_GROUP_EMPTY:
+ String actionGroup = PermissionClient.getActionGroup(perm.getAction());
+ perm.setActionGroup(actionGroup);
+ break;
+
+ case ACTION_LIST_EMPTY:
+ List<PermissionAction> actionList = PermissionClient.getActionList(perm.getActionGroup());
+ perm.setAction(actionList);
+ break;
+
+ case MATCHES:
+ // all good
+ break;
+
+ case MISMATCHES:
+ msg = String.format("Permission has mismatching action group and action list. Action group='%s' and Action list = '%s'.",
+ perm.getActionGroup(), PermissionClient.getActionGroup(perm.getAction()));
+ throw new DocumentException(msg);
+ }
+
+ List<PermissionAction> permActions = perm.getAction();
+ for (PermissionAction permAction : permActions) {
+ CSpaceAction action = getAction(permAction.getName());
+ URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), perm.getResourceName(), action);
+ permAction.setObjectIdentity(uriRes.getHashedId().toString());
+ permAction.setObjectIdentityResource(uriRes.getId());
+ //PermissionActionUtil.update(perm, permAction);
+ }
+ }
+
+ private Permission findExistingPermission(EntityManager em, Permission perm) {
+ Permission result = null;
+ String tenantId = getServiceContext().getTenantId(); // we need a tenant ID
+
+ try {
+ result = (Permission)JpaStorageUtils.getEntityByDualKeys(em,
+ Permission.class.getName(),
+ PermissionStorageConstants.RESOURCE_NAME, perm.getResourceName(),
+ PermissionStorageConstants.ACTION_GROUP, perm.getActionGroup(),
+ tenantId);
+ } catch (NoResultException e) {
+ if (logger.isTraceEnabled()) {
+ String msg = String.format("Looked for but could not find permission with resource name = '%s', action group = '%s', tenat ID = '%s'.",
+ perm.getResourceName(), perm.getActionGroup(), tenantId);
+ logger.trace(msg);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void handleCreate(DocumentWrapper<Permission> wrapDoc) throws EntityExistsException, DocumentException {
+ //
+ // First check to see if an equivalent permission exists
+ //
+ Permission permission = wrapDoc.getWrappedObject();
+
+ EntityManager em = (EntityManager) this.getServiceContext().getProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY);
+ Permission existingPermission = findExistingPermission(em, permission);
+
+ if (existingPermission == null) {
+ String id = UUID.randomUUID().toString();
+ permission.setCsid(id);
+ setTenant(permission);
+ handlePermissionActions(permission);
+ } else {
+ String msg = String.format("Found existing permission with resource name = '%s', action group = '%s', and tenant ID = '%s'.",
+ existingPermission.getResourceName(), existingPermission.getActionGroup(), existingPermission.getTenantId());
+ wrapDoc.resetWrapperObject(existingPermission); // update the wrapped document with the existing permission instance
+ throw new EntityExistsException(msg);
+ }
+ }
+
+ @Override
+ public void completeCreate(DocumentWrapper<Permission> wrapDoc) throws Exception {
+ }
+
+ @Override
+ public void handleUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
+ Permission permissionFound = wrapDoc.getWrappedObject();
+ Permission permissionReceived = getCommonPart();
+ merge(permissionReceived, permissionFound);
+ }
+
+ /**
+ * merge manually merges the from from to the to permission
+ * -this method is created due to inefficiency of JPA EM merge
+ * @param from
+ * @param to
+ * @return merged permission
+ */
+ private Permission merge(Permission from, Permission to) throws Exception {
+ if (!(from.getResourceName().equalsIgnoreCase(to.getResourceName()))) {
+ String msg = "Resource name cannot be changed " + to.getResourceName();
+ logger.error(msg);
+ throw new BadRequestException(msg);
+ }
+ //resource name, attribute cannot be changed
+
+ if (from.getDescription() != null) {
+ to.setDescription(from.getDescription());
+ }
+ if (from.getEffect() != null) {
+ to.setEffect(from.getEffect());
+ }
+ List<PermissionAction> fromActions = from.getAction();
+ if (!fromActions.isEmpty()) {
+ // Override the whole list, no reconciliation by design
+ to.setAction(fromActions);
+ // Update the actionGroup field to reflect the new action list
+ to.setActionGroup(PermissionClient.getActionGroup(fromActions));
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("merged permission=" + JaxbUtils.toString(to, Permission.class));
+ }
+
+ handlePermissionActions(to);
+ return to;
+ }
+
+ @Override
+ public void completeUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
+ Permission upAcc = wrapDoc.getWrappedObject();
+ getServiceContext().setOutput(upAcc);
+ sanitize(upAcc);
+ //FIXME update lower-layer authorization (acls)
+ //will require deleting old permissions for this resource and adding
+ //new based on new actions and effect
+ }
+
+ @Override
+ public void handleGet(DocumentWrapper<Permission> wrapDoc) throws Exception {
+ setCommonPart(extractCommonPart(wrapDoc));
+ sanitize(getCommonPart());
+ getServiceContext().setOutput(permission);
+ }
+
+ @Override
+ public void handleGetAll(DocumentWrapper<List> wrapDoc) throws Exception {
+ PermissionsList permissionsList = extractCommonPartList(wrapDoc);
+ setCommonPartList(permissionsList);
+ getServiceContext().setOutput(getCommonPartList());
+ }
+
+ @Override
+ public void completeDelete(DocumentWrapper<Permission> wrapDoc) throws Exception {
+ }
+
+ @Override
+ public Permission extractCommonPart(
+ DocumentWrapper<Permission> wrapDoc)
+ throws Exception {
+ return wrapDoc.getWrappedObject();
+ }
+
+ @Override
+ public void fillCommonPart(Permission obj, DocumentWrapper<Permission> wrapDoc)
+ throws Exception {
+ throw new UnsupportedOperationException("operation not relevant for AccountDocumentHandler");
+ }
+
+ @Override
+ public PermissionsList extractCommonPartList(
+ DocumentWrapper<List> wrapDoc)
+ throws Exception {
+
+ PermissionsList permissionsList = new PermissionsList();
+ List<Permission> list = new ArrayList<Permission>();
+ permissionsList.setPermission(list);
+ for (Object obj : wrapDoc.getWrappedObject()) {
+ Permission permission = (Permission) obj;
+ sanitize(permission);
+ list.add(permission);
+ }
+ return permissionsList;
+ }
+
+ @Override
+ public Permission getCommonPart() {
+ return permission;
+ }
+
+ @Override
+ public void setCommonPart(Permission permission) {
+ this.permission = permission;
+ }
+
+ @Override
+ public PermissionsList getCommonPartList() {
+ return permissionsList;
+ }
+
+ @Override
+ public void setCommonPartList(PermissionsList permissionsList) {
+ this.permissionsList = permissionsList;
+ }
+
+ @Override
+ public String getQProperty(
+ String prop) {
+ return null;
+ }
+
+ @Override
+ public DocumentFilter createDocumentFilter() {
+ DocumentFilter filter = new PermissionJpaFilter(this.getServiceContext());
+ return filter;
+ }
+
+ /**
+ * Sanitize removes data not needed to be sent to the consumer
+ * @param permission
+ */
+ private void sanitize(Permission permission) {
+ if (!SecurityUtils.isCSpaceAdmin()) {
+ // permission.setTenantId(null); // REM - Why are we removing the tenant ID from the payload? Commenting out this line for now.
+ }
+ }
+
+ private void setTenant(Permission permission) {
+ //set tenant only if not available from input
+ if (permission.getTenantId() == null || permission.getTenantId().isEmpty()) {
+ permission.setTenantId(getServiceContext().getTenantId());
+ }
+ }
+}
import java.util.ArrayList;
import java.util.List;
+
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.security.SecurityUtils;
import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter;
import org.collectionspace.services.authorization.PermissionsRolesList;
import org.collectionspace.services.authorization.RoleValue;
import org.collectionspace.services.authorization.SubjectType;
+
import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel;
import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.document.DocumentFilter;
} else {
//subject mismatch should have been checked during validation
}
- PermissionRoleUtil.buildPermissionRoleRel(pr, subject, prrl, handleDelete);
+
+ String tenantId = this.getServiceContext().getTenantId();
+ PermissionRoleUtil.buildPermissionRoleRel(pr, subject, prrl, handleDelete, tenantId);
}
/* (non-Javadoc)
* limitations under the License.
*/
-package org.collectionspace.services.common.authorization_mgt;
+package org.collectionspace.services.authorization.storage;
/**
* RoleStorageConstants declares query params, etc.
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
+
import org.collectionspace.authentication.AuthN;
+
import org.collectionspace.services.client.XmlTools;
+
import org.collectionspace.services.common.api.JEEServerDeployment;
import org.collectionspace.services.common.api.FileTools;
import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
import org.collectionspace.services.common.context.ServiceBindingUtils;
import org.collectionspace.services.common.init.AddIndices;
-import org.collectionspace.services.config.service.InitHandler.Params.Field;
import org.collectionspace.services.common.init.IInitHandler;
import org.collectionspace.services.common.storage.DatabaseProductType;
import org.collectionspace.services.common.storage.JDBCTools;
+
+import org.collectionspace.services.config.service.InitHandler.Params.Field;
import org.collectionspace.services.config.ClientType;
import org.collectionspace.services.config.ServiceConfig;
import org.collectionspace.services.config.service.ServiceBindingType;
import org.collectionspace.services.config.tenant.TenantBindingType;
import org.collectionspace.services.config.types.PropertyItemType;
import org.collectionspace.services.config.types.PropertyType;
+
import org.collectionspace.services.nuxeo.client.java.NuxeoConnectorEmbedded;
import org.collectionspace.services.nuxeo.client.java.TenantRepository;
import org.collectionspace.services.nuxeo.listener.CSEventListener;
import org.collectionspace.services.nuxeo.listener.AbstractCSEventListenerImpl;
+
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.collectionspace.services.client.Profiler;
import org.collectionspace.services.client.RoleClient;
import org.collectionspace.services.client.workflow.WorkflowClient;
+
import org.collectionspace.services.common.config.ServiceConfigUtils;
import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
import org.collectionspace.services.common.context.ServiceBindingUtils;
import org.collectionspace.services.common.storage.DatabaseProductType;
import org.collectionspace.services.common.storage.JDBCTools;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
+
import org.collectionspace.services.config.service.ServiceBindingType;
import org.collectionspace.services.config.tenant.EmailConfig;
import org.collectionspace.services.config.tenant.PasswordResetConfig;
import org.collectionspace.services.config.tenant.TenantBindingType;
+
import org.collectionspace.services.lifecycle.Lifecycle;
import org.collectionspace.services.lifecycle.TransitionDef;
import org.collectionspace.services.lifecycle.TransitionDefList;
final private static String GET_TENANT_MGR_ROLE_SQL =
"SELECT csid from roles WHERE tenant_id='" + AuthN.ALL_TENANTS_MANAGER_TENANT_ID + "' and rolename=?";
+ public static final String IGNORE_TENANT_ID = null; // A null constant to indicate an empty/unused value for the tenant ID
+
public static Role getRole(String tenantId, String displayName) {
Role role = null;
public static void createDefaultWorkflowPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions
{
+ java.util.logging.Logger logger = java.util.logging.Logger.getAnonymousLogger();
+
AuthZ.get().login(); //login to Spring Security manager
EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);
if (adminRole == null || readonlyRole == null) {
String msg = String.format("One or more of the required default CollectionSpace administrator roles is missing or was never created. If you're setting up a new instance of CollectionSpace, shutdown the Tomcat server and run the 'ant import' command from the root/top level CollectionSpace 'Services' source directory. Then try restarting Tomcat.");
- logger.error(msg);
+ logger.info(msg);
throw new RuntimeException("One or more of the required default CollectionSpace administrator roles is missing or was never created.");
}
}
em.getTransaction().commit();
} catch (IllegalStateException e) {
- logger.debug(e.getLocalizedMessage(), e); //We end up here if there is no document handler for the service -this is ok for some of the services.
+ logger.fine(e.getLocalizedMessage()); //We end up here if there is no document handler for the service -this is ok for some of the services.
}
} else {
- logger.warn("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "
+ logger.warning("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "
+ serviceBinding.getName());
}
}
if (em != null && em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
- if (logger.isDebugEnabled()) {
- logger.debug("Caught exception and rolling back permission creation: ", e);
- }
+ logger.fine("Caught exception and rolling back permission creation: " + e.getMessage());
throw e;
} finally {
if (em != null) {
if (permRoleRel == null) {
PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);
List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
- PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);
+ PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels,
+ false /*not for delete*/, role.getTenantId());
for (PermissionRoleRel prr : permRoleRels) {
authzStore.store(em, prr);
}
import org.collectionspace.services.authorization.Role;
import org.collectionspace.services.authorization.PermissionRoleRel;
import org.collectionspace.services.authorization.perms.Permission;
-import org.collectionspace.services.common.authorization_mgt.RoleStorageConstants;
+import org.collectionspace.services.authorization.storage.RoleStorageConstants;
import org.collectionspace.services.common.document.JaxbUtils;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
import org.slf4j.Logger;
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStore.class);
private final static String PERSISTENCE_UNIT = "org.collectionspace.services.authorization";
+ public final static String ENTITY_MANAGER_PROP_KEY = EntityManager.class.getCanonicalName();
static public Role getRoleByName(String roleName, String tenantId) {
Role theRole = null;
*/
package org.collectionspace.services.common.authorization_mgt;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
+import javax.persistence.NoResultException;
+import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.context.ServiceContextProperties;
-import org.collectionspace.services.common.storage.jpa.JpaRelationshipStorageClient;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
+import org.collectionspace.services.authorization.perms.ActionType;
+import org.collectionspace.services.authorization.perms.EffectType;
import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionAction;
+import org.collectionspace.services.authorization.storage.PermissionStorageConstants;
+import org.collectionspace.services.authorization.PermissionResource;
import org.collectionspace.services.authorization.PermissionRole;
import org.collectionspace.services.authorization.PermissionRoleRel;
import org.collectionspace.services.authorization.PermissionValue;
-import org.collectionspace.services.authorization.Role;
import org.collectionspace.services.authorization.RoleValue;
import org.collectionspace.services.authorization.SubjectType;
PermissionRole pr,
SubjectType subject,
List<PermissionRoleRel> prrl,
- boolean handleDelete) throws Exception {
+ boolean handleDelete,
+ String tenantId) throws Exception {
+
if (subject.equals(SubjectType.ROLE)) {
List<PermissionValue> permissionValues = pr.getPermission();
if (permissionValues != null && permissionValues.size() > 0) {
PermissionValue pv = permissionValues.get(0);
for (RoleValue rv : pr.getRole()) {
- PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete);
+ PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId);
prrl.add(prr);
}
}
if (roleValues != null && roleValues.size() > 0) {
RoleValue rv = roleValues.get(0);
for (PermissionValue pv : pr.getPermission()) {
- PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete);
+ PermissionRoleRel prr = buildPermissonRoleRel(em, pv, rv, subject, handleDelete, tenantId);
prrl.add(prr);
}
}
PermissionRole pr,
SubjectType subject,
List<PermissionRoleRel> prrl,
- boolean handleDelete) throws Exception {
+ boolean handleDelete,
+ String tenantId) throws Exception {
EntityManagerFactory emf = null;
EntityManager em = null;
try {
em = emf.createEntityManager();
em.getTransaction().begin();
- buildPermissionRoleRel(em, pr, subject, prrl, handleDelete);
+ buildPermissionRoleRel(em, pr, subject, prrl, handleDelete, tenantId);
em.getTransaction().commit();
em.close();
}
}
+ /*
+ * Try to find a persisted Permission record using a PermissionValue instance.
+ *
+ */
+ static private Permission lookupPermission(EntityManager em, PermissionValue permissionValue, String tenantId) {
+ Permission result = null;
+
+ String actionGroup = permissionValue.getActionGroup() != null ? permissionValue.getActionGroup().trim() : null;
+ String resourceName = permissionValue.getResourceName() != null ? permissionValue.getResourceName().trim() : null;
+ String permissionId = permissionValue.getPermissionId() != null ? permissionValue.getPermissionId().trim() : null;
+ //
+ // If we have a permission ID, use it to try to lookup the persisted permission
+ //
+ if (permissionId != null && !permissionId.isEmpty()) {
+ try {
+ result = (Permission)JpaStorageUtils.getEntity(em, permissionId, Permission.class);
+ } catch (Throwable e) {
+ String msg = String.format("Searched for but couldn't find a permission with CSID='%s'.",
+ permissionId);
+ logger.trace(msg);
+ }
+ } else if ((resourceName != null && !resourceName.isEmpty()) &&
+ (actionGroup != null && !actionGroup.isEmpty())) {
+ //
+ // If there was no permission ID, then we can try to find the permission with the resource name and action group tuple
+ //
+ try {
+ result = (Permission)JpaStorageUtils.getEntityByDualKeys(em,
+ Permission.class.getName(),
+ PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(),
+ PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(),
+ tenantId);
+ } catch (NoResultException e) {
+ String msg = String.format("Searched for but couldn't find a permission for resource='%s', action group='%s', and tenant ID='%s'.",
+ permissionValue.getResourceName(), permissionValue.getActionGroup(), tenantId);
+ logger.trace(msg);
+ }
+ } else {
+ 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'.",
+ permissionId, resourceName, actionGroup);
+ logger.warn(errMsg);
+ }
+
+ return result;
+ }
+
/**
* Builds a permisson role relationship for either 'create' or 'delete'
*
* @param rv the rv (currently using only the ID)
* @param handleDelete the handle delete
* @return the permission role rel
+ * @throws DocumentException
*/
static private PermissionRoleRel buildPermissonRoleRel(EntityManager em, PermissionValue permissionValue,
RoleValue roleValue,
SubjectType subject,
- boolean handleDelete)
- throws DocumentNotFoundException {
+ boolean handleDelete, // if 'true' then we're deleting not building a permission-role record
+ String tenantId) throws DocumentException {
PermissionRoleRel result = null;
+ Permission permission = lookupPermission(em, permissionValue, tenantId);
//
- // Ensure we can find both the Permission and Role to relate.
- // FIXME: REM - This is a workaround until the Import utility creates Perm/Role relationships
- // correctly. The import utility should create and store the permissions and roles BEFORE creating the relationships
+ // If we couldn't find an existing permission and we're not processing a DELETE request, we need to create
+ // a new permission.
//
- PermissionValue pv = permissionValue;
-
- //
- // This lookup is slow, do we really need it?
- //
- /*
- try {
- Permission permission = (Permission)JpaStorageUtils.getEntity(em, pv.getPermissionId(), //FIXME: REM 4/5/2012 - To improve performance, we should use a passed in Permission instance
- Permission.class);
- if (permission != null) {
- // If the permission already exists, then use it to fill our the relation record
- pv = JpaRelationshipStorageClient.createPermissionValue(permission);
- }
- } catch (DocumentNotFoundException e) {
- // ignore this exception, pv is set to permissionValue;
+ if (permission == null && handleDelete == false) {
+ permission = new Permission();
+ permission.setResourceName(permissionValue.getResourceName());
+ permission.setActionGroup(permissionValue.getActionGroup());
+ permission.setEffect(EffectType.PERMIT); // By default, CollectionSpace currently (11/2017) supports only PERMIT
+ List<PermissionAction> actionList = createPermActionList(permissionValue.getActionGroup());
+ permission.setAction(actionList);
+ permission = createPermission(permission);
+ if (permission == null) {
+ String errMsg = "Could not create new permission for new permission-role relationship.";
+ throw new DocumentException(errMsg);
+ }
}
- */
//
- // Ensure we can find both the Permission and Role to relate.
- // FIXME: REM - This is a workaround until the Import utility creates Perm/Role relationships
- // correctly. The import utility should create and store the permissions and roles BEFORE creating the relationships
+ // Create the permission-role to persist
//
- RoleValue rv = roleValue;
-
- /*
- * This lookup is slow, can we avoid it?
- try {
- Role role = (Role)JpaStorageUtils.getEntity(em, rv.getRoleId(),
- Role.class);
- if (role != null) {
- // If the role already exists, then use it to fill out the relation record
- rv = JpaRelationshipStorageClient.createRoleValue(role);
- }
- } catch (DocumentNotFoundException e) {
- // ignore this exception, rv is set to roleValue
- }
- */
-
result = new PermissionRoleRel();
- result.setPermissionId(pv.getPermissionId());
- result.setPermissionResource(pv.getResourceName());
- result.setActionGroup(pv.getActionGroup());
- result.setRoleId(rv.getRoleId());
- result.setRoleName(rv.getRoleName());
+ result.setPermissionId(permission.getCsid());
+ result.setPermissionResource(permission.getResourceName());
+ result.setActionGroup(permission.getActionGroup());
+ result.setRoleId(roleValue.getRoleId());
+ result.setRoleName(roleValue.getRoleName());
+
//
// For 'delete' we need to set the hjid of the existing relstionship
//
return result;
}
- /**
+ private static Permission createPermission(Permission permission) {
+ Permission result = null;
+
+ PermissionResource permissionResource = new PermissionResource(); // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton)
+ result = permissionResource.createPermissionFromInstance(permission);
+
+ return result;
+ }
+
+ private static List<PermissionAction> createPermActionList(String actionGroup) throws DocumentException {
+ ArrayList<PermissionAction> result = new ArrayList<PermissionAction>();
+
+ for (char c : actionGroup.toUpperCase().toCharArray()) {
+ PermissionAction permAction = new PermissionAction();
+ switch (c) {
+ case 'C':
+ permAction.setName(ActionType.CREATE);
+ break;
+
+ case 'R':
+ permAction.setName(ActionType.READ);
+ break;
+
+ case 'U':
+ permAction.setName(ActionType.UPDATE);
+ break;
+
+ case 'D':
+ permAction.setName(ActionType.DELETE);
+ break;
+
+ case 'L':
+ permAction.setName(ActionType.SEARCH);
+ break;
+
+ default:
+ String errMsg = String.format("Illegal action group token '%c' in permission action group '%s'.",
+ c, actionGroup);
+ throw new DocumentException(errMsg);
+ }
+
+ if (result.add(permAction) == false) {
+ String warnMsg = String.format("Illegal or duplicate action group token '%c' in permission action group '%s'.",
+ c, actionGroup);
+ logger.warn(warnMsg);
+ }
+ }
+
+ return result;
+ }
+
+ /**
* Checks if is invalid tenant.
*
* @param tenantId the tenant id
* @return wrapped object
*/
public T getWrappedObject();
+ public T resetWrapperObject(T newObject);
}
this.wrappedObject = obj;
}
- public T getWrappedObject() {
+ @Override
+ public T getWrappedObject() {
return wrappedObject;
}
+
+ @Override
+ public T resetWrapperObject(T newObject) {
+ wrappedObject = newObject;
+ return wrappedObject;
+ }
}
\ No newline at end of file
em.remove(getRelationship(em, r));
}
em.getTransaction().commit();
- handler.complete(Action.DELETE, wrapDoc);
+ handler.complete(Action.DELETE, wrapDoc); // Delete from the Spring Security tables. Would be better if this was part of the earlier transaction.
} catch (DocumentException de) {
if (em != null && em.getTransaction().isActive()) {
em.getTransaction().rollback();
import java.sql.BatchUpdateException;
+import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthorityItemSpecifier;
import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.Specifier;
import org.collectionspace.services.common.context.ServiceContextProperties;
+import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.query.QueryContext;
import org.collectionspace.services.lifecycle.TransitionDef;
public String create(ServiceContext ctx,
DocumentHandler handler) throws BadRequestException,
DocumentException {
- boolean rollbackTransaction = false;
if (ctx == null) {
throw new IllegalArgumentException(
"create: ctx is missing");
throw new IllegalArgumentException(
"create: handler is missing");
}
+
+ boolean rollbackTransaction = false;
EntityManagerFactory emf = null;
EntityManager em = null;
try {
handler.prepare(Action.CREATE);
Object entity = handler.getCommonPart();
DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
- handler.handle(Action.CREATE, wrapDoc);
- JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date());
- emf = JpaStorageUtils.getEntityManagerFactory();
+
+ emf = JpaStorageUtils.getEntityManagerFactory();
em = emf.createEntityManager();
- em.getTransaction().begin(); { //begin of transaction block
- em.persist(entity);
+ em.getTransaction().begin(); { //begin of transaction block
+ ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, em);
+ try {
+ handler.handle(Action.CREATE, wrapDoc);
+ JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date());
+ em.persist(entity);
+ } catch (EntityExistsException ee) {
+ //
+ // We found an existing matching entity in the store, so we don't need to create one. Just update the transient 'entity' instance with the existing persisted entity we found.
+ //
+ entity = wrapDoc.getWrappedObject(); // the handler should have reset the wrapped transient object with the existing persisted entity we just found.
+ }
}
em.getTransaction().commit();
handler.complete(Action.CREATE, wrapDoc);
}
throw DocumentException.createDocumentException(e);
} finally {
+ ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, null);
if (em != null) {
if (rollbackTransaction == true) {
if (em.getTransaction().isActive() == true) {
handler.handle(Action.DELETE, wrapDoc);
em.remove(entityFound);
em.getTransaction().commit();
-
handler.complete(Action.DELETE, wrapDoc);
} catch (DocumentException de) {
if (em != null && em.getTransaction().isActive()) {
boolean result = true;
boolean csAdmin = SecurityUtils.isCSpaceAdmin();
- if (csAdmin == true || tenantId == null) {
+ if (csAdmin == true) {
+ logger.trace("Running as the CSAdmin user.");
+ //Thread.dumpStack();
+ }
+
+ if (tenantId == null) {
result = false;
+ logger.trace("Ignoring tenant ID during .");
+ //Thread.dumpStack();
}
return result;
}
- public static Object getEntity(String id, Class entityClazz)
- throws DocumentNotFoundException {
+ public static Object getEntity(String id, Class entityClazz) {
EntityManagerFactory emf = null;
EntityManager em = null;
Object entityFound = null;
em = emf.createEntityManager();
//FIXME: it would be nice to verify tenantid as well
entityFound = em.find(entityClazz, id);
+ } catch (Throwable t) {
+ throw t;
} finally {
if (em != null) {
releaseEntityManagerFactory(emf);
</xs:documentation>
<xs:appinfo>
<hj:entity>
- <orm:table name="permissions" />
+ <orm:table name="permissions">
+ <orm:unique-constraint>
+ <!-- combined length should be < 1000 bytes -->
+ <orm:column-name>resource_name</orm:column-name>
+ <orm:column-name>action_group</orm:column-name>
+ <orm:column-name>tenant_id</orm:column-name>
+ </orm:unique-constraint>
+ </orm:table>
</hj:entity>
</xs:appinfo>
</xs:annotation>