KEYCLOAK-1101 - Added notUsername() to password policy.
This commit is contained in:
parent
d8b34b68ec
commit
a64ce244d5
6 changed files with 70 additions and 44 deletions
|
@ -1042,7 +1042,8 @@ module.factory('PasswordPolicy', function() {
|
|||
digits: "Minimal number (integer type) of digits in password. Default value is 1.",
|
||||
lowerCase: "Minimal number (integer type) of lowercase characters in password. Default value is 1.",
|
||||
upperCase: "Minimal number (integer type) of uppercase characters in password. Default value is 1.",
|
||||
specialChars: "Minimal number (integer type) of special characters in password. Default value is 1."
|
||||
specialChars: "Minimal number (integer type) of special characters in password. Default value is 1.",
|
||||
notUsername: "Block passwords that are equal to the username"
|
||||
}
|
||||
|
||||
p.allPolicies = [
|
||||
|
@ -1051,7 +1052,8 @@ module.factory('PasswordPolicy', function() {
|
|||
{ name: 'digits', value: 1 },
|
||||
{ name: 'lowerCase', value: 1 },
|
||||
{ name: 'upperCase', value: 1 },
|
||||
{ name: 'specialChars', value: 1 }
|
||||
{ name: 'specialChars', value: 1 },
|
||||
{ name: 'notUsername', value: 1 }
|
||||
];
|
||||
|
||||
p.parse = function(policyString) {
|
||||
|
@ -1068,9 +1070,9 @@ module.factory('PasswordPolicy', function() {
|
|||
var re = /(\w+)\(*(\d*)\)*/;
|
||||
|
||||
var policyEntry = re.exec(policyToken);
|
||||
|
||||
policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
|
||||
|
||||
if (null !== policyEntry) {
|
||||
policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
|
||||
}
|
||||
}
|
||||
|
||||
return policies;
|
||||
|
|
|
@ -46,7 +46,9 @@
|
|||
<input class="form-control disabled" type="text" value="{{p.name|capitalize}}" readonly>
|
||||
</td>
|
||||
<td>
|
||||
<input class="form-control" ng-model="p.value" type="number" placeholder="No value assigned" min="1">
|
||||
<input class="form-control" ng-model="p.value" ng-show="p.name != 'notUsername' "
|
||||
placeholder="No value assigned"
|
||||
min="1">
|
||||
</td>
|
||||
<td class="actions">
|
||||
<div class="action-div"><i class="pficon pficon-delete" ng-click="removePolicy($index)" tooltip-placement="right" tooltip="Remove Policy"></i></div>
|
||||
|
|
|
@ -52,6 +52,8 @@ public class PasswordPolicy {
|
|||
list.add(new UpperCase(args));
|
||||
} else if (name.equals(SpecialChars.NAME)) {
|
||||
list.add(new SpecialChars(args));
|
||||
} else if (name.equals(NotUsername.NAME)) {
|
||||
list.add(new NotUsername(args));
|
||||
} else if (name.equals(HashIterations.NAME)) {
|
||||
list.add(new HashIterations(args));
|
||||
}
|
||||
|
@ -74,9 +76,9 @@ public class PasswordPolicy {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
for (Policy p : policies) {
|
||||
String error = p.validate(password);
|
||||
String error = p.validate(username, password);
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
|
@ -85,7 +87,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
private static interface Policy {
|
||||
public String validate(String password);
|
||||
public String validate(String username, String password);
|
||||
}
|
||||
|
||||
private static class HashIterations implements Policy {
|
||||
|
@ -97,11 +99,23 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NotUsername implements Policy {
|
||||
private static final String NAME = "notUsername";
|
||||
|
||||
public NotUsername(String[] args) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validate(String username, String password) {
|
||||
return username.equals(password) ? "Invalid password: must not be equal to the username" : null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Length implements Policy {
|
||||
private static final String NAME = "length";
|
||||
private int min;
|
||||
|
@ -111,7 +125,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
return password.length() < min ? "Invalid password: minimum length " + min : null;
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +139,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
int count = 0;
|
||||
for (char c : password.toCharArray()) {
|
||||
if (Character.isDigit(c)) {
|
||||
|
@ -145,7 +159,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
int count = 0;
|
||||
for (char c : password.toCharArray()) {
|
||||
if (Character.isLowerCase(c)) {
|
||||
|
@ -165,7 +179,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
int count = 0;
|
||||
for (char c : password.toCharArray()) {
|
||||
if (Character.isUpperCase(c)) {
|
||||
|
@ -185,7 +199,7 @@ public class PasswordPolicy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String validate(String password) {
|
||||
public String validate(String username, String password) {
|
||||
int count = 0;
|
||||
for (char c : password.toCharArray()) {
|
||||
if (!Character.isLetterOrDigit(c)) {
|
||||
|
|
|
@ -323,7 +323,7 @@ public class UserFederationManager implements UserProvider {
|
|||
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
|
||||
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
if (realm.getPasswordPolicy() != null) {
|
||||
String error = realm.getPasswordPolicy().validate(credential.getValue());
|
||||
String error = realm.getPasswordPolicy().validate(user.getUsername(), credential.getValue());
|
||||
if (error != null) throw new ModelException(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,68 +11,76 @@ public class PasswordPolicyTest {
|
|||
@Test
|
||||
public void testLength() {
|
||||
PasswordPolicy policy = new PasswordPolicy("length");
|
||||
Assert.assertEquals("Invalid password: minimum length 8", policy.validate("1234567"));
|
||||
Assert.assertNull(policy.validate("12345678"));
|
||||
Assert.assertEquals("Invalid password: minimum length 8", policy.validate("jdoe", "1234567"));
|
||||
Assert.assertNull(policy.validate("jdoe", "12345678"));
|
||||
|
||||
policy = new PasswordPolicy("length(4)");
|
||||
Assert.assertEquals("Invalid password: minimum length 4", policy.validate("123"));
|
||||
Assert.assertNull(policy.validate("1234"));
|
||||
Assert.assertEquals("Invalid password: minimum length 4", policy.validate("jdoe", "123"));
|
||||
Assert.assertNull(policy.validate("jdoe", "1234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDigits() {
|
||||
PasswordPolicy policy = new PasswordPolicy("digits");
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 numerical digits", policy.validate("abcd"));
|
||||
Assert.assertNull(policy.validate("abcd1"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 numerical digits", policy.validate("jdoe", "abcd"));
|
||||
Assert.assertNull(policy.validate("jdoe", "abcd1"));
|
||||
|
||||
policy = new PasswordPolicy("digits(2)");
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 numerical digits", policy.validate("abcd1"));
|
||||
Assert.assertNull(policy.validate("abcd12"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 numerical digits", policy.validate("jdoe", "abcd1"));
|
||||
Assert.assertNull(policy.validate("jdoe", "abcd12"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowerCase() {
|
||||
PasswordPolicy policy = new PasswordPolicy("lowerCase");
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 lower case characters", policy.validate("ABCD1234"));
|
||||
Assert.assertNull(policy.validate("ABcD1234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 lower case characters", policy.validate("jdoe", "ABCD1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "ABcD1234"));
|
||||
|
||||
policy = new PasswordPolicy("lowerCase(2)");
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 lower case characters", policy.validate("ABcD1234"));
|
||||
Assert.assertNull(policy.validate("aBcD1234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 lower case characters", policy.validate("jdoe", "ABcD1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "aBcD1234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpperCase() {
|
||||
PasswordPolicy policy = new PasswordPolicy("upperCase");
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 upper case characters", policy.validate("abcd1234"));
|
||||
Assert.assertNull(policy.validate("abCd1234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 upper case characters", policy.validate("jdoe", "abcd1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "abCd1234"));
|
||||
|
||||
policy = new PasswordPolicy("upperCase(2)");
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 upper case characters", policy.validate("abCd1234"));
|
||||
Assert.assertNull(policy.validate("AbCd1234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 upper case characters", policy.validate("jdoe", "abCd1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "AbCd1234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpecialChars() {
|
||||
PasswordPolicy policy = new PasswordPolicy("specialChars");
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 special characters", policy.validate("abcd1234"));
|
||||
Assert.assertNull(policy.validate("ab&d1234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 1 special characters", policy.validate("jdoe", "abcd1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "ab&d1234"));
|
||||
|
||||
policy = new PasswordPolicy("specialChars(2)");
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 special characters", policy.validate("ab&d1234"));
|
||||
Assert.assertNull(policy.validate("ab&d-234"));
|
||||
Assert.assertEquals("Invalid password: must contain at least 2 special characters", policy.validate("jdoe", "ab&d1234"));
|
||||
Assert.assertNull(policy.validate("jdoe", "ab&d-234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotUsername() {
|
||||
PasswordPolicy policy = new PasswordPolicy("notUsername");
|
||||
Assert.assertEquals("Invalid password: must not be equal to the username", policy.validate("jdoe", "jdoe"));
|
||||
Assert.assertNull(policy.validate("jdoe", "ab&d1234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplex() {
|
||||
PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2)");
|
||||
Assert.assertNotNull(policy.validate("12aaBB&"));
|
||||
Assert.assertNotNull(policy.validate("aaaaBB&-"));
|
||||
Assert.assertNotNull(policy.validate("12AABB&-"));
|
||||
Assert.assertNotNull(policy.validate("12aabb&-"));
|
||||
Assert.assertNotNull(policy.validate("12aaBBcc"));
|
||||
PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2) and notUsername()");
|
||||
Assert.assertNotNull(policy.validate("jdoe", "12aaBB&"));
|
||||
Assert.assertNotNull(policy.validate("jdoe", "aaaaBB&-"));
|
||||
Assert.assertNotNull(policy.validate("jdoe", "12AABB&-"));
|
||||
Assert.assertNotNull(policy.validate("jdoe", "12aabb&-"));
|
||||
Assert.assertNotNull(policy.validate("jdoe", "12aaBBcc"));
|
||||
Assert.assertNotNull(policy.validate("12aaBB&-", "12aaBB&-"));
|
||||
|
||||
Assert.assertNull(policy.validate("12aaBB&-"));
|
||||
Assert.assertNull(policy.validate("jdoe", "12aaBB&-"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class Validation {
|
|||
}
|
||||
|
||||
public static String validatePassword(MultivaluedMap<String, String> formData, PasswordPolicy policy) {
|
||||
return policy.validate(formData.getFirst("password"));
|
||||
return policy.validate(formData.getFirst("username"), formData.getFirst("password"));
|
||||
}
|
||||
|
||||
public static String validateUpdateProfileForm(MultivaluedMap<String, String> formData) {
|
||||
|
|
Loading…
Reference in a new issue