refactor profile and totp update
This commit is contained in:
parent
f245b67036
commit
d4af694c6f
7 changed files with 78 additions and 80 deletions
|
@ -5,7 +5,7 @@
|
|||
<#elseif section = "header">
|
||||
${msg("loginProfileTitle")}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginUpdateProfileUrl}" method="post">
|
||||
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -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<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||
UserModel user = context.getUser();
|
||||
KeycloakSession session = context.getSession();
|
||||
RealmModel realm = context.getRealm();
|
||||
|
||||
|
||||
List<FormMessage> 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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, String> 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<FormMessage> 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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
Loading…
Reference in a new issue