diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-config-totp.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-config-totp.ftl
index f1effe7..fc264f9 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/login-config-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/login-config-totp.ftl
@@ -5,7 +5,7 @@
<#elseif section = "header">
${msg("loginTotpTitle")}
<#elseif section = "form">
- <form action="${url.loginUpdateTotpUrl}" class="${properties.kcFormClass!}" id="kc-totp-settings-form" method="post">
+ <form action="${url.loginAction}" class="${properties.kcFormClass!}" id="kc-totp-settings-form" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
<label for="otp" class="${properties.kcLabelClass!}">${msg("loginTotpOneTime")}</label>
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 61b035a..82adf9b 100755
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java
@@ -5,13 +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.RequiredCredentialModel;
+import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.messages.Messages;
+import org.keycloak.services.validation.Validation;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
/**
@@ -26,16 +36,46 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
@Override
public void requiredActionChallenge(RequiredActionContext context) {
- LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class)
- .setClientSessionCode(context.generateAccessCode(UserModel.RequiredAction.CONFIGURE_TOTP.name()))
- .setUser(context.getUser());
- Response challenge = loginFormsProvider.createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
+ Response challenge = context.form().createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
}
@Override
public void processAction(RequiredActionContext context) {
- context.failure();
+ EventBuilder event = context.getEvent();
+ event.event(EventType.UPDATE_TOTP);
+ MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
+ String totp = formData.getFirst("totp");
+ String totpSecret = formData.getFirst("totpSecret");
+
+ if (Validation.isBlank(totp)) {
+ Response challenge = context.form()
+ .setError(Messages.MISSING_TOTP)
+ .createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
+ context.challenge(challenge);
+ return;
+ } else if (!CredentialValidation.validOTP(context.getRealm(), totp, totpSecret)) {
+ Response challenge = context.form()
+ .setError(Messages.INVALID_TOTP)
+ .createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
+ context.challenge(challenge);
+ return;
+ }
+
+ UserCredentialModel credentials = new UserCredentialModel();
+ credentials.setType(context.getRealm().getOTPPolicy().getType());
+ credentials.setValue(totpSecret);
+ context.getSession().users().updateCredential(context.getRealm(), context.getUser(), credentials);
+
+
+ // if type is HOTP, to update counter we execute validation based on supplied token
+ UserCredentialModel cred = new UserCredentialModel();
+ cred.setType(context.getRealm().getOTPPolicy().getType());
+ cred.setValue(totp);
+ context.getSession().users().validCredentials(context.getRealm(), context.getUser(), cred);
+
+ context.getUser().setOtpEnabled(true);
+ context.success();
}
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 eea2499..edd9e6a 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -576,58 +576,6 @@ public class LoginActionsService {
return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
}
- @Path("totp")
- @POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- public Response updateTotp(@QueryParam("code") String code,
- final MultivaluedMap<String, String> formData) {
- event.event(EventType.UPDATE_TOTP);
- Checks checks = new Checks();
- if (!checks.verifyCode(code, ClientSessionModel.Action.CONFIGURE_TOTP.name())) {
- return checks.response;
- }
- ClientSessionCode accessCode = checks.clientCode;
- ClientSessionModel clientSession = accessCode.getClientSession();
- UserSessionModel userSession = clientSession.getUserSession();
- UserModel user = userSession.getUser();
-
- initEvent(clientSession);
-
- String totp = formData.getFirst("totp");
- String totpSecret = formData.getFirst("totpSecret");
-
- LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class).setUser(user);
- if (Validation.isBlank(totp)) {
- return loginForms.setError(Messages.MISSING_TOTP)
- .setClientSessionCode(accessCode.getCode())
- .createResponse(RequiredAction.CONFIGURE_TOTP);
- } else if (!CredentialValidation.validOTP(realm, totp, totpSecret)) {
- return loginForms.setError(Messages.INVALID_TOTP)
- .setClientSessionCode(accessCode.getCode())
- .createResponse(RequiredAction.CONFIGURE_TOTP);
- }
-
- UserCredentialModel credentials = new UserCredentialModel();
- credentials.setType(realm.getOTPPolicy().getType());
- credentials.setValue(totpSecret);
- session.users().updateCredential(realm, user, credentials);
-
-
- // if type is HOTP, to update counter we execute validation based on supplied token
- UserCredentialModel cred = new UserCredentialModel();
- cred.setType(realm.getOTPPolicy().getType());
- cred.setValue(totp);
- session.users().validCredentials(realm, user, cred);
-
- user.setOtpEnabled(true);
-
- user.removeRequiredAction(RequiredAction.CONFIGURE_TOTP);
-
- event.clone().event(EventType.UPDATE_TOTP).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) {