package org.cloudfoundry.identity.uaa.scim.validate;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
import org.cloudfoundry.identity.uaa.provider.PasswordPolicy;
import org.cloudfoundry.identity.uaa.provider.UaaIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.scim.exception.InvalidPasswordException;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.LengthRule;
import org.passay.PasswordData;
import org.passay.Rule;
import org.passay.RuleResult;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* ****************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
* <p>
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
* <p>
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
* *****************************************************************************
*/
public class UaaPasswordPolicyValidator implements PasswordValidator {
private final IdentityProviderProvisioning provisioning;
private final PasswordPolicy globalDefaultPolicy;
public UaaPasswordPolicyValidator(PasswordPolicy globalDefaultPolicy, IdentityProviderProvisioning provisioning) {
this.globalDefaultPolicy = globalDefaultPolicy;
this.provisioning = provisioning;
}
@Override
public void validate(String password) throws InvalidPasswordException {
if (password == null) {
password = "";
}
IdentityProvider<UaaIdentityProviderDefinition> idp = provisioning.retrieveByOrigin(OriginKeys.UAA, IdentityZoneHolder.get().getId());
if (idp==null) {
//should never happen
return;
}
PasswordPolicy policy = globalDefaultPolicy;
UaaIdentityProviderDefinition idpDefinition = idp.getConfig();
if (idpDefinition != null && idpDefinition.getPasswordPolicy() != null) {
policy = idpDefinition.getPasswordPolicy();
}
org.passay.PasswordValidator validator = getPasswordValidator(policy);
RuleResult result = validator.validate(new PasswordData(password));
if (!result.isValid()) {
List<String> errorMessages = new LinkedList<>();
for (String s : validator.getMessages(result)) {
errorMessages.add(s);
}
if (!errorMessages.isEmpty()) {
throw new InvalidPasswordException(errorMessages);
}
}
}
public org.passay.PasswordValidator getPasswordValidator(PasswordPolicy policy) {
List<Rule> rules = new ArrayList<>();
//length is always a rule. We do not allow blank password
int minLength = Math.max(1, policy.getMinLength());
int maxLength = policy.getMaxLength()>0 ? policy.getMaxLength() : Integer.MAX_VALUE;
rules.add(new LengthRule(minLength, maxLength));
if (policy.getRequireUpperCaseCharacter()>0) {
rules.add(new CharacterRule(EnglishCharacterData.UpperCase, policy.getRequireUpperCaseCharacter()));
}
if (policy.getRequireLowerCaseCharacter()>0) {
rules.add(new CharacterRule(EnglishCharacterData.LowerCase, policy.getRequireLowerCaseCharacter()));
}
if (policy.getRequireDigit()>0) {
rules.add(new CharacterRule(EnglishCharacterData.Digit, policy.getRequireDigit()));
}
if (policy.getRequireSpecialCharacter() > 0) {
rules.add(new CharacterRule(EnglishCharacterData.Special, policy.getRequireSpecialCharacter()));
}
return new org.passay.PasswordValidator(rules);
}
}