]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-3764, CSPACE-3710, CSPACE-3709: AuthZ support for Dimensions service as a...
authorRichard Millet <richard.millet@berkeley.edu>
Wed, 6 Apr 2011 04:59:50 +0000 (04:59 +0000)
committerRichard Millet <richard.millet@berkeley.edu>
Wed, 6 Apr 2011 04:59:50 +0000 (04:59 +0000)
20 files changed:
services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java
services/client/src/main/java/org/collectionspace/services/client/AbstractServiceClientImpl.java
services/client/src/main/java/org/collectionspace/services/client/CollectionSpaceProxy.java
services/client/src/main/java/org/collectionspace/services/client/PayloadOutputPart.java
services/client/src/main/java/org/collectionspace/services/client/test/AbstractServiceTestImpl.java
services/client/src/main/java/org/collectionspace/services/client/workflow/WorkflowClient.java
services/common/src/main/cspace/config/services/tenants/collectionspace/tenant-bindings.xml
services/common/src/main/java/org/collectionspace/services/common/AbstractMultiPartCollectionSpaceResourceImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContext.java
services/common/src/main/java/org/collectionspace/services/common/context/MultipartServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java
services/common/src/main/java/org/collectionspace/services/common/workflow/service/nuxeo/WorkflowDocumentModelHandler.java
services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RemoteDocumentModelHandlerImpl.java
services/dimension/client/src/test/java/org/collectionspace/services/client/test/DimensionServiceTest.java
services/jaxb/src/main/resources/workflow_common.xsd [moved from services/jaxb/src/main/resources/workflows_common.xsd with 97% similarity]
services/workflow/3rdparty/nuxeo-platform-cs-workflow/src/main/resources/OSGI-INF/core-types-contrib.xml
services/workflow/3rdparty/nuxeo-platform-cs-workflow/src/main/resources/schemas/workflow_common.xsd [moved from services/workflow/3rdparty/nuxeo-platform-cs-workflow/src/main/resources/schemas/workflows_common.xsd with 100% similarity]
services/workflow/client/src/test/java/org/collectionspace/services/client/test/WorkflowServiceTest.java
services/workflow/service/src/main/java/org/collectionspace/services/workflow/nuxeo/WorkflowValidatorHandler.java

index 450b0f3c0f53fa053ed74e2dc116f6be1ccc01e9..c203f80df16fd4f99fb91f846060f6da59f43121 100644 (file)
@@ -63,11 +63,16 @@ public class AuthorizationGen {
     final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";
     final public static String ROLE_TENANT_READER = "TENANT_READER";
     final public static String ROLE_ADMINISTRATOR_ID = "0";
+    final public static String ADMINISTRATOR_TENANT_ID = "0";
     //
     // ActionGroup labels/constants
     //
     final public static String ACTIONGROUP_CRUDL = "CRUDL";
     final public static String ACTIONGROUP_RL = "RL";
+    //
+    // Should the base resource act as a proxy for its sub-resources for AuthZ purposes
+    //
+    final public static boolean AUTHZ_IS_ENTITY_PROXY = false;
     
     final Logger logger = LoggerFactory.getLogger(AuthorizationGen.class);
     private List<Permission> adminPermList = new ArrayList<Permission>();
@@ -100,10 +105,10 @@ public class AuthorizationGen {
      */
     public void createDefaultPermissions() {
         for (String tenantId : tenantBindings.keySet()) {
-            List<Permission> adminPerms = createDefaultAdminPermissions(tenantId);
+            List<Permission> adminPerms = createDefaultAdminPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY);
             adminPermList.addAll(adminPerms);
 
-            List<Permission> readerPerms = createDefaultReaderPermissions(tenantId);
+            List<Permission> readerPerms = createDefaultReaderPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY);
             readerPermList.addAll(readerPerms);
         }
     }
