1st phase auth/required action spi

This commit is contained in:
Bill Burke committed 2015-05-18 16:32:38 -04:00
1 parent e4204a56f5
commit 338300df32
41 files changed
+1574 -58

No files matched your search

@@ -0,0 +1,358 @@
package org.keycloak.authentication;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
//
// setup
// cookie: master, alternative
// CERT_AUTH: alternative
// UserPassword: alternative
// OTP: optional
// CAPTHA: required
//
// scenario: username password
// * cookie, attempted
// * cert, attempated
// * usernamepassord, doesn't see form, sets challenge to form
//
//
//
//
//
//
//
public class AuthenticationProcessor {
protected RealmModel realm;
protected UserSessionModel userSession;
protected ClientSessionModel clientSession;
protected ClientConnection connection;
protected UriInfo uriInfo;
protected KeycloakSession session;
protected List<AuthenticatorModel> authenticators;
protected BruteForceProtector protector;
protected EventBuilder eventBuilder;
protected HttpRequest request;
public static enum Status {
SUCCESS,
CHALLENGE,
FAILURE_CHALLENGE,
FAILED,
ATTEMPTED
}
public static enum Error {
INVALID_USER,
INVALID_CREDENTIALS,
CREDENTIAL_SETUP_REQUIRED,
USER_DISABLED,
USER_CONFLICT,
USER_TEMPORARILY_DISABLED,
INTERNAL_ERROR,
UNKNOWN_USER
}
public RealmModel getRealm() {
return realm;
}
public ClientSessionModel getClientSession() {
return clientSession;
}
public ClientConnection getConnection() {
return connection;
}
public UriInfo getUriInfo() {
return uriInfo;
}
public KeycloakSession getSession() {
return session;
}
private class Result implements AuthenticatorContext {
AuthenticatorModel model;
Authenticator authenticator;
Status status;
Response challenge;
Error error;
private Result(AuthenticatorModel model, Authenticator authenticator) {
this.model = model;
this.authenticator = authenticator;
}
@Override
public AuthenticatorModel getModel() {
return model;
}
@Override
public void setModel(AuthenticatorModel model) {
this.model = model;
}
@Override
public Authenticator getAuthenticator() {
return authenticator;
}
@Override
public void setAuthenticator(Authenticator authenticator) {
this.authenticator = authenticator;
}
@Override
public Status getStatus() {
return status;
}
@Override
public void success() {
this.status = Status.SUCCESS;
}
@Override
public void failure(Error error) {
status = Status.FAILED;
this.error = error;
}
@Override
public void challenge(Response challenge) {
this.status = Status.CHALLENGE;
this.challenge = challenge;
}
@Override
public void failureChallenge(Error error, Response challenge) {
this.error = error;
this.status = Status.FAILURE_CHALLENGE;
this.challenge = challenge;
}
@Override
public void attempted() {
this.status = Status.ATTEMPTED;
}
@Override
public UserModel getUser() {
return getClientSession().getAuthenticatedUser();
}
@Override
public void setUser(UserModel user) {
UserModel previousUser = getUser();
if (previousUser != null && !user.getId().equals(previousUser.getId())) throw new AuthException(Error.USER_CONFLICT);
validateUser(user);
getClientSession().setAuthenticatedUser(user);
}
@Override
public RealmModel getRealm() {
return AuthenticationProcessor.this.getRealm();
}
@Override
public ClientSessionModel getClientSession() {
return AuthenticationProcessor.this.getClientSession();
}
@Override
public ClientConnection getConnection() {
return AuthenticationProcessor.this.getConnection();
}
@Override
public UriInfo getUriInfo() {
return AuthenticationProcessor.this.getUriInfo();
}
@Override
public KeycloakSession getSession() {
return AuthenticationProcessor.this.getSession();
}
@Override
public HttpRequest getHttpRequest() {
return AuthenticationProcessor.this.request;
}
@Override
public void attachUserSession(UserSessionModel userSession) {
AuthenticationProcessor.this.userSession = userSession;
}
@Override
public BruteForceProtector getProtector() {
return AuthenticationProcessor.this.protector;
}
}
public static class AuthException extends RuntimeException {
private Error error;
public AuthException(Error error) {
this.error = error;
}
public AuthException(String message, Error error) {
super(message);
this.error = error;
}
public AuthException(String message, Throwable cause, Error error) {
super(message, cause);
this.error = error;
}
public AuthException(Throwable cause, Error error) {
super(cause);
this.error = error;
}
public AuthException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Error error) {
super(message, cause, enableSuppression, writableStackTrace);
this.error = error;
}
}
public void logUserFailure() {
}
protected boolean isProcessed(UserSessionModel.AuthenticatorStatus status) {
return status == UserSessionModel.AuthenticatorStatus.SUCCESS || status == UserSessionModel.AuthenticatorStatus.SKIPPED
|| status == UserSessionModel.AuthenticatorStatus.ATTEMPTED
|| status == UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED;
}
public Response authenticate() {
UserModel authUser = clientSession.getAuthenticatedUser();
validateUser(authUser);
Response challenge = null;
Map<String, UserSessionModel.AuthenticatorStatus> previousAttempts = clientSession.getAuthenticators();
for (AuthenticatorModel model : authenticators) {
UserSessionModel.AuthenticatorStatus oldStatus = previousAttempts.get(model.getAlias());
if (isProcessed(oldStatus)) continue;
AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getProviderId());
Authenticator authenticator = factory.create(model);
if (authenticator.requiresUser() && authUser == null){
if ( authenticator.requiresUser()) {
if (challenge != null) return challenge;
throw new AuthException(Error.UNKNOWN_USER);
}
}
if (authUser != null && model.getRequirement() == AuthenticatorModel.Requirement.ALTERNATIVE) {
clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SKIPPED);
continue;
}
authUser = clientSession.getAuthenticatedUser();
if (authenticator.requiresUser() && authUser != null && !authenticator.configuredFor(authUser)) {
if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) {
if (model.isUserSetupAllowed()) {
clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED);
authUser.addRequiredAction(authenticator.getRequiredAction());
} else {
throw new AuthException(Error.CREDENTIAL_SETUP_REQUIRED);
}
}
continue;
}
Result context = new Result(model, authenticator);
authenticator.authenticate(context);
Status result = context.getStatus();
if (result == Status.SUCCESS){
clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SUCCESS);
if (model.isMasterAuthenticator()) return authenticationComplete();
continue;
} else if (result == Status.FAILED) {
throw new AuthException(context.error);
} else if (result == Status.CHALLENGE) {
if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) return context.challenge;
if (challenge != null) challenge = context.challenge;
continue;
} else if (result == Status.FAILURE_CHALLENGE) {
logUserFailure();
return context.challenge;
} else if (result == Status.ATTEMPTED) {
if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) throw new AuthException(Error.INVALID_CREDENTIALS);
clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.ATTEMPTED);
continue;
}
}
if (authUser == null) {
if (challenge != null) return challenge;
throw new AuthException(Error.UNKNOWN_USER);
}
return authenticationComplete();
}
public void validateUser(UserModel authenticatedUser) {
if (authenticatedUser != null) {
if (!clientSession.getAuthenticatedUser().isEnabled()) throw new AuthException(Error.USER_DISABLED);
}
if (realm.isBruteForceProtected()) {
if (protector.isTemporarilyDisabled(session, realm, authenticatedUser.getUsername())) {
throw new AuthException(Error.USER_TEMPORARILY_DISABLED);
}
}
}
protected Response authenticationComplete() {
if (userSession == null) { // if no authenticator attached a usersession
userSession = session.sessions().createUserSession(realm, clientSession.getAuthenticatedUser(), clientSession.getAuthenticatedUser().getUsername(), connection.getRemoteAddr(), "form", false, null, null);
userSession.setState(UserSessionModel.State.LOGGING_IN);
}
TokenManager.attachClientSession(userSession, clientSession);
return processRequiredActions();
}
public Response processRequiredActions() {
return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, connection, request, uriInfo, eventBuilder);
}
}
@@ -0,0 +1,17 @@
package org.keycloak.authentication;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface Authenticator extends Provider {
boolean requiresUser();
void authenticate(AuthenticatorContext context);
boolean configuredFor(UserModel user);
String getRequiredAction();
}
@@ -0,0 +1,54 @@
package org.keycloak.authentication;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.services.managers.BruteForceProtector;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AuthenticatorContext {
AuthenticatorModel getModel();
void setModel(AuthenticatorModel model);
Authenticator getAuthenticator();
void setAuthenticator(Authenticator authenticator);
AuthenticationProcessor.Status getStatus();
UserModel getUser();
void setUser(UserModel user);
RealmModel getRealm();
ClientSessionModel getClientSession();
void attachUserSession(UserSessionModel userSession);
ClientConnection getConnection();
UriInfo getUriInfo();
KeycloakSession getSession();
HttpRequest getHttpRequest();
BruteForceProtector getProtector();
void success();
void failure(AuthenticationProcessor.Error error);
void challenge(Response challenge);
void failureChallenge(AuthenticationProcessor.Error error, Response challenge);
void attempted();
}
@@ -0,0 +1,13 @@
package org.keycloak.authentication;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AuthenticatorFactory extends ProviderFactory<Authenticator> {
Authenticator create(AuthenticatorModel model);
}
@@ -0,0 +1,47 @@
package org.keycloak.authentication.authenticators;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AuthenticationManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CookieAuthenticator implements Authenticator {
@Override
public boolean requiresUser() {
return false;
}
@Override
public void authenticate(AuthenticatorContext context) {
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(context.getSession(),
context.getRealm(), context.getUriInfo(), context.getConnection(), context.getHttpRequest().getHttpHeaders(), true);
if (authResult == null) {
context.attempted();
} else {
context.setUser(authResult.getUser());
context.attachUserSession(authResult.getSession());
context.success();
}
}
@Override
public boolean configuredFor(UserModel user) {
return true;
}
@Override
public String getRequiredAction() {
return null;
}
@Override
public void close() {
}
}
@@ -0,0 +1,45 @@
package org.keycloak.authentication.authenticators;
import org.keycloak.Config;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CookieAuthenticatorFactory implements AuthenticatorFactory {
static CookieAuthenticator SINGLETON = new CookieAuthenticator();
@Override
public Authenticator create(AuthenticatorModel model) {
return SINGLETON;
}
@Override
public Authenticator create(KeycloakSession session) {
throw new IllegalStateException("illegal call");
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "auth-cookie";
}
}
@@ -0,0 +1,71 @@
package org.keycloak.authentication.authenticators;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator {
public LoginFormOTPAuthenticator(AuthenticatorModel model) {
super(model);
}
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
return;
}
validateOTP(context);
}
public void validateOTP(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.TOTP);
if (password == null) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
credentials.add(UserCredentialModel.totp(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
if (!valid) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
}
@Override
public boolean requiresUser() {
return true;
}
@Override
public boolean configuredFor(UserModel user) {
return user.configuredForCredentialType(UserCredentialModel.TOTP);
}
@Override
public String getRequiredAction() {
return UserModel.RequiredAction.CONFIGURE_TOTP.name();
}
@Override
public void close() {
}
}
@@ -0,0 +1,71 @@
package org.keycloak.authentication.authenticators;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticator {
public LoginFormPasswordAuthenticator(AuthenticatorModel model) {
super(model);
}
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
return;
}
validatePassword(context);
}
public void validatePassword(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
if (password == null) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
credentials.add(UserCredentialModel.password(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
if (!valid) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
}
@Override
public boolean requiresUser() {
return true;
}
@Override
public boolean configuredFor(UserModel user) {
return false;
}
@Override
public String getRequiredAction() {
return UserModel.RequiredAction.UPDATE_PASSWORD.name();
}
@Override
public void close() {
}
}
@@ -0,0 +1,121 @@
package org.keycloak.authentication.authenticators;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.resources.LoginActionsService;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.net.URI;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LoginFormUsernameAuthenticator implements Authenticator {
protected AuthenticatorModel model;
public LoginFormUsernameAuthenticator(AuthenticatorModel model) {
this.model = model;
}
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
if (loginHint == null) {
loginHint = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders());
if (loginHint != null) {
formData.add("rememberMe", "on");
}
}
if (loginHint != null) formData.add(AuthenticationManager.FORM_USERNAME, loginHint);
Response challengeResponse = challenge(context, formData);
context.challenge(challengeResponse);
return;
}
validateUser(context);
}
protected boolean isActionUrl(AuthenticatorContext context) {
URI expected = LoginActionsService.authenticationFormProcessor(context.getUriInfo()).build(context.getRealm().getName());
return expected.getPath().equals(context.getUriInfo().getPath());
}
@Override
public boolean requiresUser() {
return false;
}
protected Response challenge(AuthenticatorContext context, MultivaluedMap<String, String> formData) {
LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
.setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode());
if (formData.size() > 0) forms.setFormData(formData);
return forms.createLogin();
}
public void validateUser(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
String username = inputData.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
return;
}
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), username);
if (invalidUser(context, user)) return;
context.setUser(user);
}
public boolean invalidUser(AuthenticatorContext context, UserModel user) {
if (user == null) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
return true;
}
if (!user.isEnabled()) {
context.failure(AuthenticationProcessor.Error.USER_DISABLED);
return true;
}
if (context.getRealm().isBruteForceProtected()) {
if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user.getUsername())) {
context.failure(AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED);
return true;
}
}
return false;
}
public Response challenge(AuthenticatorContext context) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
return challenge(context, formData);
}
@Override
public boolean configuredFor(UserModel user) {
return true;
}
@Override
public String getRequiredAction() {
return null;
}
@Override
public void close() {
}
}
@@ -0,0 +1,97 @@
package org.keycloak.authentication.authenticators;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.resources.LoginActionsService;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OTPFormAuthenticator implements Authenticator {
protected AuthenticatorModel model;
public OTPFormAuthenticator(AuthenticatorModel model) {
this.model = model;
}
@Override
public void authenticate(AuthenticatorContext context) {
URI expected = LoginActionsService.authenticationFormProcessor(context.getUriInfo()).build(context.getRealm().getName());
if (!expected.getPath().equals(context.getUriInfo().getPath())) {
Response challengeResponse = challenge(context);
context.challenge(challengeResponse);
return;
}
validateOTP(context);
}
public void validateOTP(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.TOTP);
if (password == null) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
credentials.add(UserCredentialModel.totp(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
if (!valid) {
Response challengeResponse = challenge(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
}
@Override
public boolean requiresUser() {
return true;
}
protected Response challenge(AuthenticatorContext context, MultivaluedMap<String, String> formData) {
LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
.setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode());
if (formData.size() > 0) forms.setFormData(formData);
return forms.createLoginTotp();
}
public Response challenge(AuthenticatorContext context) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
return challenge(context, formData);
}
@Override
public boolean configuredFor(UserModel user) {
return user.configuredForCredentialType(UserCredentialModel.TOTP);
}
@Override
public String getRequiredAction() {
return UserModel.RequiredAction.CONFIGURE_TOTP.name();
}
@Override
public void close() {
}
}
@@ -406,7 +406,7 @@ public class AuthenticationManager {
}
}
}
if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
// refresh the cookies!
createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
@@ -434,12 +434,12 @@ public class AuthenticationManager {
event.detail(Details.CODE_ID, clientSession.getId());
Set<UserModel.RequiredAction> requiredActions = user.getRequiredActions();
Set<String> requiredActions = user.getRequiredActions();
if (!requiredActions.isEmpty()) {
Iterator<RequiredAction> i = user.getRequiredActions().iterator();
UserModel.RequiredAction action = i.next();
Iterator<String> i = user.getRequiredActions().iterator();
String action = i.next();
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL) && Validation.isEmpty(user.getEmail())) {
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name()) && Validation.isEmpty(user.getEmail())) {
if (i.hasNext())
action = i.next();
else
@@ -447,16 +447,16 @@ public class AuthenticationManager {
}
if (action != null) {
accessCode.setRequiredAction(action);
accessCode.setRequiredAction(RequiredAction.valueOf(action));
LoginFormsProvider loginFormsProvider = session.getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode())
.setUser(user);
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) {
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name())) {
event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success();
LoginActionsService.createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
}
return loginFormsProvider.createResponse(action);
return loginFormsProvider.createResponse(RequiredAction.valueOf(action));
}
}
@@ -117,6 +117,10 @@ public class LoginActionsService {
return loginActionsBaseUrl(baseUriBuilder);
}
public static UriBuilder authenticationFormProcessor(UriInfo uriInfo) {
return loginActionsBaseUrl(uriInfo).path("auth-form");
}
public static UriBuilder loginActionsBaseUrl(UriBuilder baseUriBuilder) {
return baseUriBuilder.path(RealmsResource.class).path(RealmsResource.class, "getLoginActionsService");
}