]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5657 Completed work on auth and AuthZImport work to handle new perms, roles...
authorPatrick Schmitz <pschmitz@berkeley.edu>
Thu, 13 Dec 2012 20:23:39 +0000 (12:23 -0800)
committerPatrick Schmitz <pschmitz@berkeley.edu>
Thu, 13 Dec 2012 20:23:39 +0000 (12:23 -0800)
16 files changed:
services/JaxRsServiceProvider/src/main/java/org/collectionspace/services/jaxrs/CollectionSpaceJaxRsApplication.java
services/account/jaxb/src/main/resources/accounts_common.xsd
services/account/service/src/main/java/org/collectionspace/services/account/TenantResource.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantDocumentHandler.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantJpaFilter.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageClient.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/TenantStorageConstants.java
services/authentication/service/src/main/java/org/collectionspace/authentication/AuthN.java
services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java
services/authorization-mgt/import/pom.xml
services/authorization-mgt/import/src/main/java/org/collectionspace/services/authorization/importer/AuthorizationGen.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java
services/common/src/main/java/org/collectionspace/services/common/context/AbstractServiceContextImpl.java
services/common/src/main/java/org/collectionspace/services/common/context/ServiceContext.java
services/common/src/main/java/org/collectionspace/services/common/document/DocumentFilter.java
services/common/src/main/java/org/collectionspace/services/common/storage/jpa/JpaDocumentFilter.java

index 2b6cb52df33feb88a4675fb8d5354be739ea0e9d..f2e3aca030ec4b7b9752ae5998368425913923d7 100644 (file)
@@ -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());
index ae82b32e2fa7800ea568c4bdd1681a59bbf383be..ec2a18d6c070221ecd788673947f35bb78860e34 100644 (file)
     </xs:complexType>
 
     <!-- FIXME tenant definition could be in a separate schema -->
-    <xs:complexType name="tenant">
-        <xs:annotation>
-            <xs:documentation>
-                Tenant defines the tenant in CollectionSpace
-            </xs:documentation>
-            <xs:appinfo>
-                <hj:entity>
-                    <orm:table name="tenants"/>
-                </hj:entity>
-            </xs:appinfo>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="id" type="xs:string" minOccurs="1">
-                <xs:annotation>
-                    <xs:appinfo>
-                        <hj:id>
-                            <orm:column name="id" length="128" nullable="false"/>
-                        </hj:id>
-                    </xs:appinfo>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="name" type="xs:string" minOccurs="1">
-                <xs:annotation>
-                    <xs:appinfo>
-                        <hj:basic>
-                            <orm:column name="name" nullable="false"/>
-                        </hj:basic>
-                    </xs:appinfo>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="disabled" type="xs:boolean">
-                <xs:annotation>
-                    <xs:appinfo>
-                        <hj:basic>
-                            <orm:column name="disabled" nullable="false"/>
-                        </hj:basic>
-                    </xs:appinfo>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="createdAt" type="xs:dateTime">
-                <xs:annotation>
-                    <xs:appinfo>
-                        <hj:basic>
-                            <orm:column name="created_at" nullable="false"/>
-                        </hj:basic>
-                    </xs:appinfo>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="updatedAt" type="xs:dateTime">
-                <xs:annotation>
-                    <xs:appinfo>
-                        <hj:basic>
-                            <orm:column name="updated_at" />
-                        </hj:basic>
-                    </xs:appinfo>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-    </xs:complexType>
+       <xs:element name="tenant">
+               <xs:complexType>
+                       <xs:annotation>
+                               <xs:documentation>
+                                       Tenant defines the tenant in CollectionSpace
+                               </xs:documentation>
+                               <xs:appinfo>
+                                       <hj:entity>
+                                               <orm:table name="tenants" />
+                                       </hj:entity>
+                               </xs:appinfo>
+                       </xs:annotation>
+                       <xs:sequence>
+                               <xs:element name="id" type="xs:string" minOccurs="1">
+                                       <xs:annotation>
+                                               <xs:appinfo>
+                                                       <hj:id>
+                                                               <orm:column name="id" length="128" nullable="false" />
+                                                       </hj:id>
+                                               </xs:appinfo>
+                                       </xs:annotation>
+                               </xs:element>
+                               <xs:element name="name" type="xs:string" minOccurs="1">
+                                       <xs:annotation>
+                                               <xs:appinfo>
+                                                       <hj:basic>
+                                                               <orm:column name="name" nullable="false" />
+                                                       </hj:basic>
+                                               </xs:appinfo>
+                                       </xs:annotation>
+                               </xs:element>
+                               <xs:element name="disabled" type="xs:boolean">
+                                       <xs:annotation>
+                                               <xs:appinfo>
+                                                       <hj:basic>
+                                                               <orm:column name="disabled" nullable="false" />
+                                                       </hj:basic>
+                                               </xs:appinfo>
+                                       </xs:annotation>
+                               </xs:element>
+                               <xs:element name="createdAt" type="xs:dateTime">
+                                       <xs:annotation>
+                                               <xs:appinfo>
+                                                       <hj:basic>
+                                                               <orm:column name="created_at" nullable="false" />
+                                                       </hj:basic>
+                                               </xs:appinfo>
+                                       </xs:annotation>
+                               </xs:element>
+                               <xs:element name="updatedAt" type="xs:dateTime">
+                                       <xs:annotation>
+                                               <xs:appinfo>
+                                                       <hj:basic>
+                                                               <orm:column name="updated_at" />
+                                                       </hj:basic>
+                                               </xs:appinfo>
+                                       </xs:annotation>
+                               </xs:element>
+                       </xs:sequence>
+               </xs:complexType>
+       </xs:element>
 
     <xs:element name="tenants-list">
         <xs:complexType>
index 9f891a5ed7e674bbe04b186e47657010a404a6d9..a149b21b0dbfd6dc69d9833b3f894a761af9a61b 100644 (file)
 
 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;
+    }    
+
 }
