]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
36d8d555c99df65d318939e0cbf5338a9af41dd0
[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.RoleClient;\r
35 import org.collectionspace.services.client.workflow.WorkflowClient;\r
36 import org.collectionspace.services.common.config.ServiceConfigUtils;\r
37 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;\r
38 import org.collectionspace.services.common.context.ServiceBindingUtils;\r
39 import org.collectionspace.services.common.document.DocumentHandler;\r
40 import org.collectionspace.services.common.profile.Profiler;\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 = UUID.randomUUID().toString(); //FIXME: Could this be something like a refname instead of a UUID?\r
252         String id = tenantId\r
253                         + "-" + resourceName\r
254                         + "-" + actionGroup.name;\r
255         Permission perm = new Permission();\r
256         perm.setCsid(id);\r
257         perm.setDescription(description);\r
258         perm.setCreatedAtItem(new Date());\r
259         perm.setResourceName(resourceName.toLowerCase().trim());\r
260         perm.setEffect(EffectType.PERMIT);\r
261         perm.setTenantId(tenantId);\r
262         \r
263         perm.setActionGroup(actionGroup.name);\r
264         ArrayList<PermissionAction> pas = new ArrayList<PermissionAction>();\r
265         perm.setAction(pas);\r
266         for (ActionType actionType : actionGroup.actions) {\r
267                 PermissionAction permAction = createPermissionAction(perm, actionType);\r
268                 pas.add(permAction);\r
269         }\r
270         \r
271         return perm;\r
272     }\r
273     \r
274     private static Permission createWorkflowPermission(TenantBindingType tenantBinding,\r
275                 ServiceBindingType serviceBinding,\r
276                 TransitionDef transitionDef,\r
277                 ActionGroup actionGroup)\r
278     {\r
279         Permission result = null;\r
280         String workFlowServiceSuffix;\r
281         String transitionName;\r
282         if (transitionDef != null) {\r
283                 transitionName = transitionDef.getName();\r
284                 workFlowServiceSuffix = WorkflowClient.SERVICE_AUTHZ_SUFFIX;\r
285         } else {\r
286                 transitionName = ""; //since the transitionDef was null, we're assuming that this is the base workflow permission to be created                 \r
287                 workFlowServiceSuffix = WorkflowClient.SERVICE_PATH;\r
288         }\r
289         \r
290         String tenantId = tenantBinding.getId();\r
291         String resourceName = "/"\r
292                         + serviceBinding.getName().toLowerCase().trim()\r
293                         + workFlowServiceSuffix\r
294                         + transitionName;\r
295         String description = "A generated workflow permission for actiongroup " + actionGroup.name;\r
296         result = createPermission(tenantId, resourceName, description, actionGroup);\r
297         \r
298         if (logger.isDebugEnabled() == true) {\r
299                 logger.debug("Generated a workflow permission: "\r
300                                 + result.getResourceName()\r
301                                 + ":" + transitionName\r
302                                 + ":" + "tenant id=" + result.getTenantId()\r
303                                 + ":" + actionGroup.name);\r
304         }\r
305         \r
306         return result;\r
307     }\r
308     \r
309     private static PermissionRole createPermissionRole(EntityManager em,\r
310                 Permission permission,\r
311                 Role role,\r
312                 boolean enforceTenancy) throws Exception\r
313     {\r
314         PermissionRole permRole = new PermissionRole();\r
315         // Check to see if the tenant ID of the permission and the tenant ID of the role match\r
316         boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId());\r
317         if (tenantIdsMatch == false && enforceTenancy == false) {\r
318                 tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched.\r
319         }\r
320                         \r
321                 if (tenantIdsMatch == true) {\r
322                 permRole.setSubject(SubjectType.ROLE);\r
323                 //\r
324                 // Set of the permission value list of the permrole\r
325                 //\r
326                 List<PermissionValue> permValues = new ArrayList<PermissionValue>();\r
327                 PermissionValue permValue = new PermissionValue();\r
328                 permValue.setPermissionId(permission.getCsid());\r
329                 permValue.setResourceName(permission.getResourceName().toLowerCase());\r
330                 permValue.setActionGroup(permission.getActionGroup());\r
331                 permValues.add(permValue);\r
332                 permRole.setPermission(permValues);\r
333                 //\r
334                 // Set of the role value list of the permrole\r
335                 //\r
336                 List<RoleValue> roleValues = new ArrayList<RoleValue>();\r
337                 RoleValue rv = new RoleValue();\r
338             // This needs to use the qualified name, not the display name\r
339             rv.setRoleName(role.getRoleName());\r
340             rv.setRoleId(role.getCsid());\r
341             roleValues.add(rv);\r
342             permRole.setRole(roleValues);\r
343                 } else {\r
344                 String errMsg = "The tenant ID of the role: " + role.getTenantId()\r
345                                 + " did not match the tenant ID of the permission: " + permission.getTenantId();\r
346                 throw new Exception(errMsg);\r
347                 }\r
348         \r
349         return permRole;\r
350     }\r
351     \r
352     \r
353     /*\r
354      * FIXME: REM - This method is way too big -over 300 lines!  We need to break it up into\r
355      * smaller, discrete, sub-methods.\r
356      */\r
357     public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) {\r
358         if (logger.isDebugEnabled()) {\r
359                 logger.debug("ServiceMain.createDefaultAccounts starting...");\r
360         }\r
361         \r
362         Hashtable<String, TenantBindingType> tenantBindings =\r
363                 tenantBindingConfigReader.getTenantBindings();\r
364         Hashtable<String, String> tenantInfo = new Hashtable<String, String>();\r
365         for (TenantBindingType tenantBinding : tenantBindings.values()) {\r
366                 String tId = tenantBinding.getId();\r
367                 String tName = tenantBinding.getName();\r
368                 tenantInfo.put(tId, tName);\r
369                 if (logger.isDebugEnabled()) {\r
370                         logger.debug("createDefaultAccounts found configured tenant id: "+tId+" name: "+tName);\r
371                 }\r
372         }\r
373         Connection conn = null;\r
374         PreparedStatement pstmt = null;\r
375         Statement stmt = null;\r
376         // TODO - need to put in tests for existence first.\r
377         // We could just look for the accounts per tenant up front, and assume that\r
378         // the rest is there if the accounts are.\r
379         // Could add a sql script to remove these if need be - Spring only does roles, \r
380         // and we're not touching that, so we could safely toss the \r
381         // accounts, users, account-tenants, account-roles, and start over.\r
382         try {\r
383                 conn = getConnection();\r
384                 // First find or create the tenants\r
385                 String queryTenantSQL = \r
386                         "SELECT id,name FROM tenants";\r
387                 stmt = conn.createStatement();\r
388                         ResultSet rs = stmt.executeQuery(queryTenantSQL);\r
389                 ArrayList<String> existingTenants = new ArrayList<String>();\r
390                         while (rs.next()) {\r
391                                 String tId = rs.getString("id");\r
392                                 String tName = rs.getString("name");\r
393                                 if(tenantInfo.containsKey(tId)) {\r
394                                         existingTenants.add(tId);\r
395                                         if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {\r
396                                                 logger.warn("Configured name for tenant: "\r
397                                                                 +tId+" in repository: "+tName\r
398                                                                 +" does not match config'd name: "+ tenantInfo.get(tId));\r
399                                         }\r
400                                 }\r
401                         }\r
402                         rs.close();\r
403 \r
404                 String insertTenantSQL = \r
405                         "INSERT INTO tenants (id,name,created_at) VALUES (?,?, now())";\r
406                 pstmt = conn.prepareStatement(insertTenantSQL); // create a statement\r
407                 for(String tId : tenantInfo.keySet()) {\r
408                         if(existingTenants.contains(tId)) {\r
409                         if (logger.isDebugEnabled()) {\r
410                                 logger.debug("createDefaultAccounts: tenant exists (skipping): "\r
411                                                 +tenantInfo.get(tId));\r
412                         }\r
413                                 continue;\r
414                         }\r
415                         pstmt.setString(1, tId);                                        // set id param\r
416                         pstmt.setString(2, tenantInfo.get(tId));        // set name param\r
417                 if (logger.isDebugEnabled()) {\r
418                         logger.debug("createDefaultAccounts adding entry for tenant: "+tId);\r
419                 }\r
420                         pstmt.executeUpdate();\r
421                 }\r
422                 pstmt.close();\r
423                 // Second find or create the users\r
424                 String queryUserSQL = \r
425                         "SELECT username FROM users WHERE username LIKE '"\r
426                                 +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"\r
427                                 +TENANT_READER_ACCT_PREFIX+"%'";\r
428                         rs = stmt.executeQuery(queryUserSQL);\r
429                 ArrayList<String> usersInRepo = new ArrayList<String>();\r
430                         while (rs.next()) {\r
431                                 String uName = rs.getString("username");\r
432                                 usersInRepo.add(uName);\r
433                         }\r
434                         rs.close();\r
435                 String insertUserSQL = \r
436                         "INSERT INTO users (username,passwd, created_at)"\r
437                         +" VALUES (?,?, now())";\r
438                 pstmt = conn.prepareStatement(insertUserSQL); // create a statement\r
439                 for(String tName : tenantInfo.values()) {\r
440                         String adminAcctName = getDefaultAdminUserID(tName);\r
441                         if(!usersInRepo.contains(adminAcctName)) {\r
442                                 String secEncPasswd = SecurityUtils.createPasswordHash(\r
443                                                 adminAcctName, DEFAULT_ADMIN_PASSWORD);\r
444                                 pstmt.setString(1, adminAcctName);      // set username param\r
445                                 pstmt.setString(2, secEncPasswd);       // set passwd param\r
446                         if (logger.isDebugEnabled()) {\r
447                                 logger.debug("createDefaultAccounts adding user: "\r
448                                                 +adminAcctName+" for tenant: "+tName);\r
449                         }\r
450                                 pstmt.executeUpdate();\r
451                         } else if (logger.isDebugEnabled()) {\r
452                         logger.debug("createDefaultAccounts: user: "+adminAcctName\r
453                                                         +" already exists - skipping.");\r
454                 }\r
455 \r
456 \r
457                         String readerAcctName =  getDefaultReaderUserID(tName);\r
458                         if(!usersInRepo.contains(readerAcctName)) {\r
459                                 String secEncPasswd = SecurityUtils.createPasswordHash(\r
460                                                 readerAcctName, DEFAULT_READER_PASSWORD);\r
461                                 pstmt.setString(1, readerAcctName);     // set username param\r
462                                 pstmt.setString(2, secEncPasswd);       // set passwd param\r
463                         if (logger.isDebugEnabled()) {\r
464                                 logger.debug("createDefaultAccounts adding user: "\r
465                                                 +readerAcctName+" for tenant: "+tName);\r
466                         }\r
467                                 pstmt.executeUpdate();\r
468                         } else if (logger.isDebugEnabled()) {\r
469                         logger.debug("createDefaultAccounts: user: "+readerAcctName\r
470                                                         +" already exists - skipping.");\r
471                         }\r
472                 }\r
473                 pstmt.close();\r
474                 // Third, create the accounts. Assume that if the users were already there,\r
475                 // then the accounts were as well\r
476             String insertAccountSQL = \r
477                 "INSERT INTO accounts_common "\r
478                 + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "\r
479                 + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";\r
480             Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();\r
481             Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();\r
482                 pstmt = conn.prepareStatement(insertAccountSQL); // create a statement\r
483                 for(String tId : tenantInfo.keySet()) {\r
484                         String tName = tenantInfo.get(tId);\r
485                 String adminCSID = UUID.randomUUID().toString();\r
486                 tenantAdminAcctCSIDs.put(tId, adminCSID);\r
487                         String adminAcctName =  getDefaultAdminUserID(tName);\r
488                         if(!usersInRepo.contains(adminAcctName)) {\r
489                                 pstmt.setString(1, adminCSID);                  // set csid param\r
490                                 pstmt.setString(2, adminAcctName);      // set email param (bogus)\r
491                                 pstmt.setString(3, adminAcctName);      // set userid param\r
492                                 pstmt.setString(4, "Administrator");// set screen name param\r
493                         if (logger.isDebugEnabled()) {\r
494                                 logger.debug("createDefaultAccounts adding account: "\r
495                                                 +adminAcctName+" for tenant: "+tName);\r
496                         }\r
497                                 pstmt.executeUpdate();\r
498                         } else if (logger.isDebugEnabled()) {\r
499                         logger.debug("createDefaultAccounts: user: "+adminAcctName\r
500                                                         +" already exists - skipping account generation.");\r
501                         }\r
502 \r
503                         String readerCSID = UUID.randomUUID().toString();       \r
504                 tenantReaderAcctCSIDs.put(tId, readerCSID);\r
505                         String readerAcctName =  getDefaultReaderUserID(tName);\r
506                         if(!usersInRepo.contains(readerAcctName)) {\r
507                                 pstmt.setString(1, readerCSID);         // set csid param\r
508                                 pstmt.setString(2, readerAcctName);     // set email param (bogus)\r
509                                 pstmt.setString(3, readerAcctName);     // set userid param\r
510                                 pstmt.setString(4, "Reader");           // set screen name param\r
511                                 if (logger.isDebugEnabled()) {\r
512                                         logger.debug("createDefaultAccounts adding account: "\r
513                                                         +readerAcctName+" for tenant: "+tName);\r
514                                 }\r
515                                 pstmt.executeUpdate();\r
516                         } else if (logger.isDebugEnabled()) {\r
517                         logger.debug("createDefaultAccounts: user: "+readerAcctName\r
518                                                         +" already exists - skipping account creation.");\r
519                         }\r
520                 }\r
521                 pstmt.close();\r
522                 // Fourth, bind accounts to tenants. Assume that if the users were already there,\r
523                 // then the accounts were bound to tenants correctly\r
524                 String insertAccountTenantSQL;\r
525                 DatabaseProductType databaseProductType = JDBCTools.getDatabaseProductType();\r
526                 if (databaseProductType == DatabaseProductType.MYSQL) {\r
527                         insertAccountTenantSQL =\r
528                                 "INSERT INTO accounts_tenants (TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
529                                 + " VALUES(?, ?)";\r
530                 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
531                         insertAccountTenantSQL =\r
532                                 "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTSCOMMON_CSID,tenant_id) "\r
533                                 + " VALUES(nextval('hibernate_sequence'), ?, ?)";\r
534                 } else {\r
535                         throw new Exception("Unrecognized database system.");\r
536                 }\r
537                 pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement\r
538                 for(String tId : tenantInfo.keySet()) {\r
539                         String tName = tenantInfo.get(tId);\r
540                         if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {\r
541                                 String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
542                                 pstmt.setString(1, adminAcct);          // set acct CSID param\r
543                                 pstmt.setString(2, tId);                        // set tenant_id param\r
544                         if (logger.isDebugEnabled()) {\r
545                                 logger.debug("createDefaultAccounts binding account id: "\r
546                                                 +adminAcct+" to tenant id: "+tId);\r
547                         }\r
548                                 pstmt.executeUpdate();\r
549                         }\r
550                         if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {\r
551                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
552                                 pstmt.setString(1, readerAcct);         // set acct CSID param\r
553                                 pstmt.setString(2, tId);                        // set tenant_id param\r
554                         if (logger.isDebugEnabled()) {\r
555                                 logger.debug("createDefaultAccounts binding account id: "\r
556                                                 +readerAcct+" to tenant id: "+tId);\r
557                         }\r
558                                 pstmt.executeUpdate();\r
559                         }\r
560                 }\r
561                 pstmt.close();\r
562                 // Fifth, fetch and save the default roles\r
563                         String springAdminRoleCSID = null;\r
564                 String querySpringRole = \r
565                         "SELECT csid from roles WHERE rolename='"+SPRING_ADMIN_ROLE+"'";\r
566                         rs = stmt.executeQuery(querySpringRole);\r
567                 if(rs.next()) {\r
568                         springAdminRoleCSID = rs.getString(1);\r
569                 if (logger.isDebugEnabled()) {\r
570                         logger.debug("createDefaultAccounts found Spring Admin role: "\r
571                                         +springAdminRoleCSID);\r
572                 }\r
573                 } else {\r
574                 String insertSpringAdminRoleSQL =\r
575                         "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "\r
576                         + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";\r
577                         stmt.executeUpdate(insertSpringAdminRoleSQL);\r
578                         springAdminRoleCSID = "-1";\r
579                 if (logger.isDebugEnabled()) {\r
580                         logger.debug("createDefaultAccounts CREATED Spring Admin role: "\r
581                                         +springAdminRoleCSID);\r
582                 }\r
583                 }\r
584                 rs.close();\r
585                 String getRoleCSIDSql =\r
586                         "SELECT csid from roles WHERE tenant_id=? and rolename=?";\r
587                 pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement\r
588                 rs = null;\r
589             Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();\r
590             Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();\r
591                 for(String tId : tenantInfo.keySet()) {\r
592                         pstmt.setString(1, tId);                                                // set tenant_id param\r
593                         pstmt.setString(2, getDefaultAdminRole(tId));   // set rolename param\r
594                         rs = pstmt.executeQuery();\r
595                         // extract data from the ResultSet\r
596                         if(!rs.next()) {\r
597                                 throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)\r
598                                                 +" for tenant id: "+tId+" in roles!");\r
599                         }\r
600                         String tenantAdminRoleCSID = rs.getString(1);\r
601                 if (logger.isDebugEnabled()) {\r
602                         logger.debug("createDefaultAccounts found role: "\r
603                                         +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID\r
604                                         +") for tenant id: "+tId);\r
605                 }\r
606                         tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);\r
607                         pstmt.setString(1, tId);                                                // set tenant_id param\r
608                         pstmt.setString(2, getDefaultReaderRole(tId));  // set rolename param\r
609                         rs.close();\r
610                         rs = pstmt.executeQuery();\r
611                         // extract data from the ResultSet\r
612                         if(!rs.next()) {\r
613                                 throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)\r
614                                                 +" for tenant id: "+tId+" in roles!");\r
615                         }\r
616                         String tenantReaderRoleCSID = rs.getString(1);\r
617                 if (logger.isDebugEnabled()) {\r
618                         logger.debug("createDefaultAccounts found role: "\r
619                                         +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID\r
620                                         +") for tenant id: "+tId);\r
621                 }\r
622                         tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);\r
623                         rs.close();\r
624                 }\r
625                 pstmt.close();\r
626                 // Sixth, bind the accounts to roles. If the users already existed,\r
627                 // we'll assume they were set up correctly.\r
628                                         String insertAccountRoleSQL;\r
629                                         if (databaseProductType == DatabaseProductType.MYSQL) {\r
630                                                 insertAccountRoleSQL =\r
631                                                 "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"\r
632                                                         +" VALUES(?, ?, ?, ?, now())";\r
633                                         } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {\r
634                                                 insertAccountRoleSQL =\r
635                                                 "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"\r
636                                                         +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";\r
637                                         } else {\r
638                                                         throw new Exception("Unrecognized database system.");\r
639                                         }\r
640                 if (logger.isDebugEnabled()) {\r
641                         logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"\r
642                                         +insertAccountRoleSQL);\r
643                 }\r
644                 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement\r
645                 for(String tId : tenantInfo.keySet()) {\r
646                         String adminUserId =  getDefaultAdminUserID(tenantInfo.get(tId));\r
647                         if(!usersInRepo.contains(adminUserId)) {\r
648                         String adminAcct = tenantAdminAcctCSIDs.get(tId);\r
649                                 String adminRoleId = tenantAdminRoleCSIDs.get(tId);\r
650                                 pstmt.setString(1, adminAcct);          // set acct CSID param\r
651                                 pstmt.setString(2, adminUserId);        // set user_id param\r
652                                 pstmt.setString(3, adminRoleId);        // set role_id param\r
653                                 pstmt.setString(4, getDefaultAdminRole(tId));   // set rolename param\r
654                         if (logger.isDebugEnabled()) {\r
655                                 logger.debug("createDefaultAccounts binding account: "\r
656                                                 +adminUserId+" to Admin role("+adminRoleId\r
657                                                 +") for tenant id: "+tId);\r
658                         }\r
659                                 pstmt.executeUpdate();\r
660                                 // Now add the Spring Admin Role to the admin accounts\r
661                                 pstmt.setString(3, springAdminRoleCSID);        // set role_id param\r
662                                 pstmt.setString(4, SPRING_ADMIN_ROLE);          // set rolename param\r
663                         if (logger.isDebugEnabled()) {\r
664                                 logger.debug("createDefaultAccounts binding account: "\r
665                                                 +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);\r
666                         }\r
667                                 pstmt.executeUpdate();\r
668                         }\r
669                         String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));\r
670                         if(!usersInRepo.contains(readerUserId)) {\r
671                                 String readerAcct = tenantReaderAcctCSIDs.get(tId);\r
672                                 String readerRoleId = tenantReaderRoleCSIDs.get(tId);\r
673                                 pstmt.setString(1, readerAcct);         // set acct CSID param\r
674                                 pstmt.setString(2, readerUserId);       // set user_id param\r
675                                 pstmt.setString(3, readerRoleId);       // set role_id param\r
676                                 pstmt.setString(4, getDefaultReaderRole(tId));  // set rolename param\r
677                         if (logger.isDebugEnabled()) {\r
678                                 logger.debug("createDefaultAccounts binding account: "\r
679                                                 +readerUserId+" to Reader role("+readerRoleId\r
680                                                 +") for tenant id: "+tId);\r
681                         }\r
682                                 pstmt.executeUpdate();\r
683                         }\r
684                 }\r
685                 pstmt.close();\r
686                         stmt.close();\r
687         } catch (RuntimeException rte) {\r
688                 if (logger.isDebugEnabled()) {\r
689                         logger.debug("Exception in createDefaultAccounts: "+\r
690                                                 rte.getLocalizedMessage());\r
691                         logger.debug(rte.getStackTrace().toString());\r
692                 }\r
693             throw rte;\r
694         } catch (SQLException sqle) {\r
695             // SQLExceptions can be chained. We have at least one exception, so\r
696             // set up a loop to make sure we let the user know about all of them\r
697             // if there happens to be more than one.\r
698                 if (logger.isDebugEnabled()) {\r
699                         SQLException tempException = sqle;\r
700                         while (null != tempException) {\r
701                                 logger.debug("SQL Exception: " + sqle.getLocalizedMessage());\r
702                                 tempException = tempException.getNextException();\r
703                         }\r
704                         logger.debug(sqle.getStackTrace().toString());\r
705                 }\r
706             throw new RuntimeException("SQL problem in createDefaultAccounts: ", sqle);\r
707         } catch (Exception e) {\r
708                 if (logger.isDebugEnabled()) {\r
709                         logger.debug("Exception in createDefaultAccounts: "+\r
710                                                 e.getLocalizedMessage());\r
711                 }\r
712         } finally {\r
713                 try {\r
714                 if(conn!=null)\r
715                     conn.close();\r
716                 if(pstmt!=null)\r
717                     pstmt.close();\r
718                 if(stmt!=null)\r
719                     stmt.close();\r
720             } catch (SQLException sqle) {\r
721                 if (logger.isDebugEnabled()) {\r
722                                 logger.debug("SQL Exception closing statement/connection: "\r
723                                                 + sqle.getLocalizedMessage());\r
724                 }\r
725                 }\r
726         }       \r
727     }\r
728     \r
729     private static String getDefaultAdminRole(String tenantId) {\r
730         return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;\r
731     }\r
732     \r
733     private static String getDefaultReaderRole(String tenantId) {\r
734         return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX;\r
735     }\r
736     \r
737     private static String getDefaultAdminUserID(String tenantName) {\r
738         return TENANT_ADMIN_ACCT_PREFIX+tenantName;\r
739     }\r
740     \r
741     private static String getDefaultReaderUserID(String tenantName) {\r
742         return TENANT_READER_ACCT_PREFIX+tenantName;\r
743     }\r
744     \r
745         static public PermissionAction createPermissionAction(Permission perm,\r
746                         ActionType actionType) {\r
747         PermissionAction pa = new PermissionAction();\r
748 \r
749             CSpaceAction action = URIResourceImpl.getAction(actionType);\r
750             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),\r
751                     perm.getResourceName(), action);\r
752             pa.setName(actionType);\r
753             pa.setObjectIdentity(uriRes.getHashedId().toString());\r
754             pa.setObjectIdentityResource(uriRes.getId());\r
755             \r
756             return pa;\r
757         }\r
758 \r
759         static public PermissionAction update(Permission perm, PermissionAction permAction) {\r
760         PermissionAction pa = new PermissionAction();\r
761 \r
762             CSpaceAction action = URIResourceImpl.getAction(permAction.getName());\r
763             URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),\r
764                     perm.getResourceName(), action);\r
765             pa.setObjectIdentity(uriRes.getHashedId().toString());\r
766             pa.setObjectIdentityResource(uriRes.getId());\r
767             \r
768             return pa;\r
769         }\r
770         \r
771         private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {\r
772                 TransitionDefList result = null;\r
773                 try {\r
774                         String serviceObjectName = serviceBinding.getObject().getName();\r
775                 DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(\r
776                                 tenantBinding, serviceBinding);\r
777                 Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName);\r
778                 if (lifecycle != null) {\r
779                         result = lifecycle.getTransitionDefList();\r
780                 }\r
781                 } catch (Exception e) {\r
782                         // Ignore this exception and return an empty non-null TransitionDefList\r
783                 }\r
784                 \r
785                 if (result == null) {\r
786                         logger.warn("Could not retrieve a lifecycle transition definition list from: "\r
787                                         + serviceBinding.getName()\r
788                                         + " with tenant ID = "\r
789                                         + tenantBinding.getId());                       \r
790                         // return an empty list                 \r
791                         result = new TransitionDefList();\r
792                 } else {\r
793                         logger.debug("Successfully etrieved a lifecycle transition definition list from: "\r
794                                         + serviceBinding.getName()\r
795                                         + " with tenant ID = "\r
796                                         + tenantBinding.getId());\r
797                 }\r
798                 \r
799                 return result;\r
800         }\r
801         \r
802     public static void createDefaultPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions\r
803     {\r
804         AuthZ.get().login(); //login to Spring Security manager\r
805         \r
806         EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);\r
807         EntityManager em = null;\r
808 \r
809         try {\r
810             em = emf.createEntityManager();\r
811 \r
812             Role superRole = AuthorizationCommon.getRole(em, ADMINISTRATOR_TENANT_ID, ROLE_ADMINISTRATOR);\r
813                 Hashtable<String, TenantBindingType> tenantBindings =\r
814                         tenantBindingConfigReader.getTenantBindings();\r
815                 for (String tenantId : tenantBindings.keySet()) {\r
816                         TenantBindingType tenantBinding = tenantBindings.get(tenantId);\r
817                         Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR);\r
818                         Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER);\r
819                         for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {\r
820                                 String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP);\r
821                                 if (prop == null ? true : Boolean.parseBoolean(prop)) {\r
822                                                 try {\r
823                                                 em.getTransaction().begin();\r
824                                                 //\r
825                                                 // For the default admin role, create the base workflow (aka, "/workflow" permissions for the service.\r
826                                                 Permission baseAdminPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_CRUDL);\r
827                                                 persist(em, baseAdminPerm, adminRole, true);\r
828                                                 //\r
829                                                 // For the default read-only role, create the base workflow (aka, "/workflow" permissions for the service.\r
830                                                 Permission baseReadonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, null, ACTIONGROUP_RL);\r
831                                                 persist(em, baseReadonlyPerm, readonlyRole, true);                                      \r
832                                                 //\r
833                                                 // Next, create a permission for each workflow transition supported by the service's document type.\r
834                                                 //\r
835                                                 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);\r
836                                                 for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) {\r
837                                                         //\r
838                                                         // Create the permission for the admin role\r
839                                                         Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_CRUDL);\r
840                                                         persist(em, adminPerm, adminRole, true);\r
841                                                         //\r
842                                                         // Create the permission for the read-only role\r
843                                                         Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_RL);\r
844                                                         \r
845                                                         Profiler profiler = new Profiler(AuthorizationCommon.class, 1);\r
846                                                         profiler.start("createDefaultPermissions started:" + readonlyPerm.getCsid());\r
847                                                         persist(em, readonlyPerm, readonlyRole, true); // Persist/store the permission and permrole records and related Spring Security info\r
848                                                         profiler.stop();\r
849                                                         logger.debug("Finished full perm generation for "\r
850                                                                         + ":" + tenantBinding.getId()\r
851                                                                         + ":" + serviceBinding.getName()\r
852                                                                         + ":" + transitionDef.getName()\r
853                                                                         + ":" + ACTIONGROUP_RL\r
854                                                                         + ":" + profiler.getCumulativeTime());                                          \r
855                                                         /*\r
856                                                         //\r
857                                                         // Create the permission for the super-admin role.  Note we use the same "adminPerm" instance we used for the "adminPermRole" instance\r
858                                                         //\r
859                                                         persist(em, adminPerm, superRole, false);\r
860                                                         */\r
861                                                 }\r
862                                                 em.getTransaction().commit();\r
863                                         } catch (IllegalStateException e) {\r
864                                                 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
865                                         }\r
866                                 } else {\r
867                                         logger.warn("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "\r
868                                                         + serviceBinding.getName());\r
869                                 }\r
870                         }\r
871                 }\r
872             em.close();\r
873         } catch (Exception e) {\r
874             if (em != null && em.getTransaction().isActive()) {\r
875                 em.getTransaction().rollback();\r
876             }\r
877             if (logger.isDebugEnabled()) {\r
878                 logger.debug("Caught exception and rolling back permission creation: ", e);\r
879             }\r
880             throw e;\r
881         } finally {\r
882             if (em != null) {\r
883                 JpaStorageUtils.releaseEntityManagerFactory(emf);\r
884             }\r
885         }\r
886     }\r
887     \r
888     private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) {\r
889         PermissionRoleRel result = null;\r
890         \r
891         try {\r
892                 String whereClause = "where permissionId = :id and roleId = :roleId";\r
893                 HashMap<String, Object> params = new HashMap<String, Object>();\r
894                 params.put("id", permissionId);\r
895                 params.put("roleId", RoleId);        \r
896         \r
897                 result = (PermissionRoleRel) JpaStorageUtils.getEntity(em,\r
898                                 PermissionRoleRel.class.getCanonicalName(), whereClause, params);\r
899         } catch (Exception e) {\r
900                 //Do nothing. Will return null;\r
901         }\r
902                 \r
903         return result;\r
904     }\r
905     \r
906     /*\r
907      * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction\r
908      */\r
909     private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy) throws Exception {\r
910                 AuthorizationStore authzStore = new AuthorizationStore();\r
911                 // First persist the Permission record\r
912                 authzStore.store(em, permission);\r
913                 \r
914                 // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload)\r
915                 // Create a PermissionRoleRel (the database relation table for the permission and role)\r
916                 PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid());\r
917                 if (permRoleRel == null) {\r
918                         PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);\r
919                 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();\r
920                 PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);\r
921                 for (PermissionRoleRel prr : permRoleRels) {\r
922                     authzStore.store(em, prr);\r
923                 }\r
924                         Profiler profiler = new Profiler(AuthorizationCommon.class, 2);\r
925                         profiler.start();\r
926                         // Add a corresponding entry in the Spring Security Tables\r
927                         addPermissionsForUri(permission, permRole);\r
928                         profiler.stop();\r
929                         logger.debug("Finished full perm generation for "\r
930                                         + ":" + permission.getTenantId()\r
931                                         + ":" + permission.getResourceName()\r
932                                         + ":" + ACTIONGROUP_RL\r
933                                         + ":" + profiler.getCumulativeTime());\r
934                 }\r
935         \r
936     }\r
937 \r
938 }\r