]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
5b246462804f0b48b5e668777dd1b3b5b628be6b
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.common.authorization_mgt;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.sql.Statement;
8 import java.util.ArrayList;
9 import java.util.Date;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Hashtable;
13 import java.util.List;
14 import java.util.UUID;
15
16 import javax.naming.NamingException;
17 import javax.persistence.EntityManager;
18 import javax.persistence.EntityManagerFactory;
19
20 import org.collectionspace.authentication.AuthN;
21 import org.collectionspace.services.authorization.AuthZ;
22 import org.collectionspace.services.authorization.CSpaceAction;
23 import org.collectionspace.services.authorization.PermissionException;
24 import org.collectionspace.services.authorization.PermissionRole;
25 import org.collectionspace.services.authorization.PermissionRoleRel;
26 import org.collectionspace.services.authorization.PermissionValue;
27 import org.collectionspace.services.authorization.Role;
28 import org.collectionspace.services.authorization.RoleValue;
29 import org.collectionspace.services.authorization.SubjectType;
30 import org.collectionspace.services.authorization.URIResourceImpl;
31 import org.collectionspace.services.authorization.perms.ActionType;
32 import org.collectionspace.services.authorization.perms.EffectType;
33 import org.collectionspace.services.authorization.perms.Permission;
34 import org.collectionspace.services.authorization.perms.PermissionAction;
35 import org.collectionspace.services.client.Profiler;
36 import org.collectionspace.services.client.RoleClient;
37 import org.collectionspace.services.client.workflow.WorkflowClient;
38 import org.collectionspace.services.common.config.ServiceConfigUtils;
39 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
40 import org.collectionspace.services.common.context.ServiceBindingUtils;
41 import org.collectionspace.services.common.document.DocumentHandler;
42 import org.collectionspace.services.common.security.SecurityUtils;
43 import org.collectionspace.services.common.storage.DatabaseProductType;
44 import org.collectionspace.services.common.storage.JDBCTools;
45 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
46 import org.collectionspace.services.config.service.ServiceBindingType;
47 import org.collectionspace.services.config.tenant.TenantBindingType;
48 import org.collectionspace.services.lifecycle.Lifecycle;
49 import org.collectionspace.services.lifecycle.TransitionDef;
50 import org.collectionspace.services.lifecycle.TransitionDefList;
51
52 //import org.mortbay.log.Log;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.security.acls.model.AlreadyExistsException;
56
57
58 public class AuthorizationCommon {
59         
60         final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup";
61     //
62     // ActionGroup labels/constants
63     //
64         
65         // for READ-WRITE
66     final public static String ACTIONGROUP_CRUDL_NAME = "CRUDL";
67     final public static ActionType[] ACTIONSET_CRUDL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.DELETE, ActionType.SEARCH};
68     // for READ-ONLY
69     final public static String ACTIONGROUP_RL_NAME = "RL";
70     final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};
71         
72         static ActionGroup ACTIONGROUP_CRUDL;
73         static ActionGroup ACTIONGROUP_RL;
74         
75         // A static block to initialize the predefined action groups
76         static {
77                 // For admin
78                 ACTIONGROUP_CRUDL = new ActionGroup();
79                 ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME;
80                 ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL;
81                 // For reader
82                 ACTIONGROUP_RL = new ActionGroup();
83                 ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;
84                 ACTIONGROUP_RL.actions = ACTIONSET_RL;
85
86         }
87         
88     final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class);
89
90     //
91     // The "super" role has a predefined ID of "0" and a tenant ID of "0";
92     //
93     final public static String ROLE_ALL_TENANTS_MANAGER = "ALL_TENANTS_MANAGER";
94     final public static String ROLE_ALL_TENANTS_MANAGER_ID = "0";
95     final public static String ALL_TENANTS_MANAGER_TENANT_ID = "0";
96
97     final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";
98     final public static String ROLE_TENANT_READER = "TENANT_READER";
99         
100     public static final String TENANT_MANAGER_USER = "tenantManager"; 
101     public static final String TENANT_MANAGER_SCREEN_NAME = TENANT_MANAGER_USER; 
102     public static final String DEFAULT_TENANT_MANAGER_PASSWORD = "manage"; 
103     public static final String DEFAULT_TENANT_MANAGER_EMAIL = "tenantManager@collectionspace.org"; 
104     
105     public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; 
106     public static final String TENANT_READER_ACCT_PREFIX = "reader@"; 
107     public static final String ROLE_PREFIX = "ROLE_"; 
108     public static final String SPRING_ADMIN_ROLE = "ROLE_SPRING_ADMIN"; 
109     public static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR"; 
110     public static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER"; 
111     public static final String DEFAULT_ADMIN_PASSWORD = "Administrator";
112     public static final String DEFAULT_READER_PASSWORD = "reader";
113
114     public static final String ROLE_SPRING_ADMIN_ID = "-1";
115     public static final String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";
116     
117     // SQL for init tasks
118         final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL = 
119                         "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"
120                                         +" VALUES(?, ?, ?, ?, now())";
121         final private static String INSERT_ACCOUNT_ROLE_SQL_POSTGRES =
122                         "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"
123                                         +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";
124         final private static String QUERY_USERS_SQL = 
125                 "SELECT username FROM users WHERE username LIKE '"
126                         +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"+TENANT_READER_ACCT_PREFIX+"%'";
127         final private static String INSERT_USER_SQL = 
128                         "INSERT INTO users (username,passwd, created_at) VALUES (?,?, now())";
129         final private static String INSERT_ACCOUNT_SQL = 
130                         "INSERT INTO accounts_common "
131                                         + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "
132                                         + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";
133         
134         // TENANT MANAGER specific SQL
135         final private static String QUERY_TENANT_MGR_USER_SQL = 
136                 "SELECT username FROM users WHERE username = '"+TENANT_MANAGER_USER+"'";
137         final private static String GET_TENANT_MGR_ROLE_SQL =
138                         "SELECT csid from roles WHERE tenant_id='"+ALL_TENANTS_MANAGER_TENANT_ID+"' and rolename=?";
139
140     public static Role getRole(String tenantId, String displayName) {
141         Role role = null;
142         
143         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
144         role = AuthorizationStore.getRoleByName(roleName, tenantId);
145         
146         return role;
147     }
148     
149     public static Role getRole(EntityManager em, String tenantId, String displayName) {
150         Role role = null;
151         
152         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
153         role = AuthorizationStore.getRoleByName(em, roleName, tenantId);
154         
155         return role;
156     }
157     
158     
159     public static Role createRole(String tenantId, String name, String description) {
160         return createRole(tenantId, name, description, false /* mutable by default */);
161     }
162     
163     public static Role createRole(String tenantId, String name, String description, boolean immutable) {
164         Role role = new Role();
165         
166         role.setCreatedAtItem(new Date());
167         role.setDisplayName(name);
168         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, name);     
169         role.setRoleName(roleName);
170         String id = UUID.randomUUID().toString(); //FIXME: The qualified role name should be unique enough to use as an ID/key
171         role.setCsid(id);
172                 role.setDescription(description);
173         role.setTenantId(tenantId);
174         if (immutable == true) {
175                 role.setMetadataProtection(RoleClient.IMMUTABLE);
176                 role.setPermsProtection(RoleClient.IMMUTABLE);
177         }
178         
179         return role;
180     }
181     
182     /**
183      * Add permission to the Spring Security tables
184      * with assumption that resource is of type URI
185      * @param permission configuration
186      */
187     public static void addPermissionsForUri(Permission perm,
188             PermissionRole permRole) throws PermissionException {
189         //
190         // First check the integrity of the incoming arguments.
191         //
192         if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) {
193             throw new IllegalArgumentException("permission ids do not"
194                     + " match for role=" + permRole.getRole().get(0).getRoleName()
195                     + " with permissionId=" + permRole.getPermission().get(0).getPermissionId()
196                     + " for permission with csid=" + perm.getCsid());
197         }
198         
199         List<String> principals = new ArrayList<String>();        
200         for (RoleValue roleValue : permRole.getRole()) {
201             principals.add(roleValue.getRoleName());
202         }
203         List<PermissionAction> permActions = perm.getAction();
204         for (PermissionAction permAction : permActions) {
205                 try {
206                     CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); 
207                     URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
208                             perm.getResourceName(), action);
209                     boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false;
210                     AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant);//CSPACE-4967
211                 } catch (PermissionException e) {
212                         //
213                         // Only throw the exception if it is *not* an already-exists exception
214                         //
215                         if (e.getCause() instanceof AlreadyExistsException == false) {
216                                 throw e;
217                         }
218                 }
219         }
220     }
221     
222     private static Connection getConnection(String databaseName) throws NamingException, SQLException {
223         return JDBCTools.getConnection(JDBCTools.CSPACE_DATASOURCE_NAME,
224                         databaseName);
225     }
226     
227     /*
228      * Spring security seems to require that all of our role names start
229      * with the ROLE_PREFIX string.
230      */
231     public static String getQualifiedRoleName(String tenantId, String name) {
232         String result = name;
233         
234         String qualifiedName = ROLE_PREFIX + tenantId.toUpperCase() + "_" + name.toUpperCase();         
235         if (name.equals(qualifiedName) == false) {
236                 result = qualifiedName;
237         }
238         
239         return result;
240     }
241         
242     private static ActionGroup getActionGroup(String actionGroupStr) {
243         ActionGroup result = null;
244         
245         if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_CRUDL_NAME)) {
246                 result = ACTIONGROUP_CRUDL;
247         } else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_RL_NAME)) {
248                 result = ACTIONGROUP_RL;
249         }
250         
251         return result;
252     }
253     
254     public static Permission createPermission(String tenantId,
255                 String resourceName,
256                 String description,
257                 String actionGroupStr) {
258         Permission result = null;
259         
260         ActionGroup actionGroup = getActionGroup(actionGroupStr);
261         result = createPermission(tenantId, resourceName, description, actionGroup);
262         
263         return result;
264     }
265     
266     private static Permission createPermission(String tenantId,
267                 String resourceName,
268                 String description,
269                 ActionGroup actionGroup) {
270         String id = tenantId
271                         + "-" + resourceName.replace('/', '_') // Remove the slashes so the ID can be used in a URI/URL
272                         + "-" + actionGroup.name;
273         Permission perm = new Permission();
274         perm.setCsid(id);
275         perm.setDescription(description);
276         perm.setCreatedAtItem(new Date());
277         perm.setResourceName(resourceName.toLowerCase().trim());
278         perm.setEffect(EffectType.PERMIT);
279         perm.setTenantId(tenantId);
280         
281         perm.setActionGroup(actionGroup.name);
282         ArrayList<PermissionAction> pas = new ArrayList<PermissionAction>();
283         perm.setAction(pas);
284         for (ActionType actionType : actionGroup.actions) {
285                 PermissionAction permAction = createPermissionAction(perm, actionType);
286                 pas.add(permAction);
287         }
288         
289         return perm;
290     }
291     
292     private static Permission createWorkflowPermission(TenantBindingType tenantBinding,
293                 ServiceBindingType serviceBinding,
294                 String transitionVerb,
295                 ActionGroup actionGroup)
296     {
297         Permission result = null;
298         String workFlowServiceSuffix;
299         String transitionName;
300         if (transitionVerb != null) {
301                 transitionName = transitionVerb;
302                 workFlowServiceSuffix = WorkflowClient.SERVICE_AUTHZ_SUFFIX;
303         } else {
304                 transitionName = ""; //since the transitionDef was null, we're assuming that this is the base workflow permission to be created                 
305                 workFlowServiceSuffix = WorkflowClient.SERVICE_PATH;
306         }
307         
308         String tenantId = tenantBinding.getId();
309         String resourceName = "/"
310                         + serviceBinding.getName().toLowerCase().trim()
311                         + workFlowServiceSuffix
312                         + transitionName;
313         String description = "A generated workflow permission for actiongroup " + actionGroup.name;
314         result = createPermission(tenantId, resourceName, description, actionGroup);
315         
316         if (logger.isDebugEnabled() == true) {
317                 logger.debug("Generated a workflow permission: "
318                                 + result.getResourceName()
319                                 + ":" + transitionName
320                                 + ":" + "tenant id=" + result.getTenantId()
321                                 + ":" + actionGroup.name);
322         }
323         
324         return result;
325     }
326     
327     private static PermissionRole createPermissionRole(EntityManager em,
328                 Permission permission,
329                 Role role,
330                 boolean enforceTenancy) throws Exception
331     {
332         PermissionRole permRole = new PermissionRole();
333         // Check to see if the tenant ID of the permission and the tenant ID of the role match
334         boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId());
335         if (tenantIdsMatch == false && enforceTenancy == false) {
336                 tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched.
337         }
338                         
339                 if (tenantIdsMatch == true) {
340                 permRole.setSubject(SubjectType.ROLE);
341                 //
342                 // Set of the permission value list of the permrole
343                 //
344                 List<PermissionValue> permValues = new ArrayList<PermissionValue>();
345                 PermissionValue permValue = new PermissionValue();
346                 permValue.setPermissionId(permission.getCsid());
347                 permValue.setResourceName(permission.getResourceName().toLowerCase());
348                 permValue.setActionGroup(permission.getActionGroup());
349                 permValues.add(permValue);
350                 permRole.setPermission(permValues);
351                 //
352                 // Set of the role value list of the permrole
353                 //
354                 List<RoleValue> roleValues = new ArrayList<RoleValue>();
355                 RoleValue rv = new RoleValue();
356             // This needs to use the qualified name, not the display name
357             rv.setRoleName(role.getRoleName());
358             rv.setRoleId(role.getCsid());
359             roleValues.add(rv);
360             permRole.setRole(roleValues);
361                 } else {
362                 String errMsg = "The tenant ID of the role: " + role.getTenantId()
363                                 + " did not match the tenant ID of the permission: " + permission.getTenantId();
364                 throw new Exception(errMsg);
365                 }
366         
367         return permRole;
368     }
369     
370     private static Hashtable<String, String> getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) {
371
372         // Note that this only handles tenants not marked as "createDisabled"
373         Hashtable<String, TenantBindingType> tenantBindings =
374                         tenantBindingConfigReader.getTenantBindings();
375         Hashtable<String, String> tenantInfo = new Hashtable<String, String>();
376         for (TenantBindingType tenantBinding : tenantBindings.values()) {
377                 String tId = tenantBinding.getId();
378                 String tName = tenantBinding.getName();
379                 tenantInfo.put(tId, tName);
380                 if (logger.isDebugEnabled()) {
381                         logger.debug("getTenantNamesFromConfig found configured tenant id: "+tId+" name: "+tName);
382                 }
383         }
384         return tenantInfo;
385     }
386     
387     private static ArrayList<String> compileExistingTenants(Connection conn, Hashtable<String, String> tenantInfo)
388         throws SQLException, Exception {
389         Statement stmt = null;
390         ArrayList<String> existingTenants = new ArrayList<String>();
391         // First find or create the tenants
392         final String queryTenantSQL = "SELECT id,name FROM tenants";
393         try {
394                 stmt = conn.createStatement();
395                 ResultSet rs = stmt.executeQuery(queryTenantSQL);
396                 while (rs.next()) {
397                         String tId = rs.getString("id");
398                         String tName = rs.getString("name");
399                         if(tenantInfo.containsKey(tId)) {
400                                 existingTenants.add(tId);
401                                 if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {
402                                         logger.warn("Configured name for tenant: "
403                                                         +tId+" in repository: "+tName
404                                                         +" does not match config'd name: "+ tenantInfo.get(tId));
405                                 }
406                         }
407                 }
408                 rs.close();
409         } catch(Exception e) {
410                 throw e;
411         } finally {
412                 if(stmt!=null)
413                         stmt.close();
414         }
415
416         return existingTenants;
417     }
418     
419     private static void createMissingTenants(Connection conn, Hashtable<String, String> tenantInfo,
420                 ArrayList<String> existingTenants) throws SQLException, Exception {
421                 // Need to define and look for a createDisabled attribute in tenant config
422         final String insertTenantSQL = 
423                 "INSERT INTO tenants (id,name,disabled,created_at) VALUES (?,?,FALSE,now())";
424         PreparedStatement pstmt = null;
425         try {
426                 pstmt = conn.prepareStatement(insertTenantSQL); // create a statement
427                 for(String tId : tenantInfo.keySet()) {
428                         if(existingTenants.contains(tId)) {
429                                 if (logger.isDebugEnabled()) {
430                                         logger.debug("createMissingTenants: tenant exists (skipping): "
431                                                         +tenantInfo.get(tId));
432                                 }
433                                 continue;
434                         }
435                         pstmt.setString(1, tId);                                        // set id param
436                         pstmt.setString(2, tenantInfo.get(tId));        // set name param
437                         if (logger.isDebugEnabled()) {
438                                 logger.debug("createMissingTenants adding entry for tenant: "+tId);
439                         }
440                         pstmt.executeUpdate();
441                 }
442                 pstmt.close();
443         } catch(Exception e) {
444                 throw e;
445         } finally {
446                 if(pstmt!=null)
447                         pstmt.close();
448         }
449     }
450     
451     private static ArrayList<String> findOrCreateDefaultUsers(Connection conn, Hashtable<String, String> tenantInfo) 
452                 throws SQLException, Exception {
453         // Second find or create the users
454         Statement stmt = null;
455         PreparedStatement pstmt = null;
456         ArrayList<String> usersInRepo = new ArrayList<String>();
457         try {
458                 stmt = conn.createStatement();
459                 ResultSet rs = stmt.executeQuery(QUERY_USERS_SQL);
460                 while (rs.next()) {
461                         String uName = rs.getString("username");
462                         usersInRepo.add(uName);
463                 }
464                 rs.close();
465                 pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement
466                 for(String tName : tenantInfo.values()) {
467                         String adminAcctName = getDefaultAdminUserID(tName);
468                         if(!usersInRepo.contains(adminAcctName)) {
469                                 String secEncPasswd = SecurityUtils.createPasswordHash(
470                                                 adminAcctName, DEFAULT_ADMIN_PASSWORD);
471                                 pstmt.setString(1, adminAcctName);      // set username param
472                                 pstmt.setString(2, secEncPasswd);       // set passwd param
473                                 if (logger.isDebugEnabled()) {
474                                         logger.debug("createDefaultUsersAndAccounts adding user: "
475                                                         +adminAcctName+" for tenant: "+tName);
476                                 }
477                                 pstmt.executeUpdate();
478                         } else if (logger.isDebugEnabled()) {
479                                 logger.debug("createDefaultUsersAndAccounts: user: "+adminAcctName
480                                                 +" already exists - skipping.");
481                         }
482
483
484                         String readerAcctName =  getDefaultReaderUserID(tName);
485                         if(!usersInRepo.contains(readerAcctName)) {
486                                 String secEncPasswd = SecurityUtils.createPasswordHash(
487                                                 readerAcctName, DEFAULT_READER_PASSWORD);
488                                 pstmt.setString(1, readerAcctName);     // set username param
489                                 pstmt.setString(2, secEncPasswd);       // set passwd param
490                                 if (logger.isDebugEnabled()) {
491                                         logger.debug("createDefaultUsersAndAccounts adding user: "
492                                                         +readerAcctName+" for tenant: "+tName);
493                                 }
494                                 pstmt.executeUpdate();
495                         } else if (logger.isDebugEnabled()) {
496                                 logger.debug("createDefaultUsersAndAccounts: user: "+readerAcctName
497                                                 +" already exists - skipping.");
498                         }
499                 }
500                 pstmt.close();
501         } catch(Exception e) {
502                 throw e;
503         } finally {
504                 if(stmt!=null)
505                         stmt.close();
506                 if(pstmt!=null)
507                         pstmt.close();
508         }
509         return usersInRepo;
510     }
511     
512     private static void findOrCreateDefaultAccounts(Connection conn, Hashtable<String, String> tenantInfo,
513                 ArrayList<String> usersInRepo,
514                 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) 
515                         throws SQLException, Exception {
516         // Third, create the accounts. Assume that if the users were already there,
517         // then the accounts were as well
518         PreparedStatement pstmt = null;
519         try {
520                 pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement
521                 for(String tId : tenantInfo.keySet()) {
522                         String tName = tenantInfo.get(tId);
523                         String adminCSID = UUID.randomUUID().toString();
524                         tenantAdminAcctCSIDs.put(tId, adminCSID);
525                         String adminAcctName =  getDefaultAdminUserID(tName);
526                         if(!usersInRepo.contains(adminAcctName)) {
527                                 pstmt.setString(1, adminCSID);                  // set csid param
528                                 pstmt.setString(2, adminAcctName);      // set email param (bogus)
529                                 pstmt.setString(3, adminAcctName);      // set userid param
530                                 pstmt.setString(4, "Administrator");// set screen name param
531                                 if (logger.isDebugEnabled()) {
532                                         logger.debug("createDefaultAccounts adding account: "
533                                                         +adminAcctName+" for tenant: "+tName);
534                                 }
535                                 pstmt.executeUpdate();
536                         } else if (logger.isDebugEnabled()) {
537                                 logger.debug("createDefaultAccounts: user: "+adminAcctName
538                                                 +" already exists - skipping account generation.");
539                         }
540
541                         String readerCSID = UUID.randomUUID().toString();       
542                         tenantReaderAcctCSIDs.put(tId, readerCSID);
543                         String readerAcctName =  getDefaultReaderUserID(tName);
544                         if(!usersInRepo.contains(readerAcctName)) {
545                                 pstmt.setString(1, readerCSID);         // set csid param
546                                 pstmt.setString(2, readerAcctName);     // set email param (bogus)
547                                 pstmt.setString(3, readerAcctName);     // set userid param
548                                 pstmt.setString(4, "Reader");           // set screen name param
549                                 if (logger.isDebugEnabled()) {
550                                         logger.debug("createDefaultAccounts adding account: "
551                                                         +readerAcctName+" for tenant: "+tName);
552                                 }
553                                 pstmt.executeUpdate();
554                         } else if (logger.isDebugEnabled()) {
555                                 logger.debug("createDefaultAccounts: user: "+readerAcctName
556                                                 +" already exists - skipping account creation.");
557                         }
558                 }
559                 pstmt.close();
560         } catch(Exception e) {
561                 throw e;
562         } finally {
563                 if(pstmt!=null)
564                         pstmt.close();
565         }
566     }
567     
568     private static boolean findOrCreateTenantManagerUserAndAccount(Connection conn) 
569                         throws SQLException, Exception {
570         // Find or create the special tenant manager account.
571         // Later can make the user name for tenant manager be configurable, settable.
572         Statement stmt = null;
573         PreparedStatement pstmt = null;
574         boolean created = false;
575         try {
576                 boolean foundTMgrUser = false;
577                 stmt = conn.createStatement();
578                 ResultSet rs = stmt.executeQuery(QUERY_TENANT_MGR_USER_SQL);
579                 // Should only find one - only consider it
580                 if(rs.next()) {
581                         String uName = rs.getString("username");
582                         foundTMgrUser = uName.equals(TENANT_MANAGER_USER);
583                 }
584                 rs.close();
585                 if(!foundTMgrUser) {
586                         pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement
587                         String secEncPasswd = SecurityUtils.createPasswordHash(
588                                         TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD);
589                         pstmt.setString(1, TENANT_MANAGER_USER);        // set username param
590                         pstmt.setString(2, secEncPasswd);       // set passwd param
591                         if (logger.isDebugEnabled()) {
592                                 logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager user: "
593                                                 +TENANT_MANAGER_USER);
594                         }
595                         pstmt.executeUpdate();
596                 pstmt.close();
597                 // Now create the account to match
598                         pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement
599                                 pstmt.setString(1, AuthN.TENANT_MANAGER_ACCT_ID);                // set csid param
600                                 pstmt.setString(2, DEFAULT_TENANT_MANAGER_EMAIL);       // set email param (bogus)
601                                 pstmt.setString(3, TENANT_MANAGER_USER);        // set userid param
602                                 pstmt.setString(4, TENANT_MANAGER_SCREEN_NAME);// set screen name param
603                                 if (logger.isDebugEnabled()) {
604                                         logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager account: "
605                                                         +TENANT_MANAGER_USER);
606                                 }
607                                 pstmt.executeUpdate();
608                         pstmt.close();
609                         created = true;
610                 } else if (logger.isDebugEnabled()) {
611                         logger.debug("findOrCreateTenantManagerUserAndAccount: tenant manager: "+TENANT_MANAGER_USER
612                                         +" already exists.");
613                 }
614         } catch(Exception e) {
615                 throw e;
616         } finally {
617                 if(stmt!=null)
618                         stmt.close();
619                 if(pstmt!=null)
620                         pstmt.close();
621         }
622         return created;
623     }
624     
625     private static void bindDefaultAccountsToTenants(Connection conn, DatabaseProductType databaseProductType,
626                 Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,
627                 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) 
628                         throws SQLException, Exception {
629         // Fourth, bind accounts to tenants. Assume that if the users were already there,
630         // then the accounts were bound to tenants correctly
631         PreparedStatement pstmt = null;
632         try {
633                 String insertAccountTenantSQL;
634                 if (databaseProductType == DatabaseProductType.MYSQL) {
635                         insertAccountTenantSQL =
636                                         "INSERT INTO accounts_tenants (TENANTS_ACCOUNTS_COMMON_CSID,tenant_id) "
637                                                         + " VALUES(?, ?)";
638                 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
639                         insertAccountTenantSQL =
640                                         "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTS_COMMON_CSID,tenant_id) "
641                                                         + " VALUES(nextval('hibernate_sequence'), ?, ?)";
642                 } else {
643                         throw new Exception("Unrecognized database system.");
644                 }
645                 pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement
646                 for(String tId : tenantInfo.keySet()) {
647                         String tName = tenantInfo.get(tId);
648                         if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {
649                                 String adminAcct = tenantAdminAcctCSIDs.get(tId);
650                                 pstmt.setString(1, adminAcct);          // set acct CSID param
651                                 pstmt.setString(2, tId);                        // set tenant_id param
652                                 if (logger.isDebugEnabled()) {
653                                         logger.debug("createDefaultAccounts binding account id: "
654                                                         +adminAcct+" to tenant id: "+tId);
655                                 }
656                                 pstmt.executeUpdate();
657                         }
658                         if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {
659                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);
660                                 pstmt.setString(1, readerAcct);         // set acct CSID param
661                                 pstmt.setString(2, tId);                        // set tenant_id param
662                                 if (logger.isDebugEnabled()) {
663                                         logger.debug("createDefaultAccounts binding account id: "
664                                                         +readerAcct+" to tenant id: "+tId);
665                                 }
666                                 pstmt.executeUpdate();
667                         }
668                 }
669                 pstmt.close();
670         } catch(Exception e) {
671                 throw e;
672         } finally {
673                 if(pstmt!=null)
674                         pstmt.close();
675         }
676     }
677     
678     
679     private static String findOrCreateDefaultRoles(Connection conn, Hashtable<String, String> tenantInfo,
680                 Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs) 
681                         throws SQLException, Exception {
682         // Fifth, fetch and save the default roles
683                 String springAdminRoleCSID = null;
684         Statement stmt = null;
685         PreparedStatement pstmt = null;
686         try {
687                 final String querySpringRole = 
688                                 "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'";
689                 stmt = conn.createStatement();
690                 ResultSet rs = stmt.executeQuery(querySpringRole);
691                 if(rs.next()) {
692                         springAdminRoleCSID = rs.getString(1);
693                         if (logger.isDebugEnabled()) {
694                                 logger.debug("createDefaultAccounts found Spring Admin role: "
695                                                 +springAdminRoleCSID);
696                         }
697                 } else {
698                         final String insertSpringAdminRoleSQL =
699                                         "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "
700                                                         + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";
701                         stmt.executeUpdate(insertSpringAdminRoleSQL);
702                         springAdminRoleCSID = "-1";
703                         if (logger.isDebugEnabled()) {
704                                 logger.debug("createDefaultAccounts CREATED Spring Admin role: "
705                                                 +springAdminRoleCSID);
706                         }
707                 }
708                 rs.close();
709                 final String getRoleCSIDSql =
710                                 "SELECT csid from roles WHERE tenant_id=? and rolename=?";
711                 pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement
712                 rs = null;
713                 for(String tId : tenantInfo.keySet()) {
714                         pstmt.setString(1, tId);                                                // set tenant_id param
715                         pstmt.setString(2, getDefaultAdminRole(tId));   // set rolename param
716                         rs = pstmt.executeQuery();
717                         // extract data from the ResultSet
718                         if(!rs.next()) {
719                                 throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)
720                                                 +" for tenant id: "+tId+" in roles!");
721                         }
722                         String tenantAdminRoleCSID = rs.getString(1);
723                         if (logger.isDebugEnabled()) {
724                                 logger.debug("createDefaultAccounts found role: "
725                                                 +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID
726                                                 +") for tenant id: "+tId);
727                         }
728                         tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);
729                         pstmt.setString(1, tId);                                                // set tenant_id param
730                         pstmt.setString(2, getDefaultReaderRole(tId));  // set rolename param
731                         rs.close();
732                         rs = pstmt.executeQuery();
733                         // extract data from the ResultSet
734                         if(!rs.next()) {
735                                 throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)
736                                                 +" for tenant id: "+tId+" in roles!");
737                         }
738                         String tenantReaderRoleCSID = rs.getString(1);
739                         if (logger.isDebugEnabled()) {
740                                 logger.debug("createDefaultAccounts found role: "
741                                                 +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID
742                                                 +") for tenant id: "+tId);
743                         }
744                         tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);
745                         rs.close();
746                 }
747                 pstmt.close();
748         } catch(Exception e) {
749                 throw e;
750         } finally {
751                 if(stmt!=null)
752                         stmt.close();
753                 if(pstmt!=null)
754                         pstmt.close();
755         }
756         return springAdminRoleCSID;
757     }
758
759     private static String findTenantManagerRole(Connection conn ) 
760                         throws SQLException, RuntimeException, Exception {
761                 String tenantMgrRoleCSID = null;
762         PreparedStatement pstmt = null;
763         try {
764                 String rolename = getQualifiedRoleName(ALL_TENANTS_MANAGER_TENANT_ID, 
765                                                                                                 ROLE_ALL_TENANTS_MANAGER);              
766                 pstmt = conn.prepareStatement(GET_TENANT_MGR_ROLE_SQL); // create a statement
767                 ResultSet rs = null;
768                 pstmt.setString(1, rolename);   // set rolename param
769                 rs = pstmt.executeQuery();
770                 if(rs.next()) {
771                         tenantMgrRoleCSID = rs.getString(1);
772                         if (logger.isDebugEnabled()) {
773                                 logger.debug("findTenantManagerRole found Tenant Mgr role: "
774                                                 +tenantMgrRoleCSID);
775                         }
776                 }
777                 rs.close();
778         } catch(Exception e) {
779                 throw e;
780         } finally {
781                 if(pstmt!=null)
782                         pstmt.close();
783         }
784         if(tenantMgrRoleCSID==null)
785                 throw new RuntimeException("findTenantManagerRole: Cound not find tenant Manager Role!");
786         return tenantMgrRoleCSID;
787     }
788
789     private static void bindAccountsToRoles(Connection conn,  DatabaseProductType databaseProductType,
790                 Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,
791                 String springAdminRoleCSID,
792                 Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs,
793                 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs) 
794                         throws SQLException, Exception {
795         // Sixth, bind the accounts to roles. If the users already existed,
796         // we'll assume they were set up correctly.
797         PreparedStatement pstmt = null;
798         try {
799                 String insertAccountRoleSQL;
800                 if (databaseProductType == DatabaseProductType.MYSQL) {
801                         insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;
802                 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
803                         insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;
804                 } else {
805                         throw new Exception("Unrecognized database system.");
806                 }
807                 if (logger.isDebugEnabled()) {
808                         logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"
809                                         +insertAccountRoleSQL);
810                 }
811                 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement
812                 for(String tId : tenantInfo.keySet()) {
813                         String adminUserId =  getDefaultAdminUserID(tenantInfo.get(tId));
814                         if(!usersInRepo.contains(adminUserId)) {
815                                 String adminAcct = tenantAdminAcctCSIDs.get(tId);
816                                 String adminRoleId = tenantAdminRoleCSIDs.get(tId);
817                                 pstmt.setString(1, adminAcct);          // set acct CSID param
818                                 pstmt.setString(2, adminUserId);        // set user_id param
819                                 pstmt.setString(3, adminRoleId);        // set role_id param
820                                 pstmt.setString(4, getDefaultAdminRole(tId));   // set rolename param
821                                 if (logger.isDebugEnabled()) {
822                                         logger.debug("createDefaultAccounts binding account: "
823                                                         +adminUserId+" to Admin role("+adminRoleId
824                                                         +") for tenant id: "+tId);
825                                 }
826                                 pstmt.executeUpdate();
827                                 // Now add the Spring Admin Role to the admin accounts
828                                 pstmt.setString(3, springAdminRoleCSID);        // set role_id param
829                                 pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param
830                                 if (logger.isDebugEnabled()) {
831                                         logger.debug("createDefaultAccounts binding account: "
832                                                         +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
833                                 }
834                                 pstmt.executeUpdate();
835                         }
836                         String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));
837                         if(!usersInRepo.contains(readerUserId)) {
838                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);
839                                 String readerRoleId = tenantReaderRoleCSIDs.get(tId);
840                                 pstmt.setString(1, readerAcct);         // set acct CSID param
841                                 pstmt.setString(2, readerUserId);       // set user_id param
842                                 pstmt.setString(3, readerRoleId);       // set role_id param
843                                 pstmt.setString(4, getDefaultReaderRole(tId));  // set rolename param
844                                 if (logger.isDebugEnabled()) {
845                                         logger.debug("createDefaultAccounts binding account: "
846                                                         +readerUserId+" to Reader role("+readerRoleId
847                                                         +") for tenant id: "+tId);
848                                 }
849                                 pstmt.executeUpdate();
850                         }
851                 }
852                 pstmt.close();
853         } catch(Exception e) {
854                 throw e;
855         } finally {
856                 if(pstmt!=null)
857                         pstmt.close();
858         }
859     }
860     
861     private static void bindTenantManagerAccountRole(Connection conn,  DatabaseProductType databaseProductType,
862                 String tenantManagerUserID, String tenantManagerAccountID, String tenantManagerRoleID, String tenantManagerRoleName ) 
863                         throws SQLException, Exception {
864         PreparedStatement pstmt = null;
865         try {
866                 String insertAccountRoleSQL;
867                 if (databaseProductType == DatabaseProductType.MYSQL) {
868                         insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;
869                 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
870                         insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;
871                 } else {
872                         throw new Exception("Unrecognized database system.");
873                 }
874                 if (logger.isDebugEnabled()) {
875                         logger.debug("bindTenantManagerAccountRole binding account to role with SQL:\n"
876                                         +insertAccountRoleSQL);
877                 }
878                 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement
879                 pstmt.setString(1, tenantManagerAccountID);             // set acct CSID param
880                 pstmt.setString(2, tenantManagerUserID);        // set user_id param
881                 pstmt.setString(3, tenantManagerRoleID);        // set role_id param
882                 pstmt.setString(4, tenantManagerRoleName);      // set rolename param
883                 if (logger.isDebugEnabled()) {
884                         logger.debug("bindTenantManagerAccountRole binding user: "
885                                         +tenantManagerUserID+" to Admin role("+tenantManagerRoleName+")");
886                 }
887                 pstmt.executeUpdate();
888                 /* At this point, tenant manager should not need the Spring Admin Role
889                 pstmt.setString(3, springAdminRoleCSID);        // set role_id param
890                 pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param
891                 if (logger.isDebugEnabled()) {
892                         logger.debug("createDefaultAccounts binding account: "
893                                         +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
894                 }
895                 pstmt.executeUpdate();
896                 */
897                 pstmt.close();
898         } catch(Exception e) {
899                 throw e;
900         } finally {
901                 if(pstmt!=null)
902                         pstmt.close();
903         }
904     }
905     
906     public static void createDefaultAccounts(
907                 TenantBindingConfigReaderImpl tenantBindingConfigReader,
908                 DatabaseProductType databaseProductType,
909                 String cspaceDatabaseName) throws Exception {
910
911         logger.debug("ServiceMain.createDefaultAccounts starting...");
912         
913         Hashtable<String, String> tenantInfo = getTenantNamesFromConfig(tenantBindingConfigReader);
914         Connection conn = null;
915         // TODO - need to put in tests for existence first.
916         // We could just look for the accounts per tenant up front, and assume that
917         // the rest is there if the accounts are.
918         // Could add a sql script to remove these if need be - Spring only does roles, 
919         // and we're not touching that, so we could safely toss the 
920         // accounts, users, account-tenants, account-roles, and start over.
921         try {
922                 conn = getConnection(cspaceDatabaseName);
923                 ArrayList<String> existingTenants = compileExistingTenants(conn, tenantInfo);
924                 
925                 // Note that this only creates tenants not marked as "createDisabled"
926                 createMissingTenants(conn, tenantInfo, existingTenants);
927                 
928                 ArrayList<String> usersInRepo = findOrCreateDefaultUsers(conn, tenantInfo);
929                 
930                 Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();
931                 Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();
932                 findOrCreateDefaultAccounts(conn, tenantInfo, usersInRepo,
933                                 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
934
935                 bindDefaultAccountsToTenants(conn, databaseProductType, tenantInfo, usersInRepo,
936                                 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
937                 
938                 Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();
939                 Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();
940                 String springAdminRoleCSID = findOrCreateDefaultRoles(conn, tenantInfo,
941                                 tenantAdminRoleCSIDs, tenantReaderRoleCSIDs);
942                 
943                 bindAccountsToRoles(conn,  databaseProductType,
944                                 tenantInfo, usersInRepo, springAdminRoleCSID,
945                                 tenantAdminRoleCSIDs, tenantReaderRoleCSIDs,
946                                 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
947                 
948                 boolean createdTenantMgrAccount = findOrCreateTenantManagerUserAndAccount(conn);
949                 if(createdTenantMgrAccount) {
950                         // If we created the account, we need to create the bindings. Otherwise, assume they
951                         // are all set (from previous initialization).
952                         String tenantManagerRoleCSID = findTenantManagerRole(conn);
953                         bindTenantManagerAccountRole(conn, databaseProductType, 
954                                         TENANT_MANAGER_USER, AuthN.TENANT_MANAGER_ACCT_ID, 
955                                         tenantManagerRoleCSID, ROLE_ALL_TENANTS_MANAGER);
956                 }
957         } catch (Exception e) {
958                         logger.debug("Exception in createDefaultAccounts: " + e.getLocalizedMessage());
959                 throw e;
960                 } finally {
961                         try {
962                                 if (conn != null)
963                                         conn.close();
964                         } catch (SQLException sqle) {
965                                 if (logger.isDebugEnabled()) {
966                                         logger.debug("SQL Exception closing statement/connection: " + sqle.getLocalizedMessage());
967                                 }
968                         }
969                 }       
970     }
971     
972     private static String getDefaultAdminRole(String tenantId) {
973         return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;
974     }
975     
976     private static String getDefaultReaderRole(String tenantId) {
977         return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX;
978     }
979     
980     private static String getDefaultAdminUserID(String tenantName) {
981         return TENANT_ADMIN_ACCT_PREFIX+tenantName;
982     }
983     
984     private static String getDefaultReaderUserID(String tenantName) {
985         return TENANT_READER_ACCT_PREFIX+tenantName;
986     }
987     
988         static public PermissionAction createPermissionAction(Permission perm,
989                         ActionType actionType) {
990         PermissionAction pa = new PermissionAction();
991
992             CSpaceAction action = URIResourceImpl.getAction(actionType);
993             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
994                     perm.getResourceName(), action);
995             pa.setName(actionType);
996             pa.setObjectIdentity(uriRes.getHashedId().toString());
997             pa.setObjectIdentityResource(uriRes.getId());
998             
999             return pa;
1000         }
1001
1002         static public PermissionAction update(Permission perm, PermissionAction permAction) {
1003         PermissionAction pa = new PermissionAction();
1004
1005             CSpaceAction action = URIResourceImpl.getAction(permAction.getName());
1006             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
1007                     perm.getResourceName(), action);
1008             pa.setObjectIdentity(uriRes.getHashedId().toString());
1009             pa.setObjectIdentityResource(uriRes.getId());
1010             
1011             return pa;
1012         }
1013         
1014         private static HashSet<String> getTransitionVerbList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
1015                 HashSet<String> result = new HashSet<String>();
1016                 
1017                 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
1018         for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) {
1019                 String transitionVerb = transitionDef.getName();
1020                 String[] tokens = transitionVerb.split("_");  // Split the verb into words.  The workflow verbs are compound words combined with the '_' character.
1021                 result.add(tokens[0]); // We only care about the first word.
1022         }
1023
1024         return result;
1025         }
1026         
1027         private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
1028                 TransitionDefList result = null;
1029                 try {
1030                         String serviceObjectName = serviceBinding.getObject().getName();
1031                 DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(
1032                                 tenantBinding, serviceBinding);
1033                 Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName);
1034                 if (lifecycle != null) {
1035                         result = lifecycle.getTransitionDefList();
1036                 }
1037                 } catch (Exception e) {
1038                         // Ignore this exception and return an empty non-null TransitionDefList
1039                 }
1040                 
1041                 if (result == null) {
1042                         if (serviceBinding.getType().equalsIgnoreCase(ServiceBindingUtils.SERVICE_TYPE_SECURITY) == false) {
1043                                 logger.debug("Could not retrieve a lifecycle transition definition list from: "
1044                                                 + serviceBinding.getName()
1045                                                 + " with tenant ID = "
1046                                                 + tenantBinding.getId());
1047                         }
1048                         // return an empty list                 
1049                         result = new TransitionDefList();
1050                 } else {
1051                         logger.debug("Successfully retrieved a lifecycle transition definition list from: "
1052                                         + serviceBinding.getName()
1053                                         + " with tenant ID = "
1054                                         + tenantBinding.getId());
1055                 }
1056                 
1057                 return result;
1058         }
1059         
1060     public static void createDefaultWorkflowPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions
1061     {
1062         AuthZ.get().login(); //login to Spring Security manager
1063         
1064         EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);
1065         EntityManager em = null;
1066
1067         try {
1068             em = emf.createEntityManager();
1069
1070                 Hashtable<String, TenantBindingType> tenantBindings =
1071                         tenantBindingConfigReader.getTenantBindings();
1072                 for (String tenantId : tenantBindings.keySet()) {
1073                         logger.info(String.format("Creating/verifying workflow permissions for tenant ID=%s.", tenantId));
1074                         TenantBindingType tenantBinding = tenantBindings.get(tenantId);
1075                         Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR);
1076                         Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER);
1077                         
1078                         if (adminRole == null || readonlyRole == null) {
1079                                 String msg = String.format("One or more of the required default CollectionSpace administrator roles is missing or was never created.  If you're setting up a new instance of CollectionSpace, shutdown the Tomcat server and run the 'ant import' command from the root/top level CollectionSpace 'Services' source directory.  Then try restarting Tomcat.");
1080                                 logger.error(msg);
1081                                 throw new RuntimeException("One or more of the required default CollectionSpace administrator roles is missing or was never created.");
1082                         }
1083                         
1084                         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
1085                                 String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP);
1086                                 if (prop == null ? true : Boolean.parseBoolean(prop)) {
1087                                                 try {
1088                                                 em.getTransaction().begin();
1089                                                 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
1090                                                 HashSet<String> transitionVerbList = getTransitionVerbList(tenantBinding, serviceBinding);
1091                                                 for (String transitionVerb : transitionVerbList) {
1092                                                         //
1093                                                         // Create the permission for the admin role
1094                                                         Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_CRUDL);
1095                                                         persist(em, adminPerm, adminRole, true, ACTIONGROUP_CRUDL);
1096                                                         //
1097                                                         // Create the permission for the read-only role
1098                                                         Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_RL);                                                      
1099                                                         persist(em, readonlyPerm, readonlyRole, true, ACTIONGROUP_RL); // Persist/store the permission and permrole records and related Spring Security info
1100                                                 }
1101                                                 em.getTransaction().commit();
1102                                         } catch (IllegalStateException e) {
1103                                                 logger.debug(e.getLocalizedMessage(), e); //We end up here if there is no document handler for the service -this is ok for some of the services.
1104                                         }
1105                                 } else {
1106                                         logger.warn("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "
1107                                                         + serviceBinding.getName());
1108                                 }
1109                         }
1110                 }
1111             em.close();
1112         } catch (Exception e) {
1113             if (em != null && em.getTransaction().isActive()) {
1114                 em.getTransaction().rollback();
1115             }
1116             if (logger.isDebugEnabled()) {
1117                 logger.debug("Caught exception and rolling back permission creation: ", e);
1118             }
1119             throw e;
1120         } finally {
1121             if (em != null) {
1122                 JpaStorageUtils.releaseEntityManagerFactory(emf);
1123             }
1124         }
1125     }
1126     
1127     private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) {
1128         PermissionRoleRel result = null;
1129         
1130         try {
1131                 String whereClause = "where permissionId = :id and roleId = :roleId";
1132                 HashMap<String, Object> params = new HashMap<String, Object>();
1133                 params.put("id", permissionId);
1134                 params.put("roleId", RoleId);        
1135         
1136                 result = (PermissionRoleRel) JpaStorageUtils.getEntity(em,
1137                                 PermissionRoleRel.class.getCanonicalName(), whereClause, params);
1138         } catch (Exception e) {
1139                 //Do nothing. Will return null;
1140         }
1141                 
1142         return result;
1143     }
1144     
1145     /*
1146      * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction
1147      */
1148     private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy, ActionGroup actionGroup) throws Exception {
1149                 AuthorizationStore authzStore = new AuthorizationStore();
1150                 // First persist the Permission record
1151                 authzStore.store(em, permission);
1152                 
1153                 // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload)
1154                 // Create a PermissionRoleRel (the database relation table for the permission and role)
1155                 PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid());
1156                 if (permRoleRel == null) {
1157                         PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);
1158                 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
1159                 PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);
1160                 for (PermissionRoleRel prr : permRoleRels) {
1161                     authzStore.store(em, prr);
1162                 }
1163                         Profiler profiler = new Profiler(AuthorizationCommon.class, 2);
1164                         profiler.start();
1165                         // Add a corresponding entry in the Spring Security Tables
1166                         addPermissionsForUri(permission, permRole);
1167                         profiler.stop();
1168                         logger.debug("Finished full perm generation for "
1169                                         + ":" + permission.getTenantId()
1170                                         + ":" + permission.getResourceName()
1171                                         + ":" + actionGroup.getName()
1172                                         + ":" + profiler.getCumulativeTime());
1173                 }
1174         
1175     }
1176
1177 }