From 165fba6b9cfbcc42d5859bfc4d60c2bea41d9317 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 21 Aug 2015 15:17:01 -0400 Subject: [PATCH] refactor update password --- .../main/resources/theme/base/login/info.ftl | 7 +- .../base/login/login-update-password.ftl | 2 +- .../requiredactions/UpdatePassword.java | 52 +++++++++++-- .../managers/AuthenticationManager.java | 11 +++ .../resources/LoginActionsService.java | 76 ++----------------- .../resources/admin/UsersResource.java | 1 + 6 files changed, 71 insertions(+), 78 deletions(-) diff --git a/forms/common-themes/src/main/resources/theme/base/login/info.ftl b/forms/common-themes/src/main/resources/theme/base/login/info.ftl index f4de8554e1..ca50401f5f 100755 --- a/forms/common-themes/src/main/resources/theme/base/login/info.ftl +++ b/forms/common-themes/src/main/resources/theme/base/login/info.ftl @@ -7,8 +7,11 @@ <#elseif section = "form">

${message.summary}

- <#if client.baseUrl??> -

${msg("backToApplication")}

+ <#if skipLink??> + <#else> + <#if client.baseUrl??> +

${msg("backToApplication")}

+
diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-update-password.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-update-password.ftl index d13729e3f2..bad990cb0f 100755 --- a/forms/common-themes/src/main/resources/theme/base/login/login-update-password.ftl +++ b/forms/common-themes/src/main/resources/theme/base/login/login-update-password.ftl @@ -5,7 +5,7 @@ <#elseif section = "header"> ${msg("updatePasswordTitle")} <#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 f88cdc8cbf..1521efa328 100755 --- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java +++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java @@ -5,14 +5,23 @@ import org.keycloak.Config; import org.keycloak.authentication.RequiredActionContext; import org.keycloak.authentication.RequiredActionFactory; import org.keycloak.authentication.RequiredActionProvider; +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.ModelException; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.services.managers.ClientSessionCode; +import org.keycloak.services.messages.Messages; +import org.keycloak.services.validation.Validation; import org.keycloak.util.Time; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import java.util.concurrent.TimeUnit; @@ -49,17 +58,48 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac @Override public void requiredActionChallenge(RequiredActionContext context) { - LoginFormsProvider loginFormsProvider = context.getSession() - .getProvider(LoginFormsProvider.class) - .setClientSessionCode(context.generateAccessCode(UserModel.RequiredAction.UPDATE_PASSWORD.name())) - .setUser(context.getUser()); - Response challenge = loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); + Response challenge = context.form().createForm("login-update-password.ftl"); context.challenge(challenge); } @Override public void processAction(RequiredActionContext context) { - context.failure(); + EventBuilder event = context.getEvent(); + MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters(); + event.event(EventType.UPDATE_PASSWORD); + String passwordNew = formData.getFirst("password-new"); + String passwordConfirm = formData.getFirst("password-confirm"); + + if (Validation.isBlank(passwordNew)) { + Response challenge = context.form() + .setError(Messages.MISSING_PASSWORD) + .createForm("login-update-password.ftl"); + context.challenge(challenge); + return; + } else if (!passwordNew.equals(passwordConfirm)) { + Response challenge = context.form() + .setError(Messages.NOTMATCH_PASSWORD) + .createForm("login-update-password.ftl"); + context.challenge(challenge); + return; + } + + try { + context.getSession().users().updateCredential(context.getRealm(), context.getUser(), UserCredentialModel.password(passwordNew)); + context.success(); + } catch (ModelException me) { + Response challenge = context.form() + .setError(me.getMessage(), me.getParameters()) + .createForm("login-update-password.ftl"); + context.challenge(challenge); + return; + } catch (Exception ape) { + Response challenge = context.form() + .setError(ape.getMessage()) + .createForm("login-update-password.ftl"); + context.challenge(challenge); + return; + } } @Override diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 52cca074fb..70f10e74b1 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -32,6 +32,7 @@ import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.RestartLoginCookie; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.representations.AccessToken; +import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.IdentityBrokerService; import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.Urls; @@ -57,6 +58,7 @@ import java.util.Set; * @version $Revision: 1 $ */ public class AuthenticationManager { + public static final String END_AFTER_REQUIRED_ACTIONS = "END_AFTER_REQUIRED_ACTIONS"; protected static Logger logger = Logger.getLogger(AuthenticationManager.class); public static final String FORM_USERNAME = "username"; // used for auth login @@ -409,6 +411,15 @@ public class AuthenticationManager { HttpRequest request, UriInfo uriInfo, EventBuilder event) { Response requiredAction = actionRequired(session, userSession, clientSession, clientConnection, request, uriInfo, event); if (requiredAction != null) return requiredAction; + if (clientSession.getNote(END_AFTER_REQUIRED_ACTIONS) != null) { + Response response = session.getProvider(LoginFormsProvider.class) + .setAttribute("skipLink", true) + .setSuccess(Messages.ACCOUNT_UPDATED) + .createInfoPage(); + session.sessions().removeUserSession(session.getContext().getRealm(), userSession); + return response; + + } event.success(); RealmModel realm = clientSession.getRealm(); return redirectAfterSuccessfulFlow(session, realm , userSession, clientSession, request, uriInfo, clientConnection); 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 dd2c90daf7..eea24990ea 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -628,67 +628,6 @@ public class LoginActionsService { return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event); } - @Path("password") - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - public Response updatePassword(@QueryParam("code") String code, - final MultivaluedMap formData) { - event.event(EventType.UPDATE_PASSWORD); - Checks checks = new Checks(); - if (!checks.verifyCode(code, ClientSessionModel.Action.UPDATE_PASSWORD.name(), ClientSessionModel.Action.RECOVER_PASSWORD.name())) { - return checks.response; - } - ClientSessionCode accessCode = checks.clientCode; - ClientSessionModel clientSession = accessCode.getClientSession(); - UserSessionModel userSession = clientSession.getUserSession(); - UserModel user = userSession.getUser(); - - initEvent(clientSession); - - String passwordNew = formData.getFirst("password-new"); - String passwordConfirm = formData.getFirst("password-confirm"); - - LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class) - .setUser(user); - if (Validation.isBlank(passwordNew)) { - return loginForms.setError(Messages.MISSING_PASSWORD) - .setClientSessionCode(accessCode.getCode()) - .createResponse(RequiredAction.UPDATE_PASSWORD); - } else if (!passwordNew.equals(passwordConfirm)) { - return loginForms.setError(Messages.NOTMATCH_PASSWORD) - .setClientSessionCode(accessCode.getCode()) - .createResponse(RequiredAction.UPDATE_PASSWORD); - } - - try { - session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew)); - } catch (ModelException me) { - return loginForms.setError(me.getMessage(), me.getParameters()) - .setClientSessionCode(accessCode.getCode()) - .createResponse(RequiredAction.UPDATE_PASSWORD); - } catch (Exception ape) { - return loginForms.setError(ape.getMessage()) - .setClientSessionCode(accessCode.getCode()) - .createResponse(RequiredAction.UPDATE_PASSWORD); - } - - user.removeRequiredAction(RequiredAction.UPDATE_PASSWORD); - - event.event(EventType.UPDATE_PASSWORD).success(); - - if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) { - session.sessions().removeClientSession(realm, clientSession); - return session.getProvider(LoginFormsProvider.class) - .setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED) - .createInfoPage(); - } - - event = event.clone().event(EventType.LOGIN); - - 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) { @@ -752,13 +691,11 @@ public class LoginActionsService { if (key != null) { Checks checks = new Checks(); if (!checks.verifyCode(key, ClientSessionModel.Action.RECOVER_PASSWORD.name())) { - event.error(Errors.RESET_CREDENTIAL_DISABLED); - return ErrorPage.error(session, Messages.INVALID_CODE); + return checks.response; } - ClientSessionCode accessCode = checks.clientCode; - return session.getProvider(LoginFormsProvider.class) - .setClientSessionCode(accessCode.getCode()) - .createResponse(RequiredAction.UPDATE_PASSWORD); + ClientSessionModel clientSession = checks.clientCode.getClientSession(); + clientSession.setNote("END_AFTER_REQUIRED_ACTIONS", "true"); + return AuthenticationManager.nextActionAfterAuthentication(session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); } else { event.error(Errors.RESET_CREDENTIAL_DISABLED); return ErrorPage.error(session, Messages.INVALID_CODE); @@ -843,6 +780,7 @@ public class LoginActionsService { } initEvent(clientSession); + event.event(EventType.CUSTOM_REQUIRED_ACTION); RequiredActionContextResult context = new RequiredActionContextResult(clientSession.getUserSession(), clientSession, realm, event, session, request, clientSession.getUserSession().getUser(), factory) { @@ -865,9 +803,9 @@ public class LoginActionsService { }; provider.processAction(context); if (context.getStatus() == RequiredActionContext.Status.SUCCESS) { - event.clone().event(EventType.CUSTOM_REQUIRED_ACTION) - .detail(Details.CUSTOM_REQUIRED_ACTION, action).success(); + event.clone().success(); clientSession.getUserSession().getUser().removeRequiredAction(factory.getId()); + event.event(EventType.LOGIN); return AuthenticationManager.nextActionAfterAuthentication(session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); } if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java index 066ce30817..6d55bc2405 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java @@ -854,6 +854,7 @@ public class UsersResource { accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD.name()); try { + user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); UriBuilder builder = Urls.recoverPasswordBuilder(uriInfo.getBaseUri()); builder.queryParam("key", accessCode.getCode());