use of com.novell.ldapchai.exception.ChaiUnavailableException in project pwm by pwm-project.
the class FormUtility method validateFormValueUniqueness.
@SuppressWarnings("checkstyle:MethodLength")
public static void validateFormValueUniqueness(final PwmApplication pwmApplication, final Map<FormConfiguration, String> formValues, final Locale locale, final Collection<UserIdentity> excludeDN, final ValidationFlag... validationFlags) throws PwmDataValidationException, PwmUnrecoverableException {
final boolean allowResultCaching = JavaHelper.enumArrayContainsValue(validationFlags, ValidationFlag.allowResultCaching);
final boolean checkReadOnlyAndHidden = JavaHelper.enumArrayContainsValue(validationFlags, ValidationFlag.checkReadOnlyAndHidden);
final Map<String, String> filterClauses = new HashMap<>();
final Map<String, String> labelMap = new HashMap<>();
for (final Map.Entry<FormConfiguration, String> entry : formValues.entrySet()) {
final FormConfiguration formItem = entry.getKey();
if (formItem.isUnique()) {
if (checkReadOnlyAndHidden || formItem.isReadonly()) {
if (checkReadOnlyAndHidden || (formItem.getType() != FormConfiguration.Type.hidden)) {
final String value = entry.getValue();
if (value != null && value.length() > 0) {
filterClauses.put(formItem.getName(), value);
labelMap.put(formItem.getName(), formItem.getLabel(locale));
}
}
}
}
}
if (filterClauses.isEmpty()) {
// nothing to search
return;
}
final StringBuilder filter = new StringBuilder();
{
// outer;
filter.append("(&");
// object classes;
filter.append("(|");
for (final String objectClass : pwmApplication.getConfig().readSettingAsStringArray(PwmSetting.DEFAULT_OBJECT_CLASSES)) {
filter.append("(objectClass=").append(objectClass).append(")");
}
filter.append(")");
// attributes
filter.append("(|");
for (final Map.Entry<String, String> entry : filterClauses.entrySet()) {
final String name = entry.getKey();
final String value = entry.getValue();
filter.append("(").append(name).append("=").append(StringUtil.escapeLdapFilter(value)).append(")");
}
filter.append(")");
filter.append(")");
}
final CacheService cacheService = pwmApplication.getCacheService();
final CacheKey cacheKey = CacheKey.makeCacheKey(Validator.class, null, "attr_unique_check_" + filter.toString());
if (allowResultCaching && cacheService != null) {
final String cacheValue = cacheService.get(cacheKey);
if (cacheValue != null) {
if (NEGATIVE_CACHE_HIT.equals(cacheValue)) {
return;
} else {
final ErrorInformation errorInformation = JsonUtil.deserialize(cacheValue, ErrorInformation.class);
throw new PwmDataValidationException(errorInformation);
}
}
}
final SearchHelper searchHelper = new SearchHelper();
searchHelper.setFilterAnd(filterClauses);
final SearchConfiguration searchConfiguration = SearchConfiguration.builder().filter(filter.toString()).build();
final int resultSearchSizeLimit = 1 + (excludeDN == null ? 0 : excludeDN.size());
final long cacheLifetimeMS = Long.parseLong(pwmApplication.getConfig().readAppProperty(AppProperty.CACHE_FORM_UNIQUE_VALUE_LIFETIME_MS));
final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpirationMS(cacheLifetimeMS);
try {
final UserSearchEngine userSearchEngine = pwmApplication.getUserSearchEngine();
final Map<UserIdentity, Map<String, String>> results = new LinkedHashMap<>(userSearchEngine.performMultiUserSearch(searchConfiguration, resultSearchSizeLimit, Collections.emptyList(), SessionLabel.SYSTEM_LABEL));
if (excludeDN != null && !excludeDN.isEmpty()) {
for (final UserIdentity loopIgnoreIdentity : excludeDN) {
results.keySet().removeIf(loopIgnoreIdentity::equals);
}
}
if (!results.isEmpty()) {
final UserIdentity userIdentity = results.keySet().iterator().next();
if (labelMap.size() == 1) {
// since only one value searched, it must be that one value
final String attributeName = labelMap.values().iterator().next();
LOGGER.trace("found duplicate value for attribute '" + attributeName + "' on entry " + userIdentity);
final ErrorInformation error = new ErrorInformation(PwmError.ERROR_FIELD_DUPLICATE, null, new String[] { attributeName });
throw new PwmDataValidationException(error);
}
// do a compare on a user values to find one that matches.
for (final Map.Entry<String, String> entry : filterClauses.entrySet()) {
final String name = entry.getKey();
final String value = entry.getValue();
final boolean compareResult;
try {
final ChaiUser theUser = pwmApplication.getProxiedChaiUser(userIdentity);
compareResult = theUser.compareStringAttribute(name, value);
} catch (ChaiOperationException | ChaiUnavailableException e) {
final PwmError error = PwmError.forChaiError(e.getErrorCode());
throw new PwmUnrecoverableException(error.toInfo());
}
if (compareResult) {
final String label = labelMap.get(name);
LOGGER.trace("found duplicate value for attribute '" + label + "' on entry " + userIdentity);
final ErrorInformation error = new ErrorInformation(PwmError.ERROR_FIELD_DUPLICATE, null, new String[] { label });
throw new PwmDataValidationException(error);
}
}
// user didn't match on the compare.. shouldn't read here but just in case
final ErrorInformation error = new ErrorInformation(PwmError.ERROR_FIELD_DUPLICATE, null);
throw new PwmDataValidationException(error);
}
} catch (PwmOperationalException e) {
if (cacheService != null) {
final String jsonPayload = JsonUtil.serialize(e.getErrorInformation());
cacheService.put(cacheKey, cachePolicy, jsonPayload);
}
throw new PwmDataValidationException(e.getErrorInformation());
}
if (allowResultCaching && cacheService != null) {
cacheService.put(cacheKey, cachePolicy, NEGATIVE_CACHE_HIT);
}
}
use of com.novell.ldapchai.exception.ChaiUnavailableException in project pwm by pwm-project.
the class PwmPasswordRuleValidator method testPassword.
public boolean testPassword(final PasswordData password, final PasswordData oldPassword, final UserInfo userInfo, final ChaiUser user) throws PwmDataValidationException, ChaiUnavailableException, PwmUnrecoverableException {
final List<ErrorInformation> errorResults = validate(password, oldPassword, userInfo);
if (!errorResults.isEmpty()) {
throw new PwmDataValidationException(errorResults.iterator().next());
}
if (user != null) {
try {
LOGGER.trace("calling chai directory password validation checker");
user.testPasswordPolicy(password.getStringValue());
} catch (UnsupportedOperationException e) {
LOGGER.trace("Unsupported operation was thrown while validating password: " + e.toString());
} catch (ChaiUnavailableException e) {
pwmApplication.getStatisticsManager().incrementValue(Statistic.LDAP_UNAVAILABLE_COUNT);
LOGGER.warn("ChaiUnavailableException was thrown while validating password: " + e.toString());
throw e;
} catch (ChaiPasswordPolicyException e) {
final ChaiError passwordError = e.getErrorCode();
final PwmError pwmError = PwmError.forChaiError(passwordError);
final ErrorInformation info = new ErrorInformation(pwmError == null ? PwmError.PASSWORD_UNKNOWN_VALIDATION : pwmError);
LOGGER.trace("ChaiPasswordPolicyException was thrown while validating password: " + e.toString());
errorResults.add(info);
}
}
if (!errorResults.isEmpty()) {
throw new PwmDataValidationException(errorResults.iterator().next());
}
return true;
}
use of com.novell.ldapchai.exception.ChaiUnavailableException in project pwm by pwm-project.
the class PasswordUtility method setPassword.
public static void setPassword(final PwmApplication pwmApplication, final SessionLabel sessionLabel, final ChaiProvider chaiProvider, final UserInfo userInfo, final PasswordData oldPassword, final PasswordData newPassword) throws PwmUnrecoverableException, PwmOperationalException {
final UserIdentity userIdentity = userInfo.getUserIdentity();
final Instant startTime = Instant.now();
final boolean bindIsSelf;
final String bindDN;
try {
final ChaiUser theUser = chaiProvider.getEntryFactory().newChaiUser(userIdentity.getUserDN());
final Locale locale = PwmConstants.DEFAULT_LOCALE;
final PwmPasswordPolicy passwordPolicy = PasswordUtility.readPasswordPolicyForUser(pwmApplication, sessionLabel, userIdentity, theUser, locale);
final PwmPasswordRuleValidator pwmPasswordRuleValidator = new PwmPasswordRuleValidator(pwmApplication, passwordPolicy);
pwmPasswordRuleValidator.testPassword(newPassword, null, userInfo, theUser);
} catch (ChaiUnavailableException e) {
throw PwmUnrecoverableException.fromChaiException(e);
} catch (PwmException e) {
throw new PwmUnrecoverableException(e.getErrorInformation());
}
try {
final ChaiUser theUser = chaiProvider.getEntryFactory().newChaiUser(userIdentity.getUserDN());
bindDN = chaiProvider.getChaiConfiguration().getSetting(ChaiSetting.BIND_DN);
bindIsSelf = userIdentity.canonicalEquals(new UserIdentity(bindDN, userIdentity.getLdapProfileID()), pwmApplication);
LOGGER.trace(sessionLabel, "preparing to setActorPassword for '" + theUser.getEntryDN() + "', using bind DN: " + bindDN);
final boolean settingEnableChange = Boolean.parseBoolean(pwmApplication.getConfig().readAppProperty(AppProperty.LDAP_PASSWORD_CHANGE_SELF_ENABLE));
if (settingEnableChange) {
if (oldPassword == null) {
theUser.setPassword(newPassword.getStringValue(), true);
} else {
theUser.changePassword(oldPassword.getStringValue(), newPassword.getStringValue());
}
} else {
LOGGER.debug(sessionLabel, "skipping actual ldap password change operation due to app property " + AppProperty.LDAP_PASSWORD_CHANGE_SELF_ENABLE.getKey() + "=false");
}
} catch (ChaiPasswordPolicyException e) {
final String errorMsg = "error setting password for user '" + userIdentity.toDisplayString() + "'' " + e.toString();
final PwmError pwmError = PwmError.forChaiError(e.getErrorCode());
final ErrorInformation error = new ErrorInformation(pwmError == null ? PwmError.PASSWORD_UNKNOWN_VALIDATION : pwmError, errorMsg);
throw new PwmOperationalException(error);
} catch (ChaiOperationException e) {
final String errorMsg = "error setting password for user '" + userIdentity.toDisplayString() + "'' " + e.getMessage();
final PwmError pwmError = PwmError.forChaiError(e.getErrorCode()) == null ? PwmError.ERROR_UNKNOWN : PwmError.forChaiError(e.getErrorCode());
final ErrorInformation error = new ErrorInformation(pwmError, errorMsg);
throw new PwmOperationalException(error);
} catch (ChaiUnavailableException e) {
throw PwmUnrecoverableException.fromChaiException(e);
}
// add the old password to the global history list (if the old password is known)
if (oldPassword != null && pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.PASSWORD_SHAREDHISTORY_ENABLE)) {
pwmApplication.getSharedHistoryManager().addWord(sessionLabel, oldPassword.getStringValue());
}
// update stats
pwmApplication.getStatisticsManager().updateEps(EpsStatistic.PASSWORD_CHANGES, 1);
final int passwordStrength = PasswordUtility.judgePasswordStrength(pwmApplication.getConfig(), newPassword.getStringValue());
pwmApplication.getStatisticsManager().updateAverageValue(Statistic.AVG_PASSWORD_STRENGTH, passwordStrength);
// at this point the password has been changed, so log it.
final String msg = (bindIsSelf ? "user " + userIdentity.toDisplayString() + " has changed own password" : "password for user '" + userIdentity.toDisplayString() + "' has been changed by " + bindDN) + " (" + TimeDuration.fromCurrent(startTime).asCompactString() + ")";
LOGGER.info(sessionLabel, msg);
}
use of com.novell.ldapchai.exception.ChaiUnavailableException in project pwm by pwm-project.
the class PasswordUtility method readLdapPasswordPolicy.
public static PwmPasswordPolicy readLdapPasswordPolicy(final PwmApplication pwmApplication, final ChaiUser theUser) throws PwmUnrecoverableException {
try {
final Map<String, String> ruleMap = new HashMap<>();
final ChaiPasswordPolicy chaiPolicy;
try {
chaiPolicy = theUser.getPasswordPolicy();
} catch (ChaiUnavailableException e) {
throw new PwmUnrecoverableException(PwmError.forChaiError(e.getErrorCode()));
}
if (chaiPolicy != null) {
for (final String key : chaiPolicy.getKeys()) {
ruleMap.put(key, chaiPolicy.getValue(key));
}
if (!"read".equals(pwmApplication.getConfig().readSettingAsString(PwmSetting.PASSWORD_POLICY_CASE_SENSITIVITY))) {
ruleMap.put(PwmPasswordRule.CaseSensitive.getKey(), pwmApplication.getConfig().readSettingAsString(PwmSetting.PASSWORD_POLICY_CASE_SENSITIVITY));
}
return PwmPasswordPolicy.createPwmPasswordPolicy(ruleMap, chaiPolicy);
}
} catch (ChaiOperationException e) {
LOGGER.warn("error reading password policy for user " + theUser.getEntryDN() + ", error: " + e.getMessage());
}
return PwmPasswordPolicy.defaultPolicy();
}
use of com.novell.ldapchai.exception.ChaiUnavailableException in project pwm by pwm-project.
the class OtpService method readOTPUserConfiguration.
public OTPUserRecord readOTPUserConfiguration(final SessionLabel sessionLabel, final UserIdentity userIdentity) throws PwmUnrecoverableException, ChaiUnavailableException {
OTPUserRecord otpConfig = null;
final Configuration config = pwmApplication.getConfig();
final Date methodStartTime = new Date();
final List<DataStorageMethod> otpSecretStorageLocations = config.getOtpSecretStorageLocations(PwmSetting.OTP_SECRET_READ_PREFERENCE);
if (otpSecretStorageLocations != null) {
final String userGUID = readGuidIfNeeded(pwmApplication, sessionLabel, otpSecretStorageLocations, userIdentity);
final Iterator<DataStorageMethod> locationIterator = otpSecretStorageLocations.iterator();
while (otpConfig == null && locationIterator.hasNext()) {
final DataStorageMethod location = locationIterator.next();
final OtpOperator operator = operatorMap.get(location);
if (operator != null) {
try {
otpConfig = operator.readOtpUserConfiguration(userIdentity, userGUID);
} catch (Exception e) {
LOGGER.error(sessionLabel, "unexpected error reading stored otp configuration from " + location + " for user " + userIdentity + ", error: " + e.getMessage());
}
} else {
LOGGER.warn(sessionLabel, String.format("storage location %s not implemented", location.toString()));
}
}
}
LOGGER.trace(sessionLabel, "readOTPUserConfiguration completed in " + TimeDuration.fromCurrent(methodStartTime).asCompactString() + (otpConfig == null ? ", no otp record found" : ", recordType=" + otpConfig.getType() + ", identifier=" + otpConfig.getIdentifier() + ", timestamp=" + JavaHelper.toIsoDate(otpConfig.getTimestamp())));
return otpConfig;
}
Aggregations