]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
DRYD-186: permissionId values in permroles payload is now optional. Service layer...
authorremillet <remillet@yahoo.com>
Sat, 2 Dec 2017 00:28:31 +0000 (16:28 -0800)
committerremillet <remillet@yahoo.com>
Sat, 2 Dec 2017 00:28:31 +0000 (16:28 -0800)
35 files changed:
services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java
services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java
services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/PermissionActionFactory.java [new file with mode: 0644]
services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/PermissionClient.java
services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/PermissionFactory.java
services/authorization-mgt/client/src/test/java/org/collectionspace/services/authorization/client/test/RolePermissionServiceTest.java
services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/driver/AuthorizationSeedDriver.java
services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java
services/authorization-mgt/service/pom.xml
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionResource.java.txt [new file with mode: 0644]
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java.txt [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java with 100% similarity]
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionValidatorHandler.java
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleDocumentHandler.java
services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/RoleJpaFilter.java
services/authorization/jaxb/src/main/resources/authorization_common.xsd
services/authorization/pstore/src/main/resources/db/postgresql/authorization.sql
services/common/pom.xml
services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionResource.java with 93% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionRoleSubResource.java with 97% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/AuthorizationDelegate.java with 97% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java [new file with mode: 0644]
services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionJpaFilter.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionJpaFilter.java with 99% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionRoleDocumentHandler.java with 99% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionStorageConstants.java [moved from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/storage/PermissionStorageConstants.java with 100% similarity]
services/common/src/main/java/org/collectionspace/services/authorization/storage/RoleStorageConstants.java [moved from services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/RoleStorageConstants.java with 95% similarity]
services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationStore.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/PermissionRoleUtil.java
services/common/src/main/java/org/collectionspace/services/common/document/DocumentWrapper.java
services/common/src/main/java/org/collectionspace/services/common/document/DocumentWrapperImpl.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaRelationshipStorageClient.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageClientImpl.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java
services/hyperjaxb/src/main/resources/permissions.xsd

index 067d2fae078bbbe8713a9285a38f9cd3cf997f34..8fcb91877dff240926483e4f35171cc4f57f28d5 100644 (file)
@@ -58,6 +58,7 @@ import org.collectionspace.services.claim.ClaimResource;
 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;
@@ -68,7 +69,6 @@ import java.util.Set;
 
 
 //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;
index 090f8ab558eafbe56d2659e920021079ae2a399b..8ba98f7560fccc322f6d0133e405db8cb2339ff0 100644 (file)
@@ -86,8 +86,8 @@ public class AccountResource extends SecurityResourceBase {
 
        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() {
diff --git a/services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/PermissionActionFactory.java b/services/authorization-mgt/client/src/main/java/org/collectionspace/services/client/PermissionActionFactory.java
new file mode 100644 (file)
index 0000000..8032174
--- /dev/null
@@ -0,0 +1,12 @@
+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; 
+       }
+}
index 442c23b88f7bb687a8837cab05bc6bae1bcf493c..9ff74c0ec9d780a4e4dab170ac9c747c93f2ef10 100644 (file)
  */
 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;
 
@@ -42,7 +48,11 @@ public class PermissionClient extends AbstractServiceClientImpl<PermissionsList,
        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();
@@ -131,4 +141,112 @@ public class PermissionClient extends AbstractServiceClientImpl<PermissionsList,
         
         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;
+       }
 }
index db52ed1c928c03dc7361047caec9b6cef1ab665d..28326ddab768ca6af29586396476e29659ae7e90 100644 (file)
@@ -25,6 +25,7 @@
 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;
@@ -62,11 +63,14 @@ public class PermissionFactory {
             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);
@@ -74,28 +78,18 @@ public class PermissionFactory {
         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;
     }