@@ -114,14 +119,14 @@ public class AuthorizationGen {
      * @param tenantId
      * @return
      */
-    public List<Permission> createDefaultAdminPermissions(String tenantId) {
+    public List<Permission> createDefaultAdminPermissions(String tenantId, boolean isEntityProxy) {
         ArrayList<Permission> apcList = new ArrayList<Permission>();
         TenantBindingType tbinding = tenantBindings.get(tenantId);
         for (ServiceBindingType sbinding : tbinding.getServiceBindings()) {
 
             //add permissions for the main path
                String resourceName = sbinding.getName().toLowerCase().trim();
-               if (SecurityUtils.isEntityProxy() == true) {
+               if (isEntityProxy == true) {
                        resourceName = SecurityUtils.getResourceEntity(resourceName);
                }
             Permission perm = buildAdminPermission(tbinding.getId(),
@@ -129,7 +134,7 @@ public class AuthorizationGen {
             apcList.add(perm);
 
             //add permissions for alternate paths
-            if (SecurityUtils.isEntityProxy() == false) {
+            if (isEntityProxy == false) {
                    List<String> uriPaths = sbinding.getUriPath();
                    for (String uriPath : uriPaths) {
                        perm = buildAdminPermission(tbinding.getId(),
@@ -180,13 +185,13 @@ public class AuthorizationGen {
      * @param tenantId
      * @return
      */
-    public List<Permission> createDefaultReaderPermissions(String tenantId) {
+    public List<Permission> createDefaultReaderPermissions(String tenantId, boolean isEntityProxy) {
         ArrayList<Permission> apcList = new ArrayList<Permission>();
         TenantBindingType tbinding = tenantBindings.get(tenantId);
         for (ServiceBindingType sbinding : tbinding.getServiceBindings()) {
             //add permissions for the main path
                String resourceName = sbinding.getName().toLowerCase().trim();
-               if (SecurityUtils.isEntityProxy() == true) {
+               if (isEntityProxy == true) {
                        resourceName = SecurityUtils.getResourceEntity(resourceName);
                }               
             Permission perm = buildReaderPermission(tbinding.getId(),
@@ -194,7 +199,7 @@ public class AuthorizationGen {
             apcList.add(perm);
 
             //add permissions for alternate paths
-            if (SecurityUtils.isEntityProxy() == false) {
+            if (isEntityProxy == false) {
                    List<String> uriPaths = sbinding.getUriPath();
                    for (String uriPath : uriPaths) {
                        perm = buildReaderPermission(tbinding.getId(),
@@ -298,12 +303,12 @@ public class AuthorizationGen {
 
     public void associateDefaultPermissionsRoles() {
         for (Permission p : adminPermList) {
-            PermissionRole permAdmRole = associatePermissionRoles(p, adminRoles);
+            PermissionRole permAdmRole = associatePermissionRoles(p, adminRoles, true);
             adminPermRoleList.add(permAdmRole);
         }
 
         for (Permission p : readerPermList) {
-            PermissionRole permRdrRole = associatePermissionRoles(p, readerRoles);
+            PermissionRole permRdrRole = associatePermissionRoles(p, readerRoles, true);
             readerPermRoleList.add(permRdrRole);
         }
         
@@ -311,23 +316,33 @@ public class AuthorizationGen {
         List<Role> roles = new ArrayList<Role>();
         roles.add(cspaceAdminRole);
         for (Permission p : adminPermList) {
-            PermissionRole permCAdmRole = associatePermissionRoles(p, roles);
+            PermissionRole permCAdmRole = associatePermissionRoles(p, roles, false);
             adminPermRoleList.add(permCAdmRole);
         }        
     }
 
-    public List<PermissionRole> associatePermissionsRoles(List<Permission> perms, List<Role> roles) {
+    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);
-            permRoles.add(permRole);
+            PermissionRole permRole = associatePermissionRoles(perm, roles, enforceTenancy);
+            if (permRole != null) {
+               permRoles.add(permRole);
+            }
+        }
+        
+        if (permRoles.isEmpty() == false) {
+               result = permRoles;
         }
-        return permRoles;
+        
+        return result;
     }
 
     private PermissionRole associatePermissionRoles(Permission perm,
-            List<Role> roles) {
-
+            List<Role> roles, boolean enforceTenancy) {
+       PermissionRole result = null;
+       
         PermissionRole pr = new PermissionRole();
         pr.setSubject(SubjectType.ROLE);
         List<PermissionValue> permValues = new ArrayList<PermissionValue>();
@@ -340,15 +355,32 @@ public class AuthorizationGen {
 
         List<RoleValue> roleValues = new ArrayList<RoleValue>();
         for (Role role : roles) {
-            RoleValue rv = new RoleValue();
-            // This needs to use the qualified name, not the display name
-            rv.setRoleName(role.getRoleName().toUpperCase());
-            rv.setRoleId(role.getCsid());
-            roleValues.add(rv);
+               boolean tenantIdsMatched = true;
+               if (enforceTenancy == true) {
+                       tenantIdsMatched = role.getTenantId().equals(perm.getTenantId());
+               }
+               if (tenantIdsMatched == true) {
+                   RoleValue rv = new RoleValue();
+                   // This needs to use the qualified name, not the display name
+                   rv.setRoleName(role.getRoleName().toUpperCase());
+                   rv.setRoleId(role.getCsid());
+                   roleValues.add(rv);
+               } else {
+                       if (logger.isDebugEnabled() == true) {
+                               logger.debug("Role and Permission tenant ID did not match."); //FIXME: REM - Remove this debug statement.
+                       }
+               }
+        }
+        //
+        // If 'roleValues' is not empty, then associate it with the incoming 'perm' values
+        // otherwise, return null;
+        //
+        if (roleValues.isEmpty() == false) {
+               pr.setRoles(roleValues);
+               result = pr;
         }
-        pr.setRoles(roleValues);
 
-        return pr;
+        return result;
     }
 
     public List<PermissionRole> getDefaultPermissionRoles() {
@@ -371,6 +403,7 @@ public class AuthorizationGen {
         role.setDisplayName(ROLE_ADMINISTRATOR);
         role.setRoleName(ROLE_PREFIX + role.getDisplayName());
         role.setCsid(ROLE_ADMINISTRATOR_ID);
+        role.setTenantId(ADMINISTRATOR_TENANT_ID);
         return role;
     }
 
index dbd105c4dc3b0583706a733c49f2c0dd38433455..84e01ee70131bd5bd3b82dfa9e060818c89f2ea5 100644 (file)
@@ -37,7 +37,7 @@ import org.apache.commons.httpclient.auth.AuthScope; //import org.collectionspac
 \r
 import org.collectionspace.services.common.authorityref.AuthorityRefList;\r
 import org.collectionspace.services.jaxb.AbstractCommonList;\r
-import org.collectionspace.services.workflow.WorkflowsCommon;\r
+import org.collectionspace.services.workflow.WorkflowCommon;\r
 import org.jboss.resteasy.client.ClientResponse; //import org.collectionspace.services.common.context.ServiceContext;\r
 import org.jboss.resteasy.client.ProxyFactory;\r
 import org.jboss.resteasy.client.core.executors.ApacheHttpClientExecutor;\r
index d751eb5f34621778954624bf7d426f414304cafa..fd1f667baf4bf039b5abf36d4a74301faa5afedd 100644 (file)
@@ -36,6 +36,7 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;\r
 import javax.ws.rs.core.Response;\r
 \r
+import org.collectionspace.services.client.workflow.WorkflowClient;\r
 import org.collectionspace.services.common.authorityref.AuthorityRefList;\r
 import org.collectionspace.services.jaxb.AbstractCommonList;\r
 \r
@@ -61,13 +62,13 @@ public interface CollectionSpaceProxy {
     @GET\r
     @Produces({"application/xml"})\r
     @Consumes({"application/xml"})    \r
-    @Path("{csid}/workflow")\r
+    @Path("{csid}" + WorkflowClient.SERVICE_PATH)\r
     ClientResponse<String> getWorkflow(@PathParam("csid") String csid);\r
     \r
     @PUT\r
     @Produces({"application/xml"})\r
     @Consumes({"application/xml"})    \r
-    @Path("{csid}/workflow")\r
+    @Path("{csid}" + WorkflowClient.SERVICE_PATH)\r
     ClientResponse<String> updateWorkflow(@PathParam("csid") String csid, byte[] xmlPayload);\r
     \r
     /*\r
index 96e1f1af8010ef6fee3bfa9ac0e5a94963384a17..bd8c50caa4e7c7dcae6e72f5c1232051c9a5fac7 100644 (file)
@@ -8,7 +8,7 @@ public class PayloadOutputPart extends PayloadPart {
        //\r
        // Constructors\r
        //\r
-       PayloadOutputPart(String label, Object body) {\r
+       public PayloadOutputPart(String label, Object body) {\r
                super(label, body);\r
        }\r
        \r
index c871478f8d3f3586b1e98fce04a54ae05a1b7c4a..9f2a6686995dfb3e93811373d8b53d757622716d 100644 (file)
@@ -28,7 +28,13 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.workflow.WorkflowCommon;
+import org.collectionspace.services.client.AbstractPoxServiceClientImpl;
 import org.collectionspace.services.client.CollectionSpaceClient;
+import org.collectionspace.services.client.PayloadOutputPart;
+import org.collectionspace.services.client.PoxPayloadIn;
+import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.jboss.resteasy.client.ClientResponse;
 
 import org.slf4j.Logger;
@@ -39,6 +45,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
 import javax.activation.MimetypesFileTypeMap;
+import javax.ws.rs.core.Response;
 
 
 /**
@@ -595,17 +602,59 @@ public abstract class AbstractServiceTestImpl extends BaseServiceTest implements
                                totalItems);//expected total num of items
         }
     }
-
-//     @Override
-//     protected CollectionSpaceClient getClientInstance() {
-//             throw new UnsupportedOperationException(); //FIXME: REM - See http://issues.collectionspace.org/browse/CSPACE-3498
-//     }
-//     
-//     @Override
-//     protected String getServiceName() {
-//             throw new UnsupportedOperationException(); //FIXME: REM - See http://issues.collectionspace.org/browse/CSPACE-3498
-//     }
-
+    
+    @SuppressWarnings("rawtypes")
+       protected void updateLifeCycleState(String testName, String resourceId, String lifeCycleState) throws Exception {
+        //
+        // Read the existing object
+        //
+       CollectionSpaceClient client = this.getClientInstance();
+       ClientResponse<String> res = client.getWorkflow(resourceId);
+        assertStatusCode(res, testName);
+        logger.debug("Got object to update life cycle state with ID: " + resourceId);
+        PoxPayloadIn input = new PoxPayloadIn(res.getEntity());
+        WorkflowCommon workflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(workflowCommons);
+        //
+        // Mark it for a soft delete.
+        //
+        logger.debug("Current workflow state:" + objectAsXmlString(workflowCommons, WorkflowCommon.class));
+        workflowCommons.setCurrentLifeCycleState(lifeCycleState);
+        PoxPayloadOut output = new PoxPayloadOut(WorkflowClient.SERVICE_PAYLOAD_NAME);
+        PayloadOutputPart commonPart = output.addPart(WorkflowClient.SERVICE_COMMONPART_NAME, workflowCommons);
+        //
+        // Perform the update
+        //
+        res = client.updateWorkflow(resourceId, output);
+        assertStatusCode(res, testName);
+        input = new PoxPayloadIn(res.getEntity());
+        WorkflowCommon updatedWorkflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(updatedWorkflowCommons);
+        //
+        // Read the updated object and make sure it was updated correctly.
+        //
+        res = client.getWorkflow(resourceId);
+        assertStatusCode(res, testName);
+        logger.debug("Got workflow state of updated object with ID: " + resourceId);
+        input = new PoxPayloadIn(res.getEntity());
+        updatedWorkflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(workflowCommons);
+        Assert.assertEquals(updatedWorkflowCommons.getCurrentLifeCycleState(), lifeCycleState);
+    }
+    
+    /*
+     * Sub-classes must override for the workflow tests.
+     */
+    
+    protected String createWorkflowTarget(String testName) throws Exception {
+       logger.warn("Sub-class test clients should override this method");
+       throw new UnsupportedOperationException();
+    }
+    
+    protected String createTestObject(String testName) throws Exception {
+       logger.warn("Sub-class test clients should override this method");
+       throw new UnsupportedOperationException();
+    }
 }
 
 
index bbbcc5b34820402668c9faf39880e0ac947a0e2d..108009054cdd3c01811bdea9db2f35dc243bf306 100644 (file)
@@ -27,11 +27,12 @@ import org.collectionspace.services.client.AbstractPoxServiceClientImpl;
  *
  */
 public class WorkflowClient extends AbstractPoxServiceClientImpl<AbstractCommonList, WorkflowProxy> {
-       public static final String SERVICE_NAME = "workflows";
+       public static final String SERVICE_NAME = "workflow";
        public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME;       
        public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT;
        public static final String SERVICE_PAYLOAD_NAME = SERVICE_NAME;
        public static final String SERVICE_COMMONPART_NAME = SERVICE_NAME + PART_LABEL_SEPARATOR + PART_COMMON_LABEL;
+       public static final String SERVICE_AUTHZ_SUFFIX = "/*/" + SERVICE_PATH_COMPONENT + "/";
        //
        // Workflow states
        //
index bf4136a5213ae22ff9ff18e89c4286e9fd4caa46..aa0ff82d6f3505df52ef69cb3fdffe21b814369f 100644 (file)
         <!-- end movement service meta-data -->
 
         <!-- begin Workflow service meta-data -->
-        <tenant:serviceBindings name="Workflows" type="procedure" version="0.1">
+        <tenant:serviceBindings name="Workflow" type="procedure" version="0.1">
             <service:repositoryDomain xmlns:service='http://collectionspace.org/services/common/service'>
                 default-domain
             </service:repositoryDomain>
                             xmlns:service='http://collectionspace.org/services/common/service'>
                 <service:part id="0" control_group="Managed"
                               versionable="true" auditable="false"
-                              label="workflows-system" updated="" order="0">
+                              label="workflow-system" updated="" order="0">
                     <service:content contentType="application/xml">
                         <service:xmlContent
                             namespaceURI="http://collectionspace.org/services/common/system"
                 </service:part>
                 <service:part id="1" control_group="Managed"
                               versionable="true" auditable="false"
-                              label="workflows_common" updated="" order="1">
+                              label="workflow_common" updated="" order="1">
                     <service:content contentType="application/xml">
                         <service:xmlContent
                             namespaceURI="http://collectionspace.org/services/workflow"
-                            schemaLocation="http://collectionspace.org/services/workflow http://services.collectionspace.org/movement/workflows_common.xsd">
+                            schemaLocation="http://collectionspace.org/services/workflow http://services.collectionspace.org/movement/workflow_common.xsd">
                         </service:xmlContent>
                     </service:content>
                 </service:part>
         <!-- begin dimension service meta-data -->
         <tenant:serviceBindings name="Dimensions" version="0.1">
             <!-- other URI paths using which this service could be accessed -->
+            <service:uriPath xmlns:service='http://collectionspace.org/services/common/service'>
+                /dimensions/*/workflow/
+            </service:uriPath>
             <service:repositoryDomain xmlns:service='http://collectionspace.org/services/common/service'>
                 default-domain
             </service:repositoryDomain>
index 20fe2241b4dd69225d2ba7d6c64a69bc5e2c056a..5f8e5ae879299c5eb848845b487bad58e0ea4f8f 100644 (file)
@@ -46,7 +46,7 @@ import org.collectionspace.services.common.document.DocumentHandler;
 import org.collectionspace.services.common.document.DocumentNotFoundException;\r
 import org.collectionspace.services.common.security.UnauthorizedException;\r
 import org.collectionspace.services.common.workflow.service.nuxeo.WorkflowDocumentModelHandler;\r
-import org.collectionspace.services.workflow.WorkflowsCommon;\r
+import org.collectionspace.services.workflow.WorkflowCommon;\r
 import org.jboss.resteasy.client.ClientResponse;\r
 \r
 import org.slf4j.Logger;\r
@@ -162,7 +162,7 @@ public abstract class AbstractMultiPartCollectionSpaceResourceImpl extends
        \r
        WorkflowDocumentModelHandler docHandler = (WorkflowDocumentModelHandler)createDocumentHandler(ctx,\r
                        WorkflowClient.SERVICE_COMMONPART_NAME,\r
-                       WorkflowsCommon.class);         \r
+                       WorkflowCommon.class);          \r
        \r
         return docHandler;\r
     }\r
@@ -172,7 +172,7 @@ public abstract class AbstractMultiPartCollectionSpaceResourceImpl extends
      */\r
        \r
     @GET\r
-    @Path("{csid}/workflow")\r
+    @Path("{csid}" + WorkflowClient.SERVICE_PATH)\r
     public byte[] getWorkflow(\r
             @PathParam("csid") String csid) {\r
         PoxPayloadOut result = null;\r
@@ -194,7 +194,7 @@ public abstract class AbstractMultiPartCollectionSpaceResourceImpl extends
     }\r
     \r
     @PUT\r
-    @Path("{csid}/workflow")\r
+    @Path("{csid}" + WorkflowClient.SERVICE_PATH)\r
     public byte[] updateWorkflow(@PathParam("csid") String csid, String xmlPayload) {\r
         PoxPayloadOut result = null;\r
        try {\r
index cf7c4ce99e817cfa94901f3e96ec689f11ee1f43..694f5c91f5002919553b43f170b4af7e1a1bef52 100644 (file)
@@ -26,6 +26,7 @@ package org.collectionspace.services.common.context;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.dom4j.Element;
@@ -110,5 +111,7 @@ public interface MultipartServiceContext
      */
     public void addOutputPart(String label, Element doc, String contentType) throws Exception;
     
+    public void addOutputPart(PayloadOutputPart outputPart) throws Exception;    
+    
     public void setRespositoryWorkspaceName(String workspaceName);    
 }
index 67dc80d73e07203e1abe06b8e6013132e3efd439..53e1d654d8e2433812b1e56b0729f0490e4de75e 100644 (file)
@@ -159,8 +159,17 @@ public class MultipartServiceContextImpl
            if (logger.isTraceEnabled() == true) {
                logger.trace("Adding part:" + label +
                                " to " + getOutput().getName() + " document.");
-                }
-            }
+           }
+    }
+
+    @Override
+    public void addOutputPart(PayloadOutputPart outputPart) throws Exception {
+           PayloadOutputPart part = getOutput().addPart(outputPart);
+           if (logger.isTraceEnabled() == true) {
+               logger.trace("Adding part:" + part.getLabel() +
+                               " to " + getOutput().getName() + " document.");
+           }
+    }
 
     /* (non-Javadoc)
      * @see org.collectionspace.services.common.context.RemoteServiceContextImpl#getLocalContext(java.lang.String)
index be23afc4d8d0ee0f0b73de0a495438e19c9e4325..455e1d433525dc7a8283e4427b30387e749327c9 100644 (file)
@@ -48,6 +48,7 @@ import org.collectionspace.authentication.AuthN;
 import org.collectionspace.services.authorization.AuthZ;
 import org.collectionspace.services.authorization.CSpaceResource;
 import org.collectionspace.services.authorization.URIResourceImpl;
+import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.common.document.JaxbUtils;
 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
 import org.collectionspace.services.common.security.SecurityUtils;
@@ -104,7 +105,26 @@ public class SecurityInterceptor implements PreProcessInterceptor {
                                Response response = Response.status(
                                                Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build();
                                throw new WebApplicationException(response);
+                       } else {
+                               //
+                               // They passed the first round of security checks, so now let's check to see if they're trying
+                               // to perform a workflow state change and make sure they are allowed to to this.
+                               //
+                               if (uriPath.endsWith(WorkflowClient.SERVICE_PATH_COMPONENT) == true) {
+                                       String workflowSubResName = getResourceName(request.getUri());
+                                       res = new URIResourceImpl(workflowSubResName, httpMethod);
+                                       if (!authZ.isAccessAllowed(res)) {
+                                               logger.error("Access to " + resName + ":" + res.getId() + " is NOT allowed to "
+                                                               + " user=" + AuthN.get().getUserId());
+                                               Response response = Response.status(
+                                                               Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build();
+                                               throw new WebApplicationException(response);
+                                       }
+                               }
                        }
+                       //
+                       // We've passed all the checks.  Now just log the results
+                       //
                        if (logger.isDebugEnabled()) {
                                logger.debug("Access to " + res.getId() + " is allowed to "
                                                + " user=" + AuthN.get().getUserId() +
index 9c7efaf0bdd94c290e831164bb1db68cb0a9eca5..4323b6ac1554ad08c7c9ed4fee1e66518e275cce 100644 (file)
@@ -67,7 +67,7 @@ public class JpaStorageUtils {
     /** The Constant CS_PERSISTENCE_UNIT. */
     public final static String CS_PERSISTENCE_UNIT = "org.collectionspace.services";
     private final static String CS_AUTHZ_PERSISTENCE_UNIT = "org.collectionspace.services.authorization";
-    private final static String CS_CURRENT_USER = "0";
+    public final static String CS_CURRENT_USER = "0";
 
     /**
      * getEntity for given id and class
@@ -166,11 +166,20 @@ public class JpaStorageUtils {
        return result;
     }
     
-    //FIXME: This method should be moved to the AccountPermissionDocumemntHandler
+    //FIXME: REM - This method should probably be moved to the AccountPermissionDocumemntHandler
     /*
      * This is a prototype for the /accounts/{csid}/permissions GET service call.
      */
     public static AccountPermission getAccountPermissions(String csid)
+               throws UnauthorizedException, DocumentNotFoundException {
+       return getAccountPermissions(csid, null, null);
+    }
+    
+    //FIXME: REM - This method should probably be moved to the AccountPermissionDocumemntHandler    
+    /*
+     * This is a prototype for the /accounts/{csid}/permissions GET service call.
+     */
+    public static AccountPermission getAccountPermissions(String csid, String currentResource, String permissionResource)
        throws UnauthorizedException, DocumentNotFoundException {
         //
         // Make sure the user asking for this list has the correct
@@ -198,8 +207,18 @@ public class JpaStorageUtils {
         try {
             StringBuilder queryStrBldr = new StringBuilder("SELECT ar, pr FROM " + AccountRoleRel.class.getName() +
                        " ar, " + PermissionRoleRel.class.getName() + " pr" +
-                       " WHERE ar.roleId = pr.roleId and ar.userId=" + "'" + userId + "'" +
-                       "group by pr.permissionId");
+                       " WHERE ar.roleId = pr.roleId and ar.userId=" + "'" + userId + "'");
+            //
+            // Filter by the permissionResource param if it is set to something
+            //
+            if (permissionResource != null && currentResource != null) {
+               queryStrBldr.append(" and (pr.permissionResource = " + "'" + currentResource + "'" +
+                               " or pr.permissionResource = " + "'" + permissionResource + "'" + ")");
+            }
+            //
+            // Add group by clause
+            //
+            queryStrBldr.append(" group by pr.permissionId");
 
             emf = getEntityManagerFactory();
             em = emf.createEntityManager();
index 61a39bbfe8371f277f80e544716fd150ae1db200..8e39057d44864fb33ef68263eb0cc508fd65ff33 100644 (file)
@@ -43,14 +43,14 @@ import org.collectionspace.services.common.service.ObjectPartType;
 import org.collectionspace.services.common.workflow.jaxb.WorkflowJAXBSchema;
 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
 import org.collectionspace.services.nuxeo.client.java.RemoteDocumentModelHandlerImpl;
-import org.collectionspace.services.workflow.WorkflowsCommon;
+import org.collectionspace.services.workflow.WorkflowCommon;
 import org.dom4j.Element;
 import org.nuxeo.ecm.core.api.DocumentModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class WorkflowDocumentModelHandler 
-       extends DocHandlerBase<WorkflowsCommon> {
+       extends DocHandlerBase<WorkflowCommon> {
 
     /** The logger. */
     private final Logger logger = LoggerFactory.getLogger(WorkflowDocumentModelHandler.class);
@@ -120,7 +120,7 @@ public class WorkflowDocumentModelHandler
                ObjectPartType partMeta, Action action,
                ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx)
                throws Exception {
-               WorkflowsCommon workflowsCommon = (WorkflowsCommon)part.getBody();
+               WorkflowCommon workflowsCommon = (WorkflowCommon)part.getBody();
                docModel.followTransition(getTransitionFromState(workflowsCommon.getCurrentLifeCycleState()));
     }
 
index 50db6a4d7f021267e13f808843038ae86b8755a0..a5f302f2d7d52235c8433d87812af70ee23e121b 100644 (file)
@@ -35,19 +35,26 @@ import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.collectionspace.services.authorization.AccountPermission;
 import org.collectionspace.services.jaxb.AbstractCommonList;
 import org.collectionspace.services.client.PayloadInputPart;
+import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.common.authorityref.AuthorityRefList;
+import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon;
 import org.collectionspace.services.common.context.MultipartServiceContext;
 import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.document.BadRequestException;
+import org.collectionspace.services.common.document.DocumentNotFoundException;
 import org.collectionspace.services.common.document.DocumentUtils;
 import org.collectionspace.services.common.document.DocumentWrapper;
 import org.collectionspace.services.common.document.DocumentFilter;
 import org.collectionspace.services.common.document.DocumentHandler.Action;
+import org.collectionspace.services.common.security.UnauthorizedException;
 import org.collectionspace.services.common.service.ObjectPartType;
+import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
 import org.collectionspace.services.common.vocabulary.RefNameUtils;
 import org.dom4j.Element;
 
@@ -182,6 +189,16 @@ public abstract class RemoteDocumentModelHandlerImpl<T, TL>
             Map<String, Object> unQObjectProperties = extractPart(docModel, schema, partMeta);
             addOutputPart(unQObjectProperties, schema, partMeta);
         }
+        addAccountPermissionsPart();
+    }
+    
+    private void addAccountPermissionsPart() throws Exception {
+        MultipartServiceContext ctx = (MultipartServiceContext) getServiceContext();
+        String currentServiceName = ctx.getServiceName();
+        AccountPermission accountPermission = JpaStorageUtils.getAccountPermissions(JpaStorageUtils.CS_CURRENT_USER,
+                       currentServiceName, "/" + currentServiceName + WorkflowClient.SERVICE_AUTHZ_SUFFIX);
+        PayloadOutputPart accountPermissionPart = new PayloadOutputPart("account_permission", accountPermission);
+        ctx.addOutputPart(accountPermissionPart);
     }
 
     /* (non-Javadoc)
index a33a5d7f3d85764fef8e76217311320157e799cc..9437bd290041a22d1318cb653558351043042bb0 100644 (file)
@@ -34,9 +34,11 @@ import org.collectionspace.services.client.PayloadInputPart;
 import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.dimension.DimensionsCommon;
 import org.collectionspace.services.dimension.DimensionsCommonList;
 import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.workflow.WorkflowCommon;
 
 import org.jboss.resteasy.client.ClientResponse;
 
@@ -755,4 +757,100 @@ public class DimensionServiceTest extends AbstractServiceTestImpl {
 
         return multipart;
     }
+
+    @Override
+    protected String createWorkflowTarget(String testName) throws Exception {
+       String result = null;
+       
+       result = createTestObject(testName);
+       
+       return result;
+    }
+       
+       @Override
+    protected String createTestObject(String testName) throws Exception {
+               String result = null;
+               
+        DimensionClient client = new DimensionClient();
+        String identifier = createIdentifier();
+        PoxPayloadOut multipart = createDimensionInstance(client.getCommonPartName(),
+                identifier);
+        ClientResponse<Response> res = client.create(multipart);
+
+        int statusCode = res.getStatus();
+        Assert.assertEquals(statusCode, STATUS_CREATED);
+
+        result = extractId(res);
+        allResourceIdsCreated.add(result);
+
+        return result;
+       }
+       
+       /*
+        * This test assumes that no objects exist yet.
+        * 
+        * http://localhost:8180/cspace-services/intakes?wf_deleted=false
+        */
+    @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, dependsOnMethods = {"update"})
+       public void readWorkflowList(String testName) throws Exception {
+       //
+       // Create 3 new objects
+       //
+       final int OBJECTS_TOTAL = 3;
+       for (int i = 0; i < OBJECTS_TOTAL; i++) {
+               this.createWorkflowTarget(testName);
+       }
+       //
+       // Mark one as soft deleted
+       //
+       int currentTotal = allResourceIdsCreated.size();
+       String csid = allResourceIdsCreated.get(currentTotal - 1); //0-based index to get the last one added
+       this.setupUpdate();
+       this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWSTATE_DELETED);
+       //
+       // Read the list back.  The deleted item should not be in the list
+       //
+//     int updatedTotal = readIncludeDeleted(testName, Boolean.FALSE);
+//     Assert.assertEquals(updatedTotal, currentTotal - 1, "Deleted items seem to be returned in list results.");
+       }
+    
+    protected void updateLifeCycleState(String testName, String resourceId, String lifeCycleState) throws Exception {
+        //
+        // Read the existing object
+        //
+        DimensionClient client = new DimensionClient();
+        ClientResponse<String> res = client.getWorkflow(resourceId);
+        assertStatusCode(res, testName);
+        logger.debug("Got object to update life cycle state with ID: " + resourceId);
+        PoxPayloadIn input = new PoxPayloadIn(res.getEntity());
+        WorkflowCommon workflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(workflowCommons);
+        //
+        // Mark it for a soft delete.
+        //
+        logger.debug("Current workflow state:" + objectAsXmlString(workflowCommons, WorkflowCommon.class));
+        workflowCommons.setCurrentLifeCycleState(lifeCycleState);
+        PoxPayloadOut output = new PoxPayloadOut(WorkflowClient.SERVICE_PAYLOAD_NAME);
+        PayloadOutputPart commonPart = output.addPart(workflowCommons, MediaType.APPLICATION_XML_TYPE);
+        commonPart.setLabel(WorkflowClient.SERVICE_COMMONPART_NAME);
+        //
+        // Perform the update
+        //
+        res = client.updateWorkflow(resourceId, output);
+        assertStatusCode(res, testName);
+        input = new PoxPayloadIn(res.getEntity());
+        WorkflowCommon updatedWorkflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(updatedWorkflowCommons);
+        //
+        // Read the updated object and make sure it was updated correctly.
+        //
+        res = client.getWorkflow(resourceId);
+        assertStatusCode(res, testName);
+        logger.debug("Got workflow state of updated object with ID: " + resourceId);
+        input = new PoxPayloadIn(res.getEntity());
+        updatedWorkflowCommons = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
+        Assert.assertNotNull(workflowCommons);
+        Assert.assertEquals(updatedWorkflowCommons.getCurrentLifeCycleState(), lifeCycleState);
+    }
+    
 }
similarity index 97%
rename from services/jaxb/src/main/resources/workflows_common.xsd
rename to services/jaxb/src/main/resources/workflow_common.xsd
index 35655b7a1ee77e326959baab218a0c0274066d7c..3ba78d7d4fab00f8bfb0c282337fca5eb3c773ae 100644 (file)
@@ -24,7 +24,7 @@
     See http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html
 -->    
     <!-- workflow -->
-    <xs:element name="workflows_common">
+    <xs:element name="workflow_common">
         <xs:complexType>
             <xs:sequence>
                 <!--  Workflow Information Group -->
index 8b34a1e8070d91e0e2be753897d0ed62ff34e047..c8de9573cac8dec9467ac4d99254229981508cb0 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <component name="org.collectionspace.workflow.coreTypes">
   <extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema">
-    <schema name="workflows_common" prefix="workflows_common" src="schemas/workflows_common.xsd"/>
+    <schema name="workflow_common" prefix="workflow_common" src="schemas/workflow_common.xsd"/>
   </extension>
 </component>
index f1e7a91c3777946a3eb3085b75db0d461f3083a6..30f23585bac227cb400bb0905a51111485f2cd06 100644 (file)
@@ -33,7 +33,7 @@ import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 
 import org.collectionspace.services.jaxb.AbstractCommonList;
-import org.collectionspace.services.workflow.WorkflowsCommon;
+import org.collectionspace.services.workflow.WorkflowCommon;
 import org.collectionspace.services.client.DimensionClient;
 import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.dimension.DimensionsCommon;
@@ -98,7 +98,21 @@ public class WorkflowServiceTest extends AbstractServiceTestImpl {
     /*
      * Create a Dimension instance to use as our test target.
      */
-    public void createTestObject(String testName) throws Exception {
+    @Override
+    protected String createWorkflowTarget(String testName) throws Exception {
+       String result = null;
+       
+       result = createTestObject(testName);
+       
+       return result;
+    }
+    
+    /*
+     * Create a Dimension instance to use as our test target.
+     */
+    protected String createTestObject(String testName) throws Exception {
+       String result = null;
+       
        logger.debug(testBanner(testName, CLASS_NAME));
        setupCreate();
        DimensionClient client = new DimensionClient();
@@ -109,7 +123,10 @@ public class WorkflowServiceTest extends AbstractServiceTestImpl {
                knownResourceId = extractId(res);  // Store the ID returned from the first resource created for additional tests below.
                logger.debug(testName + ": knownResourceId=" + knownResourceId);
        }
-       allResourceIdsCreated.add(extractId(res)); // Store the IDs from every resource created by tests so they can be deleted after tests have been run.
+       result = extractId(res);
+       allResourceIdsCreated.add(result); // Store the IDs from every resource created by tests so they can be deleted after tests have been run.
+       
+       return result;
     }
 
     @Override
@@ -126,7 +143,7 @@ public class WorkflowServiceTest extends AbstractServiceTestImpl {
         ClientResponse<String> res = client.getWorkflow(knownResourceId);
         assertStatusCode(res, testName);
         PoxPayloadIn input = new PoxPayloadIn(res.getEntity());
-        WorkflowsCommon workflowsCommon = (WorkflowsCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowsCommon.class);
+        WorkflowCommon workflowsCommon = (WorkflowCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowCommon.class);
         if (logger.isDebugEnabled() == true) {
                logger.debug("Workflow payload is: " + input.getXmlPayload());
         }
@@ -162,44 +179,6 @@ public class WorkflowServiceTest extends AbstractServiceTestImpl {
         updateLifeCycleState(testName, knownResourceId, WorkflowClient.WORKFLOWSTATE_APPROVED);
     }    
 
-    private void updateLifeCycleState(String testName, String resourceId, String lifeCycleState) throws Exception {
-        //
-        // Read the existing object
-        //
-        DimensionClient client = new DimensionClient();
-        ClientResponse<String> res = client.getWorkflow(resourceId);
-        assertStatusCode(res, testName);
-        logger.debug("Got object to update life cycle state with ID: " + resourceId);
-        PoxPayloadIn input = new PoxPayloadIn(res.getEntity());
-        WorkflowsCommon workflowCommons = (WorkflowsCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowsCommon.class);
-        Assert.assertNotNull(workflowCommons);
-        //
-        // Mark it for a soft delete.
-        //
-        logger.debug("Current workflow state:" + objectAsXmlString(workflowCommons, WorkflowsCommon.class));
-        workflowCommons.setCurrentLifeCycleState(lifeCycleState);
-        PoxPayloadOut output = new PoxPayloadOut(WorkflowClient.SERVICE_PAYLOAD_NAME);
-        PayloadOutputPart commonPart = output.addPart(workflowCommons, MediaType.APPLICATION_XML_TYPE);
-        commonPart.setLabel(WorkflowClient.SERVICE_COMMONPART_NAME);
-        //
-        // Perform the update
-        //
-        res = client.updateWorkflow(resourceId, output);
-        assertStatusCode(res, testName);
-        input = new PoxPayloadIn(res.getEntity());
-        WorkflowsCommon updatedWorkflowCommons = (WorkflowsCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowsCommon.class);
-        Assert.assertNotNull(updatedWorkflowCommons);
-        //
-        // Read the updated object and make sure it was updated correctly.
-        //
-        res = client.getWorkflow(resourceId);
-        assertStatusCode(res, testName);
-        logger.debug("Got workflow state of updated object with ID: " + resourceId);
-        input = new PoxPayloadIn(res.getEntity());
-        updatedWorkflowCommons = (WorkflowsCommon) extractPart(input, WorkflowClient.SERVICE_COMMONPART_NAME, WorkflowsCommon.class);
-        Assert.assertNotNull(workflowCommons);
-        Assert.assertEquals(updatedWorkflowCommons.getCurrentLifeCycleState(), lifeCycleState);
-    }
 
     @Override
 //    @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, dependsOnMethods = {"update", "testSubmitRequest"})
@@ -348,33 +327,42 @@ public class WorkflowServiceTest extends AbstractServiceTestImpl {
         return result;
        }
        
+       @Override
+       public void readList(String testName) throws Exception {
+       }       
+       
        /*
         * This test assumes that no objects exist yet.
         * 
         * http://localhost:8180/cspace-services/intakes?wf_deleted=false
         */
-    @Override
     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, dependsOnMethods = {"update"})
-       public void readList(String testName) throws Exception {
+       public void readWorkflow(String testName) throws Exception {
+       //
+       // Get the total count of non-deleted existing records
+       //
+       int existingRecords = readIncludeDeleted(testName, Boolean.FALSE);
+
        //
        // Create 3 new objects
        //
-       final int OBJECTS_TOTAL = 3;
-       for (int i = 0; i < OBJECTS_TOTAL; i++) {
-               this.createTestObject(testName);
+       final int OBJECTS_TO_CREATE = 3;
+       for (int i = 0; i < OBJECTS_TO_CREATE; i++) {
+               this.createWorkflowTarget(testName);
        }
+       
        //
        // Mark one as soft deleted
        //
-       int currentTotal = allResourceIdsCreated.size();
-       String csid = allResourceIdsCreated.get(currentTotal - 1); //0-based index to get the last one added
+       int existingTestCreated = allResourceIdsCreated.size(); // assumption is that no other test created records were soft deleted
+       String csid = allResourceIdsCreated.get(existingTestCreated - 1); //0-based index to get the last one added
        this.setupUpdate();
        this.updateLifeCycleState(testName, csid, WorkflowClient.WORKFLOWSTATE_DELETED);
        //
-       // Read the list back.  The deleted item should not be in the list
+       // Read the list of existing non-deleted records
        //
        int updatedTotal = readIncludeDeleted(testName, Boolean.FALSE);
-       Assert.assertEquals(updatedTotal, currentTotal - 1, "Deleted items seem to be returned in list results.");
+       Assert.assertEquals(updatedTotal, existingRecords + OBJECTS_TO_CREATE - 1, "Deleted items seem to be returned in list results.");
        }
        
        @Override
index 8ba0fe378ba96d017df91aca07d176e4ee04354f..b770103811525919a965272ae9e3df57aa320df9 100644 (file)
@@ -4,7 +4,7 @@ import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.common.document.InvalidDocumentException;
 import org.collectionspace.services.common.document.ValidatorHandlerImpl;
-import org.collectionspace.services.workflow.WorkflowsCommon;
+import org.collectionspace.services.workflow.WorkflowCommon;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -20,13 +20,13 @@ public class WorkflowValidatorHandler extends ValidatorHandlerImpl<PoxPayloadIn,
        
     @Override
     protected Class<?> getCommonPartClass() {
-       return WorkflowsCommon.class;
+       return WorkflowCommon.class;
     }
        
        @Override
        protected void handleCreate() throws InvalidDocumentException {
                try {
-                       WorkflowsCommon intakesCommon = (WorkflowsCommon)getCommonPart();
+                       WorkflowCommon intakesCommon = (WorkflowCommon)getCommonPart();
                        assert(intakesCommon != null);
        } catch (AssertionError e) {
                if (logger.isErrorEnabled() == true) {