index 33be18a03c0e00a1eecfe96a353bb6586d36849d..f4d1446c818a3b10b89d8c9cd804ccf692b381ec 100644 (file)
@@ -61,7 +61,32 @@ public class TenantDocumentHandler
 
     @Override
     public void handleUpdate(DocumentWrapper<Tenant> 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<Tenant> wrapDoc) throws Exception {
index 6bbc8b24beb11deb47ffbd651275fa9b2aac2455..fbba1d3ca39372e1e76a49041900433fc80fbc9e 100644 (file)
@@ -48,35 +48,69 @@ public class TenantJpaFilter extends JpaDocumentFilter {
     public List<ParamBinding> buildWhereForSearch(StringBuilder queryStrBldr) {
 
         List<ParamBinding> paramList = new ArrayList<ParamBinding>();
-        String name = null;
-        List<String> 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<String> 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<String> 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<ParamBinding> buildWhere(StringBuilder queryStrBldr) {
index 5f45cf945331851d7c4243e8317a9610f47d81cf..6822527f60b7cd3896a939d5e6a107b842e10317 100644 (file)
@@ -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 {
index cc523092a7afd4447d2596e50edaffe9ffe1a35a..d780179cee566fd81e8fb8e90d7a24e4c5e0dc38 100644 (file)
@@ -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";
 }
index 13a5ac599c444bcc825f357387f10b6f3d8023d0..8d91d3dbb1c5ee2132318384adc1cbe3faca623e 100644 (file)
@@ -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
index 3a3b6de485da8d8821a1f148bc7c333fc52ecf91..aa67924f390ca432158b717e38e45944b682e13d 100644 (file)
@@ -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<String, Group> groupsMap = new HashMap<String, Group>();
         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);
index 7337e72be35c588a08e746dd7b0e53d4f86798fe..7efc29c429aa874ab0b2c0ac2c51f894b8056ef5 100644 (file)
             <version>${project.version}</version>\r
             <scope>provided</scope>\r
         </dependency>\r
+        <dependency>\r
+            <groupId>org.collectionspace.services</groupId>\r
+            <artifactId>org.collectionspace.services.account.client</artifactId>\r
+            <version>${project.version}</version>\r
+        </dependency>\r
         <dependency>\r
             <groupId>org.collectionspace.services</groupId>\r
             <artifactId>org.collectionspace.services.authorization-mgt.service</artifactId>\r
index 351a4d6fa711da6d03ca9b6d7874c9e187ea6896..b45d1defd28c02d842fa6e08fbd4946494533861 100644 (file)
@@ -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<Permission> tenantMgmntPermList = new ArrayList<Permission>();
+    private List<PermissionRole> tenantMgmntPermRoleList = new ArrayList<PermissionRole>();
     private List<Permission> adminPermList = new ArrayList<Permission>();
     private List<PermissionRole> adminPermRoleList = new ArrayList<PermissionRole>();
     private List<Permission> readerPermList = new ArrayList<Permission>();
     private List<PermissionRole> readerPermRoleList = new ArrayList<PermissionRole>();
     private List<Role> adminRoles = new ArrayList<Role>();
     private List<Role> readerRoles = new ArrayList<Role>();
-    private Role cspaceAdminRole;
+    private Role cspaceTenantMgmntRole;
     private Hashtable<String, TenantBindingType> tenantBindings =
             new Hashtable<String, TenantBindingType>();
        //
@@ -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<Permission> readerPerms = createDefaultReaderPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY);
             readerPermList.addAll(readerPerms);
         }
+        
+        List<Permission> 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<Permission> createDefaultTenantMgmntPermissions() {
+        ArrayList<Permission> apcList = new ArrayList<Permission>();
+        // 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<Permission>();
                allPermList.addAll(adminPermList);
                allPermList.addAll(readerPermList);
+               allPermList.addAll(tenantMgmntPermList);
        }
         return allPermList;
     }
@@ -204,6 +236,10 @@ public class AuthorizationGen {
         return readerPermList;
     }
 
+    public List<Permission> 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<Role>();
                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<Role> roles = new ArrayList<Role>();
-        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<PermissionRole>();
                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();
index 383d1466f7d1bd618138a84807d7d508d8f0773d..dde31ac036eb9a82003af949c4b69285d36f43fd 100644 (file)
@@ -16,6 +16,7 @@ import javax.naming.NamingException;
 import javax.persistence.EntityManager;\r
 import javax.persistence.EntityManagerFactory;\r
 \r
+import org.collectionspace.authentication.AuthN;\r
 import org.collectionspace.services.authorization.AuthZ;\r
 import org.collectionspace.services.authorization.CSpaceAction;\r
 import org.collectionspace.services.authorization.PermissionException;\r
@@ -69,6 +70,7 @@ public class AuthorizationCommon {
     // for READ-ONLY\r
     final public static String ACTIONGROUP_RL_NAME = "RL";\r
     final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};\r
