From: Richard Millet Date: Mon, 20 Sep 2010 03:45:42 +0000 (+0000) Subject: CSPACE-2884: Service call to retrieve permissions for a user without having to go... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=29e374f87a2a66b4edb45423c3ade2ce67c35793;p=tmp%2Fjakarta-migration.git CSPACE-2884: Service call to retrieve permissions for a user without having to go through all the roles --- diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java b/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java index e40ca7ca9..bb7fc830f 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/AccountResource.java @@ -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. * diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java index 3da9334a2..cee44eb57 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/AccountRoleDocumentHandler.java @@ -266,7 +266,7 @@ public class AccountRoleDocumentHandler List avs = new ArrayList(); 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 avs = new ArrayList(); 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 index 000000000..6bdf5735e --- /dev/null +++ b/services/authorization/jaxb/src/main/resources/accounts_permissions.xsd @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + AccountPermission defines 1-n association between + an account and its corresponding permissions. + + + + + + + + + + + + + + diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationRoleRel.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationRoleRel.java index 4bba070b8..0b1cf4623 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationRoleRel.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationRoleRel.java @@ -1,5 +1,6 @@ package org.collectionspace.services.common.authorization_mgt; +import org.collectionspace.services.authorization.AccountValue; import org.collectionspace.services.authorization.PermissionRoleRel; import org.collectionspace.services.authorization.AccountRoleRel; import org.collectionspace.services.authorization.PermissionValue; @@ -7,6 +8,20 @@ import org.collectionspace.services.authorization.RoleValue; public class AuthorizationRoleRel { + /** + * Builds the account value. + * + * @param arr the arr + * @return the account value + */ + static public AccountValue buildAccountValue(AccountRoleRel arr) { + AccountValue av = new AccountValue(); + av.setAccountId(arr.getAccountId()); + av.setUserId(arr.getUserId()); + av.setScreenName(arr.getScreenName()); + return av; + } + /** * Builds the role value. * diff --git a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java index be950eacd..be23afc4d 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java +++ b/services/common/src/main/java/org/collectionspace/services/common/security/SecurityInterceptor.java @@ -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; } diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java index 4a6ad32e5..de8e691a0 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaStorageUtils.java @@ -23,7 +23,10 @@ */ 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 params = new HashMap(); + 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 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 accountValues = new ArrayList(); + 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 permissionValues = new ArrayList(); + 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