1 package org.collectionspace.services.common.authorization_mgt;
\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
15 import javax.naming.NamingException;
\r
16 import javax.persistence.EntityManager;
\r
17 import javax.persistence.EntityManagerFactory;
\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
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
48 import org.collectionspace.services.lifecycle.Lifecycle;
\r
49 import org.collectionspace.services.lifecycle.TransitionDef;
\r
50 import org.collectionspace.services.lifecycle.TransitionDefList;
\r
52 //import org.mortbay.log.Log;
\r
53 import org.slf4j.Logger;
\r
54 import org.slf4j.LoggerFactory;
\r
56 import org.springframework.security.acls.model.AlreadyExistsException;
\r
59 public class AuthorizationCommon {
\r
61 final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup";
\r
63 // ActionGroup labels/constants
\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
70 final public static String ACTIONGROUP_RL_NAME = "RL";
\r
71 final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};
\r
74 * Inner class to deal with predefined ADMIN and READER action groupds
\r
76 public class ActionGroup {
\r
78 ActionType[] actions;
\r
81 static ActionGroup ACTIONGROUP_CRUDL;
\r
82 static ActionGroup ACTIONGROUP_RL;
\r
84 // A static block to initialize the predefined action groups
\r
86 AuthorizationCommon ac = new AuthorizationCommon();
\r
88 ACTIONGROUP_CRUDL = ac.new ActionGroup();
\r
89 ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME;
\r
90 ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL;
\r
92 ACTIONGROUP_RL = ac.new ActionGroup();
\r
93 ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;
\r
94 ACTIONGROUP_RL.actions = ACTIONSET_RL;
\r
98 final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class);
\r
101 // The "super" role has a predefined ID of "0" and a tenant ID of "0";
\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
107 final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";
\r
108 final public static String ROLE_TENANT_READER = "TENANT_READER";
\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
119 public static String ROLE_SPRING_ADMIN_ID = "-1";
\r
120 public static String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";
\r
122 public static Role getRole(String tenantId, String displayName) {
\r
125 String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
\r
126 role = AuthorizationStore.getRoleByName(roleName, tenantId);
\r
131 public static Role getRole(EntityManager em, String tenantId, String displayName) {
\r
134 String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
\r
135 role = AuthorizationStore.getRoleByName(em, roleName, tenantId);
\r
141 public static Role createRole(String tenantId, String name, String description) {
\r
142 return createRole(tenantId, name, description, false /* mutable by default */);
\r
145 public static Role createRole(String tenantId, String name, String description, boolean immutable) {
\r
146 Role role = new Role();
\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
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
165 * Add permission to the Spring Security tables
\r
166 * with assumption that resource is of type URI
\r
167 * @param permission configuration
\r
169 public static void addPermissionsForUri(Permission perm,
\r
170 PermissionRole permRole) throws PermissionException {
\r
172 // First check the integrity of the incoming arguments.
\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
181 List<String> principals = new ArrayList<String>();
\r
182 for (RoleValue roleValue : permRole.getRole()) {
\r
183 principals.add(roleValue.getRoleName());
\r
185 List<PermissionAction> permActions = perm.getAction();
\r
186 for (PermissionAction permAction : permActions) {
\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
195 // Only throw the exception if it is *not* an already-exists exception
\r
197 if (e.getCause() instanceof AlreadyExistsException == false) {
\r
204 private static Connection getConnection() throws NamingException, SQLException {
\r
205 return JDBCTools.getConnection(JDBCTools.CSPACE_REPOSITORY_NAME);
\r
209 * Spring security seems to require that all of our role names start
\r
210 * with the ROLE_PREFIX string.
\r
212 public static String getQualifiedRoleName(String tenantId, String name) {
\r
213 String result = name;
\r
215 String qualifiedName = ROLE_PREFIX + tenantId.toUpperCase() + "_" + name.toUpperCase();
\r
216 if (name.equals(qualifiedName) == false) {
\r
217 result = qualifiedName;
\r
223 private static ActionGroup getActionGroup(String actionGroupStr) {
\r
224 ActionGroup result = null;
\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
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
241 ActionGroup actionGroup = getActionGroup(actionGroupStr);
\r
242 result = createPermission(tenantId, resourceName, description, actionGroup);
\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
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
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
274 private static Permission createWorkflowPermission(TenantBindingType tenantBinding,
\r
275 ServiceBindingType serviceBinding,
\r
276 TransitionDef transitionDef,
\r
277 ActionGroup actionGroup)
\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
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
290 String tenantId = tenantBinding.getId();
\r
291 String resourceName = "/"
\r
292 + serviceBinding.getName().toLowerCase().trim()
\r
293 + workFlowServiceSuffix
\r
295 String description = "A generated workflow permission for actiongroup " + actionGroup.name;
\r
296 result = createPermission(tenantId, resourceName, description, actionGroup);
\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
309 private static PermissionRole createPermissionRole(EntityManager em,
\r
310 Permission permission,
\r
312 boolean enforceTenancy) throws Exception
\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
321 if (tenantIdsMatch == true) {
\r
322 permRole.setSubject(SubjectType.ROLE);
\r
324 // Set of the permission value list of the permrole
\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
334 // Set of the role value list of the permrole
\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
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
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
357 public static void createDefaultAccounts(TenantBindingConfigReaderImpl tenantBindingConfigReader) {
\r
358 if (logger.isDebugEnabled()) {
\r
359 logger.debug("ServiceMain.createDefaultAccounts starting...");
\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
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
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
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
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
420 pstmt.executeUpdate();
\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
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
450 pstmt.executeUpdate();
\r
451 } else if (logger.isDebugEnabled()) {
\r
452 logger.debug("createDefaultAccounts: user: "+adminAcctName
\r
453 +" already exists - skipping.");
\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
467 pstmt.executeUpdate();
\r
468 } else if (logger.isDebugEnabled()) {
\r
469 logger.debug("createDefaultAccounts: user: "+readerAcctName
\r
470 +" already exists - skipping.");
\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
497 pstmt.executeUpdate();
\r
498 } else if (logger.isDebugEnabled()) {
\r
499 logger.debug("createDefaultAccounts: user: "+adminAcctName
\r
500 +" already exists - skipping account generation.");
\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
515 pstmt.executeUpdate();
\r
516 } else if (logger.isDebugEnabled()) {
\r
517 logger.debug("createDefaultAccounts: user: "+readerAcctName
\r
518 +" already exists - skipping account creation.");
\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
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
535 throw new Exception("Unrecognized database system.");
\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
548 pstmt.executeUpdate();
\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
558 pstmt.executeUpdate();
\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
568 springAdminRoleCSID = rs.getString(1);
\r
569 if (logger.isDebugEnabled()) {
\r
570 logger.debug("createDefaultAccounts found Spring Admin role: "
\r
571 +springAdminRoleCSID);
\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
585 String getRoleCSIDSql =
\r
586 "SELECT csid from roles WHERE tenant_id=? and rolename=?";
\r
587 pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement
\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
597 throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)
\r
598 +" for tenant id: "+tId+" in roles!");
\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
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
610 rs = pstmt.executeQuery();
\r
611 // extract data from the ResultSet
\r
613 throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)
\r
614 +" for tenant id: "+tId+" in roles!");
\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
622 tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);
\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
638 throw new Exception("Unrecognized database system.");
\r
640 if (logger.isDebugEnabled()) {
\r
641 logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"
\r
642 +insertAccountRoleSQL);
\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
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
667 pstmt.executeUpdate();
\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
682 pstmt.executeUpdate();
\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
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
704 logger.debug(sqle.getStackTrace().toString());
\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
720 } catch (SQLException sqle) {
\r
721 if (logger.isDebugEnabled()) {
\r
722 logger.debug("SQL Exception closing statement/connection: "
\r
723 + sqle.getLocalizedMessage());
\r
729 private static String getDefaultAdminRole(String tenantId) {
\r
730 return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;
\r
733 private static String getDefaultReaderRole(String tenantId) {
\r
734 return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX;
\r
737 private static String getDefaultAdminUserID(String tenantName) {
\r
738 return TENANT_ADMIN_ACCT_PREFIX+tenantName;
\r
741 private static String getDefaultReaderUserID(String tenantName) {
\r
742 return TENANT_READER_ACCT_PREFIX+tenantName;
\r
745 static public PermissionAction createPermissionAction(Permission perm,
\r
746 ActionType actionType) {
\r
747 PermissionAction pa = new PermissionAction();
\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
759 static public PermissionAction update(Permission perm, PermissionAction permAction) {
\r
760 PermissionAction pa = new PermissionAction();
\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
771 private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
\r
772 TransitionDefList result = null;
\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
781 } catch (Exception e) {
\r
782 // Ignore this exception and return an empty non-null TransitionDefList
\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
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
802 public static void createDefaultPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions
\r
804 AuthZ.get().login(); //login to Spring Security manager
\r
806 EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);
\r
807 EntityManager em = null;
\r
810 em = emf.createEntityManager();
\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
823 em.getTransaction().begin();
\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
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
833 // Next, create a permission for each workflow transition supported by the service's document type.
\r
835 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
\r
836 for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) {
\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
842 // Create the permission for the read-only role
\r
843 Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionDef, ACTIONGROUP_RL);
\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
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
857 // Create the permission for the super-admin role. Note we use the same "adminPerm" instance we used for the "adminPermRole" instance
\r
859 persist(em, adminPerm, superRole, false);
\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
867 logger.warn("AuthZ refresh service binding property is set to FALSE so default roles and permissions will NOT be refreshed.");
\r
872 } catch (Exception e) {
\r
873 if (em != null && em.getTransaction().isActive()) {
\r
874 em.getTransaction().rollback();
\r
876 if (logger.isDebugEnabled()) {
\r
877 logger.debug("Caught exception and rolling back permission creation: ", e);
\r
882 JpaStorageUtils.releaseEntityManagerFactory(emf);
\r
887 private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) {
\r
888 PermissionRoleRel result = null;
\r
891 String whereClause = "where permissionId = :id and roleId = :roleId";
\r
892 HashMap<String, Object> params = new HashMap<String, Object>();
\r
893 params.put("id", permissionId);
\r
894 params.put("roleId", RoleId);
\r
896 result = (PermissionRoleRel) JpaStorageUtils.getEntity(em,
\r
897 PermissionRoleRel.class.getCanonicalName(), whereClause, params);
\r
898 } catch (Exception e) {
\r
899 //Do nothing. Will return null;
\r
906 * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction
\r
908 private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy) throws Exception {
\r
909 AuthorizationStore authzStore = new AuthorizationStore();
\r
910 // First persist the Permission record
\r
911 authzStore.store(em, permission);
\r
913 // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload)
\r
914 // Create a PermissionRoleRel (the database relation table for the permission and role)
\r
915 PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid());
\r
916 if (permRoleRel == null) {
\r
917 PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);
\r
918 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
\r
919 PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);
\r
920 for (PermissionRoleRel prr : permRoleRels) {
\r
921 authzStore.store(em, prr);
\r
923 Profiler profiler = new Profiler(AuthorizationCommon.class, 2);
\r
925 // Add a corresponding entry in the Spring Security Tables
\r
926 addPermissionsForUri(permission, permRole);
\r
928 logger.debug("Finished full perm generation for "
\r
929 + ":" + permission.getTenantId()
\r
930 + ":" + permission.getResourceName()
\r
931 + ":" + ACTIONGROUP_RL
\r
932 + ":" + profiler.getCumulativeTime());
\r