Merge pull request #1558 from patriot1burke/master
refactor update password
This commit is contained in:
commit
945673c7da
8 changed files with 74 additions and 80 deletions
|
@ -67,7 +67,8 @@ public enum EventType {
|
|||
IDENTITY_PROVIDER_ACCCOUNT_LINKING(false),
|
||||
IDENTITY_PROVIDER_ACCCOUNT_LINKING_ERROR(false),
|
||||
IMPERSONATE(true),
|
||||
CUSTOM_REQUIRED_ACTION(true);
|
||||
CUSTOM_REQUIRED_ACTION(true),
|
||||
CUSTOM_REQUIRED_ACTION_ERROR(true);
|
||||
|
||||
private boolean saveByDefault;
|
||||
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
<#elseif section = "form">
|
||||
<div id="kc-info-message">
|
||||
<p class="instruction">${message.summary}</p>
|
||||
<#if skipLink??>
|
||||
<#else>
|
||||
<#if client.baseUrl??>
|
||||
<p><a href="${client.baseUrl}">${msg("backToApplication")}</a></p>
|
||||
</#if>
|
||||
</#if>
|
||||
</div>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -5,7 +5,7 @@
|
|||
<#elseif section = "header">
|
||||
${msg("updatePasswordTitle")}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-passwd-update-form" class="${properties.kcFormClass!}" action="${url.loginUpdatePasswordUrl}" method="post">
|
||||
<form id="kc-passwd-update-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password-new" class="${properties.kcLabelClass!}">${msg("passwordNew")}</label>
|
||||
|
|
|
@ -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<String, String> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<String, String> 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) {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ public class TermsAndConditionsTest {
|
|||
|
||||
termsPage.declineTerms();
|
||||
|
||||
events.expectLogin().detail(Details.CUSTOM_REQUIRED_ACTION, TermsAndConditions.PROVIDER_ID)
|
||||
events.expectLogin().event(EventType.CUSTOM_REQUIRED_ACTION_ERROR).detail(Details.CUSTOM_REQUIRED_ACTION, TermsAndConditions.PROVIDER_ID)
|
||||
.error(Errors.REJECTED_BY_USER)
|
||||
.removeDetail(Details.CONSENT)
|
||||
.assertEvent();
|
||||
|
|
Loading…
Reference in a new issue