1 package org.collectionspace.services.common.authorization_mgt;
3 import java.security.MessageDigest;
4 import java.security.NoSuchAlgorithmException;
5 import java.sql.Connection;
6 import java.sql.PreparedStatement;
7 import java.sql.ResultSet;
8 import java.sql.SQLException;
9 import java.sql.Statement;
10 import java.util.ArrayList;
11 import java.util.Date;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.Hashtable;
15 import java.util.List;
16 import java.util.UUID;
18 import javax.naming.NamingException;
19 import javax.persistence.EntityManager;
20 import javax.persistence.EntityManagerFactory;
22 import org.collectionspace.authentication.AuthN;
23 import org.collectionspace.services.account.AccountListItem;
25 import org.collectionspace.services.authentication.Token;
26 import org.collectionspace.services.authorization.AuthZ;
27 import org.collectionspace.services.authorization.CSpaceAction;
28 import org.collectionspace.services.authorization.PermissionException;
29 import org.collectionspace.services.authorization.PermissionRole;
30 import org.collectionspace.services.authorization.PermissionRoleRel;
31 import org.collectionspace.services.authorization.PermissionValue;
32 import org.collectionspace.services.authorization.Role;
33 import org.collectionspace.services.authorization.RoleValue;
34 import org.collectionspace.services.authorization.SubjectType;
35 import org.collectionspace.services.authorization.URIResourceImpl;
36 import org.collectionspace.services.authorization.perms.ActionType;
37 import org.collectionspace.services.authorization.perms.EffectType;
38 import org.collectionspace.services.authorization.perms.Permission;
39 import org.collectionspace.services.authorization.perms.PermissionAction;
41 import org.collectionspace.services.client.Profiler;
42 import org.collectionspace.services.client.RoleClient;
43 import org.collectionspace.services.client.workflow.WorkflowClient;
44 import org.collectionspace.services.common.config.ServiceConfigUtils;
45 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
46 import org.collectionspace.services.common.context.ServiceBindingUtils;
47 import org.collectionspace.services.common.document.DocumentHandler;
48 import org.collectionspace.services.common.security.SecurityUtils;
49 import org.collectionspace.services.common.storage.DatabaseProductType;
50 import org.collectionspace.services.common.storage.JDBCTools;
51 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
52 import org.collectionspace.services.config.service.ServiceBindingType;
53 import org.collectionspace.services.config.tenant.EmailConfig;
54 import org.collectionspace.services.config.tenant.PasswordResetConfig;
55 import org.collectionspace.services.config.tenant.TenantBindingType;
56 import org.collectionspace.services.lifecycle.Lifecycle;
57 import org.collectionspace.services.lifecycle.TransitionDef;
58 import org.collectionspace.services.lifecycle.TransitionDefList;
60 //import org.mortbay.log.Log;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63 import org.springframework.security.acls.model.AlreadyExistsException;
66 public class AuthorizationCommon {
68 final public static String REFRESH_AUTZ_PROP = "refreshAuthZOnStartup";
71 // For token generation and password reset
73 final private static String DEFAULT_PASSWORD_RESET_EMAIL_MESSAGE = "Hello {{greeting}},\n\r\n\rYou've started the process to reset your CollectionSpace account password. To finish resetting your password, go to the Reset Password page {{link}} on CollectionSpace.\n\r\n\rIf clicking the link doesn't work, copy and paste the following link into your browser address bar and click Go.\n\r\n\r{{link}}\n\r Thanks,\n\r\n\r CollectionSpace Administrator\n\r\n\rPlease do not reply to this email. This mailbox is not monitored and you will not receive a response. For assistance, contact your CollectionSpace Administrator directly.";
74 final private static String tokensalt = "74102328UserDetailsReset";
75 final private static int TIME_SCALAR = 100000;
76 private static final String DEFAULT_PASSWORD_RESET_EMAIL_SUBJECT = "Password reset for CollectionSpace account";
79 // ActionGroup labels/constants
83 final public static String ACTIONGROUP_CRUDL_NAME = "CRUDL";
84 final public static ActionType[] ACTIONSET_CRUDL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.DELETE, ActionType.SEARCH};
86 final public static String ACTIONGROUP_RL_NAME = "RL";
87 final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};
89 static ActionGroup ACTIONGROUP_CRUDL;
90 static ActionGroup ACTIONGROUP_RL;
92 // A static block to initialize the predefined action groups
95 ACTIONGROUP_CRUDL = new ActionGroup();
96 ACTIONGROUP_CRUDL.name = ACTIONGROUP_CRUDL_NAME;
97 ACTIONGROUP_CRUDL.actions = ACTIONSET_CRUDL;
99 ACTIONGROUP_RL = new ActionGroup();
100 ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;
101 ACTIONGROUP_RL.actions = ACTIONSET_RL;
105 final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class);
107 final public static String ROLE_TENANT_ADMINISTRATOR = "TENANT_ADMINISTRATOR";
108 final public static String ROLE_TENANT_READER = "TENANT_READER";
110 public static final String TENANT_MANAGER_USER = "tenantManager";
111 public static final String TENANT_MANAGER_SCREEN_NAME = TENANT_MANAGER_USER;
112 public static final String DEFAULT_TENANT_MANAGER_PASSWORD = "manage";
113 public static final String DEFAULT_TENANT_MANAGER_EMAIL = "tenantManager@collectionspace.org";
115 public static final String TENANT_ADMIN_ACCT_PREFIX = "admin@";
116 public static final String TENANT_READER_ACCT_PREFIX = "reader@";
117 public static final String ROLE_PREFIX = "ROLE_";
118 public static final String TENANT_ADMIN_ROLE_SUFFIX = "_TENANT_ADMINISTRATOR";
119 public static final String TENANT_READER_ROLE_SUFFIX = "_TENANT_READER";
120 public static final String DEFAULT_ADMIN_PASSWORD = "Administrator";
121 public static final String DEFAULT_READER_PASSWORD = "reader";
123 // SQL for init tasks
124 final private static String INSERT_ACCOUNT_ROLE_SQL_MYSQL =
125 "INSERT INTO accounts_roles(account_id, user_id, role_id, role_name, created_at)"
126 +" VALUES(?, ?, ?, ?, now())";
127 final private static String INSERT_ACCOUNT_ROLE_SQL_POSTGRES =
128 "INSERT INTO accounts_roles(HJID, account_id, user_id, role_id, role_name, created_at)"
129 +" VALUES(nextval('hibernate_sequence'), ?, ?, ?, ?, now())";
130 final private static String QUERY_USERS_SQL =
131 "SELECT username FROM users WHERE username LIKE '"
132 +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"+TENANT_READER_ACCT_PREFIX+"%'";
133 final private static String INSERT_USER_SQL =
134 "INSERT INTO users (username,passwd, created_at) VALUES (?,?, now())";
135 final private static String INSERT_ACCOUNT_SQL =
136 "INSERT INTO accounts_common "
137 + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "
138 + "VALUES (?,?,?,'ACTIVE',?, 'immutable', 'immutable', now())";
140 // TENANT MANAGER specific SQL
141 final private static String QUERY_TENANT_MGR_USER_SQL =
142 "SELECT username FROM users WHERE username = '"+TENANT_MANAGER_USER+"'";
143 final private static String GET_TENANT_MGR_ROLE_SQL =
144 "SELECT csid from roles WHERE tenant_id='" + AuthN.ALL_TENANTS_MANAGER_TENANT_ID + "' and rolename=?";
147 public static Role getRole(String tenantId, String displayName) {
150 String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
151 role = AuthorizationStore.getRoleByName(roleName, tenantId);
156 public static Role getRole(EntityManager em, String tenantId, String displayName) {
159 String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
160 role = AuthorizationStore.getRoleByName(em, roleName, tenantId);
166 public static Role createRole(String tenantId, String name, String description) {
167 return createRole(tenantId, name, description, false /* mutable by default */);
170 public static Role createRole(String tenantId, String name, String description, boolean immutable) {
171 Role role = new Role();
173 role.setCreatedAtItem(new Date());
174 role.setDisplayName(name);
175 String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, name);
176 role.setRoleName(roleName);
177 String id = UUID.randomUUID().toString(); //FIXME: The qualified role name should be unique enough to use as an ID/key
179 role.setDescription(description);
180 role.setTenantId(tenantId);
181 if (immutable == true) {
182 role.setMetadataProtection(RoleClient.IMMUTABLE);
183 role.setPermsProtection(RoleClient.IMMUTABLE);
190 * Add permission to the Spring Security tables
191 * with assumption that resource is of type URI
192 * @param permission configuration
194 public static void addPermissionsForUri(Permission perm,
195 PermissionRole permRole) throws PermissionException {
197 // First check the integrity of the incoming arguments.
199 if (!perm.getCsid().equals(permRole.getPermission().get(0).getPermissionId())) {
200 throw new IllegalArgumentException("permission ids do not"
201 + " match for role=" + permRole.getRole().get(0).getRoleName()
202 + " with permissionId=" + permRole.getPermission().get(0).getPermissionId()
203 + " for permission with csid=" + perm.getCsid());
206 List<String> principals = new ArrayList<String>();
207 for (RoleValue roleValue : permRole.getRole()) {
208 principals.add(roleValue.getRoleName());
210 List<PermissionAction> permActions = perm.getAction();
211 for (PermissionAction permAction : permActions) {
213 CSpaceAction action = URIResourceImpl.getAction(permAction.getName());
214 URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
215 perm.getResourceName(), action);
216 boolean grant = perm.getEffect().equals(EffectType.PERMIT) ? true : false;
217 AuthZ.get().addPermissions(uriRes, principals.toArray(new String[0]), grant);//CSPACE-4967
218 } catch (PermissionException e) {
220 // Only throw the exception if it is *not* an already-exists exception
222 if (e.getCause() instanceof AlreadyExistsException == false) {
229 private static Connection getConnection(String databaseName) throws NamingException, SQLException {
230 return JDBCTools.getConnection(JDBCTools.CSPACE_DATASOURCE_NAME,
235 * Spring security seems to require that all of our role names start
236 * with the ROLE_PREFIX string.
238 public static String getQualifiedRoleName(String tenantId, String name) {
239 String result = name;
241 String qualifiedName = ROLE_PREFIX + tenantId.toUpperCase() + "_" + name.toUpperCase();
242 if (name.equals(qualifiedName) == false) {
243 result = qualifiedName;
249 private static ActionGroup getActionGroup(String actionGroupStr) {
250 ActionGroup result = null;
252 if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_CRUDL_NAME)) {
253 result = ACTIONGROUP_CRUDL;
254 } else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_RL_NAME)) {
255 result = ACTIONGROUP_RL;
261 public static Permission createPermission(String tenantId,
264 String actionGroupStr) {
265 Permission result = null;
267 ActionGroup actionGroup = getActionGroup(actionGroupStr);
268 result = createPermission(tenantId, resourceName, description, actionGroup);
273 private static Permission createPermission(String tenantId,
276 ActionGroup actionGroup) {
278 + "-" + resourceName.replace('/', '_') // Remove the slashes so the ID can be used in a URI/URL
279 + "-" + actionGroup.name;
280 Permission perm = new Permission();
282 perm.setDescription(description);
283 perm.setCreatedAtItem(new Date());
284 perm.setResourceName(resourceName.toLowerCase().trim());
285 perm.setEffect(EffectType.PERMIT);
286 perm.setTenantId(tenantId);
288 perm.setActionGroup(actionGroup.name);
289 ArrayList<PermissionAction> pas = new ArrayList<PermissionAction>();
291 for (ActionType actionType : actionGroup.actions) {
292 PermissionAction permAction = createPermissionAction(perm, actionType);
299 private static Permission createWorkflowPermission(TenantBindingType tenantBinding,
300 ServiceBindingType serviceBinding,
301 String transitionVerb,
302 ActionGroup actionGroup)
304 Permission result = null;
305 String workFlowServiceSuffix;
306 String transitionName;
307 if (transitionVerb != null) {
308 transitionName = transitionVerb;
309 workFlowServiceSuffix = WorkflowClient.SERVICE_AUTHZ_SUFFIX;
311 transitionName = ""; //since the transitionDef was null, we're assuming that this is the base workflow permission to be created
312 workFlowServiceSuffix = WorkflowClient.SERVICE_PATH;
315 String tenantId = tenantBinding.getId();
316 String resourceName = "/"
317 + serviceBinding.getName().toLowerCase().trim()
318 + workFlowServiceSuffix
320 String description = "A generated workflow permission for actiongroup " + actionGroup.name;
321 result = createPermission(tenantId, resourceName, description, actionGroup);
323 if (logger.isDebugEnabled() == true) {
324 logger.debug("Generated a workflow permission: "
325 + result.getResourceName()
326 + ":" + transitionName
327 + ":" + "tenant id=" + result.getTenantId()
328 + ":" + actionGroup.name);
334 private static PermissionRole createPermissionRole(EntityManager em,
335 Permission permission,
337 boolean enforceTenancy) throws Exception
339 PermissionRole permRole = new PermissionRole();
340 // Check to see if the tenant ID of the permission and the tenant ID of the role match
341 boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId());
342 if (tenantIdsMatch == false && enforceTenancy == false) {
343 tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched.
346 if (tenantIdsMatch == true) {
347 permRole.setSubject(SubjectType.ROLE);
349 // Set of the permission value list of the permrole
351 List<PermissionValue> permValues = new ArrayList<PermissionValue>();
352 PermissionValue permValue = new PermissionValue();
353 permValue.setPermissionId(permission.getCsid());
354 permValue.setResourceName(permission.getResourceName().toLowerCase());
355 permValue.setActionGroup(permission.getActionGroup());
356 permValues.add(permValue);
357 permRole.setPermission(permValues);
359 // Set of the role value list of the permrole
361 List<RoleValue> roleValues = new ArrayList<RoleValue>();
362 RoleValue rv = new RoleValue();
363 // This needs to use the qualified name, not the display name
364 rv.setRoleName(role.getRoleName());
365 rv.setRoleId(role.getCsid());
367 permRole.setRole(roleValues);
369 String errMsg = "The tenant ID of the role: " + role.getTenantId()
370 + " did not match the tenant ID of the permission: " + permission.getTenantId();
371 throw new Exception(errMsg);
377 private static Hashtable<String, String> getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) {
379 // Note that this only handles tenants not marked as "createDisabled"
380 Hashtable<String, TenantBindingType> tenantBindings =
381 tenantBindingConfigReader.getTenantBindings();
382 Hashtable<String, String> tenantInfo = new Hashtable<String, String>();
383 for (TenantBindingType tenantBinding : tenantBindings.values()) {
384 String tId = tenantBinding.getId();
385 String tName = tenantBinding.getName();
386 tenantInfo.put(tId, tName);
387 if (logger.isDebugEnabled()) {
388 logger.debug("getTenantNamesFromConfig found configured tenant id: "+tId+" name: "+tName);
394 private static ArrayList<String> compileExistingTenants(Connection conn, Hashtable<String, String> tenantInfo)
395 throws SQLException, Exception {
396 Statement stmt = null;
397 ArrayList<String> existingTenants = new ArrayList<String>();
398 // First find or create the tenants
399 final String queryTenantSQL = "SELECT id,name FROM tenants";
401 stmt = conn.createStatement();
402 ResultSet rs = stmt.executeQuery(queryTenantSQL);
404 String tId = rs.getString("id");
405 String tName = rs.getString("name");
406 if(tenantInfo.containsKey(tId)) {
407 existingTenants.add(tId);
408 if(!tenantInfo.get(tId).equalsIgnoreCase(tName)) {
409 logger.warn("Configured name for tenant: "
410 +tId+" in repository: "+tName
411 +" does not match config'd name: "+ tenantInfo.get(tId));
416 } catch(Exception e) {
423 return existingTenants;
426 private static void createMissingTenants(Connection conn, Hashtable<String, String> tenantInfo,
427 ArrayList<String> existingTenants) throws SQLException, Exception {
428 // Need to define and look for a createDisabled attribute in tenant config
429 final String insertTenantSQL =
430 "INSERT INTO tenants (id,name,authorities_initialized,disabled,created_at) VALUES (?,?,FALSE,FALSE,now())";
431 PreparedStatement pstmt = null;
433 pstmt = conn.prepareStatement(insertTenantSQL); // create a statement
434 for(String tId : tenantInfo.keySet()) {
435 if(existingTenants.contains(tId)) {
436 if (logger.isDebugEnabled()) {
437 logger.debug("createMissingTenants: tenant exists (skipping): "
438 +tenantInfo.get(tId));
442 pstmt.setString(1, tId); // set id param
443 pstmt.setString(2, tenantInfo.get(tId)); // set name param
444 if (logger.isDebugEnabled()) {
445 logger.debug("createMissingTenants adding entry for tenant: "+tId);
447 pstmt.executeUpdate();
450 } catch(Exception e) {
458 private static ArrayList<String> findOrCreateDefaultUsers(Connection conn, Hashtable<String, String> tenantInfo)
459 throws SQLException, Exception {
460 // Second find or create the users
461 Statement stmt = null;
462 PreparedStatement pstmt = null;
463 ArrayList<String> usersInRepo = new ArrayList<String>();
465 stmt = conn.createStatement();
466 ResultSet rs = stmt.executeQuery(QUERY_USERS_SQL);
468 String uName = rs.getString("username");
469 usersInRepo.add(uName);
472 pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement
473 for(String tName : tenantInfo.values()) {
474 String adminAcctName = getDefaultAdminUserID(tName);
475 if(!usersInRepo.contains(adminAcctName)) {
476 String secEncPasswd = SecurityUtils.createPasswordHash(
477 adminAcctName, DEFAULT_ADMIN_PASSWORD);
478 pstmt.setString(1, adminAcctName); // set username param
479 pstmt.setString(2, secEncPasswd); // set passwd param
480 if (logger.isDebugEnabled()) {
481 logger.debug("createDefaultUsersAndAccounts adding user: "
482 +adminAcctName+" for tenant: "+tName);
484 pstmt.executeUpdate();
485 } else if (logger.isDebugEnabled()) {
486 logger.debug("createDefaultUsersAndAccounts: user: "+adminAcctName
487 +" already exists - skipping.");
491 String readerAcctName = getDefaultReaderUserID(tName);
492 if(!usersInRepo.contains(readerAcctName)) {
493 String secEncPasswd = SecurityUtils.createPasswordHash(
494 readerAcctName, DEFAULT_READER_PASSWORD);
495 pstmt.setString(1, readerAcctName); // set username param
496 pstmt.setString(2, secEncPasswd); // set passwd param
497 if (logger.isDebugEnabled()) {
498 logger.debug("createDefaultUsersAndAccounts adding user: "
499 +readerAcctName+" for tenant: "+tName);
501 pstmt.executeUpdate();
502 } else if (logger.isDebugEnabled()) {
503 logger.debug("createDefaultUsersAndAccounts: user: "+readerAcctName
504 +" already exists - skipping.");
508 } catch(Exception e) {
519 private static void findOrCreateDefaultAccounts(Connection conn, Hashtable<String, String> tenantInfo,
520 ArrayList<String> usersInRepo,
521 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs)
522 throws SQLException, Exception {
523 // Third, create the accounts. Assume that if the users were already there,
524 // then the accounts were as well
525 PreparedStatement pstmt = null;
527 pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement
528 for(String tId : tenantInfo.keySet()) {
529 String tName = tenantInfo.get(tId);
530 String adminCSID = UUID.randomUUID().toString();
531 tenantAdminAcctCSIDs.put(tId, adminCSID);
532 String adminAcctName = getDefaultAdminUserID(tName);
533 if(!usersInRepo.contains(adminAcctName)) {
534 pstmt.setString(1, adminCSID); // set csid param
535 pstmt.setString(2, adminAcctName); // set email param (bogus)
536 pstmt.setString(3, adminAcctName); // set userid param
537 pstmt.setString(4, "Administrator");// set screen name param
538 if (logger.isDebugEnabled()) {
539 logger.debug("createDefaultAccounts adding account: "
540 +adminAcctName+" for tenant: "+tName);
542 pstmt.executeUpdate();
543 } else if (logger.isDebugEnabled()) {
544 logger.debug("createDefaultAccounts: user: "+adminAcctName
545 +" already exists - skipping account generation.");
548 String readerCSID = UUID.randomUUID().toString();
549 tenantReaderAcctCSIDs.put(tId, readerCSID);
550 String readerAcctName = getDefaultReaderUserID(tName);
551 if(!usersInRepo.contains(readerAcctName)) {
552 pstmt.setString(1, readerCSID); // set csid param
553 pstmt.setString(2, readerAcctName); // set email param (bogus)
554 pstmt.setString(3, readerAcctName); // set userid param
555 pstmt.setString(4, "Reader"); // set screen name param
556 if (logger.isDebugEnabled()) {
557 logger.debug("createDefaultAccounts adding account: "
558 +readerAcctName+" for tenant: "+tName);
560 pstmt.executeUpdate();
561 } else if (logger.isDebugEnabled()) {
562 logger.debug("createDefaultAccounts: user: "+readerAcctName
563 +" already exists - skipping account creation.");
567 } catch(Exception e) {
575 private static boolean findOrCreateTenantManagerUserAndAccount(Connection conn)
576 throws SQLException, Exception {
577 // Find or create the special tenant manager account.
578 // Later can make the user name for tenant manager be configurable, settable.
579 Statement stmt = null;
580 PreparedStatement pstmt = null;
581 boolean created = false;
583 boolean foundTMgrUser = false;
584 stmt = conn.createStatement();
585 ResultSet rs = stmt.executeQuery(QUERY_TENANT_MGR_USER_SQL);
586 // Should only find one - only consider it
588 String uName = rs.getString("username");
589 foundTMgrUser = uName.equals(TENANT_MANAGER_USER);
593 pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement
594 String secEncPasswd = SecurityUtils.createPasswordHash(
595 TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD);
596 pstmt.setString(1, TENANT_MANAGER_USER); // set username param
597 pstmt.setString(2, secEncPasswd); // set passwd param
598 if (logger.isDebugEnabled()) {
599 logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager user: "
600 +TENANT_MANAGER_USER);
602 pstmt.executeUpdate();
604 // Now create the account to match
605 pstmt = conn.prepareStatement(INSERT_ACCOUNT_SQL); // create a statement
606 pstmt.setString(1, AuthN.TENANT_MANAGER_ACCT_ID); // set csid param
607 pstmt.setString(2, DEFAULT_TENANT_MANAGER_EMAIL); // set email param (bogus)
608 pstmt.setString(3, TENANT_MANAGER_USER); // set userid param
609 pstmt.setString(4, TENANT_MANAGER_SCREEN_NAME);// set screen name param
610 if (logger.isDebugEnabled()) {
611 logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager account: "
612 +TENANT_MANAGER_USER);
614 pstmt.executeUpdate();
617 } else if (logger.isDebugEnabled()) {
618 logger.debug("findOrCreateTenantManagerUserAndAccount: tenant manager: "+TENANT_MANAGER_USER
619 +" already exists.");
621 } catch(Exception e) {
632 private static void bindDefaultAccountsToTenants(Connection conn, DatabaseProductType databaseProductType,
633 Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,
634 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs)
635 throws SQLException, Exception {
636 // Fourth, bind accounts to tenants. Assume that if the users were already there,
637 // then the accounts were bound to tenants correctly
638 PreparedStatement pstmt = null;
640 String insertAccountTenantSQL;
641 if (databaseProductType == DatabaseProductType.MYSQL) {
642 insertAccountTenantSQL =
643 "INSERT INTO accounts_tenants (TENANTS_ACCOUNTS_COMMON_CSID,tenant_id) "
645 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
646 insertAccountTenantSQL =
647 "INSERT INTO accounts_tenants (HJID, TENANTS_ACCOUNTS_COMMON_CSID,tenant_id) "
648 + " VALUES(nextval('hibernate_sequence'), ?, ?)";
650 throw new Exception("Unrecognized database system.");
652 pstmt = conn.prepareStatement(insertAccountTenantSQL); // create a statement
653 for(String tId : tenantInfo.keySet()) {
654 String tName = tenantInfo.get(tId);
655 if(!usersInRepo.contains(getDefaultAdminUserID(tName))) {
656 String adminAcct = tenantAdminAcctCSIDs.get(tId);
657 pstmt.setString(1, adminAcct); // set acct CSID param
658 pstmt.setString(2, tId); // set tenant_id param
659 if (logger.isDebugEnabled()) {
660 logger.debug("createDefaultAccounts binding account id: "
661 +adminAcct+" to tenant id: "+tId);
663 pstmt.executeUpdate();
665 if(!usersInRepo.contains(getDefaultReaderUserID(tName))) {
666 String readerAcct = tenantReaderAcctCSIDs.get(tId);
667 pstmt.setString(1, readerAcct); // set acct CSID param
668 pstmt.setString(2, tId); // set tenant_id param
669 if (logger.isDebugEnabled()) {
670 logger.debug("createDefaultAccounts binding account id: "
671 +readerAcct+" to tenant id: "+tId);
673 pstmt.executeUpdate();
677 } catch(Exception e) {
686 private static String findOrCreateDefaultRoles(Connection conn, Hashtable<String, String> tenantInfo,
687 Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs)
688 throws SQLException, Exception {
689 // Fifth, fetch and save the default roles
690 String springAdminRoleCSID = null;
691 Statement stmt = null;
692 PreparedStatement pstmt = null;
694 final String querySpringRole =
695 "SELECT csid from roles WHERE rolename='"+AuthN.ROLE_SPRING_ADMIN_NAME+"'";
696 stmt = conn.createStatement();
697 ResultSet rs = stmt.executeQuery(querySpringRole);
699 springAdminRoleCSID = rs.getString(1);
700 if (logger.isDebugEnabled()) {
701 logger.debug("createDefaultAccounts found Spring Admin role: "
702 +springAdminRoleCSID);
705 final String insertSpringAdminRoleSQL =
706 "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "
707 + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";
708 stmt.executeUpdate(insertSpringAdminRoleSQL);
709 springAdminRoleCSID = "-1";
710 if (logger.isDebugEnabled()) {
711 logger.debug("createDefaultAccounts CREATED Spring Admin role: "
712 +springAdminRoleCSID);
716 final String getRoleCSIDSql =
717 "SELECT csid from roles WHERE tenant_id=? and rolename=?";
718 pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement
720 for(String tId : tenantInfo.keySet()) {
721 pstmt.setString(1, tId); // set tenant_id param
722 pstmt.setString(2, getDefaultAdminRole(tId)); // set rolename param
723 rs = pstmt.executeQuery();
724 // extract data from the ResultSet
726 throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)
727 +" for tenant id: "+tId+" in roles!");
729 String tenantAdminRoleCSID = rs.getString(1);
730 if (logger.isDebugEnabled()) {
731 logger.debug("createDefaultAccounts found role: "
732 +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID
733 +") for tenant id: "+tId);
735 tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);
736 pstmt.setString(1, tId); // set tenant_id param
737 pstmt.setString(2, getDefaultReaderRole(tId)); // set rolename param
739 rs = pstmt.executeQuery();
740 // extract data from the ResultSet
742 throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)
743 +" for tenant id: "+tId+" in roles!");
745 String tenantReaderRoleCSID = rs.getString(1);
746 if (logger.isDebugEnabled()) {
747 logger.debug("createDefaultAccounts found role: "
748 +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID
749 +") for tenant id: "+tId);
751 tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);
755 } catch(Exception e) {
763 return springAdminRoleCSID;
766 private static String findTenantManagerRole(Connection conn )
767 throws SQLException, RuntimeException, Exception {
768 String tenantMgrRoleCSID = null;
769 PreparedStatement pstmt = null;
771 String rolename = getQualifiedRoleName(AuthN.ALL_TENANTS_MANAGER_TENANT_ID,
772 AuthN.ROLE_ALL_TENANTS_MANAGER);
773 pstmt = conn.prepareStatement(GET_TENANT_MGR_ROLE_SQL); // create a statement
775 pstmt.setString(1, rolename); // set rolename param
776 rs = pstmt.executeQuery();
778 tenantMgrRoleCSID = rs.getString(1);
779 if (logger.isDebugEnabled()) {
780 logger.debug("findTenantManagerRole found Tenant Mgr role: "
785 } catch(Exception e) {
791 if(tenantMgrRoleCSID==null)
792 throw new RuntimeException("findTenantManagerRole: Cound not find tenant Manager Role!");
793 return tenantMgrRoleCSID;
796 private static void bindAccountsToRoles(Connection conn, DatabaseProductType databaseProductType,
797 Hashtable<String, String> tenantInfo, ArrayList<String> usersInRepo,
798 String springAdminRoleCSID,
799 Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs,
800 Hashtable<String, String> tenantAdminAcctCSIDs, Hashtable<String, String> tenantReaderAcctCSIDs)
801 throws SQLException, Exception {
802 // Sixth, bind the accounts to roles. If the users already existed,
803 // we'll assume they were set up correctly.
804 PreparedStatement pstmt = null;
806 String insertAccountRoleSQL;
807 if (databaseProductType == DatabaseProductType.MYSQL) {
808 insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;
809 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
810 insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;
812 throw new Exception("Unrecognized database system.");
814 if (logger.isDebugEnabled()) {
815 logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"
816 +insertAccountRoleSQL);
818 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement
819 for(String tId : tenantInfo.keySet()) {
820 String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId));
821 if(!usersInRepo.contains(adminUserId)) {
822 String adminAcct = tenantAdminAcctCSIDs.get(tId);
823 String adminRoleId = tenantAdminRoleCSIDs.get(tId);
824 pstmt.setString(1, adminAcct); // set acct CSID param
825 pstmt.setString(2, adminUserId); // set user_id param
826 pstmt.setString(3, adminRoleId); // set role_id param
827 pstmt.setString(4, getDefaultAdminRole(tId)); // set rolename param
828 if (logger.isDebugEnabled()) {
829 logger.debug("createDefaultAccounts binding account: "
830 +adminUserId+" to Admin role("+adminRoleId
831 +") for tenant id: "+tId);
833 pstmt.executeUpdate();
834 // Now add the Spring Admin Role to the admin accounts
835 pstmt.setString(3, springAdminRoleCSID); // set role_id param
836 pstmt.setString(4, AuthN.ROLE_SPRING_ADMIN_NAME); // set rolename param
837 if (logger.isDebugEnabled()) {
838 logger.debug("createDefaultAccounts binding account: "
839 +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
841 pstmt.executeUpdate();
843 String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));
844 if(!usersInRepo.contains(readerUserId)) {
845 String readerAcct = tenantReaderAcctCSIDs.get(tId);
846 String readerRoleId = tenantReaderRoleCSIDs.get(tId);
847 pstmt.setString(1, readerAcct); // set acct CSID param
848 pstmt.setString(2, readerUserId); // set user_id param
849 pstmt.setString(3, readerRoleId); // set role_id param
850 pstmt.setString(4, getDefaultReaderRole(tId)); // set rolename param
851 if (logger.isDebugEnabled()) {
852 logger.debug("createDefaultAccounts binding account: "
853 +readerUserId+" to Reader role("+readerRoleId
854 +") for tenant id: "+tId);
856 pstmt.executeUpdate();
860 } catch(Exception e) {
868 private static void bindTenantManagerAccountRole(Connection conn, DatabaseProductType databaseProductType,
869 String tenantManagerUserID, String tenantManagerAccountID, String tenantManagerRoleID, String tenantManagerRoleName )
870 throws SQLException, Exception {
871 PreparedStatement pstmt = null;
873 String insertAccountRoleSQL;
874 if (databaseProductType == DatabaseProductType.MYSQL) {
875 insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;
876 } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
877 insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;
879 throw new Exception("Unrecognized database system.");
881 if (logger.isDebugEnabled()) {
882 logger.debug("bindTenantManagerAccountRole binding account to role with SQL:\n"
883 +insertAccountRoleSQL);
885 pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement
886 pstmt.setString(1, tenantManagerAccountID); // set acct CSID param
887 pstmt.setString(2, tenantManagerUserID); // set user_id param
888 pstmt.setString(3, tenantManagerRoleID); // set role_id param
889 pstmt.setString(4, tenantManagerRoleName); // set rolename param
890 if (logger.isDebugEnabled()) {
891 logger.debug("bindTenantManagerAccountRole binding user: "
892 +tenantManagerUserID+" to Admin role("+tenantManagerRoleName+")");
894 pstmt.executeUpdate();
895 /* At this point, tenant manager should not need the Spring Admin Role
896 pstmt.setString(3, springAdminRoleCSID); // set role_id param
897 pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param
898 if (logger.isDebugEnabled()) {
899 logger.debug("createDefaultAccounts binding account: "
900 +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
902 pstmt.executeUpdate();
905 } catch(Exception e) {
913 public static void createDefaultAccounts(
914 TenantBindingConfigReaderImpl tenantBindingConfigReader,
915 DatabaseProductType databaseProductType,
916 String cspaceDatabaseName) throws Exception {
918 logger.debug("ServiceMain.createDefaultAccounts starting...");
920 Hashtable<String, String> tenantInfo = getTenantNamesFromConfig(tenantBindingConfigReader);
921 Connection conn = null;
922 // TODO - need to put in tests for existence first.
923 // We could just look for the accounts per tenant up front, and assume that
924 // the rest is there if the accounts are.
925 // Could add a sql script to remove these if need be - Spring only does roles,
926 // and we're not touching that, so we could safely toss the
927 // accounts, users, account-tenants, account-roles, and start over.
929 conn = getConnection(cspaceDatabaseName);
930 ArrayList<String> existingTenants = compileExistingTenants(conn, tenantInfo);
932 // Note that this only creates tenants not marked as "createDisabled"
933 createMissingTenants(conn, tenantInfo, existingTenants);
935 ArrayList<String> usersInRepo = findOrCreateDefaultUsers(conn, tenantInfo);
937 Hashtable<String, String> tenantAdminAcctCSIDs = new Hashtable<String, String>();
938 Hashtable<String, String> tenantReaderAcctCSIDs = new Hashtable<String, String>();
939 findOrCreateDefaultAccounts(conn, tenantInfo, usersInRepo,
940 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
942 bindDefaultAccountsToTenants(conn, databaseProductType, tenantInfo, usersInRepo,
943 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
945 Hashtable<String, String> tenantAdminRoleCSIDs = new Hashtable<String, String>();
946 Hashtable<String, String> tenantReaderRoleCSIDs = new Hashtable<String, String>();
947 String springAdminRoleCSID = findOrCreateDefaultRoles(conn, tenantInfo,
948 tenantAdminRoleCSIDs, tenantReaderRoleCSIDs);
950 bindAccountsToRoles(conn, databaseProductType,
951 tenantInfo, usersInRepo, springAdminRoleCSID,
952 tenantAdminRoleCSIDs, tenantReaderRoleCSIDs,
953 tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
955 boolean createdTenantMgrAccount = findOrCreateTenantManagerUserAndAccount(conn);
956 if(createdTenantMgrAccount) {
957 // If we created the account, we need to create the bindings. Otherwise, assume they
958 // are all set (from previous initialization).
959 String tenantManagerRoleCSID = findTenantManagerRole(conn);
960 bindTenantManagerAccountRole(conn, databaseProductType,
961 TENANT_MANAGER_USER, AuthN.TENANT_MANAGER_ACCT_ID,
962 tenantManagerRoleCSID, AuthN.ROLE_ALL_TENANTS_MANAGER);
964 } catch (Exception e) {
965 logger.debug("Exception in createDefaultAccounts: " + e.getLocalizedMessage());
971 } catch (SQLException sqle) {
972 if (logger.isDebugEnabled()) {
973 logger.debug("SQL Exception closing statement/connection: " + sqle.getLocalizedMessage());
979 private static String getDefaultAdminRole(String tenantId) {
980 return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;
983 private static String getDefaultReaderRole(String tenantId) {
984 return ROLE_PREFIX+tenantId+TENANT_READER_ROLE_SUFFIX;
987 private static String getDefaultAdminUserID(String tenantName) {
988 return TENANT_ADMIN_ACCT_PREFIX+tenantName;
991 private static String getDefaultReaderUserID(String tenantName) {
992 return TENANT_READER_ACCT_PREFIX+tenantName;
995 static public PermissionAction createPermissionAction(Permission perm,
996 ActionType actionType) {
997 PermissionAction pa = new PermissionAction();
999 CSpaceAction action = URIResourceImpl.getAction(actionType);
1000 URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
1001 perm.getResourceName(), action);
1002 pa.setName(actionType);
1003 pa.setObjectIdentity(uriRes.getHashedId().toString());
1004 pa.setObjectIdentityResource(uriRes.getId());
1009 static public PermissionAction update(Permission perm, PermissionAction permAction) {
1010 PermissionAction pa = new PermissionAction();
1012 CSpaceAction action = URIResourceImpl.getAction(permAction.getName());
1013 URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
1014 perm.getResourceName(), action);
1015 pa.setObjectIdentity(uriRes.getHashedId().toString());
1016 pa.setObjectIdentityResource(uriRes.getId());
1021 private static HashSet<String> getTransitionVerbList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
1022 HashSet<String> result = new HashSet<String>();
1024 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
1025 for (TransitionDef transitionDef : transitionDefList.getTransitionDef()) {
1026 String transitionVerb = transitionDef.getName();
1027 String[] tokens = transitionVerb.split("_"); // Split the verb into words. The workflow verbs are compound words combined with the '_' character.
1028 result.add(tokens[0]); // We only care about the first word.
1034 private static TransitionDefList getTransitionDefList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
1035 TransitionDefList result = null;
1037 String serviceObjectName = serviceBinding.getObject().getName();
1038 DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(
1039 tenantBinding, serviceBinding);
1040 Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName);
1041 if (lifecycle != null) {
1042 result = lifecycle.getTransitionDefList();
1044 } catch (Exception e) {
1045 // Ignore this exception and return an empty non-null TransitionDefList
1048 if (result == null) {
1049 if (serviceBinding.getType().equalsIgnoreCase(ServiceBindingUtils.SERVICE_TYPE_SECURITY) == false) {
1050 logger.debug("Could not retrieve a lifecycle transition definition list from: "
1051 + serviceBinding.getName()
1052 + " with tenant ID = "
1053 + tenantBinding.getId());
1055 // return an empty list
1056 result = new TransitionDefList();
1058 logger.debug("Successfully retrieved a lifecycle transition definition list from: "
1059 + serviceBinding.getName()
1060 + " with tenant ID = "
1061 + tenantBinding.getId());
1067 public static void createDefaultWorkflowPermissions(TenantBindingConfigReaderImpl tenantBindingConfigReader) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions
1069 AuthZ.get().login(); //login to Spring Security manager
1071 EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory(JpaStorageUtils.CS_PERSISTENCE_UNIT);
1072 EntityManager em = null;
1075 em = emf.createEntityManager();
1077 Hashtable<String, TenantBindingType> tenantBindings =
1078 tenantBindingConfigReader.getTenantBindings();
1079 for (String tenantId : tenantBindings.keySet()) {
1080 logger.info(String.format("Creating/verifying workflow permissions for tenant ID=%s.", tenantId));
1081 TenantBindingType tenantBinding = tenantBindings.get(tenantId);
1082 Role adminRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_ADMINISTRATOR);
1083 Role readonlyRole = AuthorizationCommon.getRole(em, tenantBinding.getId(), ROLE_TENANT_READER);
1085 if (adminRole == null || readonlyRole == null) {
1086 String msg = String.format("One or more of the required default CollectionSpace administrator roles is missing or was never created. If you're setting up a new instance of CollectionSpace, shutdown the Tomcat server and run the 'ant import' command from the root/top level CollectionSpace 'Services' source directory. Then try restarting Tomcat.");
1088 throw new RuntimeException("One or more of the required default CollectionSpace administrator roles is missing or was never created.");
1091 for (ServiceBindingType serviceBinding : tenantBinding.getServiceBindings()) {
1092 String prop = ServiceBindingUtils.getPropertyValue(serviceBinding, REFRESH_AUTZ_PROP);
1093 if (prop == null ? true : Boolean.parseBoolean(prop)) {
1095 em.getTransaction().begin();
1096 TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
1097 HashSet<String> transitionVerbList = getTransitionVerbList(tenantBinding, serviceBinding);
1098 for (String transitionVerb : transitionVerbList) {
1100 // Create the permission for the admin role
1101 Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_CRUDL);
1102 persist(em, adminPerm, adminRole, true, ACTIONGROUP_CRUDL);
1104 // Create the permission for the read-only role
1105 Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_RL);
1106 persist(em, readonlyPerm, readonlyRole, true, ACTIONGROUP_RL); // Persist/store the permission and permrole records and related Spring Security info
1108 em.getTransaction().commit();
1109 } catch (IllegalStateException e) {
1110 logger.debug(e.getLocalizedMessage(), e); //We end up here if there is no document handler for the service -this is ok for some of the services.
1113 logger.warn("AuthZ refresh service binding property is set to FALSE so default permissions will NOT be refreshed for: "
1114 + serviceBinding.getName());
1119 } catch (Exception e) {
1120 if (em != null && em.getTransaction().isActive()) {
1121 em.getTransaction().rollback();
1123 if (logger.isDebugEnabled()) {
1124 logger.debug("Caught exception and rolling back permission creation: ", e);
1129 JpaStorageUtils.releaseEntityManagerFactory(emf);
1134 private static PermissionRoleRel findPermRoleRel(EntityManager em, String permissionId, String RoleId) {
1135 PermissionRoleRel result = null;
1138 String whereClause = "where permissionId = :id and roleId = :roleId";
1139 HashMap<String, Object> params = new HashMap<String, Object>();
1140 params.put("id", permissionId);
1141 params.put("roleId", RoleId);
1143 result = (PermissionRoleRel) JpaStorageUtils.getEntity(em,
1144 PermissionRoleRel.class.getCanonicalName(), whereClause, params);
1145 } catch (Exception e) {
1146 //Do nothing. Will return null;
1153 * Persists the Permission, PermissionRoleRel, and Spring Security table entries all in one transaction
1155 private static void persist(EntityManager em, Permission permission, Role role, boolean enforceTenancy, ActionGroup actionGroup) throws Exception {
1156 AuthorizationStore authzStore = new AuthorizationStore();
1157 // First persist the Permission record
1158 authzStore.store(em, permission);
1160 // If the PermRoleRel doesn't already exists then relate the permission and the role in a new PermissionRole (the service payload)
1161 // Create a PermissionRoleRel (the database relation table for the permission and role)
1162 PermissionRoleRel permRoleRel = findPermRoleRel(em, permission.getCsid(), role.getCsid());
1163 if (permRoleRel == null) {
1164 PermissionRole permRole = createPermissionRole(em, permission, role, enforceTenancy);
1165 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
1166 PermissionRoleUtil.buildPermissionRoleRel(em, permRole, SubjectType.ROLE, permRoleRels, false /*not for delete*/);
1167 for (PermissionRoleRel prr : permRoleRels) {
1168 authzStore.store(em, prr);
1170 Profiler profiler = new Profiler(AuthorizationCommon.class, 2);
1172 // Add a corresponding entry in the Spring Security Tables
1173 addPermissionsForUri(permission, permRole);
1175 logger.debug("Finished full perm generation for "
1176 + ":" + permission.getTenantId()
1177 + ":" + permission.getResourceName()
1178 + ":" + actionGroup.getName()
1179 + ":" + profiler.getCumulativeTime());
1184 public static boolean hasTokenExpired(EmailConfig emailConfig, Token token) throws NoSuchAlgorithmException {
1185 boolean result = false;
1187 int maxConfigSeconds = emailConfig.getPasswordResetConfig().getTokenExpirationSeconds().intValue();
1188 int maxTokenSeconds = token.getExpireSeconds().intValue();
1190 long createdTime = token.getCreatedAtItem().getTime();
1191 long configExpirationTime = createdTime + maxConfigSeconds * 1000; // the current tenant config for how long a token stays valid
1192 long tokenDefinedExirationTime = createdTime + maxTokenSeconds * 1000; // the tenant config for how long a token stays valid when the token was created.
1194 if (configExpirationTime != tokenDefinedExirationTime) {
1195 String msg = String.format("The configured expiration time for the token = '%s' changed from when the token was created.",
1200 // Note: the current tenant bindings config for expiration takes precedence over the config used to create the token.
1202 if (System.currentTimeMillis() >= configExpirationTime) {
1210 * Validate that the password reset configuration is correct.
1212 private static String validatePasswordResetConfig(PasswordResetConfig passwordResetConfig) {
1213 String result = null;
1215 if (passwordResetConfig != null) {
1216 result = passwordResetConfig.getMessage();
1217 if (result == null || result.length() == 0) {
1218 result = DEFAULT_PASSWORD_RESET_EMAIL_MESSAGE;
1219 logger.warn("Could not find a password reset message in the tenant's configuration. Using the default one");
1222 if (result.contains("{{link}}") == false) {
1223 logger.warn("The tenant's password reset message does not contain a required '{{link}}' marker.");
1227 if (passwordResetConfig.getLoginpage() == null || passwordResetConfig.getLoginpage().trim().isEmpty()) {
1228 logger.warn("The tenant's password reset configuration is missing a 'loginpage' value. It should be set to something like '/collectionspace/ui/core/html/index.html'.");
1232 String subject = passwordResetConfig.getSubject();
1233 if (subject == null || subject.trim().isEmpty()) {
1234 passwordResetConfig.setSubject(DEFAULT_PASSWORD_RESET_EMAIL_SUBJECT);
1243 * Generate a password reset message. Embeds an authorization token to reset a user's password.
1245 public static String generatePasswordResetEmailMessage(EmailConfig emailConfig, AccountListItem accountListItem, Token token) throws Exception {
1246 String result = null;
1248 result = validatePasswordResetConfig(emailConfig.getPasswordResetConfig());
1249 if (result == null) {
1250 String errMsg = String.format("The password reset configuration for the tenant ID='%s' is missing or malformed. Could not initiate a password reset for user ID='%s. See the log files for more details.",
1251 token.getTenantId(), accountListItem.getEmail());
1252 throw new Exception(errMsg);
1255 String link = emailConfig.getBaseurl() + emailConfig.getPasswordResetConfig().getLoginpage() + "?token=" + token.getId();
1256 result = result.replaceAll("\\{\\{link\\}\\}", link);
1258 if (result.contains("{{greeting}}")) {
1259 String greeting = accountListItem.getScreenName();
1260 result = result.replaceAll("\\{\\{greeting\\}\\}", greeting);
1261 result = result.replaceAll("\\\\n", "\\\n");
1262 result = result.replaceAll("\\\\r", "\\\r");