]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-2884: Service call to retrieve permissions for a user without having to go...
authorRichard Millet <richard.millet@berkeley.edu>
Mon, 20 Sep 2010 03:45:42 +0000 (03:45 +0000)
committerRichard Millet <richard.millet@berkeley.edu>
Mon, 20 Sep 2010 03:45:42 +0000 (03:45 +0000)
services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java
services/authorization/jaxb/src/main/resources/accounts_permissions.xsd [new file with mode: 0644]
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationRoleRel.java
services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java

index e40ca7ca94330499d9b9d55e5f618fbc0fda6bd8..bb7fc830fb59ae0ac28b4291a665af86ef2c0c95 100644 (file)
@@ -40,6 +40,7 @@ import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
 import org.collectionspace.services.authorization.AccountRoleRel;
+import org.collectionspace.services.authorization.AccountPermission;
 //import org.collectionspace.services.authorization.AccountRolesList;
 import org.collectionspace.services.account.storage.AccountStorageClient;
 import org.collectionspace.services.authorization.AccountRole;
@@ -55,6 +56,7 @@ import org.collectionspace.services.common.document.DocumentNotFoundException;
 import org.collectionspace.services.common.document.DocumentHandler;
 import org.collectionspace.services.common.security.UnauthorizedException;
 import org.collectionspace.services.common.storage.StorageClient;
+import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
 import org.jboss.resteasy.util.HttpResponseCodes;
 
 import org.slf4j.Logger;
@@ -180,6 +182,7 @@ public class AccountResource
     @Path("{csid}")
     public AccountsCommon getAccount(
             @PathParam("csid") String csid) {
+       
         if (logger.isDebugEnabled()) {
             logger.debug("getAccount with csid=" + csid);
         }
@@ -542,6 +545,56 @@ public class AccountResource
         return result;
     }
 