index d264fb28e1d6fc96ff4871728ddd2be58b81c995..7ed710e0417f323db7c8f02fc1faaa3cada8486e 100644 (file)
@@ -106,7 +106,6 @@ public class RolePermissionServiceTest extends AbstractServiceTestImpl<Permissio
      */
     @BeforeClass(alwaysRun = true)
     public void seedData() throws Exception {
-
         String rn1 = getRoleName();
         String r1RoleId = createRole(rn1);
         RoleValue rv1 = new RoleValue();
@@ -121,17 +120,21 @@ public class RolePermissionServiceTest extends AbstractServiceTestImpl<Permissio
         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);
     }
@@ -570,13 +573,13 @@ public class RolePermissionServiceTest extends AbstractServiceTestImpl<Permissio
      * @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 {
@@ -597,6 +600,32 @@ public class RolePermissionServiceTest extends AbstractServiceTestImpl<Permissio
         }
         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.
index 5dfa264ba9dd470b4bafbadbfb50a73e0eeaad19..9b597be1b29e717978f352af512344e011f8d638 100644 (file)
@@ -40,6 +40,7 @@ import org.collectionspace.services.authorization.Role;
 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;
@@ -228,7 +229,8 @@ public class AuthorizationSeedDriver {
                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);
@@ -254,7 +256,20 @@ public class AuthorizationSeedDriver {
         }
     }
 
-    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);
index b2ec4ed954d82deb19fe9a311cae36d7c6fceef5..7ead5209534aba427144f8fea24ffab33206cabd 100644 (file)
@@ -299,12 +299,12 @@ public class AuthorizationGen {
 
     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);
         }
         
@@ -320,17 +320,18 @@ public class AuthorizationGen {
         // 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);
             }
@@ -343,19 +344,21 @@ public class AuthorizationGen {
         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) {
@@ -368,6 +371,7 @@ public class AuthorizationGen {
                    // 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) {
index 775f66a17bcc3f2f76aa7f38da5cd0aadfe9570f..40e1aa4237732658ee381c79dac50d984f630528 100644 (file)
         <dependency>
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.common</artifactId>
-            </dependency>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionResource.java.txt b/services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionResource.java.txt
new file mode 100644 (file)
index 0000000..22ac5c5
--- /dev/null
@@ -0,0 +1,254 @@
+/**
+ *  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);
+        }
+    }
+    
+}
index ee1d43b7138d09b64cff6779d745ad87b35932ec..c9628487ca5d5f83dcf959208af44b71322e5dd7 100644 (file)
 
 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;
@@ -53,19 +57,23 @@ public class PermissionValidatorHandler implements ValidatorHandler {
             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);
@@ -78,4 +86,30 @@ public class PermissionValidatorHandler implements ValidatorHandler {
         }
     }
 
+       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;
+       }
+
 }
index daeb5ecd720b14af2e6b0ae8f587557c3beed8bc..a7f2b2fc1665856509edff904db2f0834ad2806f 100644 (file)
@@ -87,34 +87,36 @@ public class RoleDocumentHandler
     }
 
     /**
-     * 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;
     }
 
@@ -206,7 +208,7 @@ public class RoleDocumentHandler
      */
     private void sanitize(Role role) {
         if (!SecurityUtils.isCSpaceAdmin()) {
-            role.setTenantId(null);
+            role.setTenantId(null); // REM - See no reason for hiding the tenant ID?
         }
     }
 
index e406218305930fa6ce075c9342535842d4b35b9a..25ba7f316c11d9c034fb685cc8c5dc8cc5ac6c66 100644 (file)
@@ -25,10 +25,11 @@ package org.collectionspace.services.authorization.storage;
 
 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;
 
index cadd94c4a720066dcc855727feb880b0db384f9c..aedbb2ffc3a1b0d00361cf851d5635ac79a1f6f8 100644 (file)
@@ -55,6 +55,7 @@
             <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>
 
@@ -72,6 +73,7 @@
             <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>
 
index ac9aa3efbb07ef7900d4dcf8195e347d4506510b..c5cb4b10f04b9e95a30d90d0f7e8bb4acf3fdca8 100644 (file)
@@ -6,7 +6,7 @@ DROP TABLE IF EXISTS permissions_roles CASCADE;
 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));
