From d266e1d34b3af0876f1746bb0f7fcedd182beb62 Mon Sep 17 00:00:00 2001 From: Patrick Schmitz Date: Thu, 13 Dec 2012 12:23:39 -0800 Subject: [PATCH] CSPACE-5657 Completed work on auth and AuthZImport work to handle new perms, roles, associations, etc. Special cased the assignment of tenants to the tenantManager, so it only sits in (pseudo)tenant 0. Web service and perms work now. Need to develop regression tests, and the new web app that provides a UI on this. Also need to consider getting the tenantManager password from the environment, when building it. In any case, need to be able to update the password. --- .../CollectionSpaceJaxRsApplication.java | 2 + .../src/main/resources/accounts_common.xsd | 120 +-- .../services/account/TenantResource.java | 34 + .../storage/TenantDocumentHandler.java | 25 + .../account/storage/TenantJpaFilter.java | 110 ++- .../account/storage/TenantStorageClient.java | 10 +- .../storage/TenantStorageConstants.java | 3 + .../collectionspace/authentication/AuthN.java | 4 + .../realm/db/CSpaceDbRealm.java | 80 +- services/authorization-mgt/import/pom.xml | 5 + .../importer/AuthorizationGen.java | 72 +- .../AuthorizationCommon.java | 899 ++++++++++++------ .../context/AbstractServiceContextImpl.java | 79 +- .../common/context/ServiceContext.java | 15 +- .../common/document/DocumentFilter.java | 10 +- .../common/storage/jpa/JpaDocumentFilter.java | 5 + 16 files changed, 1020 insertions(+), 453 deletions(-) diff --git a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java index 2b6cb52df..f2e3aca03 100644 --- a/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java +++ b/services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java @@ -23,6 +23,7 @@ package org.collectionspace.services.jaxrs; import org.collectionspace.services.account.AccountResource; +import org.collectionspace.services.account.TenantResource; import org.collectionspace.services.blob.BlobResource; import org.collectionspace.services.collectionobject.CollectionObjectResource; import org.collectionspace.services.id.IDResource; @@ -99,6 +100,7 @@ public class CollectionSpaceJaxRsApplication extends Application singletons.add(new SecurityInterceptor()); singletons.add(new AccountResource()); + singletons.add(new TenantResource()); singletons.add(new RoleResource()); singletons.add(new PermissionResource()); singletons.add(new ServiceGroupResource()); diff --git a/services/account/jaxb/src/main/resources/accounts_common.xsd b/services/account/jaxb/src/main/resources/accounts_common.xsd index ae82b32e2..ec2a18d6c 100644 --- a/services/account/jaxb/src/main/resources/accounts_common.xsd +++ b/services/account/jaxb/src/main/resources/accounts_common.xsd @@ -282,65 +282,67 @@ - - - - Tenant defines the tenant in CollectionSpace - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Tenant defines the tenant in CollectionSpace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java b/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java index 9f891a5ed..a149b21b0 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java @@ -25,14 +25,20 @@ package org.collectionspace.services.account; +import org.collectionspace.services.account.storage.TenantDocumentHandler; import org.collectionspace.services.account.storage.TenantStorageClient; +import org.collectionspace.services.account.storage.TenantValidatorHandler; +import org.collectionspace.services.client.IQueryManager; import org.collectionspace.services.client.TenantClient; import org.collectionspace.services.client.PayloadOutputPart; import org.collectionspace.services.common.SecurityResourceBase; import org.collectionspace.services.common.ServiceMessages; +import org.collectionspace.services.common.config.ServiceConfigUtils; 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.document.DocumentFilter; +import org.collectionspace.services.common.document.DocumentHandler; import org.collectionspace.services.common.storage.StorageClient; import org.collectionspace.services.common.storage.jpa.JpaStorageUtils; import org.jboss.resteasy.util.HttpResponseCodes; @@ -139,4 +145,32 @@ public class TenantResource extends SecurityResourceBase { } } + + /** + * Creates the document handler - special because this is not tied to a tenant or service binding + * As such, also sets up the validator handler. + * + * @param ctx the ctx + * @param commonPart the common part + * + * @return the document handler + * + * @throws Exception the exception + */ + @Override + public DocumentHandler createDocumentHandler(ServiceContext ctx, Object commonPart) throws Exception { + //DocumentHandler docHandler = ctx.getDocumentHandler(); + DocumentHandler docHandler = new TenantDocumentHandler(); + ctx.setDocumentHandler(docHandler); + docHandler.setServiceContext(ctx); + // Create a default document filter + DocumentFilter docFilter = docHandler.createDocumentFilter(); + docHandler.setDocumentFilter(docFilter); + docHandler.setCommonPart(commonPart); + // We also need to set up the validator + TenantValidatorHandler validator = new TenantValidatorHandler(); + ctx.addValidatorHandler(validator); + return docHandler; + } + } diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java index 33be18a03..f4d1446c8 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java @@ -61,7 +61,32 @@ public class TenantDocumentHandler @Override public void handleUpdate(DocumentWrapper wrapDoc) throws Exception { + Tenant tenantFound = wrapDoc.getWrappedObject(); + Tenant tenantReceived = getCommonPart(); + // If marked as metadata immutable, do not do update + merge(tenantReceived, tenantFound); } + + /** + * merge manually merges the from account to the to account + * -this method is created due to inefficiency of JPA EM merge + * @param from + * @param to + * @return merged account + */ + private Tenant merge(Tenant from, Tenant to) { + Date now = new Date(); + to.setUpdatedAtItem(now); + // The only thing we allow changing at this point is the disabled flag + to.setDisabled(from.isDisabled()); + + if (logger.isDebugEnabled()) { + logger.debug("merged account=" + + JaxbUtils.toString(to, Tenant.class)); + } + return to; + } + @Override public void completeUpdate(DocumentWrapper wrapDoc) throws Exception { diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java index 6bbc8b24b..fbba1d3ca 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java @@ -48,35 +48,69 @@ public class TenantJpaFilter extends JpaDocumentFilter { public List buildWhereForSearch(StringBuilder queryStrBldr) { List paramList = new ArrayList(); - String name = null; - List nvals = getQueryParam(TenantStorageConstants.Q_NAME); - if (null != nvals && nvals.size() > 0) { - name = nvals.get(0); - } - boolean csAdmin = SecurityUtils.isCSpaceAdmin(); - if (null != name && !name.isEmpty()) { - queryStrBldr.append(" WHERE UPPER(a."); - queryStrBldr.append(TenantStorageConstants.NAME_FIELD); - queryStrBldr.append(") LIKE :"); - queryStrBldr.append(" :" + TenantStorageConstants.Q_NAME); - paramList.add(new ParamBinding( - TenantStorageConstants.Q_NAME, "%" + name.toUpperCase() + "%")); + List paramVals = null; + boolean whereAdded = false; + { + // Look for a name filter + String name = null; + paramVals = getQueryParam(TenantStorageConstants.Q_NAME); + if (null != paramVals && paramVals.size() > 0) { + name = paramVals.get(0); + } + //boolean csAdmin = SecurityUtils.isCSpaceAdmin(); + if (null != name && !name.isEmpty()) { + queryStrBldr.append(" WHERE UPPER(a."); + queryStrBldr.append(TenantStorageConstants.NAME_FIELD); + queryStrBldr.append(") LIKE :"); + queryStrBldr.append(TenantStorageConstants.Q_NAME); + paramList.add(new ParamBinding( + TenantStorageConstants.Q_NAME, "%" + name.toUpperCase() + "%")); + whereAdded = true; + } } - String includeDisabledStr = null; - List inclDisVals = getQueryParam(TenantStorageConstants.Q_INCLUDE_DISABLED); - if (null != inclDisVals && inclDisVals.size() > 0) { - includeDisabledStr = inclDisVals.get(0); + { + // Look for a disabled sense filter + String includeDisabledStr = null; + paramVals = getQueryParam(TenantStorageConstants.Q_INCLUDE_DISABLED); + if (null != paramVals && paramVals.size() > 0) { + includeDisabledStr = paramVals.get(0); + } + // Default is to exclude disabled tenants, unless they specify to include them + boolean includeDisabled = (null != includeDisabledStr && !includeDisabledStr.isEmpty() + && Boolean.parseBoolean(includeDisabledStr)); + // If excluding, then add a clause + if(!includeDisabled) { + queryStrBldr.append(whereAdded?" AND ":" WHERE "); + queryStrBldr.append("a."); + queryStrBldr.append(TenantStorageConstants.DISABLED_FIELD); + queryStrBldr.append("=false"); + } } - // Default is to exclude disabled tenants, unless they specify to include them - boolean includeDisabled = (null != includeDisabledStr && !includeDisabledStr.isEmpty() - && Boolean.parseBoolean(includeDisabledStr)); - // If excluding, then add a clause - if(!includeDisabled) { - queryStrBldr.append(" WHERE NOT a."); - queryStrBldr.append(TenantStorageConstants.DISABLED_FIELD); + // Consider order by param. Just pick first for now. + { + String orderBy = null; + paramVals = getQueryParam(TenantStorageConstants.Q_ORDER_BY); + if (null != paramVals && paramVals.size() > 0) { + orderBy = paramVals.get(0); + } + orderBy = checkOrderByField(orderBy); + queryStrBldr.append(" ORDER BY a."); + queryStrBldr.append(orderBy); } + // Consider order direction param. Just pick first for now. + { + String orderDir = null; + paramVals = getQueryParam(TenantStorageConstants.Q_ORDER_DIR); + if (null != paramVals && paramVals.size() > 0) { + orderDir = paramVals.get(0); + } + orderDir = checkOrderDirValue(orderDir); + queryStrBldr.append(orderDir); + } + + if (logger.isDebugEnabled()) { String query = queryStrBldr.toString(); logger.debug("query=" + query); @@ -84,6 +118,34 @@ public class TenantJpaFilter extends JpaDocumentFilter { return paramList; } + + private String checkOrderByField(String input) { + String returnVal = TenantStorageConstants.NAME_FIELD; // This is the default + if (null != input && !input.isEmpty()) { + if(TenantStorageConstants.ID_FIELD.equalsIgnoreCase(input)) { + returnVal = TenantStorageConstants.ID_FIELD; + /* Effect of default is same, so skip this + } else if(TenantStorageConstants.NAME_FIELD.equalsIgnoreCase(input)) { + returnVal = TenantStorageConstants.NAME_FIELD; + */ + } + } + return returnVal; + } + + private String checkOrderDirValue(String input) { + String returnVal = JPA_ASC; // This is the default + if (null != input && !input.isEmpty()) { + if(Q_DESC.equalsIgnoreCase(input)) { + returnVal = JPA_DESC; + /* Effect of default is same, so skip this + } else if(Q_ASC.equalsIgnoreCase(input)) { + returnVal = JPA_ASC; + */ + } + } + return returnVal; + } @Override public List buildWhere(StringBuilder queryStrBldr) { diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java index 5f45cf945..6822527f6 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java @@ -63,10 +63,12 @@ public class TenantStorageClient extends JpaStorageClientImpl { DocumentHandler handler) throws BadRequestException, DocumentException { + /* if (ctx == null) { throw new IllegalArgumentException( "TenantStorageClient.create : ctx is missing"); } + */ if (handler == null) { throw new IllegalArgumentException( "TenantStorageClient.create: handler is missing"); @@ -124,10 +126,12 @@ public class TenantStorageClient extends JpaStorageClientImpl { @Override public void get(ServiceContext ctx, String id, DocumentHandler handler) throws DocumentNotFoundException, DocumentException { + /* if (ctx == null) { throw new IllegalArgumentException( "get: ctx is missing"); - } + } + */ if (handler == null) { throw new IllegalArgumentException( "get: handler is missing"); @@ -175,10 +179,12 @@ public class TenantStorageClient extends JpaStorageClientImpl { public void update(ServiceContext ctx, String id, DocumentHandler handler) throws BadRequestException, DocumentNotFoundException, DocumentException { + /* if (ctx == null) { throw new IllegalArgumentException( "TenantStorageClient.update : ctx is missing"); } + */ if (handler == null) { throw new IllegalArgumentException( "TenantStorageClient.update: handler is missing"); @@ -228,10 +234,12 @@ public class TenantStorageClient extends JpaStorageClientImpl { if (logger.isDebugEnabled()) { logger.debug("deleting entity with id=" + id); } + /* if (ctx == null) { throw new IllegalArgumentException( "TenantStorageClient.delete : ctx is missing"); } + */ EntityManagerFactory emf = null; EntityManager em = null; try { diff --git a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java index cc523092a..d780179ce 100644 --- a/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java +++ b/services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java @@ -58,7 +58,10 @@ public class TenantStorageConstants { final public static String Q_NAME = "name"; final public static String Q_INCLUDE_DISABLED= "inclDis"; + final public static String Q_ORDER_BY= "o"; + final public static String Q_ORDER_DIR= "d"; + final public static String ID_FIELD = "id"; final public static String NAME_FIELD = "name"; final public static String DISABLED_FIELD = "disabled"; } diff --git a/services/authentication/service/src/main/java/org/collectionspace/authentication/AuthN.java b/services/authentication/service/src/main/java/org/collectionspace/authentication/AuthN.java index 13a5ac599..8d91d3dbb 100644 --- a/services/authentication/service/src/main/java/org/collectionspace/authentication/AuthN.java +++ b/services/authentication/service/src/main/java/org/collectionspace/authentication/AuthN.java @@ -67,6 +67,10 @@ public class AuthN { private static volatile AuthN self = new AuthN(); private static DataSource dataSource = null; private AuthNContext authnContext; + + // Define a special account value for the tenantManager. Yes, this is a hack, but + // less troublesome than the alternatives. + public static final String TENANT_MANAGER_ACCT_ID = "0"; private AuthN() { //hardcoded initialization of a provider diff --git a/services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java b/services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java index 3a3b6de48..aa67924f3 100644 --- a/services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java +++ b/services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java @@ -298,6 +298,46 @@ public class CSpaceDbRealm implements CSpaceRealm { return getTenants(username, groupClassName, false); } + private boolean userIsTenantManager(Connection conn, String username) { + String acctQuery = "SELECT csid FROM accounts_common WHERE userid=?"; + PreparedStatement ps = null; + ResultSet rs = null; + boolean accountIsTenantManager = false; + try { + ps = conn.prepareStatement(acctQuery); + ps.setString(1, username); + rs = ps.executeQuery(); + if (rs.next()) { + String acctCSID = rs.getString(1); + if(AuthN.TENANT_MANAGER_ACCT_ID.equals(acctCSID)) { + accountIsTenantManager = true; + } + } + } catch (SQLException ex) { + if(logger.isDebugEnabled()) { + logger.debug("userIsTenantManager query failed on SQL error: " + ex.getLocalizedMessage()); + } + } catch (Exception e) { + if(logger.isDebugEnabled()) { + logger.debug("userIsTenantManager unknown error: " + e.getLocalizedMessage()); + } + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + } + } + if (ps != null) { + try { + ps.close(); + } catch (SQLException e) { + } + } + } + return accountIsTenantManager; + } + /** * Execute the tenantsQuery against the datasourceName to obtain the tenants for * the authenticated user. @@ -316,6 +356,7 @@ public class CSpaceDbRealm implements CSpaceRealm { HashMap groupsMap = new HashMap(); PreparedStatement ps = null; ResultSet rs = null; + final String defaultGroupName = "Tenants"; try { conn = getConnection(); @@ -328,15 +369,34 @@ public class CSpaceDbRealm implements CSpaceRealm { } rs = ps.executeQuery(); if (rs.next() == false) { - if (logger.isDebugEnabled()) { - logger.debug("No tenants found"); - } - // We are running with an unauthenticatedIdentity so create an - // empty Tenants set and return. - // FIXME should this be allowed? - Group g = createGroup(groupClassName, "Tenants"); - groupsMap.put(g.getName(), g); - return groupsMap.values(); + Group group = (Group) groupsMap.get(defaultGroupName); + if (group == null) { + group = createGroup(groupClassName, defaultGroupName); + groupsMap.put(defaultGroupName, group); + } + // Check for the tenantManager + if(userIsTenantManager(conn, username)) { + if (logger.isDebugEnabled()) { + logger.debug("GetTenants called with tenantManager - synthesizing the pseudo-tenant"); + } + try { + Principal p = createTenant("PseudoTenant", AuthN.TENANT_MANAGER_ACCT_ID); + if (logger.isDebugEnabled()) { + logger.debug("Assign tenantManager to tenant " + AuthN.TENANT_MANAGER_ACCT_ID); + } + group.addMember(p); + } catch (Exception e) { + logger.error("Failed to create pseudo-tenant: " + e.toString()); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("No tenants found"); + } + // We are running with an unauthenticatedIdentity so return an + // empty Tenants set. + // FIXME should this be allowed? + } + return groupsMap.values(); } do { @@ -344,7 +404,7 @@ public class CSpaceDbRealm implements CSpaceRealm { String tenantName = rs.getString(2); String groupName = rs.getString(3); if (groupName == null || groupName.length() == 0) { - groupName = "Tenants"; + groupName = defaultGroupName; } Group group = (Group) groupsMap.get(groupName); diff --git a/services/authorization-mgt/import/pom.xml b/services/authorization-mgt/import/pom.xml index 7337e72be..7efc29c42 100644 --- a/services/authorization-mgt/import/pom.xml +++ b/services/authorization-mgt/import/pom.xml @@ -53,6 +53,11 @@ ${project.version} provided + + org.collectionspace.services + org.collectionspace.services.account.client + ${project.version} + org.collectionspace.services org.collectionspace.services.authorization-mgt.service diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java index 351a4d6fa..b45d1defd 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java @@ -43,6 +43,7 @@ import org.collectionspace.services.authorization.PermissionValue; import org.collectionspace.services.authorization.perms.PermissionsList; import org.collectionspace.services.authorization.PermissionsRolesList; import org.collectionspace.services.client.RoleClient; +import org.collectionspace.services.client.TenantClient; import org.collectionspace.services.authorization.Role; import org.collectionspace.services.authorization.RoleValue; import org.collectionspace.services.authorization.RolesList; @@ -65,14 +66,18 @@ public class AuthorizationGen { // final public static boolean AUTHZ_IS_ENTITY_PROXY = false; + final public static String TENANT_MGMNT_ID = "0"; + final Logger logger = LoggerFactory.getLogger(AuthorizationGen.class); + private List tenantMgmntPermList = new ArrayList(); + private List tenantMgmntPermRoleList = new ArrayList(); private List adminPermList = new ArrayList(); private List adminPermRoleList = new ArrayList(); private List readerPermList = new ArrayList(); private List readerPermRoleList = new ArrayList(); private List adminRoles = new ArrayList(); private List readerRoles = new ArrayList(); - private Role cspaceAdminRole; + private Role cspaceTenantMgmntRole; private Hashtable tenantBindings = new Hashtable(); // @@ -87,7 +92,7 @@ public class AuthorizationGen { new TenantBindingConfigReaderImpl(tenantRootDirPath); tenantBindingConfigReader.read(); tenantBindings = tenantBindingConfigReader.getTenantBindings(); - cspaceAdminRole = buildCSpaceAdminRole(); + cspaceTenantMgmntRole = buildTenantMgmntRole(); if (logger.isDebugEnabled()) { logger.debug("initialized with tenant bindings from " + tenantRootDirPath); @@ -108,6 +113,9 @@ public class AuthorizationGen { List readerPerms = createDefaultReaderPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY); readerPermList.addAll(readerPerms); } + + List tenantMgmntPerms = createDefaultTenantMgmntPermissions(); + tenantMgmntPermList.addAll(tenantMgmntPerms); } /** @@ -144,6 +152,29 @@ public class AuthorizationGen { return apcList; } + /** + * createDefaultTenantMgmntPermissions creates default permissions for known + * Tenant Mgmnt services. + * @return + */ + public List createDefaultTenantMgmntPermissions() { + ArrayList apcList = new ArrayList(); + // Later can think about ways to configure this if we want to + Permission perm = createTenantMgmntPermission(TenantClient.SERVICE_NAME); + apcList.add(perm); + + return apcList; + } + + /** + * createTenantMgmntPermission creates special admin permissions for tenant management + * @return + */ + private Permission createTenantMgmntPermission(String resourceName) { + Permission perm = buildAdminPermission(TENANT_MGMNT_ID, resourceName); + return perm; + } + private Permission buildAdminPermission(String tenantId, String resourceName) { String description = "Generated admin permission."; return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_CRUDL_NAME); @@ -192,6 +223,7 @@ public class AuthorizationGen { allPermList = new ArrayList(); allPermList.addAll(adminPermList); allPermList.addAll(readerPermList); + allPermList.addAll(tenantMgmntPermList); } return allPermList; } @@ -204,6 +236,10 @@ public class AuthorizationGen { return readerPermList; } + public List getDefaultTenantMgmntPermissions() { + return tenantMgmntPermList; + } + /** * createDefaultRoles creates default admin and reader roles * for each tenant found in the given tenant binding file @@ -251,8 +287,8 @@ public class AuthorizationGen { allRoleList = new ArrayList(); allRoleList.addAll(adminRoles); allRoleList.addAll(readerRoles); - // Finally, add the "super" role to the list - allRoleList.add(cspaceAdminRole); + // Finally, add the tenant manager role to the list + allRoleList.add(cspaceTenantMgmntRole); } return allRoleList; } @@ -268,12 +304,20 @@ public class AuthorizationGen { readerPermRoleList.add(permRdrRole); } - //CSpace Administrator has all access + //CSpace Tenant Manager has all access + // PLS - this looks wrong. This should be a tenantMgmnt role, and only have access to + // tenantMgmnt perms. Will leave this for now... List roles = new ArrayList(); - roles.add(cspaceAdminRole); - for (Permission p : adminPermList) { + roles.add(cspaceTenantMgmntRole); + /* for (Permission p : adminPermList) { PermissionRole permCAdmRole = associatePermissionRoles(p, roles, false); adminPermRoleList.add(permCAdmRole); + } */ + // 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); + tenantMgmntPermRoleList.add(permTMRole); } } @@ -344,6 +388,7 @@ public class AuthorizationGen { allPermRoleList = new ArrayList(); allPermRoleList.addAll(adminPermRoleList); allPermRoleList.addAll(readerPermRoleList); + allPermRoleList.addAll(tenantMgmntPermRoleList); } return allPermRoleList; } @@ -356,18 +401,19 @@ public class AuthorizationGen { return readerPermRoleList; } - private Role buildCSpaceAdminRole() { + private Role buildTenantMgmntRole() { Role role = new Role(); - role.setDescription("A generated super role that has permissions across tenancies."); - role.setDisplayName(AuthorizationCommon.ROLE_ADMINISTRATOR); + role.setDescription("A generated super role that has permissions to manage tenants."); + role.setDisplayName(AuthorizationCommon.ROLE_ALL_TENANTS_MANAGER); role.setRoleName(AuthorizationCommon.getQualifiedRoleName( - AuthorizationCommon.ADMINISTRATOR_TENANT_ID, role.getDisplayName())); - role.setCsid(AuthorizationCommon.ROLE_ADMINISTRATOR_ID); - role.setTenantId(AuthorizationCommon.ADMINISTRATOR_TENANT_ID); + AuthorizationCommon.ALL_TENANTS_MANAGER_TENANT_ID, role.getDisplayName())); + role.setCsid(AuthorizationCommon.ROLE_ALL_TENANTS_MANAGER_ID); + role.setTenantId(AuthorizationCommon.ALL_TENANTS_MANAGER_TENANT_ID); return role; } + public void exportDefaultRoles(String fileName) { RolesList rList = new RolesList(); diff --git a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java index 383d1466f..dde31ac03 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java +++ b/services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java @@ -16,6 +16,7 @@ import javax.naming.NamingException; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; +import org.collectionspace.authentication.AuthN; import org.collectionspace.services.authorization.AuthZ; import org.collectionspace.services.authorization.CSpaceAction; import org.collectionspace.services.authorization.PermissionException; @@ -69,6 +70,7 @@ public class AuthorizationCommon { // for READ-ONLY final public static String ACTIONGROUP_RL_NAME = "RL"; final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH}; + /* * Inner class to deal with predefined ADMIN and READER action groupds @@ -100,13 +102,18 @@ public class AuthorizationCommon { // // The "super" role has a predefined ID of "0" and a tenant ID of "0"; // - final public static String ROLE_ADMINISTRATOR = "ADMINISTRATOR"; - final public static String ROLE_ADMINISTRATOR_ID = "0"; - final public static String ADMINISTRATOR_TENANT_ID = "0"; + final public static String ROLE_ALL_TENANTS_MANAGER = "ALL_TENANTS_MANAGER"; + final public static String ROLE_ALL_TENANTS_MANAGER_ID = "0"; + final public static String ALL_TENANTS_MANAGER_TENANT_ID = "0"; final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR"; final public static String ROLE_TENANT_READER = "TENANT_READER"; + public static final String TENANT_MANAGER_USER = "tenantManager"; + public static final String TENANT_MANAGER_SCREEN_NAME = TENANT_MANAGER_USER; + public static final String DEFAULT_TENANT_MANAGER_PASSWORD = "manage"; + public static final String DEFAULT_TENANT_MANAGER_EMAIL = "tenantManager@collectionspace.org"; + public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; public static final String TENANT_READER_ACCT_PREFIX = "reader@"; public static final String ROLE_PREFIX = "ROLE_"; @@ -119,6 +126,29 @@ public class AuthorizationCommon { public static String ROLE_SPRING_ADMIN_ID = "-1"; public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + // SQL for init tasks + final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL = + "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)" + +" VALUES(?, ?, ?, ?, now())"; + final private static String INSERT_ACCOUNT_ROLE_SQL_POSTGRES = + "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)" + +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())"; + final private static String QUERY_USERS_SQL = + "SELECT username FROM users WHERE username LIKE '" + +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"+TENANT_READER_ACCT_PREFIX+"%'"; + final private static String INSERT_USER_SQL = + "INSERT INTO users (username,passwd, created_at) VALUES (?,?, now())"; + final private static String INSERT_ACCOUNT_SQL = + "INSERT INTO accounts_common " + + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) " + + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())"; + + // TENANT MANAGER specific SQL + final private static String QUERY_TENANT_MGR_USER_SQL = + "SELECT username FROM users WHERE username = '"+TENANT_MANAGER_USER+"'"; + final private static String GET_TENANT_MGR_ROLE_SQL = + "SELECT csid from roles WHERE tenant_id='"+ALL_TENANTS_MANAGER_TENANT_ID+"' and rolename=?"; + public static Role getRole(String tenantId, String displayName) { Role role = null; @@ -348,341 +378,591 @@ public class AuthorizationCommon { return permRole; } + private static Hashtable getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) { + + Hashtable tenantBindings = + tenantBindingConfigReader.getTenantBindings(); + Hashtable tenantInfo = new Hashtable(); + for (TenantBindingType tenantBinding : tenantBindings.values()) { + String tId = tenantBinding.getId(); + String tName = tenantBinding.getName(); + tenantInfo.put(tId, tName); + if (logger.isDebugEnabled()) { + logger.debug("getTenantNamesFromConfig found configured tenant id: "+tId+" name: "+tName); + } + } + return tenantInfo; + } - /* - * FIXME: REM - This method is way too big -over 300 lines! We need to break it up into - * smaller, discrete, sub-methods. - */ - public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) { - if (logger.isDebugEnabled()) { - logger.debug("ServiceMain.createDefaultAccounts starting..."); + private static ArrayList compileExistingTenants(Connection conn, Hashtable tenantInfo) + throws SQLException, Exception { + Statement stmt = null; + ArrayList existingTenants = new ArrayList(); + // First find or create the tenants + final String queryTenantSQL = "SELECT id,name FROM tenants"; + try { + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(queryTenantSQL); + while (rs.next()) { + String tId = rs.getString("id"); + String tName = rs.getString("name"); + if(tenantInfo.containsKey(tId)) { + existingTenants.add(tId); + if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) { + logger.warn("Configured name for tenant: " + +tId+" in repository: "+tName + +" does not match config'd name: "+ tenantInfo.get(tId)); + } + } + } + rs.close(); + } catch(Exception e) { + throw e; + } finally { + if(stmt!=null) + stmt.close(); } - - Hashtable tenantBindings = - tenantBindingConfigReader.getTenantBindings(); - Hashtable tenantInfo = new Hashtable(); - for (TenantBindingType tenantBinding : tenantBindings.values()) { - String tId = tenantBinding.getId(); - String tName = tenantBinding.getName(); - tenantInfo.put(tId, tName); - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts found configured tenant id: "+tId+" name: "+tName); - } - } - Connection conn = null; + + return existingTenants; + } + + private static void createMissingTenants(Connection conn, Hashtable tenantInfo, + ArrayList existingTenants) throws SQLException, Exception { + // Need to define and look for a createDisabled attribute in tenant config + final String insertTenantSQL = + "INSERT INTO tenants (id,name,disabled,created_at) VALUES (?,?,FALSE,now())"; PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(insertTenantSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + if(existingTenants.contains(tId)) { + if (logger.isDebugEnabled()) { + logger.debug("createMissingTenants: tenant exists (skipping): " + +tenantInfo.get(tId)); + } + continue; + } + pstmt.setString(1, tId); // set id param + pstmt.setString(2, tenantInfo.get(tId)); // set name param + if (logger.isDebugEnabled()) { + logger.debug("createMissingTenants adding entry for tenant: "+tId); + } + pstmt.executeUpdate(); + } + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + } + + private static ArrayList findOrCreateDefaultUsers(Connection conn, Hashtable tenantInfo) + throws SQLException, Exception { + // Second find or create the users Statement stmt = null; - // TODO - need to put in tests for existence first. - // We could just look for the accounts per tenant up front, and assume that - // the rest is there if the accounts are. - // Could add a sql script to remove these if need be - Spring only does roles, - // and we're not touching that, so we could safely toss the - // accounts, users, account-tenants, account-roles, and start over. + PreparedStatement pstmt = null; + ArrayList usersInRepo = new ArrayList(); try { - conn = getConnection(); - // First find or create the tenants - String queryTenantSQL = - "SELECT id,name FROM tenants"; - stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(queryTenantSQL); - ArrayList existingTenants = new ArrayList(); - while (rs.next()) { - String tId = rs.getString("id"); - String tName = rs.getString("name"); - if(tenantInfo.containsKey(tId)) { - existingTenants.add(tId); - if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) { - logger.warn("Configured name for tenant: " - +tId+" in repository: "+tName - +" does not match config'd name: "+ tenantInfo.get(tId)); - } - } - } - rs.close(); - - String insertTenantSQL = - "INSERT INTO tenants (id,name,disabled,created_at) VALUES (?,?,FALSE,now())"; - pstmt = conn.prepareStatement(insertTenantSQL); // create a statement - for(String tId : tenantInfo.keySet()) { - if(existingTenants.contains(tId)) { - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts: tenant exists (skipping): " - +tenantInfo.get(tId)); - } - continue; - } - pstmt.setString(1, tId); // set id param - pstmt.setString(2, tenantInfo.get(tId)); // set name param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts adding entry for tenant: "+tId); - } - pstmt.executeUpdate(); + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(QUERY_USERS_SQL); + while (rs.next()) { + String uName = rs.getString("username"); + usersInRepo.add(uName); } - pstmt.close(); - // Second find or create the users - String queryUserSQL = - "SELECT username FROM users WHERE username LIKE '" - +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '" - +TENANT_READER_ACCT_PREFIX+"%'"; - rs = stmt.executeQuery(queryUserSQL); - ArrayList usersInRepo = new ArrayList(); - while (rs.next()) { - String uName = rs.getString("username"); - usersInRepo.add(uName); - } - rs.close(); - String insertUserSQL = - "INSERT INTO users (username,passwd, created_at)" - +" VALUES (?,?, now())"; - pstmt = conn.prepareStatement(insertUserSQL); // create a statement + rs.close(); + pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement for(String tName : tenantInfo.values()) { String adminAcctName = getDefaultAdminUserID(tName); if(!usersInRepo.contains(adminAcctName)) { - String secEncPasswd = SecurityUtils.createPasswordHash( - adminAcctName, DEFAULT_ADMIN_PASSWORD); - pstmt.setString(1, adminAcctName); // set username param - pstmt.setString(2, secEncPasswd); // set passwd param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts adding user: " - +adminAcctName+" for tenant: "+tName); - } - pstmt.executeUpdate(); - } else if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts: user: "+adminAcctName - +" already exists - skipping."); - } - - - String readerAcctName = getDefaultReaderUserID(tName); - if(!usersInRepo.contains(readerAcctName)) { - String secEncPasswd = SecurityUtils.createPasswordHash( - readerAcctName, DEFAULT_READER_PASSWORD); - pstmt.setString(1, readerAcctName); // set username param - pstmt.setString(2, secEncPasswd); // set passwd param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts adding user: " - +readerAcctName+" for tenant: "+tName); - } - pstmt.executeUpdate(); - } else if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts: user: "+readerAcctName - +" already exists - skipping."); - } - } - pstmt.close(); - // Third, create the accounts. Assume that if the users were already there, - // then the accounts were as well - String insertAccountSQL = - "INSERT INTO accounts_common " - + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) " - + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())"; - Hashtable tenantAdminAcctCSIDs = new Hashtable(); - Hashtable tenantReaderAcctCSIDs = new Hashtable(); - pstmt = conn.prepareStatement(insertAccountSQL); // create a statement - for(String tId : tenantInfo.keySet()) { - String tName = tenantInfo.get(tId); - String adminCSID = UUID.randomUUID().toString(); - tenantAdminAcctCSIDs.put(tId, adminCSID); - String adminAcctName = getDefaultAdminUserID(tName); - if(!usersInRepo.contains(adminAcctName)) { - pstmt.setString(1, adminCSID); // set csid param - pstmt.setString(2, adminAcctName); // set email param (bogus) - pstmt.setString(3, adminAcctName); // set userid param - pstmt.setString(4, "Administrator");// set screen name param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts adding account: " - +adminAcctName+" for tenant: "+tName); - } - pstmt.executeUpdate(); + String secEncPasswd = SecurityUtils.createPasswordHash( + adminAcctName, DEFAULT_ADMIN_PASSWORD); + pstmt.setString(1, adminAcctName); // set username param + pstmt.setString(2, secEncPasswd); // set passwd param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultUsersAndAccounts adding user: " + +adminAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); } else if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts: user: "+adminAcctName - +" already exists - skipping account generation."); + logger.debug("createDefaultUsersAndAccounts: user: "+adminAcctName + +" already exists - skipping."); } - String readerCSID = UUID.randomUUID().toString(); - tenantReaderAcctCSIDs.put(tId, readerCSID); + String readerAcctName = getDefaultReaderUserID(tName); if(!usersInRepo.contains(readerAcctName)) { - pstmt.setString(1, readerCSID); // set csid param - pstmt.setString(2, readerAcctName); // set email param (bogus) - pstmt.setString(3, readerAcctName); // set userid param - pstmt.setString(4, "Reader"); // set screen name param + String secEncPasswd = SecurityUtils.createPasswordHash( + readerAcctName, DEFAULT_READER_PASSWORD); + pstmt.setString(1, readerAcctName); // set username param + pstmt.setString(2, secEncPasswd); // set passwd param if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts adding account: " + logger.debug("createDefaultUsersAndAccounts adding user: " +readerAcctName+" for tenant: "+tName); } pstmt.executeUpdate(); } else if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts: user: "+readerAcctName - +" already exists - skipping account creation."); + logger.debug("createDefaultUsersAndAccounts: user: "+readerAcctName + +" already exists - skipping."); } } pstmt.close(); - // Fourth, bind accounts to tenants. Assume that if the users were already there, - // then the accounts were bound to tenants correctly - String insertAccountTenantSQL; - DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType(); - if (databaseProductType == DatabaseProductType.MYSQL) { - insertAccountTenantSQL = - "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " - + " VALUES(?, ?)"; - } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { - insertAccountTenantSQL = - "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " - + " VALUES(nextval('hibernate_sequence'), ?, ?)"; - } else { - throw new Exception("Unrecognized database system."); + } catch(Exception e) { + throw e; + } finally { + if(stmt!=null) + stmt.close(); + if(pstmt!=null) + pstmt.close(); + } + return usersInRepo; + } + + private static void findOrCreateDefaultAccounts(Connection conn, Hashtable tenantInfo, + ArrayList usersInRepo, + Hashtable tenantAdminAcctCSIDs, Hashtable tenantReaderAcctCSIDs) + throws SQLException, Exception { + // Third, create the accounts. Assume that if the users were already there, + // then the accounts were as well + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String tName = tenantInfo.get(tId); + String adminCSID = UUID.randomUUID().toString(); + tenantAdminAcctCSIDs.put(tId, adminCSID); + String adminAcctName = getDefaultAdminUserID(tName); + if(!usersInRepo.contains(adminAcctName)) { + pstmt.setString(1, adminCSID); // set csid param + pstmt.setString(2, adminAcctName); // set email param (bogus) + pstmt.setString(3, adminAcctName); // set userid param + pstmt.setString(4, "Administrator");// set screen name param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding account: " + +adminAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+adminAcctName + +" already exists - skipping account generation."); + } + + String readerCSID = UUID.randomUUID().toString(); + tenantReaderAcctCSIDs.put(tId, readerCSID); + String readerAcctName = getDefaultReaderUserID(tName); + if(!usersInRepo.contains(readerAcctName)) { + pstmt.setString(1, readerCSID); // set csid param + pstmt.setString(2, readerAcctName); // set email param (bogus) + pstmt.setString(3, readerAcctName); // set userid param + pstmt.setString(4, "Reader"); // set screen name param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts adding account: " + +readerAcctName+" for tenant: "+tName); + } + pstmt.executeUpdate(); + } else if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts: user: "+readerAcctName + +" already exists - skipping account creation."); + } + } + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + } + + private static boolean findOrCreateTenantManagerUserAndAccount(Connection conn) + throws SQLException, Exception { + // Find or create the special tenant manager account. + // Later can make the user name for tenant manager be configurable, settable. + Statement stmt = null; + PreparedStatement pstmt = null; + boolean created = false; + try { + boolean foundTMgrUser = false; + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(QUERY_TENANT_MGR_USER_SQL); + // Should only find one - only consider it + if(rs.next()) { + String uName = rs.getString("username"); + foundTMgrUser = uName.equals(TENANT_MANAGER_USER); } - pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement - for(String tId : tenantInfo.keySet()) { - String tName = tenantInfo.get(tId); - if(!usersInRepo.contains(getDefaultAdminUserID(tName))) { - String adminAcct = tenantAdminAcctCSIDs.get(tId); - pstmt.setString(1, adminAcct); // set acct CSID param - pstmt.setString(2, tId); // set tenant_id param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding account id: " - +adminAcct+" to tenant id: "+tId); - } - pstmt.executeUpdate(); - } - if(!usersInRepo.contains(getDefaultReaderUserID(tName))) { - String readerAcct = tenantReaderAcctCSIDs.get(tId); - pstmt.setString(1, readerAcct); // set acct CSID param - pstmt.setString(2, tId); // set tenant_id param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding account id: " - +readerAcct+" to tenant id: "+tId); - } - pstmt.executeUpdate(); - } + rs.close(); + if(!foundTMgrUser) { + pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement + String secEncPasswd = SecurityUtils.createPasswordHash( + TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD); + pstmt.setString(1, TENANT_MANAGER_USER); // set username param + pstmt.setString(2, secEncPasswd); // set passwd param + if (logger.isDebugEnabled()) { + logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager user: " + +TENANT_MANAGER_USER); + } + pstmt.executeUpdate(); + pstmt.close(); + // Now create the account to match + pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement + pstmt.setString(1, AuthN.TENANT_MANAGER_ACCT_ID); // set csid param + pstmt.setString(2, DEFAULT_TENANT_MANAGER_EMAIL); // set email param (bogus) + pstmt.setString(3, TENANT_MANAGER_USER); // set userid param + pstmt.setString(4, TENANT_MANAGER_SCREEN_NAME);// set screen name param + if (logger.isDebugEnabled()) { + logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager account: " + +TENANT_MANAGER_USER); + } + pstmt.executeUpdate(); + pstmt.close(); + created = true; + } else if (logger.isDebugEnabled()) { + logger.debug("findOrCreateTenantManagerUserAndAccount: tenant manager: "+TENANT_MANAGER_USER + +" already exists."); } - pstmt.close(); - // Fifth, fetch and save the default roles - String springAdminRoleCSID = null; - String querySpringRole = - "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'"; - rs = stmt.executeQuery(querySpringRole); + } catch(Exception e) { + throw e; + } finally { + if(stmt!=null) + stmt.close(); + if(pstmt!=null) + pstmt.close(); + } + return created; + } + + private static void bindDefaultAccountsToTenants(Connection conn, DatabaseProductType databaseProductType, + Hashtable tenantInfo, ArrayList usersInRepo, + Hashtable tenantAdminAcctCSIDs, Hashtable tenantReaderAcctCSIDs) + throws SQLException, Exception { + // Fourth, bind accounts to tenants. Assume that if the users were already there, + // then the accounts were bound to tenants correctly + PreparedStatement pstmt = null; + try { + String insertAccountTenantSQL; + if (databaseProductType == DatabaseProductType.MYSQL) { + insertAccountTenantSQL = + "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " + + " VALUES(?, ?)"; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + insertAccountTenantSQL = + "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) " + + " VALUES(nextval('hibernate_sequence'), ?, ?)"; + } else { + throw new Exception("Unrecognized database system."); + } + pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String tName = tenantInfo.get(tId); + if(!usersInRepo.contains(getDefaultAdminUserID(tName))) { + String adminAcct = tenantAdminAcctCSIDs.get(tId); + pstmt.setString(1, adminAcct); // set acct CSID param + pstmt.setString(2, tId); // set tenant_id param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account id: " + +adminAcct+" to tenant id: "+tId); + } + pstmt.executeUpdate(); + } + if(!usersInRepo.contains(getDefaultReaderUserID(tName))) { + String readerAcct = tenantReaderAcctCSIDs.get(tId); + pstmt.setString(1, readerAcct); // set acct CSID param + pstmt.setString(2, tId); // set tenant_id param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account id: " + +readerAcct+" to tenant id: "+tId); + } + pstmt.executeUpdate(); + } + } + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + } + + + private static String findOrCreateDefaultRoles(Connection conn, Hashtable tenantInfo, + Hashtable tenantAdminRoleCSIDs, Hashtable tenantReaderRoleCSIDs) + throws SQLException, Exception { + // Fifth, fetch and save the default roles + String springAdminRoleCSID = null; + Statement stmt = null; + PreparedStatement pstmt = null; + try { + final String querySpringRole = + "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'"; + stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(querySpringRole); if(rs.next()) { springAdminRoleCSID = rs.getString(1); - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts found Spring Admin role: " - +springAdminRoleCSID); - } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found Spring Admin role: " + +springAdminRoleCSID); + } } else { - String insertSpringAdminRoleSQL = - "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) " - + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')"; + final String insertSpringAdminRoleSQL = + "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) " + + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')"; stmt.executeUpdate(insertSpringAdminRoleSQL); springAdminRoleCSID = "-1"; - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts CREATED Spring Admin role: " - +springAdminRoleCSID); - } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts CREATED Spring Admin role: " + +springAdminRoleCSID); + } } - rs.close(); - String getRoleCSIDSql = - "SELECT csid from roles WHERE tenant_id=? and rolename=?"; - pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement - rs = null; - Hashtable tenantAdminRoleCSIDs = new Hashtable(); - Hashtable tenantReaderRoleCSIDs = new Hashtable(); - for(String tId : tenantInfo.keySet()) { - pstmt.setString(1, tId); // set tenant_id param - pstmt.setString(2, getDefaultAdminRole(tId)); // set rolename param - rs = pstmt.executeQuery(); - // extract data from the ResultSet - if(!rs.next()) { - throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId) - +" for tenant id: "+tId+" in roles!"); - } + rs.close(); + final String getRoleCSIDSql = + "SELECT csid from roles WHERE tenant_id=? and rolename=?"; + pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement + rs = null; + for(String tId : tenantInfo.keySet()) { + pstmt.setString(1, tId); // set tenant_id param + pstmt.setString(2, getDefaultAdminRole(tId)); // set rolename param + rs = pstmt.executeQuery(); + // extract data from the ResultSet + if(!rs.next()) { + throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId) + +" for tenant id: "+tId+" in roles!"); + } String tenantAdminRoleCSID = rs.getString(1); - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts found role: " - +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID - +") for tenant id: "+tId); - } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found role: " + +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID + +") for tenant id: "+tId); + } tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID); - pstmt.setString(1, tId); // set tenant_id param - pstmt.setString(2, getDefaultReaderRole(tId)); // set rolename param - rs.close(); - rs = pstmt.executeQuery(); - // extract data from the ResultSet - if(!rs.next()) { - throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId) - +" for tenant id: "+tId+" in roles!"); - } + pstmt.setString(1, tId); // set tenant_id param + pstmt.setString(2, getDefaultReaderRole(tId)); // set rolename param + rs.close(); + rs = pstmt.executeQuery(); + // extract data from the ResultSet + if(!rs.next()) { + throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId) + +" for tenant id: "+tId+" in roles!"); + } String tenantReaderRoleCSID = rs.getString(1); - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts found role: " - +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID - +") for tenant id: "+tId); - } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts found role: " + +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID + +") for tenant id: "+tId); + } tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID); - rs.close(); - } - pstmt.close(); - // Sixth, bind the accounts to roles. If the users already existed, - // we'll assume they were set up correctly. - String insertAccountRoleSQL; - if (databaseProductType == DatabaseProductType.MYSQL) { - insertAccountRoleSQL = - "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)" - +" VALUES(?, ?, ?, ?, now())"; - } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { - insertAccountRoleSQL = - "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)" - +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())"; - } else { - throw new Exception("Unrecognized database system."); - } - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n" - +insertAccountRoleSQL); - } - pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement - for(String tId : tenantInfo.keySet()) { - String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId)); - if(!usersInRepo.contains(adminUserId)) { - String adminAcct = tenantAdminAcctCSIDs.get(tId); - String adminRoleId = tenantAdminRoleCSIDs.get(tId); - pstmt.setString(1, adminAcct); // set acct CSID param - pstmt.setString(2, adminUserId); // set user_id param - pstmt.setString(3, adminRoleId); // set role_id param - pstmt.setString(4, getDefaultAdminRole(tId)); // set rolename param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding account: " - +adminUserId+" to Admin role("+adminRoleId - +") for tenant id: "+tId); - } - pstmt.executeUpdate(); - // Now add the Spring Admin Role to the admin accounts - pstmt.setString(3, springAdminRoleCSID); // set role_id param - pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding account: " - +adminUserId+" to Spring Admin role: "+springAdminRoleCSID); - } - pstmt.executeUpdate(); - } - String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId)); - if(!usersInRepo.contains(readerUserId)) { - String readerAcct = tenantReaderAcctCSIDs.get(tId); - String readerRoleId = tenantReaderRoleCSIDs.get(tId); - pstmt.setString(1, readerAcct); // set acct CSID param - pstmt.setString(2, readerUserId); // set user_id param - pstmt.setString(3, readerRoleId); // set role_id param - pstmt.setString(4, getDefaultReaderRole(tId)); // set rolename param - if (logger.isDebugEnabled()) { - logger.debug("createDefaultAccounts binding account: " - +readerUserId+" to Reader role("+readerRoleId - +") for tenant id: "+tId); - } - pstmt.executeUpdate(); - } - } - pstmt.close(); - stmt.close(); + rs.close(); + } + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(stmt!=null) + stmt.close(); + if(pstmt!=null) + pstmt.close(); + } + return springAdminRoleCSID; + } + + private static String findTenantManagerRole(Connection conn ) + throws SQLException, RuntimeException, Exception { + String tenantMgrRoleCSID = null; + PreparedStatement pstmt = null; + try { + String rolename = getQualifiedRoleName(ALL_TENANTS_MANAGER_TENANT_ID, + ROLE_ALL_TENANTS_MANAGER); + pstmt = conn.prepareStatement(GET_TENANT_MGR_ROLE_SQL); // create a statement + ResultSet rs = null; + pstmt.setString(1, rolename); // set rolename param + rs = pstmt.executeQuery(); + if(rs.next()) { + tenantMgrRoleCSID = rs.getString(1); + if (logger.isDebugEnabled()) { + logger.debug("findTenantManagerRole found Tenant Mgr role: " + +tenantMgrRoleCSID); + } + } + rs.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + if(tenantMgrRoleCSID==null) + throw new RuntimeException("findTenantManagerRole: Cound not find tenant Manager Role!"); + return tenantMgrRoleCSID; + } + + private static void bindAccountsToRoles(Connection conn, DatabaseProductType databaseProductType, + Hashtable tenantInfo, ArrayList usersInRepo, + String springAdminRoleCSID, + Hashtable tenantAdminRoleCSIDs, Hashtable tenantReaderRoleCSIDs, + Hashtable tenantAdminAcctCSIDs, Hashtable tenantReaderAcctCSIDs) + throws SQLException, Exception { + // Sixth, bind the accounts to roles. If the users already existed, + // we'll assume they were set up correctly. + PreparedStatement pstmt = null; + try { + String insertAccountRoleSQL; + if (databaseProductType == DatabaseProductType.MYSQL) { + insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES; + } else { + throw new Exception("Unrecognized database system."); + } + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n" + +insertAccountRoleSQL); + } + pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement + for(String tId : tenantInfo.keySet()) { + String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId)); + if(!usersInRepo.contains(adminUserId)) { + String adminAcct = tenantAdminAcctCSIDs.get(tId); + String adminRoleId = tenantAdminRoleCSIDs.get(tId); + pstmt.setString(1, adminAcct); // set acct CSID param + pstmt.setString(2, adminUserId); // set user_id param + pstmt.setString(3, adminRoleId); // set role_id param + pstmt.setString(4, getDefaultAdminRole(tId)); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +adminUserId+" to Admin role("+adminRoleId + +") for tenant id: "+tId); + } + pstmt.executeUpdate(); + // Now add the Spring Admin Role to the admin accounts + pstmt.setString(3, springAdminRoleCSID); // set role_id param + pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +adminUserId+" to Spring Admin role: "+springAdminRoleCSID); + } + pstmt.executeUpdate(); + } + String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId)); + if(!usersInRepo.contains(readerUserId)) { + String readerAcct = tenantReaderAcctCSIDs.get(tId); + String readerRoleId = tenantReaderRoleCSIDs.get(tId); + pstmt.setString(1, readerAcct); // set acct CSID param + pstmt.setString(2, readerUserId); // set user_id param + pstmt.setString(3, readerRoleId); // set role_id param + pstmt.setString(4, getDefaultReaderRole(tId)); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +readerUserId+" to Reader role("+readerRoleId + +") for tenant id: "+tId); + } + pstmt.executeUpdate(); + } + } + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + } + + private static void bindTenantManagerAccountRole(Connection conn, DatabaseProductType databaseProductType, + String tenantManagerUserID, String tenantManagerAccountID, String tenantManagerRoleID, String tenantManagerRoleName ) + throws SQLException, Exception { + PreparedStatement pstmt = null; + try { + String insertAccountRoleSQL; + if (databaseProductType == DatabaseProductType.MYSQL) { + insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL; + } else if (databaseProductType == DatabaseProductType.POSTGRESQL) { + insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES; + } else { + throw new Exception("Unrecognized database system."); + } + if (logger.isDebugEnabled()) { + logger.debug("bindTenantManagerAccountRole binding account to role with SQL:\n" + +insertAccountRoleSQL); + } + pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement + pstmt.setString(1, tenantManagerAccountID); // set acct CSID param + pstmt.setString(2, tenantManagerUserID); // set user_id param + pstmt.setString(3, tenantManagerRoleID); // set role_id param + pstmt.setString(4, tenantManagerRoleName); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("bindTenantManagerAccountRole binding user: " + +tenantManagerUserID+" to Admin role("+tenantManagerRoleName+")"); + } + pstmt.executeUpdate(); + /* At this point, tenant manager should not need the Spring Admin Role + pstmt.setString(3, springAdminRoleCSID); // set role_id param + pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param + if (logger.isDebugEnabled()) { + logger.debug("createDefaultAccounts binding account: " + +adminUserId+" to Spring Admin role: "+springAdminRoleCSID); + } + pstmt.executeUpdate(); + */ + pstmt.close(); + } catch(Exception e) { + throw e; + } finally { + if(pstmt!=null) + pstmt.close(); + } + } + + public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) { + if (logger.isDebugEnabled()) { + logger.debug("ServiceMain.createDefaultAccounts starting..."); + } + + Hashtable tenantInfo = getTenantNamesFromConfig(tenantBindingConfigReader); + + Connection conn = null; + // TODO - need to put in tests for existence first. + // We could just look for the accounts per tenant up front, and assume that + // the rest is there if the accounts are. + // Could add a sql script to remove these if need be - Spring only does roles, + // and we're not touching that, so we could safely toss the + // accounts, users, account-tenants, account-roles, and start over. + try { + DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType(); + conn = getConnection(); + ArrayList existingTenants = compileExistingTenants(conn, tenantInfo); + + createMissingTenants(conn, tenantInfo, existingTenants); + + ArrayList usersInRepo = findOrCreateDefaultUsers(conn, tenantInfo); + + Hashtable tenantAdminAcctCSIDs = new Hashtable(); + Hashtable tenantReaderAcctCSIDs = new Hashtable(); + findOrCreateDefaultAccounts(conn, tenantInfo, usersInRepo, + tenantAdminAcctCSIDs, tenantReaderAcctCSIDs); + + bindDefaultAccountsToTenants(conn, databaseProductType, tenantInfo, usersInRepo, + tenantAdminAcctCSIDs, tenantReaderAcctCSIDs); + + Hashtable tenantAdminRoleCSIDs = new Hashtable(); + Hashtable tenantReaderRoleCSIDs = new Hashtable(); + String springAdminRoleCSID = findOrCreateDefaultRoles(conn, tenantInfo, + tenantAdminRoleCSIDs, tenantReaderRoleCSIDs); + + bindAccountsToRoles(conn, databaseProductType, + tenantInfo, usersInRepo, springAdminRoleCSID, + tenantAdminRoleCSIDs, tenantReaderRoleCSIDs, + tenantAdminAcctCSIDs, tenantReaderAcctCSIDs); + + boolean createdTenantMgrAccount = findOrCreateTenantManagerUserAndAccount(conn); + if(createdTenantMgrAccount) { + // If we created the account, we need to create the bindings. Otherwise, assume they + // are all set (from previous initialization). + String tenantManagerRoleCSID = findTenantManagerRole(conn); + bindTenantManagerAccountRole(conn, databaseProductType, + TENANT_MANAGER_USER, AuthN.TENANT_MANAGER_ACCT_ID, + tenantManagerRoleCSID, ROLE_ALL_TENANTS_MANAGER); + } } catch (RuntimeException rte) { if (logger.isDebugEnabled()) { logger.debug("Exception in createDefaultAccounts: "+ @@ -712,10 +992,6 @@ public class AuthorizationCommon { try { if(conn!=null) conn.close(); - if(pstmt!=null) - pstmt.close(); - if(stmt!=null) - stmt.close(); } catch (SQLException sqle) { if (logger.isDebugEnabled()) { logger.debug("SQL Exception closing statement/connection: " @@ -808,7 +1084,6 @@ public class AuthorizationCommon { try { em = emf.createEntityManager(); - Role superRole = AuthorizationCommon.getRole(em, ADMINISTRATOR_TENANT_ID, ROLE_ADMINISTRATOR); Hashtable tenantBindings = tenantBindingConfigReader.getTenantBindings(); for (String tenantId : tenantBindings.keySet()) { @@ -840,12 +1115,6 @@ public class AuthorizationCommon { + ":" + transitionDef.getName() + ":" + ACTIONGROUP_RL + ":" + profiler.getCumulativeTime()); - /* - // - // Create the permission for the super-admin role. Note we use the same "adminPerm" instance we used for the "adminPermRole" instance - // - persist(em, adminPerm, superRole, false); - */ } em.getTransaction().commit(); } catch (IllegalStateException e) { diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java index 1b03aa473..178c2fbfc 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java @@ -33,6 +33,7 @@ import javax.ws.rs.core.UriInfo; import org.collectionspace.services.client.IQueryManager; import org.collectionspace.services.client.workflow.WorkflowClient; import org.collectionspace.services.common.ServiceMain; +import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon; import org.collectionspace.services.common.config.PropertyItemUtils; import org.collectionspace.services.common.config.ServiceConfigUtils; import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; @@ -124,35 +125,42 @@ public abstract class AbstractServiceContextImpl //make sure tenant context exists checkTenantContext(); - //retrieve service bindings - TenantBindingConfigReaderImpl tReader = - ServiceMain.getInstance().getTenantBindingConfigReader(); String tenantId = securityContext.getCurrentTenantId(); - tenantBinding = tReader.getTenantBinding(tenantId); - if (tenantBinding == null) { - String msg = "No tenant binding found for tenantId=" + tenantId - + " while processing request for service= " + serviceName; - logger.error(msg); - throw new IllegalStateException(msg); - } - serviceBinding = tReader.getServiceBinding(tenantId, serviceName); - if (serviceBinding == null) { - String msg = "No service binding found while processing request for " - + serviceName + " for tenant id=" + getTenantId() - + " name=" + getTenantName(); - logger.error(msg); - throw new IllegalStateException(msg); - } - if (logger.isDebugEnabled()) { - logger.debug("tenantId=" + tenantId - + " service binding=" + serviceBinding.getName()); - } - repositoryDomain = tReader.getRepositoryDomain(tenantId, serviceName); - if (repositoryDomain != null) { - if (logger.isDebugEnabled()) { - logger.debug("tenantId=" + tenantId - + " repository doamin=" + repositoryDomain.getName()); - } + if(AuthorizationCommon.ALL_TENANTS_MANAGER_TENANT_ID.equals(tenantId)) { + // Tenant Manager has no tenant binding, so don't bother... + tenantBinding = null; + serviceBinding = null; + repositoryDomain = null; + } else { + //retrieve service bindings + TenantBindingConfigReaderImpl tReader = + ServiceMain.getInstance().getTenantBindingConfigReader(); + tenantBinding = tReader.getTenantBinding(tenantId); + if (tenantBinding == null) { + String msg = "No tenant binding found for tenantId=" + tenantId + + " while processing request for service= " + serviceName; + logger.error(msg); + throw new IllegalStateException(msg); + } + serviceBinding = tReader.getServiceBinding(tenantId, serviceName); + if (serviceBinding == null) { + String msg = "No service binding found while processing request for " + + serviceName + " for tenant id=" + getTenantId() + + " name=" + getTenantName(); + logger.error(msg); + throw new IllegalStateException(msg); + } + if (logger.isDebugEnabled()) { + logger.debug("tenantId=" + tenantId + + " service binding=" + serviceBinding.getName()); + } + repositoryDomain = tReader.getRepositoryDomain(tenantId, serviceName); + if (repositoryDomain != null) { + if (logger.isDebugEnabled()) { + logger.debug("tenantId=" + tenantId + + " repository doamin=" + repositoryDomain.getName()); + } + } } } @@ -525,6 +533,13 @@ public abstract class AbstractServiceContextImpl return result; } + @Override + public void setDocumentHandler(DocumentHandler handler) throws Exception { + if (handler != null) { + docHandler = handler; + } + } + /* (non-Javadoc) * @see org.collectionspace.services.common.context.ServiceContext#getDocumentHanlder(javax.ws.rs.core.MultivaluedMap) */ @@ -572,6 +587,14 @@ public abstract class AbstractServiceContextImpl valHandlers = handlers; return valHandlers; } + + @Override + public void addValidatorHandler(ValidatorHandler validator) throws Exception { + if (valHandlers == null) { + valHandlers = new ArrayList>(); + } + valHandlers.add(validator); + } /* (non-Javadoc) * @see java.lang.Object#toString() diff --git a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java index dea896e93..bbb9f2a33 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java +++ b/services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java @@ -266,12 +266,18 @@ public interface ServiceContext { public String getServiceBindingPropertyValue(String propName); /** - * getDocumentHanlder returns document handler configured in the the binding + * getDocumentHandler returns document handler configured in the the binding * it creates the handler if necessary. * @return document handler */ public DocumentHandler getDocumentHandler() throws Exception; + /** + * setDocumentHandler allows for setting an externally created handler + * @param handler the dochandler to set into this context + */ + public void setDocumentHandler(DocumentHandler handler) throws Exception; + /** * Gets the document hanlder. * @@ -290,6 +296,13 @@ public interface ServiceContext { */ public List> getValidatorHandlers() throws Exception; + /** + * getValidatorHandlers returns registered (from binding) validtor handlers + * for the service. it creates the handlers if necessary. + * @return validation handlers + */ + public void addValidatorHandler(ValidatorHandler validator) throws Exception; + /** * Gets the query params. * diff --git a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java index 7c1b4d403..df1c25704 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java +++ b/services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java @@ -120,8 +120,14 @@ public class DocumentFilter { * @param ctx the ctx */ public DocumentFilter(ServiceContext ctx) { - this.setPageSize(ctx.getServiceBindingPropertyValue( - DocumentFilter.PAGE_SIZE_DEFAULT_PROPERTY)); + // Ignore errors - some contexts do not have proper service binding info + try { + String pageSizeString = ctx.getServiceBindingPropertyValue( + DocumentFilter.PAGE_SIZE_DEFAULT_PROPERTY); + this.setPageSize(pageSizeString); + } catch(Exception e) { + this.setPageSize(defaultPageSize); + } } /** diff --git a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentFilter.java b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentFilter.java index eb345010c..735257349 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentFilter.java +++ b/services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentFilter.java @@ -58,6 +58,11 @@ import org.collectionspace.services.common.context.ServiceContext; * JPA query specific document filter */ public class JpaDocumentFilter extends DocumentFilter { + + public static final String Q_ASC = "asc"; + public static final String Q_DESC = "desc"; + public static final String JPA_ASC = " ASC"; + public static final String JPA_DESC = " DESC"; public JpaDocumentFilter(ServiceContext ctx) { super(ctx); -- 2.47.3