totp refactor
This commit is contained in:
parent
c25967bd61
commit
f245b67036
3 changed files with 46 additions and 58 deletions
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue