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