+\r
     \r
        /*\r
         * Inner class to deal with predefined ADMIN and READER action groupds\r
@@ -100,13 +102,18 @@ public class AuthorizationCommon {
     //\r
     // The "super" role has a predefined ID of "0" and a tenant ID of "0";\r
     //\r
-    final public static String ROLE_ADMINISTRATOR = "ADMINISTRATOR";\r
-    final public static String ROLE_ADMINISTRATOR_ID = "0";\r
-    final public static String ADMINISTRATOR_TENANT_ID = "0";\r
+    final public static String ROLE_ALL_TENANTS_MANAGER = "ALL_TENANTS_MANAGER";\r
+    final public static String ROLE_ALL_TENANTS_MANAGER_ID = "0";\r
+    final public static String ALL_TENANTS_MANAGER_TENANT_ID = "0";\r
 \r
     final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";\r
     final public static String ROLE_TENANT_READER = "TENANT_READER";\r
        \r
+    public static final String TENANT_MANAGER_USER = "tenantManager"; \r
+    public static final String TENANT_MANAGER_SCREEN_NAME = TENANT_MANAGER_USER; \r
+    public static final String DEFAULT_TENANT_MANAGER_PASSWORD = "manage"; \r
+    public static final String DEFAULT_TENANT_MANAGER_EMAIL = "tenantManager@collectionspace.org"; \r
+    \r
     public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; \r
     public static final String TENANT_READER_ACCT_PREFIX = "reader@"; \r
     public static final String ROLE_PREFIX = "ROLE_"; \r
@@ -119,6 +126,29 @@ public class AuthorizationCommon {
     public static String ROLE_SPRING_ADMIN_ID = "-1";\r
     public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";\r
 \r
+    // SQL for init tasks\r
+       final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL = \r
+                       "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"\r
+                                       +" VALUES(?, ?, ?, ?, now())";\r
+       final private static String INSERT_ACCOUNT_ROLE_SQL_POSTGRES =\r
+                       "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"\r
+                                       +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";\r
+       final private static String QUERY_USERS_SQL = \r
+               "SELECT username FROM users WHERE username LIKE '"\r
+                       +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"+TENANT_READER_ACCT_PREFIX+"%'";\r
+       final private static String INSERT_USER_SQL = \r
+                       "INSERT INTO users (username,passwd, created_at) VALUES (?,?, now())";\r
+       final private static String INSERT_ACCOUNT_SQL = \r
+                       "INSERT INTO accounts_common "\r
+                                       + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "\r
+                                       + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";\r
+       \r
+       // TENANT MANAGER specific SQL\r
+       final private static String QUERY_TENANT_MGR_USER_SQL = \r
+               "SELECT username FROM users WHERE username = '"+TENANT_MANAGER_USER+"'";\r
+       final private static String GET_TENANT_MGR_ROLE_SQL =\r
+                       "SELECT csid from roles WHERE tenant_id='"+ALL_TENANTS_MANAGER_TENANT_ID+"' and rolename=?";\r
+\r
     public static Role getRole(String tenantId, String displayName) {\r
        Role role = null;\r
        \r
@@ -348,341 +378,591 @@ public class AuthorizationCommon {
        return permRole;\r
     }\r
     \r
+    private static Hashtable<String, String> getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) {\r
+\r
+       Hashtable<String, TenantBindingType> tenantBindings =\r
+                       tenantBindingConfigReader.getTenantBindings();\r
+       Hashtable<String, String> tenantInfo = new Hashtable<String, String>();\r
+       for (TenantBindingType tenantBinding : tenantBindings.values()) {\r
+               String tId = tenantBinding.getId();\r
+               String tName = tenantBinding.getName();\r
+               tenantInfo.put(tId, tName);\r
+               if (logger.isDebugEnabled()) {\r
+                       logger.debug("getTenantNamesFromConfig found configured tenant id: "+tId+" name: "+tName);\r
+               }\r
+       }\r
+       return tenantInfo;\r
+    }\r
     \r
-    /*\r
-     * FIXME: REM - This method is way too big -over 300 lines!  We need to break it up into\r
-     * smaller, discrete, sub-methods.\r
-     */\r
-    public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) {\r
-       if (logger.isDebugEnabled()) {\r
-               logger.debug("ServiceMain.createDefaultAccounts starting...");\r
+    private static ArrayList<String> compileExistingTenants(Connection conn, Hashtable<String, String> tenantInfo)\r
+       throws SQLException, Exception {\r
+       Statement stmt = null;\r
+       ArrayList<String> existingTenants = new ArrayList<String>();\r
+       // First find or create the tenants\r
+       final String queryTenantSQL = "SELECT id,name FROM tenants";\r
+       try {\r
+               stmt = conn.createStatement();\r
+               ResultSet rs = stmt.executeQuery(queryTenantSQL);\r
+               while (rs.next()) {\r
+                       String tId = rs.getString("id");\r
+                       String tName = rs.getString("name");\r
+                       if(tenantInfo.containsKey(tId)) {\r
+                               existingTenants.add(tId);\r
+                               if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {\r
+                                       logger.warn("Configured name for tenant: "\r
+                                                       +tId+" in repository: "+tName\r
+                                                       +" does not match config'd name: "+ tenantInfo.get(tId));\r
+                               }\r
+                       }\r
+               }\r
+               rs.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(stmt!=null)\r
+                       stmt.close();\r
        }\r
-       \r
-        Hashtable<String, TenantBindingType> tenantBindings =\r
-               tenantBindingConfigReader.getTenantBindings();\r
-        Hashtable<String, String> tenantInfo = new Hashtable<String, String>();\r
-        for (TenantBindingType tenantBinding : tenantBindings.values()) {\r
-               String tId = tenantBinding.getId();\r
-               String tName = tenantBinding.getName();\r
-               tenantInfo.put(tId, tName);\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts found configured tenant id: "+tId+" name: "+tName);\r
-               }\r
-        }\r
-        Connection conn = null;\r
+\r
+       return existingTenants;\r
+    }\r
+    \r
+    private static void createMissingTenants(Connection conn, Hashtable<String, String> tenantInfo,\r
+               ArrayList<String> existingTenants) throws SQLException, Exception {\r
+               // Need to define and look for a createDisabled attribute in tenant config\r
+       final String insertTenantSQL = \r
+               "INSERT INTO tenants (id,name,disabled,created_at) VALUES (?,?,FALSE,now())";\r
         PreparedStatement pstmt = null;\r
+       try {\r
+               pstmt = conn.prepareStatement(insertTenantSQL); // create a statement\r
+               for(String tId : tenantInfo.keySet()) {\r
+                       if(existingTenants.contains(tId)) {\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createMissingTenants: tenant exists (skipping): "\r
+                                                       +tenantInfo.get(tId));\r
+                               }\r
+                               continue;\r
+                       }\r
+                       pstmt.setString(1, tId);                                        // set id param\r
+                       pstmt.setString(2, tenantInfo.get(tId));        // set name param\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("createMissingTenants adding entry for tenant: "+tId);\r
+                       }\r
+                       pstmt.executeUpdate();\r
+               }\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+    }\r
+    \r
+    private static ArrayList<String> findOrCreateDefaultUsers(Connection conn, Hashtable<String, String> tenantInfo) \r
+               throws SQLException, Exception {\r
+       // Second find or create the users\r
        Statement stmt = null;\r
-        // TODO - need to put in tests for existence first.\r
-        // We could just look for the accounts per tenant up front, and assume that\r
-        // the rest is there if the accounts are.\r
-        // Could add a sql script to remove these if need be - Spring only does roles, \r
-        // and we're not touching that, so we could safely toss the \r
-        // accounts, users, account-tenants, account-roles, and start over.\r
+        PreparedStatement pstmt = null;\r
+       ArrayList<String> usersInRepo = new ArrayList<String>();\r
         try {\r
-               conn = getConnection();\r
-               // First find or create the tenants\r
-               String queryTenantSQL = \r
-                       "SELECT id,name FROM tenants";\r
-               stmt = conn.createStatement();\r
-                       ResultSet rs = stmt.executeQuery(queryTenantSQL);\r
-               ArrayList<String> existingTenants = new ArrayList<String>();\r
-                       while (rs.next()) {\r
-                               String tId = rs.getString("id");\r
-                               String tName = rs.getString("name");\r
-                               if(tenantInfo.containsKey(tId)) {\r
-                                       existingTenants.add(tId);\r
-                                       if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {\r
-                                               logger.warn("Configured name for tenant: "\r
-                                                               +tId+" in repository: "+tName\r
-                                                               +" does not match config'd name: "+ tenantInfo.get(tId));\r
-                                       }\r
-                               }\r
-                       }\r
-                       rs.close();\r
-\r
-               String insertTenantSQL = \r
-                       "INSERT INTO tenants (id,name,disabled,created_at) VALUES (?,?,FALSE,now())";\r
-               pstmt = conn.prepareStatement(insertTenantSQL); // create a statement\r
-               for(String tId : tenantInfo.keySet()) {\r
-                       if(existingTenants.contains(tId)) {\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts: tenant exists (skipping): "\r
-                                               +tenantInfo.get(tId));\r
-                       }\r
-                               continue;\r
-                       }\r
-                       pstmt.setString(1, tId);                                        // set id param\r
-                       pstmt.setString(2, tenantInfo.get(tId));        // set name param\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts adding entry for tenant: "+tId);\r
-               }\r
-                       pstmt.executeUpdate();\r
+               stmt = conn.createStatement();\r
+               ResultSet rs = stmt.executeQuery(QUERY_USERS_SQL);\r
+               while (rs.next()) {\r
+                       String uName = rs.getString("username");\r
+                       usersInRepo.add(uName);\r
                }\r
