/** * This method is used when the admin is updating the credentials with an empty credential. A * random password will be generated and will be mailed to the user. */ @Override public boolean doPreUpdateCredentialByAdmin( String userName, Object newCredential, UserStoreManager userStoreManager) throws UserStoreException { if (log.isDebugEnabled()) { log.debug("Pre update credential by admin is called in IdentityMgtEventListener"); } IdentityMgtConfig config = IdentityMgtConfig.getInstance(); if (!config.isListenerEnable()) { return true; } try { // Enforcing the password policies. if (newCredential != null && (newCredential instanceof StringBuffer && (newCredential.toString().trim().length() > 0))) { policyRegistry.enforcePasswordPolicies(newCredential.toString(), userName); } } catch (PolicyViolationException pe) { log.error(pe.getMessage()); throw new UserStoreException(pe.getMessage()); } if (newCredential == null || (newCredential instanceof StringBuffer && ((StringBuffer) newCredential).toString().trim().length() < 1)) { if (!config.isEnableTemporaryPassword()) { log.error("Empty passwords are not allowed"); return false; } if (log.isDebugEnabled()) { log.debug("Credentials are null. Using a temporary password as credentials"); } // temporary passwords will be used char[] temporaryPassword = UserIdentityManagementUtil.generateTemporaryPassword(); // setting the password value ((StringBuffer) newCredential) .replace(0, temporaryPassword.length, new String(temporaryPassword)); UserIdentityMgtBean bean = new UserIdentityMgtBean(); bean.setUserId(userName); bean.setConfirmationCode(newCredential.toString()); bean.setRecoveryType(IdentityMgtConstants.Notification.TEMPORARY_PASSWORD); log.debug("Sending the tempory password to the user " + userName); UserIdentityManagementUtil.notifyViaEmail(bean); } else { log.debug("Updating credentials of user " + userName + " by admin with a non-empty password"); } return true; }
/** * This method will set the default/random password if the password provided is null. The thread * local parameter EMPTY_PASSWORD_USED will be used to track if the password empty in the * doPostAddUser. This method will filter the security question URIs from claims and put those to * the thread local properties. */ @Override public boolean doPreAddUser( String userName, Object credential, String[] roleList, Map<String, String> claims, String profile, UserStoreManager userStoreManager) throws UserStoreException { if (log.isDebugEnabled()) { log.debug("Pre add user is called in IdentityMgtEventListener"); } IdentityMgtConfig config = IdentityMgtConfig.getInstance(); if (!config.isListenerEnable()) { return true; } try { // Enforcing the password policies. if (credential != null && (credential instanceof StringBuffer && (credential.toString().trim().length() > 0))) { policyRegistry.enforcePasswordPolicies(credential.toString(), userName); } } catch (PolicyViolationException pe) { log.error(pe.getMessage()); throw new UserStoreException(pe.getMessage()); } // empty password account creation if (credential == null || (credential instanceof StringBuffer && (credential.toString().trim().length() < 1))) { if (!config.isEnableTemporaryPassword()) { log.error("Empty passwords are not allowed"); return false; } if (log.isDebugEnabled()) { log.debug("Credentials are null. Using a temporary password as credentials"); } // setting the thread-local to check in doPostAddUser threadLocalProperties.get().put(EMPTY_PASSWORD_USED, true); // temporary passwords will be used char[] temporaryPassword = UserIdentityManagementUtil.generateTemporaryPassword(); // setting the password value ((StringBuffer) credential) .replace(0, temporaryPassword.length, new String(temporaryPassword)); } // Filtering security question URIs from claims and add them to the thread local dto Map<String, String> userDataMap = new HashMap<String, String>(); // TODO why challenge Q Iterator<Entry<String, String>> it = claims.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> claim = it.next(); if (claim.getKey().contains(UserCoreConstants.ClaimTypeURIs.CHALLENGE_QUESTION_URI) || claim.getKey().contains(UserCoreConstants.ClaimTypeURIs.IDENTITY_CLAIM_URI)) { userDataMap.put(claim.getKey(), claim.getValue()); it.remove(); } } UserIdentityClaimsDO identityDTO = new UserIdentityClaimsDO(userName, userDataMap); // adding dto to thread local to be read again from the doPostAddUser method threadLocalProperties.get().put(USER_IDENTITY_DO, identityDTO); return true; }
/** * This method locks the accounts after a configured number of authentication failure attempts. * And unlocks accounts based on successful authentications. */ @Override public boolean doPostAuthenticate( String userName, boolean authenticated, UserStoreManager userStoreManager) throws UserStoreException { if (log.isDebugEnabled()) { log.debug("Post authenticator is called in IdentityMgtEventListener"); } IdentityMgtConfig config = IdentityMgtConfig.getInstance(); if (!config.isEnableAuthPolicy()) { return authenticated; } UserIdentityClaimsDO userIdentityDTO = module.load(userName, userStoreManager); if (userIdentityDTO == null) { userIdentityDTO = new UserIdentityClaimsDO(userName); } boolean userOTPEnabled = userIdentityDTO.getOneTimeLogin(); // One time password check if (authenticated && config.isAuthPolicyOneTimePasswordCheck() && (!userStoreManager.isReadOnly())) { // reset password of the user and notify user of the new password if (userOTPEnabled) { String password = UserIdentityManagementUtil.generateTemporaryPassword().toString(); userStoreManager.updateCredentialByAdmin(userName, password); // Get email user claim value String email = userStoreManager.getUserClaimValue( userName, UserCoreConstants.ClaimTypeURIs.EMAIL_ADDRESS, null); if (email == null) { throw new UserStoreException("No user email provided for user " + userName); } List<NotificationSendingModule> notificationModules = config.getNotificationSendingModules(); if (notificationModules != null) { NotificationDataDTO notificationData = new NotificationDataDTO(); NotificationData emailNotificationData = new NotificationData(); String emailTemplate = null; int tenantId = userStoreManager.getTenantId(); String firstName = null; try { firstName = Utils.getClaimFromUserStoreManager( userName, tenantId, "http://wso2.org/claims/givenname"); } catch (IdentityException e2) { throw new UserStoreException("Could not load user given name"); } emailNotificationData.setTagData("first-name", firstName); emailNotificationData.setTagData("user-name", userName); emailNotificationData.setTagData("otp-password", password); emailNotificationData.setSendTo(email); Config emailConfig = null; ConfigBuilder configBuilder = ConfigBuilder.getInstance(); try { emailConfig = configBuilder.loadConfiguration(ConfigType.EMAIL, StorageType.REGISTRY, tenantId); } catch (Exception e1) { throw new UserStoreException("Could not load the email template configuration"); } emailTemplate = emailConfig.getProperty("otp"); Notification emailNotification = null; try { emailNotification = NotificationBuilder.createNotification( "EMAIL", emailTemplate, emailNotificationData); } catch (Exception e) { throw new UserStoreException("Could not create the email notification"); } NotificationSender sender = new NotificationSender(); for (NotificationSendingModule notificationSendingModule : notificationModules) { if (IdentityMgtConfig.getInstance().isNotificationInternallyManaged()) { notificationSendingModule.setNotificationData(notificationData); notificationSendingModule.setNotification(emailNotification); sender.sendNotification(notificationSendingModule); notificationData.setNotificationSent(true); } } } else { throw new UserStoreException("No notification modules configured"); } } } // Password expire check. Not for OTP enabled users. if (authenticated && config.isAuthPolicyExpirePasswordCheck() && !userOTPEnabled && (!userStoreManager.isReadOnly())) { // TODO - password expire impl // Refactor adduser and change password api to stamp the time // Check user's expire time in the claim // if expired redirect to change password // else pass through /* long timestamp = userIdentityDTO.getPasswordTimeStamp(); // Only allow behavior to users with this claim. Intent bypass for admin? if (timestamp > 0) { Calendar passwordExpireTime = Calendar.getInstance(); passwordExpireTime.setTimeInMillis(timestamp); int expireDuration = config.getAuthPolicyPasswordExpireTime(); if (expireDuration > 0) { passwordExpireTime.add(Calendar.DATE, expireDuration); Calendar currentTime = Calendar.getInstance(); if (currentTime.compareTo(passwordExpireTime) > 0) { // password expired // set flag to redirect log.error("Password is expired ..........."); // throw new UserStoreException("Password is expired"); } } } */ } if (!authenticated && config.isAuthPolicyAccountLockOnFailure()) { userIdentityDTO.setFailAttempts(); // reading the max allowed #of failure attempts if (userIdentityDTO.getFailAttempts() >= config.getAuthPolicyMaxLoginAttempts()) { if (log.isDebugEnabled()) { log.debug( "User, " + userName + " has exceed the max failed login attempts. " + "User account would be locked"); } userIdentityDTO.setAccountLock(true); // lock time from the config int lockTime = IdentityMgtConfig.getInstance().getAuthPolicyLockingTime(); if (lockTime != 0) { userIdentityDTO.setUnlockTime(System.currentTimeMillis() + (lockTime * 60 * 1000)); } } try { module.store(userIdentityDTO, userStoreManager); } catch (IdentityException e) { throw new UserStoreException("Error while doPostAuthenticate", e); } } else { // if the account was locked due to account verification process, // the unlock the account and reset the number of failedAttempts if (userIdentityDTO.isAccountLocked() || userIdentityDTO.getFailAttempts() > 0) { userIdentityDTO.setAccountLock(false); userIdentityDTO.setFailAttempts(0); userIdentityDTO.setUnlockTime(0); try { module.store(userIdentityDTO, userStoreManager); } catch (IdentityException e) { throw new UserStoreException("Error while doPostAuthenticate", e); } } } return true; }
/** * This method used to confirm the self registered user account and unlock it. * * @param username * @param code * @param captcha * @param tenantDomain * @return * @throws IdentityMgtServiceException */ public VerificationBean confirmUserSelfRegistration( String username, String code, CaptchaInfoBean captcha, String tenantDomain) throws IdentityMgtServiceException { VerificationBean bean = new VerificationBean(); if (log.isDebugEnabled()) { log.debug("User registration verification request received with username :"******" Error while validating captcha for user : "******"Trying to confirm users in unauthorized tenant space"; log.error(msg); } if (tenantDomain == null || tenantDomain.isEmpty()) { tenantDomain = loggedInTenant; } } UserDTO userDTO = null; try { userDTO = Utils.processUserId(username + "@" + tenantDomain); } catch (IdentityException e) { bean = handleError( VerificationBean.ERROR_CODE_INVALID_USER + " Error verifying user account for user : "******"Error retrieving the user store manager for the tenant : " + tenantDomain, e); return bean; } try { bean = processor.verifyConfirmationCode(1, username, code); if (bean.isVerified()) { UserIdentityManagementUtil.unlockUserAccount(username, userStoreManager); bean.setVerified(true); } else { bean.setVerified(false); bean.setKey(""); log.error("User verification failed against the given confirmation code"); } } catch (IdentityException e) { bean = handleError("Error while validating confirmation code for user : " + username, e); return bean; } } finally { if (IdentityMgtConfig.getInstance().isSaasEnabled()) { PrivilegedCarbonContext.endTenantFlow(); } } return bean; }
/** * This method is used to register an user in the system. The account will be locked if the * Authentication.Policy.Account.Lock.On.Creation is set to true. Else user will be able to login * after registration. * * @param userName * @param password * @param claims * @param profileName * @param tenantDomain * @return * @throws IdentityMgtServiceException */ public VerificationBean registerUser( String userName, String password, UserIdentityClaimDTO[] claims, String profileName, String tenantDomain) throws IdentityMgtServiceException { VerificationBean vBean = new VerificationBean(); org.wso2.carbon.user.core.UserStoreManager userStoreManager = null; Permission permission = null; if (!IdentityMgtConfig.getInstance().isSaasEnabled()) { String loggedInTenant = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); if (tenantDomain != null && !tenantDomain.isEmpty() && !loggedInTenant.equals(tenantDomain)) { String msg = "Trying to create users in unauthorized tenant space"; log.error(msg); throw new IdentityMgtServiceException(msg); } if (tenantDomain == null || tenantDomain.isEmpty()) { tenantDomain = loggedInTenant; } } RealmService realmService = IdentityMgtServiceComponent.getRealmService(); int tenantId; try { tenantId = Utils.getTenantId(tenantDomain); if (realmService.getTenantUserRealm(tenantId) != null) { userStoreManager = (org.wso2.carbon.user.core.UserStoreManager) realmService.getTenantUserRealm(tenantId).getUserStoreManager(); } } catch (Exception e) { vBean = handleError( VerificationBean.ERROR_CODE_UNEXPECTED + " Error retrieving the user store manager for the tenant", e); return vBean; } try { if (userStoreManager == null) { vBean = new VerificationBean(); vBean.setVerified(false); vBean.setError( VerificationBean.ERROR_CODE_UNEXPECTED + " Error retrieving the user store manager for the tenant"); return vBean; } Map<String, String> claimsMap = new HashMap<String, String>(); for (UserIdentityClaimDTO userIdentityClaimDTO : claims) { claimsMap.put(userIdentityClaimDTO.getClaimUri(), userIdentityClaimDTO.getClaimValue()); } userStoreManager.addUser(userName, password, null, claimsMap, profileName); String identityRoleName = UserCoreConstants.INTERNAL_DOMAIN + CarbonConstants.DOMAIN_SEPARATOR + IdentityConstants.IDENTITY_DEFAULT_ROLE; if (!userStoreManager.isExistingRole(identityRoleName, false)) { permission = new Permission("/permission/admin/login", UserMgtConstants.EXECUTE_ACTION); userStoreManager.addRole( identityRoleName, new String[] {userName}, new Permission[] {permission}, false); } else { userStoreManager.updateUserListOfRole( identityRoleName, new String[] {}, new String[] {userName}); } IdentityEventListener identityEventListener = IdentityUtil.readEventListenerProperty( UserOperationEventListener.class.getName(), IdentityMgtEventListener.class.getName()); boolean isListenerEnable = true; if (identityEventListener != null) { if (StringUtils.isNotBlank(identityEventListener.getEnable())) { isListenerEnable = Boolean.parseBoolean(identityEventListener.getEnable()); } } IdentityMgtConfig config = IdentityMgtConfig.getInstance(); if (isListenerEnable && config.isAuthPolicyAccountLockOnCreation()) { UserDTO userDTO = new UserDTO(userName); userDTO.setTenantId(tenantId); UserRecoveryDTO dto = new UserRecoveryDTO(userDTO); dto.setNotification(IdentityMgtConstants.Notification.ACCOUNT_CONFORM); dto.setNotificationType("EMAIL"); RecoveryProcessor processor = IdentityMgtServiceComponent.getRecoveryProcessor(); vBean = processor.updateConfirmationCode(1, userName, tenantId); dto.setConfirmationCode(vBean.getKey()); NotificationDataDTO notificationDto = processor.notifyWithEmail(dto); vBean.setVerified(notificationDto.isNotificationSent()); // Send email data only if not internally managed. if (!(IdentityMgtConfig.getInstance().isNotificationInternallyManaged())) { vBean.setNotificationData(notificationDto); } } else { vBean.setVerified(true); } } catch (UserStoreException | IdentityException e) { UserIdentityManagementUtil.getCustomErrorMessages(e, userName); // Rollback if user exists try { if (userStoreManager.isExistingUser(userName)) { userStoreManager.deleteUser(userName); } } catch (org.wso2.carbon.user.core.UserStoreException e1) { UserIdentityManagementUtil.getCustomErrorMessages(e1, userName); } return vBean; } return vBean; }
/** * Verifies the user against the provided claims and captcha information. * * @param claims * @param captcha * @param tenantDomain * @return * @throws IdentityMgtServiceException */ public VerificationBean verifyAccount( UserIdentityClaimDTO[] claims, CaptchaInfoBean captcha, String tenantDomain) throws IdentityMgtServiceException { VerificationBean vBean = new VerificationBean(); if (IdentityMgtConfig.getInstance().isCaptchaVerificationInternallyManaged()) { try { CaptchaUtil.processCaptchaInfoBean(captcha); } catch (Exception e) { vBean = handleError( VerificationBean.ERROR_CODE_INVALID_CAPTCHA + " Error processing captcha", e); return vBean; } } if (!IdentityMgtConfig.getInstance().isSaasEnabled()) { String loggedInTenant = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); if (tenantDomain != null && !tenantDomain.isEmpty() && !loggedInTenant.equals(tenantDomain)) { String msg = "Trying to verify account unauthorized tenant space"; log.error(msg); throw new IdentityMgtServiceException(msg); } if (tenantDomain == null || tenantDomain.isEmpty()) { tenantDomain = loggedInTenant; } } try { int tenantId = Utils.getTenantId(tenantDomain); String userName = UserIdentityManagementUtil.getUsernameByClaims(claims, tenantId); if (userName != null) { UserDTO userDTO = new UserDTO(userName); userDTO.setTenantId(tenantId); UserRecoveryDTO dto = new UserRecoveryDTO(userDTO); dto.setNotification(IdentityMgtConstants.Notification.ACCOUNT_ID_RECOVERY); dto.setNotificationType("EMAIL"); RecoveryProcessor processor = IdentityMgtServiceComponent.getRecoveryProcessor(); NotificationDataDTO notificationDto = processor.notifyWithEmail(dto); vBean.setVerified(notificationDto.isNotificationSent()); // Send email data only if not internally managed. if (!(IdentityMgtConfig.getInstance().isNotificationInternallyManaged())) { vBean.setNotificationData(notificationDto); } } else { vBean.setError("User not found"); vBean.setVerified(false); } } catch (Exception e) { vBean = handleError( VerificationBean.ERROR_CODE_INVALID_USER + " Error verifying user account", e); return vBean; } return vBean; }