KEYCLOAK-1101 - Added notUsername() to password policy.

This commit is contained in:
Juraci Paixão Kröhling 2015-03-13 09:29:14 +01:00
parent d8b34b68ec
commit a64ce244d5
6 changed files with 70 additions and 44 deletions

View file

@ -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;

View file

@ -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>

View file

@ -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)) {

View file

@ -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);
}
}

View file

@ -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&-"));
}
}

View file

@ -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) {