-               pstmt.close();\r
-               // Second find or create the users\r
-               String queryUserSQL = \r
-                       "SELECT username FROM users WHERE username LIKE '"\r
-                               +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"\r
-                               +TENANT_READER_ACCT_PREFIX+"%'";\r
-                       rs = stmt.executeQuery(queryUserSQL);\r
-               ArrayList<String> usersInRepo = new ArrayList<String>();\r
-                       while (rs.next()) {\r
-                               String uName = rs.getString("username");\r
-                               usersInRepo.add(uName);\r
-                       }\r
-                       rs.close();\r
-               String insertUserSQL = \r
-                       "INSERT INTO users (username,passwd, created_at)"\r
-                       +" VALUES (?,?, now())";\r
-               pstmt = conn.prepareStatement(insertUserSQL); // create a statement\r
+               rs.close();\r
+               pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement\r
                for(String tName : tenantInfo.values()) {\r
                        String adminAcctName = getDefaultAdminUserID(tName);\r
                        if(!usersInRepo.contains(adminAcctName)) {\r
-                               String secEncPasswd = SecurityUtils.createPasswordHash(\r
-                                               adminAcctName, DEFAULT_ADMIN_PASSWORD);\r
-                               pstmt.setString(1, adminAcctName);      // set username param\r
-                               pstmt.setString(2, secEncPasswd);       // set passwd param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts adding user: "\r
-                                               +adminAcctName+" for tenant: "+tName);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       } else if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts: user: "+adminAcctName\r
-                                                       +" already exists - skipping.");\r
-               }\r
-\r
-\r
-                       String readerAcctName =  getDefaultReaderUserID(tName);\r
-                       if(!usersInRepo.contains(readerAcctName)) {\r
-                               String secEncPasswd = SecurityUtils.createPasswordHash(\r
-                                               readerAcctName, DEFAULT_READER_PASSWORD);\r
-                               pstmt.setString(1, readerAcctName);     // set username param\r
-                               pstmt.setString(2, secEncPasswd);       // set passwd param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts adding user: "\r
-                                               +readerAcctName+" for tenant: "+tName);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       } else if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts: user: "+readerAcctName\r
-                                                       +" already exists - skipping.");\r
-                       }\r
-               }\r
-               pstmt.close();\r
-               // Third, create the accounts. Assume that if the users were already there,\r
-               // then the accounts were as well\r
-            String insertAccountSQL = \r
-               "INSERT INTO accounts_common "\r
-               + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "\r
-               + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";\r
-            Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();\r
-            Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();\r
-               pstmt = conn.prepareStatement(insertAccountSQL); // create a statement\r
-               for(String tId : tenantInfo.keySet()) {\r
-                       String tName = tenantInfo.get(tId);\r
-               String adminCSID = UUID.randomUUID().toString();\r
-               tenantAdminAcctCSIDs.put(tId, adminCSID);\r
-                       String adminAcctName =  getDefaultAdminUserID(tName);\r
-                       if(!usersInRepo.contains(adminAcctName)) {\r
-                               pstmt.setString(1, adminCSID);                  // set csid param\r
-                               pstmt.setString(2, adminAcctName);      // set email param (bogus)\r
-                               pstmt.setString(3, adminAcctName);      // set userid param\r
-                               pstmt.setString(4, "Administrator");// set screen name param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts adding account: "\r
-                                               +adminAcctName+" for tenant: "+tName);\r
-                       }\r
-                               pstmt.executeUpdate();\r
+                               String secEncPasswd = SecurityUtils.createPasswordHash(\r
+                                               adminAcctName, DEFAULT_ADMIN_PASSWORD);\r
+                               pstmt.setString(1, adminAcctName);      // set username param\r
+                               pstmt.setString(2, secEncPasswd);       // set passwd param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultUsersAndAccounts adding user: "\r
+                                                       +adminAcctName+" for tenant: "+tName);\r
+                               }\r
+                               pstmt.executeUpdate();\r
                        } else if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts: user: "+adminAcctName\r
-                                                       +" already exists - skipping account generation.");\r
+                               logger.debug("createDefaultUsersAndAccounts: user: "+adminAcctName\r
+                                               +" already exists - skipping.");\r
                        }\r
 \r
-                       String readerCSID = UUID.randomUUID().toString();       \r
-               tenantReaderAcctCSIDs.put(tId, readerCSID);\r
+\r
                        String readerAcctName =  getDefaultReaderUserID(tName);\r
                        if(!usersInRepo.contains(readerAcctName)) {\r
-                               pstmt.setString(1, readerCSID);         // set csid param\r
-                               pstmt.setString(2, readerAcctName);     // set email param (bogus)\r
-                               pstmt.setString(3, readerAcctName);     // set userid param\r
-                               pstmt.setString(4, "Reader");           // set screen name param\r
+                               String secEncPasswd = SecurityUtils.createPasswordHash(\r
+                                               readerAcctName, DEFAULT_READER_PASSWORD);\r
+                               pstmt.setString(1, readerAcctName);     // set username param\r
+                               pstmt.setString(2, secEncPasswd);       // set passwd param\r
                                if (logger.isDebugEnabled()) {\r
-                                       logger.debug("createDefaultAccounts adding account: "\r
+                                       logger.debug("createDefaultUsersAndAccounts adding user: "\r
                                                        +readerAcctName+" for tenant: "+tName);\r
                                }\r
                                pstmt.executeUpdate();\r
                        } else if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts: user: "+readerAcctName\r
-                                                       +" already exists - skipping account creation.");\r
+                               logger.debug("createDefaultUsersAndAccounts: user: "+readerAcctName\r
+                                               +" already exists - skipping.");\r
                        }\r
                }\r
                pstmt.close();\r
