public ChaiUser getProxiedChaiUser(final UserIdentity userIdentity) throws PwmUnrecoverableException { try { final ChaiProvider proxiedProvider = getProxyChaiProvider(userIdentity.getLdapProfileID()); return ChaiFactory.createChaiUser(userIdentity.getUserDN(), proxiedProvider); } catch (ChaiUnavailableException e) { throw PwmUnrecoverableException.fromChaiException(e); } }
private ChaiProvider makeProxyProvider() throws ChaiUnavailableException, PwmUnrecoverableException { final LdapProfile profile = pwmApplication.getConfig().getLdapProfiles().get(userIdentity.getLdapProfileID()); final String proxyDN = profile.readSettingAsString(PwmSetting.LDAP_PROXY_USER_DN); final PasswordData proxyPassword = profile.readSettingAsPassword(PwmSetting.LDAP_PROXY_USER_PASSWORD); return LdapOperationsHelper.createChaiProvider( sessionLabel, profile, pwmApplication.getConfig(), proxyDN, proxyPassword); }
private PasswordData setTempUserPassword() throws ChaiUnavailableException, ImpossiblePasswordPolicyException, PwmUnrecoverableException { final boolean configAlwaysUseProxy = pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.AD_USE_PROXY_FOR_FORGOTTEN); final ChaiProvider chaiProvider = pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID()); final ChaiUser chaiUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), chaiProvider); // try setting a random password on the account to authenticate. if (!configAlwaysUseProxy && requestedAuthType == AuthenticationType.AUTH_FROM_PUBLIC_MODULE) { log(PwmLogLevel.DEBUG, "attempting to set temporary random password"); PwmPasswordPolicy passwordPolicy = PasswordUtility.readPasswordPolicyForUser( pwmApplication, sessionLabel, userIdentity, chaiUser, PwmConstants.DEFAULT_LOCALE); // create random password for user RandomPasswordGenerator.RandomGeneratorConfig randomGeneratorConfig = new RandomPasswordGenerator.RandomGeneratorConfig(); randomGeneratorConfig.setSeedlistPhrases(RandomPasswordGenerator.DEFAULT_SEED_PHRASES); randomGeneratorConfig.setPasswordPolicy(passwordPolicy); final PasswordData currentPass = RandomPasswordGenerator.createRandomPassword( sessionLabel, randomGeneratorConfig, pwmApplication); try { final String oracleDS_PrePasswordAllowChangeTime = oraclePreTemporaryPwHandler(chaiProvider, chaiUser); // write the random password for the user. chaiUser.setPassword(currentPass.getStringValue()); oraclePostTemporaryPwHandler(chaiProvider, chaiUser, oracleDS_PrePasswordAllowChangeTime); log( PwmLogLevel.INFO, "user " + userIdentity + " password has been set to random value to use for user authentication"); } catch (ChaiOperationException e) { final String errorStr = "error setting random password for user " + userIdentity + " " + e.getMessage(); log(PwmLogLevel.ERROR, errorStr); throw new PwmUnrecoverableException( new ErrorInformation(PwmError.ERROR_BAD_SESSION_PASSWORD, errorStr)); } return currentPass; } return null; }
private static Date determinePwdLastModified( final PwmApplication pwmApplication, final SessionLabel sessionLabel, final ChaiUser theUser, final UserIdentity userIdentity) throws ChaiUnavailableException, PwmUnrecoverableException { // fetch last password modification time from pwm last update attribute operation try { final Date chaiReadDate = theUser.readPasswordModificationDate(); if (chaiReadDate != null) { LOGGER.trace( sessionLabel, "read last user password change timestamp (via chai) as: " + PwmConstants.DEFAULT_DATETIME_FORMAT.format(chaiReadDate)); return chaiReadDate; } } catch (ChaiOperationException e) { LOGGER.error( sessionLabel, "unexpected error reading password last modified timestamp: " + e.getMessage()); } final LdapProfile ldapProfile = pwmApplication.getConfig().getLdapProfiles().get(userIdentity.getLdapProfileID()); final String pwmLastSetAttr = ldapProfile.readSettingAsString(PwmSetting.PASSWORD_LAST_UPDATE_ATTRIBUTE); if (pwmLastSetAttr != null && pwmLastSetAttr.length() > 0) { try { final Date pwmPwdLastModified = theUser.readDateAttribute(pwmLastSetAttr); LOGGER.trace( sessionLabel, "read pwmPasswordChangeTime as: " + (pwmPwdLastModified == null ? "n/a" : PwmConstants.DEFAULT_DATETIME_FORMAT.format(pwmPwdLastModified))); return pwmPwdLastModified; } catch (ChaiOperationException e) { LOGGER.error( sessionLabel, "error parsing password last modified PWM password value for user " + theUser.getEntryDN() + "; error: " + e.getMessage()); } } LOGGER.debug(sessionLabel, "unable to determine time of user's last password modification"); return null; }
public static Map<String, Date> readIndividualReplicaLastPasswordTimes( final PwmApplication pwmApplication, final SessionLabel sessionLabel, final UserIdentity userIdentity) throws PwmUnrecoverableException { final Map<String, Date> returnValue = new LinkedHashMap<>(); final ChaiProvider chaiProvider = pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID()); final Collection<ChaiConfiguration> perReplicaConfigs = ChaiUtility.splitConfigurationPerReplica( chaiProvider.getChaiConfiguration(), Collections.singletonMap(ChaiSetting.FAILOVER_CONNECT_RETRIES, "1")); for (final ChaiConfiguration loopConfiguration : perReplicaConfigs) { final String loopReplicaUrl = loopConfiguration.getSetting(ChaiSetting.BIND_DN); ChaiProvider loopProvider = null; try { loopProvider = ChaiProviderFactory.createProvider(loopConfiguration); final Date lastModifiedDate = determinePwdLastModified(pwmApplication, sessionLabel, userIdentity); returnValue.put(loopReplicaUrl, lastModifiedDate); } catch (ChaiUnavailableException e) { LOGGER.error(sessionLabel, "unreachable server during replica password sync check"); e.printStackTrace(); } finally { if (loopProvider != null) { try { loopProvider.close(); } catch (Exception e) { final String errorMsg = "error closing loopProvider to " + loopReplicaUrl + " while checking individual password sync status"; LOGGER.error(sessionLabel, errorMsg); } } } } return returnValue; }
private PasswordData learnUserPassword() throws ChaiUnavailableException, PwmUnrecoverableException { log(PwmLogLevel.TRACE, "beginning auth processes for user with unknown password"); if (userIdentity == null || userIdentity.getUserDN() == null || userIdentity.getUserDN().length() < 1) { throw new NullPointerException("invalid user (null)"); } final ChaiProvider chaiProvider = pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID()); final ChaiUser chaiUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), chaiProvider); // use chai (nmas) to retrieve user password if (pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.EDIRECTORY_READ_USER_PWD)) { String currentPass = null; try { final String readPassword = chaiUser.readPassword(); if (readPassword != null && readPassword.length() > 0) { currentPass = readPassword; log( PwmLogLevel.DEBUG, "successfully retrieved user's current password from ldap, now conducting standard authentication"); } } catch (Exception e) { log(PwmLogLevel.ERROR, "unable to retrieve user password from ldap: " + e.getMessage()); } // actually do the authentication since we have user pw. if (currentPass != null && currentPass.length() > 0) { return new PasswordData(currentPass); } } else { log(PwmLogLevel.TRACE, "skipping attempt to read user password, option disabled"); } return null; }
private boolean updateCachedRecordFromLdap( final UserIdentity userIdentity, final UserInfoBean userInfoBean, final UserCacheService.StorageKey storageKey) throws ChaiUnavailableException, PwmUnrecoverableException, LocalDBException { final UserCacheRecord userCacheRecord = userCacheService.readStorageKey(storageKey); TimeDuration cacheAge = null; if (userCacheRecord != null && userCacheRecord.getCacheTimestamp() != null) { cacheAge = TimeDuration.fromCurrent(userCacheRecord.getCacheTimestamp()); } boolean updateCache = false; if (userInfoBean != null) { updateCache = true; } else { if (cacheAge == null) { LOGGER.trace( PwmConstants.REPORTING_SESSION_LABEL, "stored cache for " + userIdentity + " is missing cache storage timestamp, will update"); updateCache = true; } else if (cacheAge.isLongerThan(settings.getMinCacheAge())) { LOGGER.trace( PwmConstants.REPORTING_SESSION_LABEL, "stored cache for " + userIdentity + " is " + cacheAge.asCompactString() + " old, will update"); updateCache = true; } } if (updateCache) { if (userCacheRecord != null) { if (summaryData != null && summaryData.getEpoch() != null && summaryData.getEpoch().equals(userCacheRecord.getSummaryEpoch())) { summaryData.remove(userCacheRecord); } } final UserInfoBean newUserBean; if (userInfoBean != null) { newUserBean = userInfoBean; } else { newUserBean = new UserInfoBean(); final UserStatusReader.Settings readerSettings = new UserStatusReader.Settings(); readerSettings.setSkipReportUpdate(true); final ChaiProvider chaiProvider = pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID()); final UserStatusReader userStatusReader = new UserStatusReader( pwmApplication, PwmConstants.REPORTING_SESSION_LABEL, readerSettings); userStatusReader.populateUserInfoBean( newUserBean, PwmConstants.DEFAULT_LOCALE, userIdentity, chaiProvider); } final UserCacheRecord newUserCacheRecord = userCacheService.updateUserCache(newUserBean); if (summaryData != null && summaryData.getEpoch() != null && newUserCacheRecord != null) { if (!summaryData.getEpoch().equals(newUserCacheRecord.getSummaryEpoch())) { newUserCacheRecord.setSummaryEpoch(summaryData.getEpoch()); userCacheService.store(newUserCacheRecord); } summaryData.update(newUserCacheRecord); } } return updateCache; }
private AuthenticationResult authenticateUserImpl(final PasswordData password) throws ChaiUnavailableException, PwmUnrecoverableException, PwmOperationalException { if (startTime == null) { startTime = new Date(); } log( PwmLogLevel.DEBUG, "preparing to authenticate user using authenticationType=" + this.requestedAuthType + " using strategy " + this.strategy); final StatisticsManager statisticsManager = pwmApplication.getStatisticsManager(); final IntruderManager intruderManager = pwmApplication.getIntruderManager(); intruderManager.convenience().checkUserIdentity(userIdentity); intruderManager.check(RecordType.ADDRESS, sessionLabel.getSrcAddress()); boolean allowBindAsUser = true; if (strategy == AuthenticationStrategy.ADMIN_PROXY) { allowBindAsUser = false; } if (allowBindAsUser) { try { testCredentials(userIdentity, password); } catch (PwmOperationalException e) { boolean permitAuthDespiteError = false; final ChaiProvider.DIRECTORY_VENDOR vendor = pwmApplication .getProxyChaiProvider(userIdentity.getLdapProfileID()) .getDirectoryVendor(); if (PwmError.PASSWORD_NEW_PASSWORD_REQUIRED == e.getError()) { if (vendor == ChaiProvider.DIRECTORY_VENDOR.MICROSOFT_ACTIVE_DIRECTORY) { if (pwmApplication .getConfig() .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_REQUIRE_NEW_PWD)) { log( PwmLogLevel.INFO, "auth bind failed, but will allow login due to 'must change password on next login AD error', error: " + e.getErrorInformation().toDebugStr()); allowBindAsUser = false; permitAuthDespiteError = true; } } else if (vendor == ChaiProvider.DIRECTORY_VENDOR.ORACLE_DS) { if (pwmApplication .getConfig() .readSettingAsBoolean(PwmSetting.ORACLE_DS_ALLOW_AUTH_REQUIRE_NEW_PWD)) { log( PwmLogLevel.INFO, "auth bind failed, but will allow login due to 'pwdReset' user attribute, error: " + e.getErrorInformation().toDebugStr()); allowBindAsUser = false; permitAuthDespiteError = true; } } } else if (PwmError.PASSWORD_EXPIRED == e.getError()) { // handle ad case where password is expired if (vendor == ChaiProvider.DIRECTORY_VENDOR.MICROSOFT_ACTIVE_DIRECTORY) { if (pwmApplication .getConfig() .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_REQUIRE_NEW_PWD)) { if (!pwmApplication .getConfig() .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_EXPIRED)) { throw e; } log( PwmLogLevel.INFO, "auth bind failed, but will allow login due to 'password expired AD error', error: " + e.getErrorInformation().toDebugStr()); allowBindAsUser = false; permitAuthDespiteError = true; } } } if (!permitAuthDespiteError) { // auth failed, presumably due to wrong password. statisticsManager.incrementValue(Statistic.AUTHENTICATION_FAILURES); throw e; } } } else { // verify user is not account disabled AuthenticationUtility.checkIfUserEligibleToAuthentication(pwmApplication, userIdentity); } statisticsManager.incrementValue(Statistic.AUTHENTICATIONS); statisticsManager.updateEps(Statistic.EpsType.AUTHENTICATION, 1); statisticsManager.updateAverageValue( Statistic.AVG_AUTHENTICATION_TIME, TimeDuration.fromCurrent(startTime).getTotalMilliseconds()); final AuthenticationType returnAuthType; if (!allowBindAsUser) { returnAuthType = AuthenticationType.AUTH_BIND_INHIBIT; } else { if (requestedAuthType == null) { returnAuthType = AuthenticationType.AUTHENTICATED; } else { if (requestedAuthType == AuthenticationType.AUTH_WITHOUT_PASSWORD) { returnAuthType = AuthenticationType.AUTHENTICATED; } else if (requestedAuthType == AuthenticationType.AUTH_FROM_PUBLIC_MODULE) { returnAuthType = AuthenticationType.AUTH_FROM_PUBLIC_MODULE; } else { returnAuthType = requestedAuthType; } } } final boolean useProxy = determineIfLdapProxyNeeded(returnAuthType, password); final ChaiProvider returnProvider = useProxy ? makeProxyProvider() : userProvider; final AuthenticationResult authenticationResult = new AuthenticationResult(returnProvider, returnAuthType, password); final StringBuilder debugMsg = new StringBuilder(); debugMsg.append("successful ldap authentication for ").append(userIdentity); debugMsg.append(" (").append(TimeDuration.fromCurrent(startTime).asCompactString()).append(")"); debugMsg.append(" type: ").append(returnAuthType).append(", using strategy ").append(strategy); debugMsg.append(", using proxy connection: ").append(useProxy); debugMsg .append(", returning bind dn: ") .append( returnProvider == null ? "none" : returnProvider.getChaiConfiguration().getSetting(ChaiSetting.BIND_DN)); log(PwmLogLevel.INFO, debugMsg); pwmApplication .getAuditManager() .submit( pwmApplication .getAuditManager() .createUserAuditRecord( AuditEvent.AUTHENTICATE, this.userIdentity, makeAuditLogMessage(returnAuthType), sessionLabel.getSrcAddress(), sessionLabel.getSrcHostname())); return authenticationResult; }