index fe74be5e6b61096431352b43bb46fac83ca733a5..f4220b5a9f423a7fbe406627a1ac6d7ff5039cf6 100644 (file)
                        <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 -->
similarity index 93%
rename from services/authorization-mgt/service/src/main/java/org/collectionspace/services/authorization/PermissionResource.java
rename to services/common/src/main/java/org/collectionspace/services/authorization/PermissionResource.java
index 9cb736d81862d0d19823f71b5a43227c9dfa4543..8256574206fd37c5356e5e85501677287505982f 100644 (file)
  */
 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;
@@ -91,6 +95,19 @@ public class PermissionResource extends 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;
@@ -65,7 +65,7 @@ public class AuthorizationDelegate {
      * @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)) {
@@ -116,7 +116,7 @@ public class AuthorizationDelegate {
      * @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();
@@ -225,7 +225,7 @@ public class AuthorizationDelegate {
      * @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()) {
diff --git a/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java b/services/common/src/main/java/org/collectionspace/services/authorization/storage/PermissionDocumentHandler.java
new file mode 100644 (file)
index 0000000..5aed20f
--- /dev/null
@@ -0,0 +1,331 @@
+/**
+ *  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());
+        }
+    }
+}
@@ -26,6 +26,7 @@ package org.collectionspace.services.authorization.storage;
 
 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;
@@ -32,6 +32,7 @@ import org.collectionspace.services.authorization.PermissionValue;
 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;
@@ -206,7 +207,9 @@ public class PermissionRoleDocumentHandler
         } 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)
index 0eeda956a7aff5975ba73ceb70573cd434a0a48d..ccb118ef9364bd17342393be727012b3912cd0cc 100644 (file)
@@ -18,8 +18,11 @@ import javax.sql.DataSource;
 
 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;
@@ -30,10 +33,11 @@ import org.collectionspace.services.common.config.ServicesConfigReaderImpl;
 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;
@@ -43,10 +47,12 @@ import org.collectionspace.services.config.tenant.RepositoryDomainType;
 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;
index c9376c2685b5e0bfcfd400069d9dfa49340da63c..6e686f06416791634c2810ea71decf0da2f5fbed 100644 (file)
@@ -41,6 +41,7 @@ import org.collectionspace.services.authorization.perms.PermissionAction;
 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;
@@ -49,10 +50,12 @@ import org.collectionspace.services.common.security.SecurityUtils;
 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;
@@ -143,6 +146,8 @@ public class AuthorizationCommon {
        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;
@@ -1066,6 +1071,8 @@ public class AuthorizationCommon {
        
     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);
@@ -1084,7 +1091,7 @@ public class AuthorizationCommon {
                        
                        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.");
                        }
                        
@@ -1107,10 +1114,10 @@ public class AuthorizationCommon {
                                                }
                                                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());
                                }
                        }
@@ -1120,9 +1127,7 @@ public class AuthorizationCommon {
             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) {
@@ -1163,7 +1168,8 @@ public class AuthorizationCommon {
                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);
                }
index 7aff76a86e1e1414d02ae0a193e8339620d77dc5..be9c907af162b720cab4af925d50e3a4a0373c6f 100644 (file)
@@ -34,7 +34,7 @@ import javax.persistence.EntityManagerFactory;
 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;
@@ -48,6 +48,7 @@ public class AuthorizationStore {
 
     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;
index f55daf08d69d5d6169f846b13731e89cdd0c9d3d..125662130217659081f769b676e91c4aa6b3448e 100644 (file)
  */
 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;
 
@@ -101,13 +106,15 @@ public class PermissionRoleUtil {
                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);
                    }
                }
@@ -116,7 +123,7 @@ public class PermissionRoleUtil {
                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);
                    }
                }