-               // Fourth, bind accounts to tenants. Assume that if the users were already there,\r
-               // then the accounts were bound to tenants correctly\r
-               String insertAccountTenantSQL;\r
-               DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType();\r
-               if (databaseProductType == DatabaseProductType.MYSQL) {\r
-                       insertAccountTenantSQL =\r
-                               "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
-                               + " VALUES(?, ?)";\r
-               } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
-                       insertAccountTenantSQL =\r
-                               "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
-                               + " VALUES(nextval('hibernate_sequence'), ?, ?)";\r
-               } else {\r
-                       throw new Exception("Unrecognized database system.");\r
+        } catch(Exception e) {\r
+               throw e;\r
+        } finally {\r
+               if(stmt!=null)\r
+                       stmt.close();\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+        }\r
+        return usersInRepo;\r
+    }\r
+    \r
+    private static void findOrCreateDefaultAccounts(Connection conn, Hashtable<String, String> tenantInfo,\r
+               ArrayList<String> usersInRepo,\r
+               Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) \r
+                       throws SQLException, Exception {\r
+       // Third, create the accounts. Assume that if the users were already there,\r
+       // then the accounts were as well\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement\r
+               for(String tId : tenantInfo.keySet()) {\r
+                       String tName = tenantInfo.get(tId);\r
+                       String adminCSID = UUID.randomUUID().toString();\r
+                       tenantAdminAcctCSIDs.put(tId, adminCSID);\r
+                       String adminAcctName =  getDefaultAdminUserID(tName);\r
+                       if(!usersInRepo.contains(adminAcctName)) {\r
+                               pstmt.setString(1, adminCSID);                  // set csid param\r
+                               pstmt.setString(2, adminAcctName);      // set email param (bogus)\r
+                               pstmt.setString(3, adminAcctName);      // set userid param\r
+                               pstmt.setString(4, "Administrator");// set screen name param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts adding account: "\r
+                                                       +adminAcctName+" for tenant: "+tName);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       } else if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts: user: "+adminAcctName\r
+                                               +" already exists - skipping account generation.");\r
+                       }\r
+\r
+                       String readerCSID = UUID.randomUUID().toString();       \r
+                       tenantReaderAcctCSIDs.put(tId, readerCSID);\r
+                       String readerAcctName =  getDefaultReaderUserID(tName);\r
+                       if(!usersInRepo.contains(readerAcctName)) {\r
+                               pstmt.setString(1, readerCSID);         // set csid param\r
+                               pstmt.setString(2, readerAcctName);     // set email param (bogus)\r
+                               pstmt.setString(3, readerAcctName);     // set userid param\r
+                               pstmt.setString(4, "Reader");           // set screen name param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts adding account: "\r
+                                                       +readerAcctName+" for tenant: "+tName);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       } else if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts: user: "+readerAcctName\r
+                                               +" already exists - skipping account creation.");\r
+                       }\r
+               }\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+    }\r
+    \r
+    private static boolean findOrCreateTenantManagerUserAndAccount(Connection conn) \r
+                       throws SQLException, Exception {\r
+       // Find or create the special tenant manager account.\r
+       // Later can make the user name for tenant manager be configurable, settable.\r
+       Statement stmt = null;\r
+        PreparedStatement pstmt = null;\r
+        boolean created = false;\r
+        try {\r
+               boolean foundTMgrUser = false;\r
+               stmt = conn.createStatement();\r
+               ResultSet rs = stmt.executeQuery(QUERY_TENANT_MGR_USER_SQL);\r
+               // Should only find one - only consider it\r
+               if(rs.next()) {\r
+                       String uName = rs.getString("username");\r
+                       foundTMgrUser = uName.equals(TENANT_MANAGER_USER);\r
                }\r
-               pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement\r
-               for(String tId : tenantInfo.keySet()) {\r
-                       String tName = tenantInfo.get(tId);\r
-                       if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {\r
-                               String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
-                               pstmt.setString(1, adminAcct);          // set acct CSID param\r
-                               pstmt.setString(2, tId);                        // set tenant_id param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts binding account id: "\r
-                                               +adminAcct+" to tenant id: "+tId);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       }\r
-                       if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {\r
-                               String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
-                               pstmt.setString(1, readerAcct);         // set acct CSID param\r
-                               pstmt.setString(2, tId);                        // set tenant_id param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts binding account id: "\r
-                                               +readerAcct+" to tenant id: "+tId);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       }\r
+               rs.close();\r
+               if(!foundTMgrUser) {\r
+                       pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement\r
+                       String secEncPasswd = SecurityUtils.createPasswordHash(\r
+                                       TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD);\r
+                       pstmt.setString(1, TENANT_MANAGER_USER);        // set username param\r
+                       pstmt.setString(2, secEncPasswd);       // set passwd param\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager user: "\r
+                                               +TENANT_MANAGER_USER);\r
+                       }\r
+                       pstmt.executeUpdate();\r
+               pstmt.close();\r
+               // Now create the account to match\r
+                       pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement\r
+                               pstmt.setString(1, AuthN.TENANT_MANAGER_ACCT_ID);                // set csid param\r
+                               pstmt.setString(2, DEFAULT_TENANT_MANAGER_EMAIL);       // set email param (bogus)\r
+                               pstmt.setString(3, TENANT_MANAGER_USER);        // set userid param\r
+                               pstmt.setString(4, TENANT_MANAGER_SCREEN_NAME);// set screen name param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager account: "\r
+                                                       +TENANT_MANAGER_USER);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       pstmt.close();\r
+                       created = true;\r
+               } else if (logger.isDebugEnabled()) {\r
+                       logger.debug("findOrCreateTenantManagerUserAndAccount: tenant manager: "+TENANT_MANAGER_USER\r
+                                       +" already exists.");\r
                }\r
