Details
diff --git a/server-spi/src/main/java/org/keycloak/events/Errors.java b/server-spi/src/main/java/org/keycloak/events/Errors.java
index 0981806..ea2b887 100755
--- a/server-spi/src/main/java/org/keycloak/events/Errors.java
+++ b/server-spi/src/main/java/org/keycloak/events/Errors.java
@@ -71,4 +71,8 @@ public interface Errors {
String INVALID_EMAIL = "invalid_email";
String IDENTITY_PROVIDER_LOGIN_FAILURE = "identity_provider_login_failure";
String IDENTITY_PROVIDER_ERROR = "identity_provider_error";
+
+ String PASSWORD_CONFIRM_ERROR = "password_confirm_error";
+ String PASSWORD_MISSING = "password_missing";
+ String PASSWORD_REJECTED = "password_rejected";
}
diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
index 47c9d5b..7918815 100755
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
@@ -21,6 +21,8 @@ import org.keycloak.Config;
import org.keycloak.authentication.RequiredActionContext;
import org.keycloak.authentication.RequiredActionFactory;
import org.keycloak.authentication.RequiredActionProvider;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.KeycloakSession;
@@ -84,17 +86,23 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm");
+ EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
+ .client(context.getClientSession().getClient())
+ .user(context.getClientSession().getUserSession().getUser());
+
if (Validation.isBlank(passwordNew)) {
Response challenge = context.form()
.setError(Messages.MISSING_PASSWORD)
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
context.challenge(challenge);
+ errorEvent.error(Errors.PASSWORD_MISSING);
return;
} else if (!passwordNew.equals(passwordConfirm)) {
Response challenge = context.form()
.setError(Messages.NOTMATCH_PASSWORD)
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
context.challenge(challenge);
+ errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
return;
}
@@ -102,12 +110,14 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
context.getSession().users().updateCredential(context.getRealm(), context.getUser(), UserCredentialModel.password(passwordNew));
context.success();
} catch (ModelException me) {
+ errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
Response challenge = context.form()
.setError(me.getMessage(), me.getParameters())
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
context.challenge(challenge);
return;
} catch (Exception ape) {
+ errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
Response challenge = context.form()
.setError(ape.getMessage())
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 251cd8e..bf6fb88 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -16,7 +16,7 @@
*/
package org.keycloak.services.resources;
-import org.jboss.logging.Logger;
+import org.keycloak.events.Errors;
import org.keycloak.forms.account.AccountPages;
import org.keycloak.forms.account.AccountProvider;
import org.keycloak.events.Details;
@@ -612,26 +612,34 @@ public class AccountService extends AbstractSecuredLocalService {
String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm");
+ EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
+ .client(auth.getClient())
+ .user(auth.getClientSession().getUserSession().getUser());
+
if (requireCurrent) {
if (Validation.isBlank(password)) {
setReferrerOnPage();
+ errorEvent.error(Errors.PASSWORD_MISSING);
return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
}
UserCredentialModel cred = UserCredentialModel.password(password);
if (!session.users().validCredentials(session, realm, user, cred)) {
setReferrerOnPage();
+ errorEvent.error(Errors.INVALID_USER_CREDENTIALS);
return account.setError(Messages.INVALID_PASSWORD_EXISTING).createResponse(AccountPages.PASSWORD);
}
}
if (Validation.isBlank(passwordNew)) {
setReferrerOnPage();
+ errorEvent.error(Errors.PASSWORD_MISSING);
return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
}
if (!passwordNew.equals(passwordConfirm)) {
setReferrerOnPage();
+ errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
return account.setError(Messages.INVALID_PASSWORD_CONFIRM).createResponse(AccountPages.PASSWORD);
}
@@ -639,14 +647,17 @@ public class AccountService extends AbstractSecuredLocalService {
session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew));
} catch (ModelReadOnlyException mre) {
setReferrerOnPage();
+ errorEvent.error(Errors.NOT_ALLOWED);
return account.setError(Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD);
- }catch (ModelException me) {
+ } catch (ModelException me) {
logger.failedToUpdatePassword(me);
setReferrerOnPage();
+ errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
return account.setError(me.getMessage(), me.getParameters()).createResponse(AccountPages.PASSWORD);
- }catch (Exception ape) {
+ } catch (Exception ape) {
logger.failedToUpdatePassword(ape);
setReferrerOnPage();
+ errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index cf8791e..66dee2e 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -892,7 +892,7 @@ public class LoginActionsService {
return AuthenticationManager.finishedRequiredActions(session, userSession, clientSession, clientConnection, request, uriInfo, event);
}
- }
+ }
if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
return context.getChallenge();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index a4f7257..5f8a51d 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -21,6 +21,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.services.resources.AccountService;
@@ -168,22 +169,20 @@ public class AccountTest extends TestRealmKeycloakTest {
EventRepresentation event = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
String sessionId = event.getSessionId();
String userId = event.getUserId();
- changePasswordPage.changePassword("", "new-password", "new-password");
+ changePasswordPage.changePassword("", "new-password", "new-password");
Assert.assertEquals("Please specify password.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_MISSING).assertEvent();
changePasswordPage.changePassword("password", "new-password", "new-password2");
-
Assert.assertEquals("Password confirmation doesn't match.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_CONFIRM_ERROR).assertEvent();
changePasswordPage.changePassword("password", "new-password", "new-password");
-
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
changePasswordPage.logout();
-
events.expectLogout(sessionId).detail(Details.REDIRECT_URI, changePasswordPage.getPath()).assertEvent();
loginPage.open();
@@ -191,7 +190,7 @@ public class AccountTest extends TestRealmKeycloakTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().session((String) null).error("invalid_user_credentials")
+ events.expectLogin().session((String) null).error(Errors.INVALID_USER_CREDENTIALS)
.removeDetail(Details.CONSENT)
.assertEvent();
@@ -214,18 +213,14 @@ public class AccountTest extends TestRealmKeycloakTest {
changePasswordPage.open();
loginPage.login("test-user@localhost", "password");
-
-
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("", "new", "new");
-
Assert.assertEquals("Please specify password.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_MISSING).assertEvent();
changePasswordPage.changePassword("password", "new-password", "new-password");
-
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
@@ -235,31 +230,26 @@ public class AccountTest extends TestRealmKeycloakTest {
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: must not be equal to any of last 2 passwords.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
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: must not be equal to any of last 2 passwords.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password1", "password1", "password1");
-
Assert.assertEquals("Invalid password: must not be equal to any of last 2 passwords.", profilePage.getError());
+ events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
changePasswordPage.changePassword("password1", "password2", "password2");
-
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 98a3fe6..78d20d9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -314,6 +314,7 @@ public class ResetPasswordTest extends TestRealmKeycloakTest {
assertTrue(updatePasswordPage.isCurrent());
assertEquals(error, updatePasswordPage.getError());
+ events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
}
@Test
@@ -544,6 +545,8 @@ public class ResetPasswordTest extends TestRealmKeycloakTest {
assertEquals("Invalid password: minimum length 8.", resetPasswordPage.getErrorMessage());
+ events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
+
updatePasswordPage.changePassword("resetPasswordWithPasswordPolicy", "resetPasswordWithPasswordPolicy");
String sessionId = events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();