@@ -127,7 +134,8 @@ public class PermissionRoleUtil {
                PermissionRole pr,
                SubjectType subject,
                List<PermissionRoleRel> prrl,
-               boolean handleDelete) throws Exception {
+               boolean handleDelete,
+               String tenantId) throws Exception {
         EntityManagerFactory emf = null;
         EntityManager em = null;
         try {
@@ -135,7 +143,7 @@ public class PermissionRoleUtil {
             em = emf.createEntityManager();
             em.getTransaction().begin();
             
-            buildPermissionRoleRel(em, pr, subject, prrl, handleDelete);
+            buildPermissionRoleRel(em, pr, subject, prrl, handleDelete, tenantId);
             
             em.getTransaction().commit();
                em.close();            
@@ -154,6 +162,52 @@ public class PermissionRoleUtil {
         }
     }    
 
+    /*
+     * 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'
      *
@@ -161,65 +215,45 @@ public class PermissionRoleUtil {
      * @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
         //
@@ -236,7 +270,58 @@ public class PermissionRoleUtil {
         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
index b5ca45f1e921c1b53a93cbea8e9f7bab532cb1bc..315d3bf40adb93b3ed4923545080fa74d5ec8047 100644 (file)
@@ -36,5 +36,6 @@ public interface DocumentWrapper<T> {
      * @return wrapped object
      */
     public T getWrappedObject();
+    public T resetWrapperObject(T newObject);
 
 }
index e3083b79ed1ff21d810df995ab766b0392f9e630..5f7de8972978029ebc23f9a00f95d6aabe8afad9 100644 (file)
@@ -32,7 +32,14 @@ public class DocumentWrapperImpl<T> implements DocumentWrapper<T>{
         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
index 4c52dba953af06a5796f67f83ac33139bdb182cd..ad86f0088a0efe5165bdd0dc0b959cfd15da6638 100644 (file)
@@ -413,7 +413,7 @@ public class JpaRelationshipStorageClient<T> extends JpaStorageClientImpl {
                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();
index 759719ffb3c0a2d0b729d8125a06ff50ec51e7ef..334ce0650666ed3fc184b90f4f193030b551852c 100644 (file)
@@ -24,6 +24,7 @@ import javax.persistence.RollbackException;
 
 import java.sql.BatchUpdateException;
 
+import javax.persistence.EntityExistsException;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.Query;
@@ -42,6 +43,7 @@ import org.collectionspace.services.common.storage.StorageClient;
 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;
@@ -105,7 +107,6 @@ public class JpaStorageClientImpl implements StorageClient {
     public String create(ServiceContext ctx,
             DocumentHandler handler) throws BadRequestException,
             DocumentException {
-       boolean rollbackTransaction = false;
         if (ctx == null) {
             throw new IllegalArgumentException(
                     "create: ctx is missing");
@@ -114,18 +115,29 @@ public class JpaStorageClientImpl implements StorageClient {
             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);
@@ -143,6 +155,7 @@ public class JpaStorageClientImpl implements StorageClient {
             }
             throw DocumentException.createDocumentException(e);
         } finally {
+            ctx.setProperty(AuthorizationStore.ENTITY_MANAGER_PROP_KEY, null);
             if (em != null) {
                if (rollbackTransaction == true) {
                        if (em.getTransaction().isActive() == true) {
@@ -493,7 +506,6 @@ public class JpaStorageClientImpl implements StorageClient {
             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()) {
index 5e9d750fc507aca101e59b6f3a434d01f8065a88..fa459de0b85a5f6d90c4d5c66ecc42a05368a8af 100644 (file)
@@ -75,15 +75,21 @@ public class JpaStorageUtils {
        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;
@@ -92,6 +98,8 @@ public class JpaStorageUtils {
             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);
index 35161ad4685e5f3f171b1f7d1b77e91642d4f62f..7b3051febede698d57ad9d8482d47fa5c8f050d2 100644 (file)
             </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>