-               pstmt.close();\r
-               // Fifth, fetch and save the default roles\r
-                       String springAdminRoleCSID = null;\r
-               String querySpringRole = \r
-                       "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'";\r
-                       rs = stmt.executeQuery(querySpringRole);\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(stmt!=null)\r
+                       stmt.close();\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+        return created;\r
+    }\r
+    \r
+    private static void bindDefaultAccountsToTenants(Connection conn, DatabaseProductType databaseProductType,\r
+               Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,\r
+               Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) \r
+                       throws SQLException, Exception {\r
+       // Fourth, bind accounts to tenants. Assume that if the users were already there,\r
+       // then the accounts were bound to tenants correctly\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               String insertAccountTenantSQL;\r
+               if (databaseProductType == DatabaseProductType.MYSQL) {\r
+                       insertAccountTenantSQL =\r
+                                       "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
+                                                       + " VALUES(?, ?)";\r
+               } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
+                       insertAccountTenantSQL =\r
+                                       "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
+                                                       + " VALUES(nextval('hibernate_sequence'), ?, ?)";\r
+               } else {\r
+                       throw new Exception("Unrecognized database system.");\r
+               }\r
+               pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement\r
+               for(String tId : tenantInfo.keySet()) {\r
+                       String tName = tenantInfo.get(tId);\r
+                       if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {\r
+                               String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
+                               pstmt.setString(1, adminAcct);          // set acct CSID param\r
+                               pstmt.setString(2, tId);                        // set tenant_id param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts binding account id: "\r
+                                                       +adminAcct+" to tenant id: "+tId);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       }\r
+                       if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {\r
+                               String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
+                               pstmt.setString(1, readerAcct);         // set acct CSID param\r
+                               pstmt.setString(2, tId);                        // set tenant_id param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts binding account id: "\r
+                                                       +readerAcct+" to tenant id: "+tId);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       }\r
+               }\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+    }\r
+    \r
+    \r
+    private static String findOrCreateDefaultRoles(Connection conn, Hashtable<String, String> tenantInfo,\r
+               Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs) \r
+                       throws SQLException, Exception {\r
+       // Fifth, fetch and save the default roles\r
+               String springAdminRoleCSID = null;\r
+       Statement stmt = null;\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               final String querySpringRole = \r
+                               "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'";\r
+               stmt = conn.createStatement();\r
+               ResultSet rs = stmt.executeQuery(querySpringRole);\r
                if(rs.next()) {\r
                        springAdminRoleCSID = rs.getString(1);\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts found Spring Admin role: "\r
-                                       +springAdminRoleCSID);\r
-               }\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts found Spring Admin role: "\r
+                                               +springAdminRoleCSID);\r
+                       }\r
                } else {\r
-                String insertSpringAdminRoleSQL =\r
-                       "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "\r
-                       + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";\r
+                       final String insertSpringAdminRoleSQL =\r
+                                       "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "\r
+                                                       + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";\r
                        stmt.executeUpdate(insertSpringAdminRoleSQL);\r
                        springAdminRoleCSID = "-1";\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts CREATED Spring Admin role: "\r
-                                       +springAdminRoleCSID);\r
-               }\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts CREATED Spring Admin role: "\r
+                                               +springAdminRoleCSID);\r
+                       }\r
                }\r
-               rs.close();\r
-               String getRoleCSIDSql =\r
-                       "SELECT csid from roles WHERE tenant_id=? and rolename=?";\r
-               pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement\r
-               rs = null;\r
-            Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();\r
-            Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();\r
-               for(String tId : tenantInfo.keySet()) {\r
-                       pstmt.setString(1, tId);                                                // set tenant_id param\r
-                       pstmt.setString(2, getDefaultAdminRole(tId));   // set rolename param\r
-                       rs = pstmt.executeQuery();\r
-                       // extract data from the ResultSet\r
-                       if(!rs.next()) {\r
-                               throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)\r
-                                               +" for tenant id: "+tId+" in roles!");\r
-                       }\r
+               rs.close();\r
+               final String getRoleCSIDSql =\r
+                               "SELECT csid from roles WHERE tenant_id=? and rolename=?";\r
+               pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement\r
+               rs = null;\r
+               for(String tId : tenantInfo.keySet()) {\r
+                       pstmt.setString(1, tId);                                                // set tenant_id param\r
+                       pstmt.setString(2, getDefaultAdminRole(tId));   // set rolename param\r
+                       rs = pstmt.executeQuery();\r
+                       // extract data from the ResultSet\r
+                       if(!rs.next()) {\r
+                               throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)\r
+                                               +" for tenant id: "+tId+" in roles!");\r
+                       }\r
                        String tenantAdminRoleCSID = rs.getString(1);\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts found role: "\r
-                                       +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID\r
-                                       +") for tenant id: "+tId);\r
-               }\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts found role: "\r
+                                               +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID\r
+                                               +") for tenant id: "+tId);\r
+                       }\r
                        tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);\r
-                       pstmt.setString(1, tId);                                                // set tenant_id param\r
-                       pstmt.setString(2, getDefaultReaderRole(tId));  // set rolename param\r
-                       rs.close();\r
-                       rs = pstmt.executeQuery();\r
-                       // extract data from the ResultSet\r
-                       if(!rs.next()) {\r
-                               throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)\r
-                                               +" for tenant id: "+tId+" in roles!");\r
-                       }\r
+                       pstmt.setString(1, tId);                                                // set tenant_id param\r
+                       pstmt.setString(2, getDefaultReaderRole(tId));  // set rolename param\r
+                       rs.close();\r
+                       rs = pstmt.executeQuery();\r
+                       // extract data from the ResultSet\r
+                       if(!rs.next()) {\r
+                               throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)\r
+                                               +" for tenant id: "+tId+" in roles!");\r
+                       }\r
                        String tenantReaderRoleCSID = rs.getString(1);\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts found role: "\r
-                                       +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID\r
-                                       +") for tenant id: "+tId);\r
-               }\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("createDefaultAccounts found role: "\r
+                                               +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID\r
+                                               +") for tenant id: "+tId);\r
+                       }\r
                        tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);\r
