diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl index f80909e96e..22575087ff 100755 --- a/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl +++ b/forms/common-themes/src/main/resources/theme/base/login/login-update-profile.ftl @@ -5,7 +5,7 @@ <#elseif section = "header"> ${msg("loginProfileTitle")} <#elseif section = "form"> -
+
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 1521efa328..d336fb98e2 100755 --- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java +++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java @@ -58,7 +58,8 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac @Override public void requiredActionChallenge(RequiredActionContext context) { - Response challenge = context.form().createForm("login-update-password.ftl"); + Response challenge = context.form() + .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); context.challenge(challenge); } @@ -73,13 +74,13 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac if (Validation.isBlank(passwordNew)) { Response challenge = context.form() .setError(Messages.MISSING_PASSWORD) - .createForm("login-update-password.ftl"); + .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); context.challenge(challenge); return; } else if (!passwordNew.equals(passwordConfirm)) { Response challenge = context.form() .setError(Messages.NOTMATCH_PASSWORD) - .createForm("login-update-password.ftl"); + .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); context.challenge(challenge); return; } @@ -90,13 +91,13 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac } catch (ModelException me) { Response challenge = context.form() .setError(me.getMessage(), me.getParameters()) - .createForm("login-update-password.ftl"); + .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); context.challenge(challenge); return; } catch (Exception ape) { Response challenge = context.form() .setError(ape.getMessage()) - .createForm("login-update-password.ftl"); + .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); context.challenge(challenge); return; } diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java index 9ca78a67cc..42c2e02348 100755 --- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java +++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateProfile.java @@ -5,12 +5,25 @@ 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.EventBuilder; +import org.keycloak.events.EventType; import org.keycloak.login.LoginFormsProvider; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.utils.FormMessage; +import org.keycloak.services.managers.ClientSessionCode; +import org.keycloak.services.messages.Messages; +import org.keycloak.services.resources.AttributeFormDataProcessor; +import org.keycloak.services.validation.Validation; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import java.util.List; /** * @author Bill Burke @@ -24,16 +37,63 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact @Override public void requiredActionChallenge(RequiredActionContext context) { - LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class) - .setClientSessionCode(context.generateAccessCode(UserModel.RequiredAction.UPDATE_PROFILE.name())) - .setUser(context.getUser()); - Response challenge = loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PROFILE); + Response challenge = context.form() + .createResponse(UserModel.RequiredAction.UPDATE_PROFILE); context.challenge(challenge); } @Override public void processAction(RequiredActionContext context) { - context.failure(); + EventBuilder event = context.getEvent(); + event.event(EventType.UPDATE_PROFILE); + MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters(); + UserModel user = context.getUser(); + KeycloakSession session = context.getSession(); + RealmModel realm = context.getRealm(); + + + List errors = Validation.validateUpdateProfileForm(formData); + if (errors != null && !errors.isEmpty()) { + Response challenge = context.form() + .setErrors(errors) + .setFormData(formData) + .createResponse(UserModel.RequiredAction.UPDATE_PROFILE); + context.challenge(challenge); + return; + } + + user.setFirstName(formData.getFirst("firstName")); + user.setLastName(formData.getFirst("lastName")); + + String email = formData.getFirst("email"); + + String oldEmail = user.getEmail(); + boolean emailChanged = oldEmail != null ? !oldEmail.equals(email) : email != null; + + if (emailChanged) { + UserModel userByEmail = session.users().getUserByEmail(email, realm); + + // check for duplicated email + if (userByEmail != null && !userByEmail.getId().equals(user.getId())) { + Response challenge = context.form() + .setError(Messages.EMAIL_EXISTS) + .setFormData(formData) + .createResponse(UserModel.RequiredAction.UPDATE_PROFILE); + context.challenge(challenge); + return; + } + + user.setEmail(email); + user.setEmailVerified(false); + } + + AttributeFormDataProcessor.process(formData, realm, user); + + if (emailChanged) { + event.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success(); + } + context.success(); + } diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java index 82adf9b7c8..18e6682ecd 100755 --- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java +++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java @@ -36,7 +36,8 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory @Override public void requiredActionChallenge(RequiredActionContext context) { - Response challenge = context.form().createResponse(UserModel.RequiredAction.CONFIGURE_TOTP); + Response challenge = context.form() + .createResponse(UserModel.RequiredAction.CONFIGURE_TOTP); context.challenge(challenge); } 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 edd9e6a037..0a8d3c6b21 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -512,70 +512,6 @@ public class LoginActionsService { return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection); } - @Path("profile") - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - public Response updateProfile(@QueryParam("code") String code, - final MultivaluedMap formData) { - event.event(EventType.UPDATE_PROFILE); - Checks checks = new Checks(); - if (!checks.verifyCode(code, ClientSessionModel.Action.UPDATE_PROFILE.name())) { - return checks.response; - } - ClientSessionCode accessCode = checks.clientCode; - ClientSessionModel clientSession = accessCode.getClientSession(); - UserSessionModel userSession = clientSession.getUserSession(); - UserModel user = userSession.getUser(); - - initEvent(clientSession); - - List errors = Validation.validateUpdateProfileForm(formData); - if (errors != null && !errors.isEmpty()) { - return session.getProvider(LoginFormsProvider.class) - .setClientSessionCode(accessCode.getCode()) - .setUser(user) - .setErrors(errors) - .setFormData(formData) - .createResponse(RequiredAction.UPDATE_PROFILE); - } - - user.setFirstName(formData.getFirst("firstName")); - user.setLastName(formData.getFirst("lastName")); - - String email = formData.getFirst("email"); - - String oldEmail = user.getEmail(); - boolean emailChanged = oldEmail != null ? !oldEmail.equals(email) : email != null; - - if (emailChanged) { - UserModel userByEmail = session.users().getUserByEmail(email, realm); - - // check for duplicated email - if (userByEmail != null && !userByEmail.getId().equals(user.getId())) { - return session.getProvider(LoginFormsProvider.class) - .setUser(user) - .setError(Messages.EMAIL_EXISTS) - .setClientSessionCode(accessCode.getCode()) - .setFormData(formData) - .createResponse(RequiredAction.UPDATE_PROFILE); - } - - user.setEmail(email); - user.setEmailVerified(false); - } - - AttributeFormDataProcessor.process(formData, realm, user); - - user.removeRequiredAction(RequiredAction.UPDATE_PROFILE); - event.clone().event(EventType.UPDATE_PROFILE).success(); - - if (emailChanged) { - event.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success(); - } - - return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event); - } - @Path("email-verification") @GET public Response emailVerification(@QueryParam("code") String code, @QueryParam("key") String key) { diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java index 4d16a1b1dc..868a76cc50 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java @@ -123,12 +123,12 @@ public class RequiredActionMultipleActionsTest { public String updateProfile(String sessionId) { updateProfilePage.update("New first", "New last", "new@email.com"); - AssertEvents.ExpectedEvent expectedEvent = events.expectRequiredAction(EventType.UPDATE_PROFILE); + AssertEvents.ExpectedEvent expectedEvent = events.expectRequiredAction(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com"); if (sessionId != null) { expectedEvent.session(sessionId); } sessionId = expectedEvent.assertEvent().getSessionId(); - events.expectRequiredAction(EventType.UPDATE_EMAIL).session(sessionId).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent(); + events.expectRequiredAction(EventType.UPDATE_PROFILE).session(sessionId).assertEvent(); return sessionId; } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java index a7c84a0723..e3d6ac921d 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java @@ -89,8 +89,8 @@ public class RequiredActionUpdateProfileTest { updateProfilePage.update("New first", "New last", "new@email.com"); - String sessionId = events.expectRequiredAction(EventType.UPDATE_PROFILE).assertEvent().getSessionId(); - events.expectRequiredAction(EventType.UPDATE_EMAIL).session(sessionId).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent(); + String sessionId = events.expectRequiredAction(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent().getSessionId(); + events.expectRequiredAction(EventType.UPDATE_PROFILE).session(sessionId).assertEvent(); Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());