]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
49975136b546f83cb11c094b2e22c041c52f1551
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.common.authorization_mgt;\r
2 \r
3 import java.sql.Connection;\r
4 import java.sql.PreparedStatement;\r
5 import java.sql.ResultSet;\r
6 import java.sql.SQLException;\r
7 import java.sql.Statement;\r
8 import java.util.ArrayList;\r
9 import java.util.Date;\r
10 import java.util.HashMap;\r
11 import java.util.Hashtable;\r
12 import java.util.List;\r
13 import java.util.UUID;\r
14 \r
15 import javax.naming.NamingException;\r
16 import javax.persistence.EntityManager;\r
17 import javax.persistence.EntityManagerFactory;\r
18 \r
19 import org.collectionspace.services.authorization.AuthZ;\r
20 import org.collectionspace.services.authorization.CSpaceAction;\r
21 import org.collectionspace.services.authorization.PermissionException;\r
22 import org.collectionspace.services.authorization.PermissionRole;\r
23 import org.collectionspace.services.authorization.PermissionRoleRel;\r
24 import org.collectionspace.services.authorization.PermissionValue;\r
25 import org.collectionspace.services.authorization.Role;\r
26 import org.collectionspace.services.authorization.RoleValue;\r
27 import org.collectionspace.services.authorization.SubjectType;\r
28 import org.collectionspace.services.authorization.URIResourceImpl;\r
29 import org.collectionspace.services.authorization.perms.ActionType;\r
30 import org.collectionspace.services.authorization.perms.EffectType;\r
31 import org.collectionspace.services.authorization.perms.Permission;\r
32 import org.collectionspace.services.authorization.perms.PermissionAction;\r
33 \r
34 import org.collectionspace.services.client.Profiler;\r
35 import org.collectionspace.services.client.RoleClient;\r
36 import org.collectionspace.services.client.workflow.WorkflowClient;\r
37 import org.collectionspace.services.common.config.ServiceConfigUtils;\r
38 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;\r
39 import org.collectionspace.services.common.context.ServiceBindingUtils;\r
40 import org.collectionspace.services.common.document.DocumentHandler;\r
41 import org.collectionspace.services.common.security.SecurityUtils;\r
42 import org.collectionspace.services.common.storage.DatabaseProductType;\r
43 import org.collectionspace.services.common.storage.JDBCTools;\r
44 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;\r
45 import org.collectionspace.services.config.service.ServiceBindingType;\r
46 import org.collectionspace.services.config.tenant.TenantBindingType;\r
47 \r
48 import org.collectionspace.services.lifecycle.Lifecycle;\r
49 import org.collectionspace.services.lifecycle.TransitionDef;\r
50 import org.collectionspace.services.lifecycle.TransitionDefList;\r
51 \r
52 //import org.mortbay.log.Log;\r
53 import org.slf4j.Logger;\r
54 import org.slf4j.LoggerFactory;\r
55 \r
56 import org.springframework.security.acls.model.AlreadyExistsException;\r
57 \r
58 \r
59 public class AuthorizationCommon {\r
60         \r
61         final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup";\r
62     //\r
63     // ActionGroup labels/constants\r
64     //\r
65         \r
66         // for READ-WRITE\r
67     final public static String ACTIONGROUP_CRUDL_NAME = "CRUDL";\r
68     final public static ActionType[] ACTIONSET_CRUDL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.DELETE, ActionType.SEARCH};\r
69     // for READ-ONLY\r
70     final public static String ACTIONGROUP_RL_NAME = "RL";\r
71     final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};\r
72     \r
73         /*\r
74          * Inner class to deal with predefined ADMIN and READER action groupds\r
75          */\r
76         public class ActionGroup {\r
77                 String name;\r
78                 ActionType[] actions;\r
79         }\r
80         \r
81         static ActionGroup ACTIONGROUP_CRUDL;\r
82         static ActionGroup ACTIONGROUP_RL;\r
83         \r
84         // A static block to initialize the predefined action groups\r
85         static {\r
86                 AuthorizationCommon ac = new AuthorizationCommon();\r
87                 // For admin\r
88                 ACTIONGROUP_CRUDL = ac.new ActionGroup();\r
89                 ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME;\r
90                 ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL;\r
91                 // For reader\r
92                 ACTIONGROUP_RL = ac.new ActionGroup();\r
93                 ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;\r
94                 ACTIONGROUP_RL.actions = ACTIONSET_RL;\r
95 \r
96         }\r
97         \r
98     final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class);\r
99 \r
100     //\r
101     // The "super" role has a predefined ID of "0" and a tenant ID of "0";\r
102     //\r
103     final public static String ROLE_ADMINISTRATOR = "ADMINISTRATOR";\r
104     final public static String ROLE_ADMINISTRATOR_ID = "0";\r
105     final public static String ADMINISTRATOR_TENANT_ID = "0";\r
106 \r
107     final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";\r
108     final public static String ROLE_TENANT_READER = "TENANT_READER";\r
109         \r
110     public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@"; \r
111     public static final String TENANT_READER_ACCT_PREFIX = "reader@"; \r
112     public static final String ROLE_PREFIX = "ROLE_"; \r
113     public static final String SPRING_ADMIN_ROLE = "ROLE_SPRING_ADMIN"; \r
114     public static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR"; \r
115     public static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER"; \r
116     public static final String DEFAULT_ADMIN_PASSWORD = "Administrator";\r
117     public static final String DEFAULT_READER_PASSWORD = "reader";\r
118 \r
119     public static String ROLE_SPRING_ADMIN_ID = "-1";\r
120     public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";\r
121 \r
122     public static Role getRole(String tenantId, String displayName) {\r
123         Role role = null;\r
124         \r
125         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);\r
126         role = AuthorizationStore.getRoleByName(roleName, tenantId);\r
127         \r
128         return role;\r
129     }\r
130     \r
131     public static Role getRole(EntityManager em, String tenantId, String displayName) {\r
132         Role role = null;\r
133         \r
134         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);\r
135         role = AuthorizationStore.getRoleByName(em, roleName, tenantId);\r
136         \r
137         return role;\r
138     }\r
139     \r
140     \r
141     public static Role createRole(String tenantId, String name, String description) {\r
142         return createRole(tenantId, name, description, false /* mutable by default */);\r
143     }\r
144     \r
145     public static Role createRole(String tenantId, String name, String description, boolean immutable) {\r
146         Role role = new Role();\r
147         \r
148         role.setCreatedAtItem(new Date());\r
149         role.setDisplayName(name);\r
150         String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, name);     \r
151         role.setRoleName(roleName);\r
152         String id = UUID.randomUUID().toString(); //FIXME: The qualified role name should be unique enough to use as an ID/key\r
153         role.setCsid(id);\r
154                 role.setDescription(description);\r
155         role.setTenantId(tenantId);\r
156         if (immutable == true) {\r
157                 role.setMetadataProtection(RoleClient.IMMUTABLE);\r
158                 role.setPermsProtection(RoleClient.IMMUTABLE);\r
159         }\r
160         \r
161         return role;\r
162     }\r
163     \r
164     /**\r
165      * Add permission to the Spring Security tables\r
166      * with assumption that resource is of type URI\r
167      * @param permission configuration\r
168      */\r
169     public static void addPermissionsForUri(Permission perm,\r
170             PermissionRole permRole) throws PermissionException {\r
171         //\r
172         // First check the integrity of the incoming arguments.\r
173         //\r
174         if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) {\r
175             throw new IllegalArgumentException("permission ids do not"\r
176                     + " match for role=" + permRole.getRole().get(0).getRoleName()\r
177                     + " with permissionId=" + permRole.getPermission().get(0).getPermissionId()\r
178                     + " for permission with csid=" + perm.getCsid());\r
179         }\r
180         \r
181         List<String> principals = new ArrayList<String>();        \r
182         for (RoleValue roleValue : permRole.getRole()) {\r
183             principals.add(roleValue.getRoleName());\r
184         }\r
185         List<PermissionAction> permActions = perm.getAction();\r
186         for (PermissionAction permAction : permActions) {\r
187                 try {\r
188                     CSpaceAction action = URIResourceImpl.getAction(permAction.getName()); \r
189                     URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),\r
190                             perm.getResourceName(), action);\r
191                     boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false;\r
192                     AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant);//CSPACE-4967\r
193                 } catch (PermissionException e) {\r
194                         //\r
195                         // Only throw the exception if it is *not* an already-exists exception\r
196                         //\r
197                         if (e.getCause() instanceof AlreadyExistsException == false) {\r
198                                 throw e;\r
199                         }\r
200                 }\r
201         }\r
202     }\r
203     \r
204     private static Connection getConnection() throws NamingException, SQLException {\r
205         return JDBCTools.getConnection(JDBCTools.CSPACE_REPOSITORY_NAME);\r
206     }\r
207     \r
208     /*\r
209      * Spring security seems to require that all of our role names start\r
210      * with the ROLE_PREFIX string.\r
211      */\r
212     public static String getQualifiedRoleName(String tenantId, String name) {\r
213         String result = name;\r
214         \r
215         String qualifiedName = ROLE_PREFIX + tenantId.toUpperCase() + "_" + name.toUpperCase();         \r
216         if (name.equals(qualifiedName) == false) {\r
217                 result = qualifiedName;\r
218         }\r
219         \r
220         return result;\r
221     }\r
222         \r
223     private static ActionGroup getActionGroup(String actionGroupStr) {\r
224         ActionGroup result = null;\r
225         \r
226         if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_CRUDL_NAME)) {\r
227                 result = ACTIONGROUP_CRUDL;\r
228         } else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_RL_NAME)) {\r
229                 result = ACTIONGROUP_RL;\r
230         }\r
231         \r
232         return result;\r
233     }\r
234     \r
235     public static Permission createPermission(String tenantId,\r
236                 String resourceName,\r
237                 String description,\r
238                 String actionGroupStr) {\r
239         Permission result = null;\r
240         \r
241         ActionGroup actionGroup = getActionGroup(actionGroupStr);\r
242         result = createPermission(tenantId, resourceName, description, actionGroup);\r
243         \r
244         return result;\r
245     }\r
246     \r
247     private static Permission createPermission(String tenantId,\r
248                 String resourceName,\r
249                 String description,\r
250                 ActionGroup actionGroup) {\r
251         String id = tenantId\r
252                         + "-" + resourceName.replace('/', '_') // Remove the slashes so the ID can be used in a URI/URL\r
253                         + "-" + actionGroup.name;\r
254         Permission perm = new Permission();\r
255         perm.setCsid(id);\r
256         perm.setDescription(description);\r
257         perm.setCreatedAtItem(new Date());\r
258         perm.setResourceName(resourceName.toLowerCase().trim());\r
259         perm.setEffect(EffectType.PERMIT);\r
260         perm.setTenantId(tenantId);\r
261         \r
262         perm.setActionGroup(actionGroup.name);\r
263         ArrayList<PermissionAction> pas = new ArrayList<PermissionAction>();\r
264         perm.setAction(pas);\r
265         for (ActionType actionType : actionGroup.actions) {\r
266                 PermissionAction permAction = createPermissionAction(perm, actionType);\r
267                 pas.add(permAction);\r
268         }\r
269         \r
270         return perm;\r
271     }\r
272     \r
273     private static Permission createWorkflowPermission(TenantBindingType tenantBinding,\r
274                 ServiceBindingType serviceBinding,\r
275                 TransitionDef transitionDef,\r
276                 ActionGroup actionGroup)\r
277     {\r
278         Permission result = null;\r
279         String workFlowServiceSuffix;\r
280         String transitionName;\r
281         if (transitionDef != null) {\r
282                 transitionName = transitionDef.getName();\r
283                 workFlowServiceSuffix = WorkflowClient.SERVICE_AUTHZ_SUFFIX;\r
284         } else {\r
285                 transitionName = ""; //since the transitionDef was null, we're assuming that this is the base workflow permission to be created                 \r
286                 workFlowServiceSuffix = WorkflowClient.SERVICE_PATH;\r
287         }\r
288         \r
289         String tenantId = tenantBinding.getId();\r
290         String resourceName = "/"\r
291                         + serviceBinding.getName().toLowerCase().trim()\r
292                         + workFlowServiceSuffix\r
293                         + transitionName;\r
294         String description = "A generated workflow permission for actiongroup " + actionGroup.name;\r
295         result = createPermission(tenantId, resourceName, description, actionGroup);\r
296         \r
297         if (logger.isDebugEnabled() == true) {\r
298                 logger.debug("Generated a workflow permission: "\r
299                                 + result.getResourceName()\r
300                                 + ":" + transitionName\r
301                                 + ":" + "tenant id=" + result.getTenantId()\r
302                                 + ":" + actionGroup.name);\r
303         }\r
304         \r
305         return result;\r
306     }\r
307     \r
308     private static PermissionRole createPermissionRole(EntityManager em,\r
309                 Permission permission,\r
310                 Role role,\r
311                 boolean enforceTenancy) throws Exception\r
312     {\r
313         PermissionRole permRole = new PermissionRole();\r
314         // Check to see if the tenant ID of the permission and the tenant ID of the role match\r
315         boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId());\r
316         if (tenantIdsMatch == false && enforceTenancy == false) {\r
317                 tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched.\r
318         }\r
319                         \r
320                 if (tenantIdsMatch == true) {\r
321                 permRole.setSubject(SubjectType.ROLE);\r
322                 //\r
323                 // Set of the permission value list of the permrole\r
324                 //\r
325                 List<PermissionValue> permValues = new ArrayList<PermissionValue>();\r
326                 PermissionValue permValue = new PermissionValue();\r
327                 permValue.setPermissionId(permission.getCsid());\r
328                 permValue.setResourceName(permission.getResourceName().toLowerCase());\r
329                 permValue.setActionGroup(permission.getActionGroup());\r
330                 permValues.add(permValue);\r
331                 permRole.setPermission(permValues);\r
332                 //\r
333                 // Set of the role value list of the permrole\r
334                 //\r
335                 List<RoleValue> roleValues = new ArrayList<RoleValue>();\r
336                 RoleValue rv = new RoleValue();\r
337             // This needs to use the qualified name, not the display name\r
338             rv.setRoleName(role.getRoleName());\r
339             rv.setRoleId(role.getCsid());\r
340             roleValues.add(rv);\r
341             permRole.setRole(roleValues);\r
342                 } else {\r
343                 String errMsg = "The tenant ID of the role: " + role.getTenantId()\r
344                                 + " did not match the tenant ID of the permission: " + permission.getTenantId();\r
345                 throw new Exception(errMsg);\r
346                 }\r
347         \r
348         return permRole;\r
349     }\r
350     \r
351     \r
352     /*\r
353      * FIXME: REM - This method is way too big -over 300 lines!  We need to break it up into\r
354      * smaller, discrete, sub-methods.\r
355      */\r
356     public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) {\r
357         if (logger.isDebugEnabled()) {\r
358                 logger.debug("ServiceMain.createDefaultAccounts starting...");\r
359         }\r
360         \r
361         Hashtable<String, TenantBindingType> tenantBindings =\r
362                 tenantBindingConfigReader.getTenantBindings();\r
363         Hashtable<String, String> tenantInfo = new Hashtable<String, String>();\r
364         for (TenantBindingType tenantBinding : tenantBindings.values()) {\r
365                 String tId = tenantBinding.getId();\r
366                 String tName = tenantBinding.getName();\r
367                 tenantInfo.put(tId, tName);\r
368                 if (logger.isDebugEnabled()) {\r
369                         logger.debug("createDefaultAccounts found configured tenant id: "+tId+" name: "+tName);\r
370                 }\r
371         }\r
372         Connection conn = null;\r
373         PreparedStatement pstmt = null;\r
374         Statement stmt = null;\r
375         // TODO - need to put in tests for existence first.\r
376         // We could just look for the accounts per tenant up front, and assume that\r
377         // the rest is there if the accounts are.\r
378         // Could add a sql script to remove these if need be - Spring only does roles, \r
379         // and we're not touching that, so we could safely toss the \r
380         // accounts, users, account-tenants, account-roles, and start over.\r
381         try {\r
382                 conn = getConnection();\r
383                 // First find or create the tenants\r
384                 String queryTenantSQL = \r
385                         "SELECT id,name FROM tenants";\r
386                 stmt = conn.createStatement();\r
387                         ResultSet rs = stmt.executeQuery(queryTenantSQL);\r
388                 ArrayList<String> existingTenants = new ArrayList<String>();\r
389                         while (rs.next()) {\r
390                                 String tId = rs.getString("id");\r
391                                 String tName = rs.getString("name");\r
392                                 if(tenantInfo.containsKey(tId)) {\r
393                                         existingTenants.add(tId);\r
394                                         if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {\r
395                                                 logger.warn("Configured name for tenant: "\r
396                                                                 +tId+" in repository: "+tName\r
397                                                                 +" does not match config'd name: "+ tenantInfo.get(tId));\r
398                                         }\r
399                                 }\r
400                         }\r
401                         rs.close();\r
402 \r
403                 String insertTenantSQL = \r
404                         "INSERT INTO tenants (id,name,created_at) VALUES (?,?, now())";\r
405                 pstmt = conn.prepareStatement(insertTenantSQL); // create a statement\r
406                 for(String tId : tenantInfo.keySet()) {\r
407                         if(existingTenants.contains(tId)) {\r
408                         if (logger.isDebugEnabled()) {\r
409                                 logger.debug("createDefaultAccounts: tenant exists (skipping): "\r
410                                                 +tenantInfo.get(tId));\r
411                         }\r
412                                 continue;\r
413                         }\r
414                         pstmt.setString(1, tId);                                        // set id param\r
415                         pstmt.setString(2, tenantInfo.get(tId));        // set name param\r
416                 if (logger.isDebugEnabled()) {\r
417                         logger.debug("createDefaultAccounts adding entry for tenant: "+tId);\r
418                 }\r
419                         pstmt.executeUpdate();\r
420                 }\r
421                 pstmt.close();\r
422                 // Second find or create the users\r
423                 String queryUserSQL = \r
424                         "SELECT username FROM users WHERE username LIKE '"\r
425                                 +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"\r
426                                 +TENANT_READER_ACCT_PREFIX+"%'";\r
427                         rs = stmt.executeQuery(queryUserSQL);\r
428                 ArrayList<String> usersInRepo = new ArrayList<String>();\r
429                         while (rs.next()) {\r
430                                 String uName = rs.getString("username");\r
431                                 usersInRepo.add(uName);\r
432                         }\r
433                         rs.close();\r
434                 String insertUserSQL = \r
435                         "INSERT INTO users (username,passwd, created_at)"\r
436                         +" VALUES (?,?, now())";\r
437                 pstmt = conn.prepareStatement(insertUserSQL); // create a statement\r
438                 for(String tName : tenantInfo.values()) {\r
439                         String adminAcctName = getDefaultAdminUserID(tName);\r
440                         if(!usersInRepo.contains(adminAcctName)) {\r
441                                 String secEncPasswd = SecurityUtils.createPasswordHash(\r
442                                                 adminAcctName, DEFAULT_ADMIN_PASSWORD);\r
443                                 pstmt.setString(1, adminAcctName);      // set username param\r
444                                 pstmt.setString(2, secEncPasswd);       // set passwd param\r
445                         if (logger.isDebugEnabled()) {\r
446                                 logger.debug("createDefaultAccounts adding user: "\r
447                                                 +adminAcctName+" for tenant: "+tName);\r
448                         }\r
449                                 pstmt.executeUpdate();\r
450                         } else if (logger.isDebugEnabled()) {\r
451                         logger.debug("createDefaultAccounts: user: "+adminAcctName\r
452                                                         +" already exists - skipping.");\r
453                 }\r
454 \r
455 \r
456                         String readerAcctName =  getDefaultReaderUserID(tName);\r
457                         if(!usersInRepo.contains(readerAcctName)) {\r
458                                 String secEncPasswd = SecurityUtils.createPasswordHash(\r
459                                                 readerAcctName, DEFAULT_READER_PASSWORD);\r
460                                 pstmt.setString(1, readerAcctName);     // set username param\r
461                                 pstmt.setString(2, secEncPasswd);       // set passwd param\r
462                         if (logger.isDebugEnabled()) {\r
463                                 logger.debug("createDefaultAccounts adding user: "\r
464                                                 +readerAcctName+" for tenant: "+tName);\r
465                         }\r
466                                 pstmt.executeUpdate();\r
467                         } else if (logger.isDebugEnabled()) {\r
468                         logger.debug("createDefaultAccounts: user: "+readerAcctName\r
469                                                         +" already exists - skipping.");\r
470                         }\r
471                 }\r
472                 pstmt.close();\r
473                 // Third, create the accounts. Assume that if the users were already there,\r
474                 // then the accounts were as well\r
475             String insertAccountSQL = \r
476                 "INSERT INTO accounts_common "\r
477                 + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "\r
478                 + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";\r
479             Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();\r
480             Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();\r
481                 pstmt = conn.prepareStatement(insertAccountSQL); // create a statement\r
482                 for(String tId : tenantInfo.keySet()) {\r
483                         String tName = tenantInfo.get(tId);\r
484                 String adminCSID = UUID.randomUUID().toString();\r
485                 tenantAdminAcctCSIDs.put(tId, adminCSID);\r
486                         String adminAcctName =  getDefaultAdminUserID(tName);\r
487                         if(!usersInRepo.contains(adminAcctName)) {\r
488                                 pstmt.setString(1, adminCSID);                  // set csid param\r
489                                 pstmt.setString(2, adminAcctName);      // set email param (bogus)\r
490                                 pstmt.setString(3, adminAcctName);      // set userid param\r
491                                 pstmt.setString(4, "Administrator");// set screen name param\r
492                         if (logger.isDebugEnabled()) {\r
493                                 logger.debug("createDefaultAccounts adding account: "\r
494                                                 +adminAcctName+" for tenant: "+tName);\r
495                         }\r
496                                 pstmt.executeUpdate();\r
497                         } else if (logger.isDebugEnabled()) {\r
498                         logger.debug("createDefaultAccounts: user: "+adminAcctName\r
499                                                         +" already exists - skipping account generation.");\r
500                         }\r
501 \r
502                         String readerCSID = UUID.randomUUID().toString();       \r
503                 tenantReaderAcctCSIDs.put(tId, readerCSID);\r
504                         String readerAcctName =  getDefaultReaderUserID(tName);\r
505                         if(!usersInRepo.contains(readerAcctName)) {\r
506                                 pstmt.setString(1, readerCSID);         // set csid param\r
507                                 pstmt.setString(2, readerAcctName);     // set email param (bogus)\r
508                                 pstmt.setString(3, readerAcctName);     // set userid param\r
509                                 pstmt.setString(4, "Reader");           // set screen name param\r
510                                 if (logger.isDebugEnabled()) {\r
511                                         logger.debug("createDefaultAccounts adding account: "\r
512                                                         +readerAcctName+" for tenant: "+tName);\r
513                                 }\r
514                                 pstmt.executeUpdate();\r
515                         } else if (logger.isDebugEnabled()) {\r
516                         logger.debug("createDefaultAccounts: user: "+readerAcctName\r
517                                                         +" already exists - skipping account creation.");\r
518                         }\r
519                 }\r
520                 pstmt.close();\r
521                 // Fourth, bind accounts to tenants. Assume that if the users were already there,\r
522                 // then the accounts were bound to tenants correctly\r
523                 String insertAccountTenantSQL;\r
524                 DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType();\r
525                 if (databaseProductType == DatabaseProductType.MYSQL) {\r
526                         insertAccountTenantSQL =\r
527                                 "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
528                                 + " VALUES(?, ?)";\r
529                 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
530                         insertAccountTenantSQL =\r
531                                 "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
532                                 + " VALUES(nextval('hibernate_sequence'), ?, ?)";\r
533                 } else {\r
534                         throw new Exception("Unrecognized database system.");\r
535                 }\r
536                 pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement\r
537                 for(String tId : tenantInfo.keySet()) {\r
538                         String tName = tenantInfo.get(tId);\r
539                         if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {\r
540                                 String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
541                                 pstmt.setString(1, adminAcct);          // set acct CSID param\r
542                                 pstmt.setString(2, tId);                        // set tenant_id param\r
543                         if (logger.isDebugEnabled()) {\r
544                                 logger.debug("createDefaultAccounts binding account id: "\r
545                                                 +adminAcct+" to tenant id: "+tId);\r
546                         }\r
547                                 pstmt.executeUpdate();\r
548                         }\r
549                         if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {\r
550                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
551                                 pstmt.setString(1, readerAcct);         // set acct CSID param\r
552                                 pstmt.setString(2, tId);                        // set tenant_id param\r
553                         if (logger.isDebugEnabled()) {\r
554                                 logger.debug("createDefaultAccounts binding account id: "\r
555                                                 +readerAcct+" to tenant id: "+tId);\r
556                         }\r
557                                 pstmt.executeUpdate();\r
558                         }\r
559                 }\r
560                 pstmt.close();\r
561                 // Fifth, fetch and save the default roles\r
562                         String springAdminRoleCSID = null;\r
563                 String querySpringRole = \r
564                         "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'";\r
565                         rs = stmt.executeQuery(querySpringRole);\r
566                 if(rs.next()) {\r
567                         springAdminRoleCSID = rs.getString(1);\r
568                 if (logger.isDebugEnabled()) {\r
569                         logger.debug("createDefaultAccounts found Spring Admin role: "\r
570                                         +springAdminRoleCSID);\r
571                 }\r
572                 } else {\r
573                 String insertSpringAdminRoleSQL =\r
574                         "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "\r
575                         + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";\r
576                         stmt.executeUpdate(insertSpringAdminRoleSQL);\r
577                         springAdminRoleCSID = "-1";\r
578                 if (logger.isDebugEnabled()) {\r
579                         logger.debug("createDefaultAccounts CREATED Spring Admin role: "\r
580                                         +springAdminRoleCSID);\r
581                 }\r
582                 }\r
583                 rs.close();\r
584                 String getRoleCSIDSql =\r
585                         "SELECT csid from roles WHERE tenant_id=? and rolename=?";\r
586                 pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement\r
587                 rs = null;\r
588             Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();\r
589             Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();\r
590                 for(String tId : tenantInfo.keySet()) {\r
591                         pstmt.setString(1, tId);                                                // set tenant_id param\r
592                         pstmt.setString(2, getDefaultAdminRole(tId));   // set rolename param\r
593                         rs = pstmt.executeQuery();\r
594                         // extract data from the ResultSet\r
595                         if(!rs.next()) {\r
596                                 throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)\r
597                                                 +" for tenant id: "+tId+" in roles!");\r
598                         }\r
599                         String tenantAdminRoleCSID = rs.getString(1);\r
600                 if (logger.isDebugEnabled()) {\r
601                         logger.debug("createDefaultAccounts found role: "\r
602                                         +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID\r
603                                         +") for tenant id: "+tId);\r
604                 }\r
605                         tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);\r
606                         pstmt.setString(1, tId);                                                // set tenant_id param\r
607                         pstmt.setString(2, getDefaultReaderRole(tId));  // set rolename param\r
608                         rs.close();\r
609                         rs = pstmt.executeQuery();\r
610                         // extract data from the ResultSet\r
611                         if(!rs.next()) {\r
612                                 throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)\r
613                                                 +" for tenant id: "+tId+" in roles!");\r
614                         }\r
615                         String tenantReaderRoleCSID = rs.getString(1);\r
616                 if (logger.isDebugEnabled()) {\r
617                         logger.debug("createDefaultAccounts found role: "\r
618                                         +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID\r
619                                         +") for tenant id: "+tId);\r
620                 }\r
621                         tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);\r
622                         rs.close();\r
623                 }\r
624                 pstmt.close();\r
625                 // Sixth, bind the accounts to roles. If the users already existed,\r
626                 // we'll assume they were set up correctly.\r
627                                         String insertAccountRoleSQL;\r
628                                         if (databaseProductType == DatabaseProductType.MYSQL) {\r
629                                                 insertAccountRoleSQL =\r
630                                                 "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"\r
631                                                         +" VALUES(?, ?, ?, ?, now())";\r
632                                         } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
633                                                 insertAccountRoleSQL =\r
634                                                 "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"\r
635                                                         +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";\r
636                                         } else {\r
637                                                         throw new Exception("Unrecognized database system.");\r
638                                         }\r
639                 if (logger.isDebugEnabled()) {\r
640                         logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"\r
641                                         +insertAccountRoleSQL);\r
642                 }\r
643                 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement\r
644                 for(String tId : tenantInfo.keySet()) {\r
645                         String adminUserId =  getDefaultAdminUserID(tenantInfo.get(tId));\r
646                         if(!usersInRepo.contains(adminUserId)) {\r
647                         String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
648                                 String adminRoleId = tenantAdminRoleCSIDs.get(tId);\r
649                                 pstmt.setString(1, adminAcct);          // set acct CSID param\r
650                                 pstmt.setString(2, adminUserId);        // set user_id param\r
651                                 pstmt.setString(3, adminRoleId);        // set role_id param\r
652                                 pstmt.setString(4, getDefaultAdminRole(tId));   // set rolename param\r
653                         if (logger.isDebugEnabled()) {\r
654                                 logger.debug("createDefaultAccounts binding account: "\r
655                                                 +adminUserId+" to Admin role("+adminRoleId\r
656                                                 +") for tenant id: "+tId);\r
657                         }\r
658                                 pstmt.executeUpdate();\r
659                                 // Now add the Spring Admin Role to the admin accounts\r
660                                 pstmt.setString(3, springAdminRoleCSID);        // set role_id param\r
661                                 pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param\r
662                         if (logger.isDebugEnabled()) {\r
663                                 logger.debug("createDefaultAccounts binding account: "\r
664                                                 +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);\r
665                         }\r
666                                 pstmt.executeUpdate();\r
667                         }\r
668                         String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));\r
669                         if(!usersInRepo.contains(readerUserId)) {\r
670                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
671                                 String readerRoleId = tenantReaderRoleCSIDs.get(tId);\r
672                                 pstmt.setString(1, readerAcct);         // set acct CSID param\r
673                                 pstmt.setString(2, readerUserId);       // set user_id param\r
674                                 pstmt.setString(3, readerRoleId);       // set role_id param\r
675                                 pstmt.setString(4, getDefaultReaderRole(tId));  // set rolename param\r
676                         if (logger.isDebugEnabled()) {\r
677                                 logger.debug("createDefaultAccounts binding account: "\r
678                                                 +readerUserId+" to Reader role("+readerRoleId\r
679                                                 +") for tenant id: "+tId);\r
680                         }\r
681                                 pstmt.executeUpdate();\r
682                         }\r
683                 }\r
684                 pstmt.close();\r
685                         stmt.close();\r
686         } catch (RuntimeException rte) {\r
687                 if (logger.isDebugEnabled()) {\r
688                         logger.debug("Exception in createDefaultAccounts: "+\r
689                                                 rte.getLocalizedMessage());\r
690                         logger.debug(rte.getStackTrace().toString());\r
691                 }\r
692             throw rte;\r
693         } catch (SQLException sqle) {\r
694             // SQLExceptions can be chained. We have at least one exception, so\r
695             // set up a loop to make sure we let the user know about all of them\r
696             // if there happens to be more than one.\r
697                 if (logger.isDebugEnabled()) {\r
698                         SQLException tempException = sqle;\r
699                         while (null != tempException) {\r
700                                 logger.debug("SQL Exception: " + sqle.getLocalizedMessage());\r
701                                 tempException = tempException.getNextException();\r
702                         }\r
703                         logger.debug(sqle.getStackTrace().toString());\r
704                 }\r
705             throw new RuntimeException("SQL problem in createDefaultAccounts: ", sqle);\r
706         } catch (Exception e) {\r
707                 if (logger.isDebugEnabled()) {\r
708                         logger.debug("Exception in createDefaultAccounts: "+\r
709                                                 e.getLocalizedMessage());\r
710                 }\r
711         } finally {\r
712                 try {\r
713                 if(conn!=null)\r
714                     conn.close();\r
715                 if(pstmt!=null)\r
716                     pstmt.close();\r
717                 if(stmt!=null)\r
718                     stmt.close();\r
719             } catch (SQLException sqle) {\r
720                 if (logger.isDebugEnabled()) {\r
721                                 logger.debug("SQL Exception closing statement/connection: "\r
722                                                 + sqle.getLocalizedMessage());\r
723                 }\r
724                 }\r
725         }       \r
726     }\r
727     \r
728     private static String getDefaultAdminRole(String tenantId) {\r
729         return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;\r
730     }\r
731     \r
732     private static String getDefaultReaderRole(String tenantId) {\r
733         return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX;\r
734     }\r
735     \r
736     private static String getDefaultAdminUserID(String tenantName) {\r
737         return TENANT_ADMIN_ACCT_PREFIX+tenantName;\r
738     }\r
739     \r
740     private static String getDefaultReaderUserID(String tenantName) {\r
741         return TENANT_READER_ACCT_PREFIX+tenantName;\r
742     }\r
743     \r
744         static public PermissionAction createPermissionAction(Permission perm,\r
745                         ActionType actionType) {\r
746         PermissionAction pa = new PermissionAction();\r
747 \r
748             CSpaceAction action = URIResourceImpl.getAction(actionType);\r
749             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),\r
750                     perm.getResourceName(), action);\r
751             pa.setName(actionType);\r
752             pa.setObjectIdentity(uriRes.getHashedId().toString());\r
753             pa.setObjectIdentityResource(uriRes.getId());\r
754             \r
755             return pa;\r
756         }\r
757 \r
758         static public PermissionAction update(Permission perm, PermissionAction permAction) {\r
759         PermissionAction pa = new PermissionAction();\r
760 \r
761             CSpaceAction action = URIResourceImpl.getAction(permAction.getName());\r
762             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),\r
763                     perm.getResourceName(), action);\r
764             pa.setObjectIdentity(uriRes.getHashedId().toString());\r
765             pa.setObjectIdentityResource(uriRes.getId());\r
766             \r
767             return pa;\r
768         }\r
769         \r
770         private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {\r
771                 TransitionDefList result = null;\r
772                 try {\r
773                         String serviceObjectName = serviceBinding.getObject().getName();\r
774                 DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(\r
775                                 tenantBinding, serviceBinding);\r
776                 Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName);\r
777                 if (lifecycle != null) {\r
778                         result = lifecycle.getTransitionDefList();\r
779                 }\r
780                 } catch (Exception e) {\r
781                         // Ignore this exception and return an empty non-null TransitionDefList\r
782                 }\r
783                 \r
784                 if (result == null) {\r
785                         logger.warn("Could not retrieve a lifecycle transition definition list from: "\r
786                                         + serviceBinding.getName()\r
787                                         + " with tenant ID = "\r
788                                         + tenantBinding.getId());                       \r
789                         // return an empty list                 \r
790                         result = new TransitionDefList();\r
791                 } else {\r
792                         logger.debug("Successfully etrieved a lifecycle transition definition list from: "\r
793                                         + serviceBinding.getName()\r
794                                         + " with tenant ID = "\r
795                                         + tenantBinding.getId());\r
796                 }\r
797                 \r
798                 return result;\r
799         }\r
800         \r
801     public static void createDefaultWorkflowPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions\r
802     {\r
803         AuthZ.get().login(); //login to Spring Security manager\r
804         \r
805         EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);\r
806         EntityManager em = null;\r
807 \r
808         try {\r
809             em = emf.createEntityManager();\r
810 \r
811             Role superRole = AuthorizationCommon.getRole(em, ADMINISTRATOR_TENANT_ID, ROLE_ADMINISTRATOR);\r
812                 Hashtable<String, TenantBindingType> tenantBindings =\r
813                         tenantBindingConfigReader.getTenantBindings();\r
814                 for (String tenantId : tenantBindings.keySet()) {\r
815                         TenantBindingType tenantBinding = tenantBindings.get(tenantId);\r
816                         Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR);\r
817                         Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER);\r
818                         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {\r
819                                 String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP);\r
820                                 if (prop == null ? true : Boolean.parseBoolean(prop)) {\r
821                                                 try {\r
822                                                 em.getTransaction().begin();\r
823                                                 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);\r
824                                                 for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) {\r
825                                                         //\r
826                                                         // Create the permission for the admin role\r
827                                                         Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_CRUDL);\r
828                                                         persist(em, adminPerm, adminRole, true);\r
829                                                         //\r
830                                                         // Create the permission for the read-only role\r
831                                                         Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_RL);\r
832                                                         \r
833                                                         Profiler profiler = new Profiler(AuthorizationCommon.class, 1);\r
834                                                         profiler.start("createDefaultPermissions started:" + readonlyPerm.getCsid());\r
835                                                         persist(em, readonlyPerm, readonlyRole, true); // Persist/store the permission and permrole records and related Spring Security info\r
836                                                         profiler.stop();\r
837                                                         logger.debug("Finished full perm generation for "\r
838                                                                         + ":" + tenantBinding.getId()\r
839                                                                         + ":" + serviceBinding.getName()\r
840                                                                         + ":" + transitionDef.getName()\r
841                                                                         + ":" + ACTIONGROUP_RL\r
842                                                                         + ":" + profiler.getCumulativeTime());                                          \r
843                                                         /*\r
844                                                         //\r
845                                                         // Create the permission for the super-admin role.  Note we use the same "adminPerm" instance we used for the "adminPermRole" instance\r
846                                                         //\r
847                                                         persist(em, adminPerm, superRole, false);\r
848                                                         */\r
849                                                 }\r
850                                                 em.getTransaction().commit();\r
851                                         } catch (IllegalStateException e) {\r
852                                                 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.\r
853                                         }\r
854                                 } else {\r
855                                         logger.warn("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "\r
856                                                         + serviceBinding.getName());\r
857                                 }\r
858                         }\r
859                 }\r
860             em.close();\r
861         } catch (Exception e) {\r
862             if (em != null && em.getTransaction().isActive()) {\r
863                 em.getTransaction().rollback();\r
864             }\r
865             if (logger.isDebugEnabled()) {\r
866                 logger.debug("Caught exception and rolling back permission creation: ", e);\r
867             }\r
868             throw e;\r
869         } finally {\r
870             if (em != null) {\r
871                 JpaStorageUtils.releaseEntityManagerFactory(emf);\r
872             }\r
873         }\r
874     }\r
875     \r
876     private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) {\r
877         PermissionRoleRel result = null;\r
878         \r
879         try {\r
880                 String whereClause = "where permissionId = :id and roleId = :roleId";\r
881                 HashMap<String, Object> params = new HashMap<String, Object>();\r
882                 params.put("id", permissionId);\r
883                 params.put("roleId", RoleId);        \r
884         \r
885                 result = (PermissionRoleRel) JpaStorageUtils.getEntity(em,\r
886                                 PermissionRoleRel.class.getCanonicalName(), whereClause, params);\r
887         } catch (Exception e) {\r
888                 //Do nothing. Will return null;\r
889         }\r
890                 \r
891         return result;\r
892     }\r
893     \r
894     /*\r
895      * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction\r
896      */\r
897     private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy) throws Exception {\r
898                 AuthorizationStore authzStore = new AuthorizationStore();\r
899                 // First persist the Permission record\r
900                 authzStore.store(em, permission);\r
901                 \r
902                 // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload)\r
903                 // Create a PermissionRoleRel (the database relation table for the permission and role)\r
904                 PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid());\r
905                 if (permRoleRel == null) {\r
906                         PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);\r
907                 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();\r
908                 PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);\r
909                 for (PermissionRoleRel prr : permRoleRels) {\r
910                     authzStore.store(em, prr);\r
911                 }\r
912                         Profiler profiler = new Profiler(AuthorizationCommon.class, 2);\r
913                         profiler.start();\r
914                         // Add a corresponding entry in the Spring Security Tables\r
915                         addPermissionsForUri(permission, permRole);\r
916                         profiler.stop();\r
917                         logger.debug("Finished full perm generation for "\r
918                                         + ":" + permission.getTenantId()\r
919                                         + ":" + permission.getResourceName()\r
920                                         + ":" + ACTIONGROUP_RL\r
921                                         + ":" + profiler.getCumulativeTime());\r
922                 }\r
923         \r
924     }\r
925 \r
926 }\r