-                       rs.close();\r
-               }\r
-               pstmt.close();\r
-               // Sixth, bind the accounts to roles. If the users already existed,\r
-               // we'll assume they were set up correctly.\r
-                                       String insertAccountRoleSQL;\r
-                                       if (databaseProductType == DatabaseProductType.MYSQL) {\r
-                                               insertAccountRoleSQL =\r
-                                               "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"\r
-                                                       +" VALUES(?, ?, ?, ?, now())";\r
-                                       } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
-                                               insertAccountRoleSQL =\r
-                                               "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"\r
-                                                       +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";\r
-                                       } else {\r
-                                                       throw new Exception("Unrecognized database system.");\r
-                                       }\r
-               if (logger.isDebugEnabled()) {\r
-                       logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"\r
-                                       +insertAccountRoleSQL);\r
-               }\r
-               pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement\r
-               for(String tId : tenantInfo.keySet()) {\r
-                       String adminUserId =  getDefaultAdminUserID(tenantInfo.get(tId));\r
-                       if(!usersInRepo.contains(adminUserId)) {\r
-                       String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
-                               String adminRoleId = tenantAdminRoleCSIDs.get(tId);\r
-                               pstmt.setString(1, adminAcct);          // set acct CSID param\r
-                               pstmt.setString(2, adminUserId);        // set user_id param\r
-                               pstmt.setString(3, adminRoleId);        // set role_id param\r
-                               pstmt.setString(4, getDefaultAdminRole(tId));   // set rolename param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts binding account: "\r
-                                               +adminUserId+" to Admin role("+adminRoleId\r
-                                               +") for tenant id: "+tId);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                               // Now add the Spring Admin Role to the admin accounts\r
-                               pstmt.setString(3, springAdminRoleCSID);        // set role_id param\r
-                               pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts binding account: "\r
-                                               +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       }\r
-                       String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));\r
-                       if(!usersInRepo.contains(readerUserId)) {\r
-                               String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
-                               String readerRoleId = tenantReaderRoleCSIDs.get(tId);\r
-                               pstmt.setString(1, readerAcct);         // set acct CSID param\r
-                               pstmt.setString(2, readerUserId);       // set user_id param\r
-                               pstmt.setString(3, readerRoleId);       // set role_id param\r
-                               pstmt.setString(4, getDefaultReaderRole(tId));  // set rolename param\r
-                       if (logger.isDebugEnabled()) {\r
-                               logger.debug("createDefaultAccounts binding account: "\r
-                                               +readerUserId+" to Reader role("+readerRoleId\r
-                                               +") for tenant id: "+tId);\r
-                       }\r
-                               pstmt.executeUpdate();\r
-                       }\r
-               }\r
-               pstmt.close();\r
-                       stmt.close();\r
+                       rs.close();\r
+               }\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(stmt!=null)\r
+                       stmt.close();\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+       return springAdminRoleCSID;\r
+    }\r
+\r
+    private static String findTenantManagerRole(Connection conn ) \r
+                       throws SQLException, RuntimeException, Exception {\r
+               String tenantMgrRoleCSID = null;\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               String rolename = getQualifiedRoleName(ALL_TENANTS_MANAGER_TENANT_ID, \r
+                                                                                               ROLE_ALL_TENANTS_MANAGER);              \r
+               pstmt = conn.prepareStatement(GET_TENANT_MGR_ROLE_SQL); // create a statement\r
+               ResultSet rs = null;\r
+               pstmt.setString(1, rolename);   // set rolename param\r
+               rs = pstmt.executeQuery();\r
+               if(rs.next()) {\r
+                       tenantMgrRoleCSID = rs.getString(1);\r
+                       if (logger.isDebugEnabled()) {\r
+                               logger.debug("findTenantManagerRole found Tenant Mgr role: "\r
+                                               +tenantMgrRoleCSID);\r
+                       }\r
+               }\r
+               rs.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+       if(tenantMgrRoleCSID==null)\r
+               throw new RuntimeException("findTenantManagerRole: Cound not find tenant Manager Role!");\r
+       return tenantMgrRoleCSID;\r
+    }\r
+\r
+    private static void bindAccountsToRoles(Connection conn,  DatabaseProductType databaseProductType,\r
+               Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,\r
+               String springAdminRoleCSID,\r
+               Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs,\r
+               Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) \r
+                       throws SQLException, Exception {\r
+       // Sixth, bind the accounts to roles. If the users already existed,\r
+       // we'll assume they were set up correctly.\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               String insertAccountRoleSQL;\r
+               if (databaseProductType == DatabaseProductType.MYSQL) {\r
+                       insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;\r
+               } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
+                       insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;\r
+               } else {\r
+                       throw new Exception("Unrecognized database system.");\r
+               }\r
+               if (logger.isDebugEnabled()) {\r
+                       logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"\r
+                                       +insertAccountRoleSQL);\r
+               }\r
+               pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement\r
+               for(String tId : tenantInfo.keySet()) {\r
+                       String adminUserId =  getDefaultAdminUserID(tenantInfo.get(tId));\r
+                       if(!usersInRepo.contains(adminUserId)) {\r
+                               String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
+                               String adminRoleId = tenantAdminRoleCSIDs.get(tId);\r
+                               pstmt.setString(1, adminAcct);          // set acct CSID param\r
+                               pstmt.setString(2, adminUserId);        // set user_id param\r
+                               pstmt.setString(3, adminRoleId);        // set role_id param\r
+                               pstmt.setString(4, getDefaultAdminRole(tId));   // set rolename param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts binding account: "\r
+                                                       +adminUserId+" to Admin role("+adminRoleId\r
+                                                       +") for tenant id: "+tId);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                               // Now add the Spring Admin Role to the admin accounts\r
+                               pstmt.setString(3, springAdminRoleCSID);        // set role_id param\r
+                               pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts binding account: "\r
+                                                       +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       }\r
+                       String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));\r
+                       if(!usersInRepo.contains(readerUserId)) {\r
+                               String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
+                               String readerRoleId = tenantReaderRoleCSIDs.get(tId);\r
+                               pstmt.setString(1, readerAcct);         // set acct CSID param\r
+                               pstmt.setString(2, readerUserId);       // set user_id param\r
+                               pstmt.setString(3, readerRoleId);       // set role_id param\r
+                               pstmt.setString(4, getDefaultReaderRole(tId));  // set rolename param\r
+                               if (logger.isDebugEnabled()) {\r
+                                       logger.debug("createDefaultAccounts binding account: "\r
+                                                       +readerUserId+" to Reader role("+readerRoleId\r
+                                                       +") for tenant id: "+tId);\r
+                               }\r
+                               pstmt.executeUpdate();\r
+                       }\r
+               }\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+    }\r
+    \r
+    private static void bindTenantManagerAccountRole(Connection conn,  DatabaseProductType databaseProductType,\r
+               String tenantManagerUserID, String tenantManagerAccountID, String tenantManagerRoleID, String tenantManagerRoleName ) \r
+                       throws SQLException, Exception {\r
+       PreparedStatement pstmt = null;\r
+       try {\r
+               String insertAccountRoleSQL;\r
+               if (databaseProductType == DatabaseProductType.MYSQL) {\r
+                       insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;\r
+               } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
+                       insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;\r
+               } else {\r
+                       throw new Exception("Unrecognized database system.");\r
+               }\r
+               if (logger.isDebugEnabled()) {\r
+                       logger.debug("bindTenantManagerAccountRole binding account to role with SQL:\n"\r
+                                       +insertAccountRoleSQL);\r
+               }\r
+               pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement\r
+               pstmt.setString(1, tenantManagerAccountID);             // set acct CSID param\r
+               pstmt.setString(2, tenantManagerUserID);        // set user_id param\r
+               pstmt.setString(3, tenantManagerRoleID);        // set role_id param\r
+               pstmt.setString(4, tenantManagerRoleName);      // set rolename param\r
+               if (logger.isDebugEnabled()) {\r
+                       logger.debug("bindTenantManagerAccountRole binding user: "\r
+                                       +tenantManagerUserID+" to Admin role("+tenantManagerRoleName+")");\r
+               }\r
+               pstmt.executeUpdate();\r
+               /* At this point, tenant manager should not need the Spring Admin Role\r
+               pstmt.setString(3, springAdminRoleCSID);        // set role_id param\r
+               pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param\r
+               if (logger.isDebugEnabled()) {\r
+                       logger.debug("createDefaultAccounts binding account: "\r
+                                       +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);\r
+               }\r
+               pstmt.executeUpdate();\r
+               */\r
+               pstmt.close();\r
+       } catch(Exception e) {\r
+               throw e;\r
+       } finally {\r
+               if(pstmt!=null)\r
+                       pstmt.close();\r
+       }\r
+    }\r
+    \r
+    public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) {\r
+       if (logger.isDebugEnabled()) {\r
+               logger.debug("ServiceMain.createDefaultAccounts starting...");\r
+       }\r
+       \r
+        Hashtable<String, String> tenantInfo = getTenantNamesFromConfig(tenantBindingConfigReader);\r
+        \r
+        Connection conn = null;\r
+        // TODO - need to put in tests for existence first.\r
+        // We could just look for the accounts per tenant up front, and assume that\r
+        // the rest is there if the accounts are.\r
+        // Could add a sql script to remove these if need be - Spring only does roles, \r
+        // and we're not touching that, so we could safely toss the \r
+        // accounts, users, account-tenants, account-roles, and start over.\r
+        try {\r
+               DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType();\r
+               conn = getConnection();\r
+               ArrayList<String> existingTenants = compileExistingTenants(conn, tenantInfo);\r
+               \r
+               createMissingTenants(conn, tenantInfo, existingTenants);\r
+               \r
+               ArrayList<String> usersInRepo = findOrCreateDefaultUsers(conn, tenantInfo);\r
+               \r
+               Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();\r
+               Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();\r
+               findOrCreateDefaultAccounts(conn, tenantInfo, usersInRepo,\r
+                               tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);\r
+\r
+               bindDefaultAccountsToTenants(conn, databaseProductType, tenantInfo, usersInRepo,\r
+                               tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);\r
+               \r
+               Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();\r
+               Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();\r
+               String springAdminRoleCSID = findOrCreateDefaultRoles(conn, tenantInfo,\r
+                               tenantAdminRoleCSIDs, tenantReaderRoleCSIDs);\r
+               \r
+               bindAccountsToRoles(conn,  databaseProductType,\r
+                               tenantInfo, usersInRepo, springAdminRoleCSID,\r
+                               tenantAdminRoleCSIDs, tenantReaderRoleCSIDs,\r
+                               tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);\r
+               \r
+               boolean createdTenantMgrAccount = findOrCreateTenantManagerUserAndAccount(conn);\r
+               if(createdTenantMgrAccount) {\r
+                       // If we created the account, we need to create the bindings. Otherwise, assume they\r
+                       // are all set (from previous initialization).\r
+                       String tenantManagerRoleCSID = findTenantManagerRole(conn);\r
+                       bindTenantManagerAccountRole(conn, databaseProductType, \r
+                                       TENANT_MANAGER_USER, AuthN.TENANT_MANAGER_ACCT_ID, \r
+                                       tenantManagerRoleCSID, ROLE_ALL_TENANTS_MANAGER);\r
+               }\r
         } catch (RuntimeException rte) {\r
                if (logger.isDebugEnabled()) {\r
                        logger.debug("Exception in createDefaultAccounts: "+\r
@@ -712,10 +992,6 @@ public class AuthorizationCommon {
                try {\r
                if(conn!=null)\r
                     conn.close();\r
-               if(pstmt!=null)\r
-                    pstmt.close();\r
-               if(stmt!=null)\r
-                    stmt.close();\r
             } catch (SQLException sqle) {\r
                if (logger.isDebugEnabled()) {\r
                                logger.debug("SQL Exception closing statement/connection: "\r
@@ -808,7 +1084,6 @@ public class AuthorizationCommon {
         try {\r
             em = emf.createEntityManager();\r
 \r
-            Role superRole = AuthorizationCommon.getRole(em, ADMINISTRATOR_TENANT_ID, ROLE_ADMINISTRATOR);\r
                Hashtable<String, TenantBindingType> tenantBindings =\r
                        tenantBindingConfigReader.getTenantBindings();\r
                for (String tenantId : tenantBindings.keySet()) {\r
@@ -840,12 +1115,6 @@ public class AuthorizationCommon {
                                                                        + ":" + transitionDef.getName()\r
                                                                        + ":" + ACTIONGROUP_RL\r
                                                                        + ":" + profiler.getCumulativeTime());                                          \r
-                                                       /*\r
-                                                       //\r
-                                                       // Create the permission for the super-admin role.  Note we use the same "adminPerm" instance we used for the "adminPermRole" instance\r
-                                                       //\r
-                                                       persist(em, adminPerm, superRole, false);\r
-                                                       */\r
                                                }\r
                                                em.getTransaction().commit();\r
                                        } catch (IllegalStateException e) {\r
index 1b03aa47323fb2a4306a92e16f34bc2e3ce6a001..178c2fbfcd05e5a1e6fc4e6fc9ebe4bbeb5c343b 100644 (file)
@@ -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<IT, OT>
         //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<IT, OT>
         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<IT, OT>
         valHandlers = handlers;
         return valHandlers;
     }
+    
+    @Override
+    public void addValidatorHandler(ValidatorHandler<IT, OT> validator) throws Exception {
+        if (valHandlers == null) {
+            valHandlers = new ArrayList<ValidatorHandler<IT, OT>>();
+        }
+        valHandlers.add(validator);
+    }
 
     /* (non-Javadoc)
      * @see java.lang.Object#toString()
index dea896e93987e1ba0915bce0f9564f2fb210cb96..bbb9f2a33d9a2fe10af45d72aeb50188d31e26c4 100644 (file)
@@ -266,12 +266,18 @@ public interface ServiceContext<IT, OT> {
     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<IT, OT> {
      */
     public List<ValidatorHandler<IT, OT>> 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<IT, OT> validator) throws Exception;
+
     /**
      * Gets the query params.
      * 
index 7c1b4d4033b34e507d92c3eadd60863751af2128..df1c25704b4ce1e31f890792dfe3427428331cab 100644 (file)
@@ -120,8 +120,14 @@ public class DocumentFilter {
      * @param ctx the ctx\r
      */\r
     public DocumentFilter(ServiceContext ctx) {\r
-        this.setPageSize(ctx.getServiceBindingPropertyValue(\r
-                DocumentFilter.PAGE_SIZE_DEFAULT_PROPERTY));\r
+       // Ignore errors - some contexts do not have proper service binding info\r
+       try {\r
+               String pageSizeString = ctx.getServiceBindingPropertyValue(\r
+                    DocumentFilter.PAGE_SIZE_DEFAULT_PROPERTY); \r
+               this.setPageSize(pageSizeString);\r
+       } catch(Exception e) {\r
+               this.setPageSize(defaultPageSize);\r
+       } \r
     }\r
 \r
     /**\r
index eb345010cebf0da944f087e3cfdf19653ab80b49..73525734973cc6235bce11361558d10622517d5f 100644 (file)
@@ -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);