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