+    @GET
+    @Path("{csid}/accountperms")
+    public AccountPermission getAccountPerm(
+               @PathParam("csid") String accCsid) {
+       
+        if (logger.isDebugEnabled()) {
+            logger.debug("getAccountPerm with accCsid=" + accCsid);
+        }
+        if (accCsid == null || "".equals(accCsid)) {
+            logger.error("getAccountPerm: missing accCsid!");
+            Response response = Response.status(Response.Status.BAD_REQUEST).entity(
+                    ServiceMessages.GET_FAILED + "getAccountPerm account "
+                    + ServiceMessages.MISSING_INVALID_CSID + accCsid).type(
+                    "text/plain").build();
+            throw new WebApplicationException(response);
+        }
+
+        AccountPermission result = null;
+        String userId = "undefined";
+        try {
+            result = JpaStorageUtils.getAccountPermissions(accCsid);
+        } catch (UnauthorizedException ue) {
+            Response response = Response.status(Response.Status.UNAUTHORIZED).entity(ServiceMessages.GET_FAILED +
+                    ue.getErrorReason()).type("text/plain").build();
+            throw new WebApplicationException(response);
+        } catch (DocumentNotFoundException dnfe) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("getAccountPerm", dnfe);
+            }
+            Response response = Response.status(Response.Status.NOT_FOUND).entity(ServiceMessages.GET_FAILED +
+                       "account userId=" + userId).type("text/plain").build();
+            throw new WebApplicationException(response);
+        } catch (Exception e) {
+            if (logger.isDebugEnabled()) {
+               logger.debug("getAccountPerm", e);
+            }
+            logger.error(ServiceMessages.UNKNOWN_ERROR_MSG, e);
+            Response response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
+                    ServiceMessages.GET_FAILED + ServiceMessages.UNKNOWN_ERROR_MSG).type("text/plain").build();
+            throw new WebApplicationException(response);
+        }
+        if (result == null) {
+            Response response = Response.status(Response.Status.NOT_FOUND).entity(
+                    ServiceMessages.GET_FAILED + "account userId=" + userId).type(
+                    "text/plain").build();
+            throw new WebApplicationException(response);
+        }
+        return result;
+    }
+    
     /**
      * Delete account role.
      *
index 3da9334a23dbc52000f693d021c2138ad186b97f..cee44eb57c8577ccab700a842e3f238c4de5b37a 100644 (file)
@@ -266,7 +266,7 @@ public class AccountRoleDocumentHandler
 
             List<AccountValue> avs = new ArrayList<AccountValue>();
             ar.setAccounts(avs);
-            AccountValue av = buildAccountValue(ar0);
+            AccountValue av = AuthorizationRoleRel.buildAccountValue(ar0);
             avs.add(av);
 
             //add roles
@@ -287,7 +287,7 @@ public class AccountRoleDocumentHandler
             List<AccountValue> avs = new ArrayList<AccountValue>();
             ar.setAccounts(avs);
             for (AccountRoleRel arr : arrl) {
-                AccountValue av = buildAccountValue(arr);
+                AccountValue av = AuthorizationRoleRel.buildAccountValue(arr);
                 avs.add(av);
             }
         }
@@ -344,20 +344,6 @@ public class AccountRoleDocumentHandler
         return new DocumentFilter(this.getServiceContext());
     }
 
-    /**
-     * Builds the account value.
-     *
-     * @param arr the arr
-     * @return the account value
-     */
-    private AccountValue buildAccountValue(AccountRoleRel arr) {
-        AccountValue av = new AccountValue();
-        av.setAccountId(arr.getAccountId());
-        av.setUserId(arr.getUserId());
-        av.setScreenName(arr.getScreenName());
-        return av;
-    }
-
     /**
      * Builds the account role rel.
      *
diff --git a/services/authorization/jaxb/src/main/resources/accounts_permissions.xsd b/services/authorization/jaxb/src/main/resources/accounts_permissions.xsd
new file mode 100644 (file)
index 0000000..6bdf573
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+\r
+<!--\r
+    CollectionSpace default (security) authorization provider schema (XSD)\r
+\r
+    $LastChangedRevision: 916 $\r
+    $LastChangedDate: 2009-11-05 16:59:20 -0800 (Thu, 05 Nov 2009) $\r
+-->\r
+\r
+<xs:schema\r
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"\r
+    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"\r
+    jaxb:version="1.0" elementFormDefault="unqualified"\r
+    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"\r
+    xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"\r
+    xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"\r
+    xmlns:ns="http://collectionspace.org/services/authorization"\r
+    xmlns="http://collectionspace.org/services/authorization"\r
+    targetNamespace="http://collectionspace.org/services/authorization"\r
+    version="0.1"\r
+    jaxb:extensionBindingPrefixes="hj orm xjc"\r
+    >\r
+\r
+    <!--\r
+    Avoid XmlRootElement nightmare:\r
+    See http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html\r
+    -->\r
+\r
+    <!--xs:annotation>\r
+    Note that roles.xsd already defines global bindings for the authorization namespace\r
+    so, it is not necessary to give the bindingings here because all the xsds are compiled\r
+    at once for this namespace\r
+        <xs:appinfo>\r
+            <jaxb:globalBindings>\r
+                <xjc:simple />\r
+            </jaxb:globalBindings>\r
+        </xs:appinfo>\r
+    </xs:annotation-->\r
+\r
+    <xs:include schemaLocation="authorization_common.xsd"/>\r
+\r
+    <xs:element name="account_permission" type="account_permission"/>\r
+    <xs:complexType name="account_permission">\r
+        <xs:annotation>\r
+            <xs:documentation>\r
+                AccountPermission defines 1-n association between\r
+                an account and its corresponding permissions.\r
+            </xs:documentation>\r
+            <xs:appinfo>\r
+                <hj:ignored/>\r
+            </xs:appinfo>\r
+        </xs:annotation>\r
+        <xs:sequence>\r
+            <!-- subject is not required to be given by the service consumer -->\r
+            <!-- subject is for service use only -->\r
+            <xs:element name="account" type="ns:account_value" minOccurs="1" maxOccurs="unbounded"/>\r
+            <xs:element name="permission" type="ns:permission_value" minOccurs="1" maxOccurs="unbounded"/>\r
+        </xs:sequence>\r
+    </xs:complexType>\r
+</xs:schema>\r
+\r
index 4bba070b8284adcc79133177a1a53141e0e85faf..0b1cf4623c5793c9ee2cb049dea6148d1a425302 100644 (file)
@@ -1,5 +1,6 @@
 package org.collectionspace.services.common.authorization_mgt;\r
 \r
+import org.collectionspace.services.authorization.AccountValue;\r
 import org.collectionspace.services.authorization.PermissionRoleRel;\r
 import org.collectionspace.services.authorization.AccountRoleRel;\r
 import org.collectionspace.services.authorization.PermissionValue;\r
@@ -7,6 +8,20 @@ import org.collectionspace.services.authorization.RoleValue;
 \r
 public class AuthorizationRoleRel {\r
 \r
+    /**\r
+     * Builds the account value.\r
+     *\r
+     * @param arr the arr\r
+     * @return the account value\r
+     */\r
+    static public AccountValue buildAccountValue(AccountRoleRel arr) {\r
+        AccountValue av = new AccountValue();\r
+        av.setAccountId(arr.getAccountId());\r
+        av.setUserId(arr.getUserId());\r
+        av.setScreenName(arr.getScreenName());\r
+        return av;\r
+    }\r
+       \r
     /**\r
      * Builds the role value.\r
      *\r
index be950eacdd9399ff07bea7334409a7e8db487f2a..be23afc4d8d0ee0f0b73de0a495438e19c9e4325 100644 (file)
@@ -65,6 +65,7 @@ public class SecurityInterceptor implements PreProcessInterceptor {
 
        /** The Constant logger. */
        private static final Logger logger = LoggerFactory.getLogger(SecurityInterceptor.class);
