Added password policy test cases for regex and password history.
This commit is contained in:
parent
0ff4b6dd93
commit
ad715371a3
9 changed files with 209 additions and 19 deletions
|
@ -89,14 +89,14 @@ identityProviderRemovedMessage=Identity Provider erfolgreich entfernt.
|
|||
accountDisabledMessage=Benutzerkonto ist gesperrt, bitte kontaktieren Sie den Admin.
|
||||
|
||||
accountTemporarilyDisabledMessage=Benutzerkonto ist tempor\u00E4r gesperrt, bitte kontaktieren Sie den Admin oder versuchen Sie es sp\u00E4ter noch einmal.
|
||||
invalidPasswordMinLengthMessage=Ung\u00FCltiges Passwort: minimum l\u00E4nge {0}.
|
||||
invalidPasswordMinDigitsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Zahl(en) beinhalten.
|
||||
invalidPasswordMinLowerCaseCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Kleinbuchstaben beinhalten.
|
||||
invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Grossbuchstaben beinhalten.
|
||||
invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort: muss mindestens {0} Spezialzeichen beinhalten.
|
||||
invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort: darf nicht gleich sein wie Benutzername.
|
||||
invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort: nicht Regex-Muster (n) entsprechen.
|
||||
invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort: muss nicht gleich einem der letzten {0} Kennw\u00F6rter sein.
|
||||
invalidPasswordMinLengthMessage=Ung\u00FCltiges Passwort\: minimum l\u00E4nge {0}.
|
||||
invalidPasswordMinDigitsMessage=Ung\u00FCltiges Passwort\: muss mindestens {0} Zahl(en) beinhalten.
|
||||
invalidPasswordMinLowerCaseCharsMessage=Ung\u00FCltiges Passwort\: muss mindestens {0} Kleinbuchstaben beinhalten.
|
||||
invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort\: muss mindestens {0} Grossbuchstaben beinhalten.
|
||||
invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort\: muss mindestens {0} Spezialzeichen beinhalten.
|
||||
invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort\: darf nicht gleich sein wie Benutzername.
|
||||
invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort\: nicht Regex-Muster (n) entsprechen.
|
||||
invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort {0}: darf nicht gleich einem der letzten Passwortgeschichte.
|
||||
|
||||
locale_de=Deutsch
|
||||
locale_en=Englisch
|
||||
|
|
|
@ -95,7 +95,7 @@ invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least
|
|||
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
|
||||
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
|
||||
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
|
||||
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
|
||||
invalidPasswordHistoryMessage=Invalid password {0}: must not be equal to any of last password history.
|
||||
|
||||
locale_de=German
|
||||
locale_en=English
|
||||
|
|
|
@ -53,7 +53,7 @@ invalidPasswordMinUpperCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo m
|
|||
invalidPasswordMinSpecialCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caracteres especiais
|
||||
invalidPasswordNotUsernameMessage=Senha inv\u00E1lida\: n\u00E3o deve ser igual ao nome de usu\u00E1rio
|
||||
invalidPasswordRegexPatternMessage=Senha inv\u00E1lida\: n\u00E3o correspondem ao padr\u00E3o regex(s).
|
||||
invalidPasswordHistoryMessage=Senha inv\u00E1lida\: não deve ser igual a qualquer um dos últimos {0} senhas.
|
||||
invalidPasswordHistoryMessage=Senha inv\u00E1lida {0}\: n\u00E3o deve ser igual a qualquer uma \u00FAltima hist\u00F3ria senha.
|
||||
|
||||
locale_de=Deutsch
|
||||
locale_en=English
|
||||
|
|
|
@ -132,7 +132,7 @@ invalidPasswordMinUpperCaseCharsMessage=Ung\u00FCltiges Passwort\: muss mindeste
|
|||
invalidPasswordMinSpecialCharsMessage=Ung\u00FCltiges Passwort\: muss mindestens {0} Spezialzeichen beinhalten.
|
||||
invalidPasswordNotUsernameMessage=Ung\u00FCltiges Passwort\: darf nicht gleich sein wie Benutzername.
|
||||
invalidPasswordRegexPatternMessage=Ung\u00FCltiges Passwort\: nicht Regex-Muster (n) entsprechen.
|
||||
invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort\: muss nicht gleich einem der letzten {0} Kennw\u00F6rter sein.
|
||||
invalidPasswordHistoryMessage=Ung\u00FCltiges Passwort {0}\: darf nicht gleich einem der letzten Passwortgeschichte.
|
||||
|
||||
failedToProcessResponseMessage=Konnte Response nicht verarbeiten.
|
||||
httpsRequiredMessage=HTTPS erforderlich.
|
||||
|
|
|
@ -129,7 +129,7 @@ invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least
|
|||
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
|
||||
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
|
||||
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
|
||||
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
|
||||
invalidPasswordHistoryMessage=Invalid password {0}: must not be equal to any of last password history.
|
||||
|
||||
failedToProcessResponseMessage=Failed to process response
|
||||
httpsRequiredMessage=HTTPS required
|
||||
|
|
|
@ -119,14 +119,14 @@ accountPasswordUpdatedMessage=Sua senha foi atualizada
|
|||
|
||||
noAccessMessage=Sem acesso
|
||||
|
||||
invalidPasswordMinLengthMessage=Senha inv\u00E1lida: comprimento m\u00EDnimo {0}
|
||||
invalidPasswordMinLengthMessage=Senha inv\u00E1lida\: comprimento m\u00EDnimo {0}
|
||||
invalidPasswordMinDigitsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} d\u00EDgitos num\u00E9ricos
|
||||
invalidPasswordMinLowerCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caracteres min\u00FAsculos
|
||||
invalidPasswordMinUpperCaseCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caracteres mai\u00FAsculos
|
||||
invalidPasswordMinSpecialCharsMessage=Senha inv\u00E1lida\: deve conter pelo menos {0} caracteres especiais
|
||||
invalidPasswordNotUsernameMessage=Senha inv\u00E1lida\: n\u00E3o deve ser igual ao nome de usu\u00E1rio
|
||||
invalidPasswordRegexPatternMessage=Senha inv\u00E1lida\: n\u00E3o correspondem ao padr\u00E3o regex(s).
|
||||
invalidPasswordHistoryMessage=Senha inv\u00E1lida\: não deve ser igual a qualquer um dos últimos {0} senhas.
|
||||
invalidPasswordHistoryMessage=Senha inv\u00E1lida {0}\: n\u00E3o deve ser igual a qualquer uma \u00FAltima hist\u00F3ria senha.
|
||||
|
||||
failedToProcessResponseMessage=Falha ao processar a resposta
|
||||
httpsRequiredMessage=HTTPS requerido
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -79,6 +83,48 @@ public class PasswordPolicyTest {
|
|||
Assert.assertEquals("invalidPasswordNotUsernameMessage", policy.validate("jdoe", "jdoe").getMessage());
|
||||
Assert.assertNull(policy.validate("jdoe", "ab&d1234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegexPatterns() {
|
||||
PasswordPolicy policy = null;
|
||||
try {
|
||||
policy = new PasswordPolicy("regexPatterns");
|
||||
fail("Expected NullPointerEXception: Regex Pattern cannot be null.");
|
||||
} catch (NullPointerException e) {
|
||||
// Expected NPE as regex pattern is null.
|
||||
}
|
||||
|
||||
try {
|
||||
policy = new PasswordPolicy("regexPatterns(*)");
|
||||
fail("Expected PatternSyntaxException: Regex Pattern cannot be null.");
|
||||
} catch (PatternSyntaxException e) {
|
||||
// Expected PSE as regex pattern(or any of its token) is not quantifiable.
|
||||
}
|
||||
|
||||
try {
|
||||
policy = new PasswordPolicy("regexPatterns(*,**)");
|
||||
fail("Expected PatternSyntaxException: Regex Pattern cannot be null.");
|
||||
} catch (PatternSyntaxException e) {
|
||||
// Expected PSE as regex pattern(or any of its token) is not quantifiable.
|
||||
}
|
||||
|
||||
//Fails to match one of the regex pattern
|
||||
policy = new PasswordPolicy("regexPatterns(jdoe,j*d)");
|
||||
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage());
|
||||
|
||||
////Fails to match all of the regex patterns
|
||||
policy = new PasswordPolicy("regexPatterns(j*p,j*d,adoe)");
|
||||
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage());
|
||||
|
||||
policy = new PasswordPolicy("regexPatterns([a-z][a-z][a-z][a-z][0-9])");
|
||||
Assert.assertEquals("invalidPasswordRegexPatternMessage", policy.validate("jdoe", "jdoe").getMessage());
|
||||
|
||||
policy = new PasswordPolicy("regexPatterns(jdoe)");
|
||||
Assert.assertNull(policy.validate("jdoe", "jdoe"));
|
||||
|
||||
policy = new PasswordPolicy("regexPatterns([a-z][a-z][a-z][a-z][0-9])");
|
||||
Assert.assertNull(policy.validate("jdoe", "jdoe0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplex() {
|
||||
|
|
|
@ -229,7 +229,7 @@ public class AccountTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void changePasswordWithPasswordPolicy() {
|
||||
public void changePasswordWithLengthPasswordPolicy() {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
|
@ -262,6 +262,55 @@ public class AccountTest {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changePasswordWithPasswordHistoryPolicy() {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setPasswordPolicy(new PasswordPolicy("passwordHistory(2)"));
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
changePasswordPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
|
||||
|
||||
changePasswordPage.changePassword("password", "password", "password");
|
||||
|
||||
Assert.assertEquals("Invalid password password: must not be equal to any of last password history.", profilePage.getError());
|
||||
|
||||
changePasswordPage.changePassword("password", "password1", "password1");
|
||||
|
||||
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
|
||||
|
||||
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
|
||||
changePasswordPage.changePassword("password1", "password", "password");
|
||||
|
||||
Assert.assertEquals("Invalid password password: must not be equal to any of last password history.", profilePage.getError());
|
||||
|
||||
changePasswordPage.changePassword("password1", "password1", "password1");
|
||||
|
||||
Assert.assertEquals("Invalid password password1: must not be equal to any of last password history.", profilePage.getError());
|
||||
|
||||
changePasswordPage.changePassword("password1", "password2", "password2");
|
||||
|
||||
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
|
||||
|
||||
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
|
||||
} finally {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setPasswordPolicy(new PasswordPolicy(null));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeProfile() {
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.keycloak.services.managers.RealmManager;
|
|||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.MailUtil;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.Retry;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.pages.ErrorPage;
|
||||
|
@ -57,8 +56,7 @@ import javax.mail.internet.MimeMessage;
|
|||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -241,6 +239,44 @@ public class ResetPasswordTest {
|
|||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
}
|
||||
|
||||
private void resetPassword(String username, String password) throws IOException, MessagingException {
|
||||
loginPage.open();
|
||||
loginPage.resetPassword();
|
||||
|
||||
resetPasswordPage.assertCurrent();
|
||||
|
||||
resetPasswordPage.changePassword(username);
|
||||
|
||||
resetPasswordPage.assertCurrent();
|
||||
|
||||
String sessionId = events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).user(userId)
|
||||
.detail(Details.USERNAME, username).detail(Details.EMAIL, "login@test.com").assertEvent().getSessionId();
|
||||
|
||||
assertEquals("You should receive an email shortly with further instructions.", resetPasswordPage.getSuccessMessage());
|
||||
|
||||
MimeMessage message = greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1];
|
||||
|
||||
String body = (String) message.getContent();
|
||||
String changePasswordUrl = MailUtil.getLink(body);
|
||||
|
||||
driver.navigate().to(changePasswordUrl.trim());
|
||||
|
||||
updatePasswordPage.assertCurrent();
|
||||
|
||||
updatePasswordPage.changePassword(password, password);
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).session(sessionId)
|
||||
.detail(Details.USERNAME, username).assertEvent();
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectLogin().user(userId).detail(Details.USERNAME, username).session(sessionId).assertEvent();
|
||||
|
||||
oauth.openLogout();
|
||||
|
||||
events.expectLogout(sessionId).user(userId).session(sessionId).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetPasswordWrongEmail() throws IOException, MessagingException, InterruptedException {
|
||||
loginPage.open();
|
||||
|
@ -405,7 +441,7 @@ public class ResetPasswordTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void resetPasswordWithPasswordPolicy() throws IOException, MessagingException {
|
||||
public void resetPasswordWithLengthPasswordPolicy() throws IOException, MessagingException {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
|
@ -462,6 +498,65 @@ public class ResetPasswordTest {
|
|||
events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetPasswordWithPasswordHisoryPolicy() throws IOException, MessagingException {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
//Block passwords that are equal to previous passwords. Default value is 3.
|
||||
appRealm.setPasswordPolicy(new PasswordPolicy("passwordHistory"));
|
||||
}
|
||||
});
|
||||
|
||||
// try-catch blocks have been commented out to reduce execution time for this test case(30s->15s).
|
||||
// TODO : Comment out any other piece of code, if applicable, in order to reduce execution time.
|
||||
|
||||
resetPassword("login-test", "password1");
|
||||
/*try {
|
||||
resetPassword("login-test", "password1");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password1" matches with password history
|
||||
}*/
|
||||
|
||||
resetPassword("login-test", "password2");
|
||||
/*try {
|
||||
resetPassword("login-test", "password1");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password1" matches with password history
|
||||
}
|
||||
try {
|
||||
resetPassword("login-test", "password2");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password2" matches with password history
|
||||
}*/
|
||||
|
||||
resetPassword("login-test", "password3");
|
||||
try {
|
||||
resetPassword("login-test", "password1");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password1" matches with password history
|
||||
}
|
||||
try {
|
||||
resetPassword("login-test", "password2");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password2" matches with password history
|
||||
}
|
||||
try {
|
||||
resetPassword("login-test", "password3");
|
||||
fail("Expected NullPointerException: Block passwords that are equal to previous passwords.");
|
||||
} catch (Exception e) {
|
||||
// Expected NPE as "password3" matches with password history
|
||||
}
|
||||
|
||||
resetPassword("login-test", "password");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resetPasswordNewBrowserSession() throws IOException, MessagingException {
|
||||
String username = "login-test";
|
||||
|
|
Loading…
Reference in a new issue