From 1e933f379066a56410686ed6a83347aef9243d62 Mon Sep 17 00:00:00 2001 From: Richard Millet Date: Tue, 27 Mar 2012 17:24:46 -0700 Subject: [PATCH] CSPACE-4964: A shuffling of methods from ServiceMain.java to AuthorizationCommon.java in preparation for dynamic creation of workflow/lifecycle permissions. --- pom.xml | 2 + services/authorization-mgt/import/build.xml | 2 +- .../driver/AuthorizationSeedDriver.java | 6 +- .../importer/AuthorizationGen.java | 4 +- .../importer/AuthorizationSeed.java | 41 +- .../importer/AuthorizationStore.java | 2 +- services/common/pom.xml | 7 +- .../services/common/ServiceMain.java | 405 +-------------- .../AuthorizationCommon.java | 489 +++++++++++++++++- 9 files changed, 508 insertions(+), 450 deletions(-) diff --git a/pom.xml b/pom.xml index 72531d35a..40f641d74 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,8 @@ --> 2.2-SNAPSHOT 2.2-SNAPSHOT + 3.0.0.RELEASE + 3.0.2.RELEASE diff --git a/services/authorization-mgt/import/build.xml b/services/authorization-mgt/import/build.xml index b3a77ee73..bb32302d8 100644 --- a/services/authorization-mgt/import/build.xml +++ b/services/authorization-mgt/import/build.xml @@ -124,7 +124,7 @@ - + diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/driver/AuthorizationSeedDriver.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/driver/AuthorizationSeedDriver.java index 737bbcec6..5002a6e4f 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/driver/AuthorizationSeedDriver.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/driver/AuthorizationSeedDriver.java @@ -123,7 +123,7 @@ public class AuthorizationSeedDriver { public void seed() { TransactionStatus status = null; try { - // Push all the authz info into the cspace DB tables. + // Push all the authz info into the cspace DB tables -this include default roles, permissions, and permroles store(); setupSpring(); @@ -167,7 +167,7 @@ public class AuthorizationSeedDriver { private void login() { //GrantedAuthority cspace_admin = new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"); - GrantedAuthority spring_security_admin = new GrantedAuthorityImpl("ROLE_SPRING_ADMIN"); + GrantedAuthority spring_security_admin = new GrantedAuthorityImpl("ROLE_SPRING_ADMIN"); //NOTE: Must match with value in applicationContext-authorization-test.xml (aka SPRING_SECURITY_METADATA) HashSet gauths = new HashSet(); //gauths.add(cspace_admin); gauths.add(spring_security_admin); @@ -203,7 +203,7 @@ public class AuthorizationSeedDriver { } } - for (Permission perm : authzGen.getDefaultPermissions()) { + for (Permission perm : authzGen.getDefaultPermissions()) { //FIXME: REM - 3/27/2012 - If we change the CSID of permissions to something like a refname, then we need to check for existing perms just like we did above for roles authzStore.store(perm); } 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 cd9b16612..3ebd9d7bb 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 @@ -155,7 +155,7 @@ public class AuthorizationGen { } private Permission buildAdminPermission(String tenantId, String resourceName) { - String id = UUID.randomUUID().toString(); + String id = UUID.randomUUID().toString(); //FIXME: Could this be something like a refname instead of a UUID? Permission perm = new Permission(); perm.setCsid(id); perm.setDescription("generated admin permission"); @@ -310,7 +310,7 @@ public class AuthorizationGen { allRoleList.addAll(adminRoles); allRoleList.addAll(readerRoles); } - return allRoleList; + return allRoleList; //FIXME: REM - 3/27/2012, The super role "cspaceAdminRole" is not on this list. Intentional? } public void associateDefaultPermissionsRoles() { diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java index 1fa6a01b3..5a766a8ba 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationSeed.java @@ -35,7 +35,6 @@ import javax.xml.bind.Unmarshaller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.security.acls.model.AlreadyExistsException; import org.collectionspace.services.authorization.AuthZ; import org.collectionspace.services.authorization.CSpaceAction; import org.collectionspace.services.authorization.perms.EffectType; @@ -47,6 +46,7 @@ import org.collectionspace.services.authorization.perms.PermissionsList; import org.collectionspace.services.authorization.PermissionsRolesList; import org.collectionspace.services.authorization.RoleValue; import org.collectionspace.services.authorization.URIResourceImpl; +import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon; /** * AuthorizationSeed seeds authorizations (permission, role) into authz provider database @@ -107,48 +107,13 @@ public class AuthorizationSeed { } for (PermissionRole pr : permRoleList) { if (pr.getPermission().get(0).getPermissionId().equals(p.getCsid())) { - addPermissionsForUri(p, pr); + AuthorizationCommon.addPermissionsForUri(p, pr); } } } } - /** - * addPermissionsForUri add permissions from given permission configuration - * with assumption that resource is of type URI - * @param permission configuration - */ - private void addPermissionsForUri(Permission perm, - PermissionRole permRole) throws PermissionException { - List principals = new ArrayList(); - if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) { - throw new IllegalArgumentException("permission ids do not" - + " match for role=" + permRole.getRole().get(0).getRoleName() - + " with permissionId=" + permRole.getPermission().get(0).getPermissionId() - + " for permission with csid=" + perm.getCsid()); - } - for (RoleValue roleValue : permRole.getRole()) { - principals.add(roleValue.getRoleName()); - } - List permActions = perm.getAction(); - for (PermissionAction permAction : permActions) { - try { - CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); - URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), - perm.getResourceName(), action); - boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false; - AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant); - } catch (PermissionException e) { - // - // Only throw the exception if it is *not* an already-exists exception - // - if (e.getCause() instanceof AlreadyExistsException == false) { - throw e; - } - } - } - } - + /** * getAction is a convenience method to get corresponding action for * given ActionType diff --git a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationStore.java b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationStore.java index 593101fda..a9b3dc2b3 100644 --- a/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationStore.java +++ b/services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationStore.java @@ -96,7 +96,7 @@ public class AuthorizationStore { em.getTransaction().commit(); String id = null; try{ - id = (String) JaxbUtils.getValue(entity, "getCsid"); + id = (String) JaxbUtils.getValue(entity, "getCsid"); //NOTE: Not all entities have a CSID attribute } catch(NoSuchMethodException nsme) { //do nothing ok, relationship does not have csid } diff --git a/services/common/pom.xml b/services/common/pom.xml index cb15ea4fe..65dccb52d 100644 --- a/services/common/pom.xml +++ b/services/common/pom.xml @@ -7,7 +7,6 @@ 4.0.0 - org.collectionspace.services org.collectionspace.services.common services.common jar @@ -314,6 +313,12 @@ commons-io commons-io + + org.springframework.security + spring-security-acl + ${spring.security.version} + provided + diff --git a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java index 2151c31ca..c8c1b4118 100644 --- a/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java +++ b/services/common/src/main/java/org/collectionspace/services/common/ServiceMain.java @@ -18,6 +18,7 @@ import javax.servlet.ServletContext; import javax.sql.DataSource; import org.collectionspace.authentication.AuthN; +import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon; import org.collectionspace.services.common.config.ServicesConfigReaderImpl; import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; import org.collectionspace.services.common.init.IInitHandler; @@ -53,14 +54,6 @@ public class ServiceMain { private ServicesConfigReaderImpl servicesConfigReader; private TenantBindingConfigReaderImpl tenantBindingConfigReader; - private static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; - private static final String TENANT_READER_ACCT_PREFIX = "reader@"; - private static final String ROLE_PREFIX = "ROLE_"; - private static final String SPRING_ADMIN_ROLE = "ROLE_SPRING_ADMIN"; - private static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR"; - private static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER"; - private static final String DEFAULT_ADMIN_PASSWORD = "Administrator"; - private static final String DEFAULT_READER_PASSWORD = "reader"; private static final String SERVER_HOME_PROPERTY = "catalina.home"; private ServiceMain() { @@ -151,7 +144,7 @@ public class ServiceMain { // Create all the default user accounts // try { - createDefaultAccounts(); + AuthorizationCommon.createDefaultAccounts(tenantBindingConfigReader); } catch(Exception e) { logger.error("Default accounts setup failed with exception(s): " + e.getLocalizedMessage()); } @@ -209,396 +202,6 @@ public class ServiceMain { } } - /* - * FIXME: REM - This method is way too big -over 300 lines! We need to break it up into - * smaller, discrete, sub-methods. - */ - private void createDefaultAccounts() { - if (logger.isDebugEnabled()) { - logger.debug("ServiceMain.createDefaultAccounts starting..."); - } - 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; - PreparedStatement pstmt = null; - 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. - 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,created_at) VALUES (?,?, 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(); - } - 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 - 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(); - } 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(); - // 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."); - } - 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(); - // 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); - if(rs.next()) { - springAdminRoleCSID = rs.getString(1); - 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')"; - stmt.executeUpdate(insertSpringAdminRoleSQL); - springAdminRoleCSID = "-1"; - 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!"); - } - String tenantAdminRoleCSID = rs.getString(1); - 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!"); - } - String tenantReaderRoleCSID = rs.getString(1); - 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(); - } catch (RuntimeException rte) { - if (logger.isDebugEnabled()) { - logger.debug("Exception in createDefaultAccounts: "+ - rte.getLocalizedMessage()); - logger.debug(rte.getStackTrace().toString()); - } - throw rte; - } catch (SQLException sqle) { - // SQLExceptions can be chained. We have at least one exception, so - // set up a loop to make sure we let the user know about all of them - // if there happens to be more than one. - if (logger.isDebugEnabled()) { - SQLException tempException = sqle; - while (null != tempException) { - logger.debug("SQL Exception: " + sqle.getLocalizedMessage()); - tempException = tempException.getNextException(); - } - logger.debug(sqle.getStackTrace().toString()); - } - throw new RuntimeException("SQL problem in createDefaultAccounts: ", sqle); - } catch (Exception e) { - if (logger.isDebugEnabled()) { - logger.debug("Exception in createDefaultAccounts: "+ - e.getLocalizedMessage()); - } - } finally { - 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: " - + sqle.getLocalizedMessage()); - } - } - } - } - - private String getDefaultAdminRole(String tenantId) { - return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX; - } - - private String getDefaultReaderRole(String tenantId) { - return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX; - } - - private String getDefaultAdminUserID(String tenantName) { - return TENANT_ADMIN_ACCT_PREFIX+tenantName; - } - - private String getDefaultReaderUserID(String tenantName) { - return TENANT_READER_ACCT_PREFIX+tenantName; - } public void firePostInitHandlers() throws Exception { DataSource dataSource = JDBCTools.getDataSource(JDBCTools.NUXEO_REPOSITORY_NAME); @@ -649,10 +252,6 @@ public class ServiceMain { return null; } - private Connection getConnection() throws NamingException, SQLException { - return JDBCTools.getConnection(JDBCTools.CSPACE_REPOSITORY_NAME); - } - void retrieveAllWorkspaceIds() throws Exception { //all configs are read, connector is initialized, retrieve workspaceids Hashtable tenantBindings = 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 62ac660e8..68ceaffa9 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 @@ -1,8 +1,495 @@ package org.collectionspace.services.common.authorization_mgt; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.UUID; + +import javax.naming.NamingException; + +import org.collectionspace.services.authorization.AuthZ; +import org.collectionspace.services.authorization.CSpaceAction; +import org.collectionspace.services.authorization.PermissionException; +import org.collectionspace.services.authorization.PermissionRole; +import org.collectionspace.services.authorization.RoleValue; +import org.collectionspace.services.authorization.URIResourceImpl; +import org.collectionspace.services.authorization.perms.EffectType; +import org.collectionspace.services.authorization.perms.Permission; +import org.collectionspace.services.authorization.perms.PermissionAction; +import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl; +import org.collectionspace.services.common.security.SecurityUtils; +import org.collectionspace.services.common.storage.DatabaseProductType; +import org.collectionspace.services.common.storage.JDBCTools; +import org.collectionspace.services.common.tenant.TenantBindingType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.acls.model.AlreadyExistsException; + + public class AuthorizationCommon { + final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class); + + 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_"; + public static final String SPRING_ADMIN_ROLE = "ROLE_SPRING_ADMIN"; + public static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR"; + public static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER"; + public static final String DEFAULT_ADMIN_PASSWORD = "Administrator"; + public static final String DEFAULT_READER_PASSWORD = "reader"; public static String ROLE_SPRING_ADMIN_ID = "-1"; - public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN"; + + /** + * addPermissionsForUri add permissions from given permission configuration + * with assumption that resource is of type URI + * @param permission configuration + */ + public static void addPermissionsForUri(Permission perm, + PermissionRole permRole) throws PermissionException { + List principals = new ArrayList(); + if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) { + throw new IllegalArgumentException("permission ids do not" + + " match for role=" + permRole.getRole().get(0).getRoleName() + + " with permissionId=" + permRole.getPermission().get(0).getPermissionId() + + " for permission with csid=" + perm.getCsid()); + } + for (RoleValue roleValue : permRole.getRole()) { + principals.add(roleValue.getRoleName()); + } + List permActions = perm.getAction(); + for (PermissionAction permAction : permActions) { + try { + CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); + URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), + perm.getResourceName(), action); + boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false; + AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant);//CSPACE-4967 + } catch (PermissionException e) { + // + // Only throw the exception if it is *not* an already-exists exception + // + if (e.getCause() instanceof AlreadyExistsException == false) { + throw e; + } + } + } + } + + private static Connection getConnection() throws NamingException, SQLException { + return JDBCTools.getConnection(JDBCTools.CSPACE_REPOSITORY_NAME); + } + + public static void createDefaultPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) + { + // For each service binding in each tenancy, get the Nuxeo document type and retrieve it's life cycle type. For + // that life cycle type, ask Nuxeo for all the configured transitions. For each of those transitions, + // create: + // * a URI of the form - //*/workflow/ + // * a CRUDL Permission for the URI + // * a RL Permission for the URI + // * a PermissionRole for admin role + // * a PermissionRole for the reader role + // + // * add a new Permission/PermissionRole tuple to the Spring AuthZ tables + // * persist the new Permission, and PermissionRole to the cspace database + } + + /* + * 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..."); + } + + 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; + PreparedStatement pstmt = null; + 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. + 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,created_at) VALUES (?,?, 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(); + } + 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 + 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(); + } 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(); + // 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."); + } + 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(); + // 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); + if(rs.next()) { + springAdminRoleCSID = rs.getString(1); + 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')"; + stmt.executeUpdate(insertSpringAdminRoleSQL); + springAdminRoleCSID = "-1"; + 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!"); + } + String tenantAdminRoleCSID = rs.getString(1); + 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!"); + } + String tenantReaderRoleCSID = rs.getString(1); + 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(); + } catch (RuntimeException rte) { + if (logger.isDebugEnabled()) { + logger.debug("Exception in createDefaultAccounts: "+ + rte.getLocalizedMessage()); + logger.debug(rte.getStackTrace().toString()); + } + throw rte; + } catch (SQLException sqle) { + // SQLExceptions can be chained. We have at least one exception, so + // set up a loop to make sure we let the user know about all of them + // if there happens to be more than one. + if (logger.isDebugEnabled()) { + SQLException tempException = sqle; + while (null != tempException) { + logger.debug("SQL Exception: " + sqle.getLocalizedMessage()); + tempException = tempException.getNextException(); + } + logger.debug(sqle.getStackTrace().toString()); + } + throw new RuntimeException("SQL problem in createDefaultAccounts: ", sqle); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Exception in createDefaultAccounts: "+ + e.getLocalizedMessage()); + } + } finally { + 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: " + + sqle.getLocalizedMessage()); + } + } + } + } + + private static String getDefaultAdminRole(String tenantId) { + return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX; + } + + private static String getDefaultReaderRole(String tenantId) { + return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX; + } + + private static String getDefaultAdminUserID(String tenantName) { + return TENANT_ADMIN_ACCT_PREFIX+tenantName; + } + + private static String getDefaultReaderUserID(String tenantName) { + return TENANT_READER_ACCT_PREFIX+tenantName; + } } -- 2.47.3