+       private static final String ACCOUNT_PERMISSIONS = "accounts/*/accountperms";
 
        /* (non-Javadoc)
         * @see org.jboss.resteasy.spi.interception.PreProcessInterceptor#preProcess(org.jboss.resteasy.spi.HttpRequest, org.jboss.resteasy.core.ResourceMethod)
@@ -84,25 +85,33 @@ public class SecurityInterceptor implements PreProcessInterceptor {
                // If the resource entity is acting as a proxy then all sub-resource will map to the resource itself.
                // This essentially means that the sub-resource inherit all the authz permissions of the entity.
                //
-               if (SecurityUtils.isEntityProxy() == true) {
+               if (SecurityUtils.isEntityProxy() == true && !resName.equalsIgnoreCase(ACCOUNT_PERMISSIONS)) {
                        resName = resEntity;
                }
                
                checkActive();
-               AuthZ authZ = AuthZ.get();
-               CSpaceResource res = new URIResourceImpl(resName, httpMethod);
-               if (!authZ.isAccessAllowed(res)) {
-                       logger.error("Access to " + res.getId() + " is NOT allowed to "
-                                       + " user=" + AuthN.get().getUserId());
-                       Response response = Response.status(
-                                       Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build();
-                       throw new WebApplicationException(response);
-               }
-               if (logger.isDebugEnabled()) {
-                       logger.debug("Access to " + res.getId() + " is allowed to "
-                                       + " user=" + AuthN.get().getUserId() +
-                                       " for tenant id=" + AuthN.get().getCurrentTenantName());
+               
+               //
+               // All active users are allowed to the their current list of permissions.  If this is not
+               // the request, then we'll do a full AuthZ check.
+               //
+               if (resName.equalsIgnoreCase(ACCOUNT_PERMISSIONS) != true) {
+                       AuthZ authZ = AuthZ.get();
+                       CSpaceResource res = new URIResourceImpl(resName, httpMethod);
+                       if (!authZ.isAccessAllowed(res)) {
+                               logger.error("Access to " + res.getId() + " is NOT allowed to "
+                                               + " user=" + AuthN.get().getUserId());
+                               Response response = Response.status(
+                                               Response.Status.FORBIDDEN).entity(uriPath + " " + httpMethod).type("text/plain").build();
+                               throw new WebApplicationException(response);
+                       }
+                       if (logger.isDebugEnabled()) {
+                               logger.debug("Access to " + res.getId() + " is allowed to "
+                                               + " user=" + AuthN.get().getUserId() +
+                                               " for tenant id=" + AuthN.get().getCurrentTenantName());
+                       }
                }
+               
                return null;
        }
 
index 4a6ad32e558c222554fd93b8a740b107271dd2ad..de8e691a0a9a6e5a102c93007292412b10d5b4c4 100644 (file)
  */
 package org.collectionspace.services.common.storage.jpa;
 
+import java.util.List;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 
 import javax.persistence.PersistenceException;
 import javax.persistence.EntityManager;
@@ -31,8 +34,24 @@ import javax.persistence.EntityManagerFactory;
 import javax.persistence.NoResultException;
 import javax.persistence.Persistence;
 import javax.persistence.Query;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
 
+import org.collectionspace.authentication.AuthN;
+import org.collectionspace.services.authorization.AccountPermission;
+import org.collectionspace.services.authorization.AccountValue;
+import org.collectionspace.services.authorization.AccountRole;
+import org.collectionspace.services.authorization.AccountRoleRel;
+import org.collectionspace.services.authorization.AuthZ;
+import org.collectionspace.services.authorization.CSpaceResource;
+import org.collectionspace.services.authorization.PermissionRole;
+import org.collectionspace.services.authorization.PermissionRoleRel;
+import org.collectionspace.services.authorization.PermissionValue;
+import org.collectionspace.services.authorization.URIResourceImpl;
+import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel;
 import org.collectionspace.services.common.document.DocumentNotFoundException;
+import org.collectionspace.services.common.security.UnauthorizedException;
+import org.collectionspace.services.common.document.JaxbUtils;
 import org.collectionspace.services.common.security.SecurityUtils;
 
 import org.slf4j.Logger;
@@ -108,6 +127,124 @@ public class JpaStorageUtils {
         //FIXME: it would be nice to verify tenantid as well
         return em.find(entityClazz, id);
     }
+    
+    private static String getUserId(String csid)
+               throws DocumentNotFoundException  {
+       String result = null;
+       
+       //FIXME: Why can't the common jar depend on the account service?  Can we move the account
+       //jaxb classes to the common "jaxb" module?
+       try {
+                       //can't use JAXB here as this runs from the common jar which cannot
+                       //depend upon the account service
+                       String whereClause = "where csid = :csid";
+                       HashMap<String, Object> params = new HashMap<String, Object>();
+                       params.put("csid", csid);
+       
+                       Object account = JpaStorageUtils.getEntity(
+                                       "org.collectionspace.services.account.AccountsCommon", whereClause, params);
+                       if (account == null) {
+                               String msg = "User's account not found, csid=" + csid;
+                               throw new DocumentNotFoundException(msg);
+                       }
+                       //
+                       // Retrieve the userId that corresponds to the csid passed in to us
+                       //
+                       result = (String)JaxbUtils.getValue(account, "getUserId");
+       } catch (Exception e) {
+                       String msg = "User's account is in invalid state, csid=" + csid;
+                       throw new DocumentNotFoundException(msg);               
+       }
+               
+       return result;
+    }
+    
+    //FIXME: This method should be moved to the AccountPermissionDocumemntHandler
+    /*
+     * This is a prototype for the /accounts/{csid}/permissions GET service call.
+     */
+    public static AccountPermission getAccountPermissions(String csid)
+       throws UnauthorizedException, DocumentNotFoundException {
+        //
+        // Make sure the user asking for this list has the correct
+        // permission -that is, the csid's userId match the currently logged in userId or
+       // that they have read access to the "accounts" resource.
+        //
+       String userId = getUserId(csid);
+       String currentUserId = AuthN.get().getUserId(); 
+        if (currentUserId.equalsIgnoreCase(userId) == false) {
+                       CSpaceResource res = new URIResourceImpl("accounts", "GET");
+                       if (AuthZ.get().isAccessAllowed(res) == false) {
+                       String msg = "Access to the permissions for the account with csid = " + csid + " is NOT allowed for " +
+                                       " user=" + currentUserId;
+                       if (logger.isDebugEnabled() == true) {
+                               logger.debug(msg);
+                       }
+                               throw new UnauthorizedException(msg);
+                       }
+        }
+        
+        AccountPermission result = new AccountPermission();
+       EntityManagerFactory emf = null;
+        EntityManager em = null;
+        Iterator<Object[]> tuples = null;
+        try {
+            StringBuilder queryStrBldr = new StringBuilder("SELECT ar, pr FROM " + AccountRoleRel.class.getName() +
+                       " ar, " + PermissionRoleRel.class.getName() + " pr" +
+                       " WHERE ar.roleId = pr.roleId and ar.userId=" + "'" + userId + "'" +
+                       "group by pr.permissionId");
+
+            emf = getEntityManagerFactory();
+            em = emf.createEntityManager();
+            String queryStr = queryStrBldr.toString(); //for debugging
+            Query q = em.createQuery(queryStr);            
+            tuples = q.getResultList().iterator();
+            if (tuples.hasNext()) {
+               //
+               // get the first tuple, extract the AccountRoleRel and set the Account value for the result list
+               //
+               Object[] tuple = tuples.next();
+               List<AccountValue> accountValues = new ArrayList<AccountValue>();
+               accountValues.add(AuthorizationRoleRel.buildAccountValue((AccountRoleRel)tuple[0]));
+               //
+               // Since we extracted the first tuple, we need to store the first perm value as well
+               // before iterating over the rest of the tuples.
+               //
+               List<PermissionValue> permissionValues = new ArrayList<PermissionValue>();
+               permissionValues.add(AuthorizationRoleRel.buildPermissionValue((PermissionRoleRel)tuple[1]));
+               //
+               // Now finish add the permission values.
+               //
+                   while (tuples.hasNext()) {
+                       tuple = tuples.next();
+                       permissionValues.add(AuthorizationRoleRel.buildPermissionValue((PermissionRoleRel)tuple[1]));
+                   }
+                   result.setAccounts(accountValues);
+                   result.setPermissions(permissionValues);
+            }
+        } catch (NoResultException nre) {
+            if (em != null && em.getTransaction().isActive()) {
+                em.getTransaction().rollback();
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug("could not find entity with id=" + userId, nre);
+            }
+            //returns null
+        } catch (Exception e) {
+            if (em != null && em.getTransaction().isActive()) {
+                em.getTransaction().rollback();
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug("could not find entity(2) with id=" + userId, e);
+            }
+        } finally {
+            if (em != null) {
+                releaseEntityManagerFactory(emf);
+            }
+        }
+        
+        return result;
+    }
 
     /**
      * getEntity