clientsession.action to String

This commit is contained in:
Bill Burke 2015-06-10 09:21:23 -04:00
parent dcc40b0a63
commit 95349e6e2e
44 changed files with 989 additions and 561 deletions

View file

@ -7,6 +7,13 @@
<delete tableName="CLIENT_SESSION"/>
<delete tableName="USER_SESSION_NOTE"/>
<delete tableName="USER_SESSION"/>
<createTable tableName="DEFAULT_REQUIRED_ACTIONS">
<column name="REALM_ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VALUE" type="VARCHAR(36)"/>
</createTable>
<createTable tableName="ADMIN_EVENT_ENTITY">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
@ -145,6 +152,63 @@
<column name="REQUIRED_ACTION" value="UPDATE_PASSWORD"/>
<where>ACTION = 3</where>
</update>
<addColumn tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</addColumn>
<!-- OAUTH_GRANT,
CODE_TO_TOKEN,
VERIFY_EMAIL,
UPDATE_PROFILE,
CONFIGURE_TOTP,
UPDATE_PASSWORD,
RECOVER_PASSWORD,
AUTHENTICATE,
SOCIAL_CALLBACK,
LOGGED_OUT -->
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="OAUTH_GRANT"/>
<where>ACTION = 0</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="CODE_TO_TOKEN"/>
<where>ACTION = 1</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="VERIFY_EMAIL"/>
<where>ACTION = 2</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="UPDATE_PROFILE"/>
<where>ACTION = 3</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="CONFIGURE_TOTP"/>
<where>ACTION = 4</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="UPDATE_PASSWORD"/>
<where>ACTION = 5</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="RECOVER_PASSWORD"/>
<where>ACTION = 6</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="AUTHENTICATE"/>
<where>ACTION = 7</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="SOCIAL_CALLBACK"/>
<where>ACTION = 8</where>
</update>
<update tableName="CLIENT_SESSION">
<column name="CURRENT_ACTION" value="LOGGED_OUT"/>
<where>ACTION = 9</where>
</update>
<createTable tableName="CLIENT_USER_SESSION_NOTE">
<column name="NAME" type="VARCHAR(255)">
<constraints nullable="false"/>
@ -162,10 +226,12 @@
<addPrimaryKey columnNames="AUTHENTICATOR_ID, NAME" constraintName="CONSTRAINT_AUTHENTICATOR_CONFIG_PK" tableName="AUTHENTICATOR_CONFIG"/>
<dropPrimaryKey constraintName="CONSTRAINT_2" tableName="USER_REQUIRED_ACTION"/>
<dropColumn tableName="USER_REQUIRED_ACTION" columnName="ACTION"/>
<dropColumn tableName="CLIENT_SESSION" columnName="ACTION"/>
<addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTRAINT_REQUIRED_ACTION" tableName="USER_REQUIRED_ACTION"/>
<addPrimaryKey columnNames="CLIENT_SESSION, AUTHENTICATOR" constraintName="CONSTRAINT_AUTH_STATUS_PK" tableName="CLIENT_SESSION_AUTH_STATUS"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FEDMAPPERPM" tableName="USER_FEDERATION_MAPPER"/>
<addPrimaryKey columnNames="USER_FEDERATION_MAPPER_ID, NAME" constraintName="CONSTRAINT_FEDMAPPER_CFG_PM" tableName="USER_FEDERATION_MAPPER_CONFIG"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="DEFAULT_REQUIRED_ACTIONS" constraintName="FK_DEFAULT_REQUIRED_ACTIONS_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_AUTH_STATUS" constraintName="AUTH_STATUS_CONSTRAINT" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATOR" constraintName="FK_AUTHENTICATOR_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATION_FLOW" constraintName="FK_AUTHENTICATION_FLOW_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>

View file

@ -22,9 +22,9 @@ public interface ClientSessionModel {
public void setTimestamp(int timestamp);
public Action getAction();
public String getAction();
public void setAction(Action action);
public void setAction(String action);
public Set<String> getRoles();
public void setRoles(Set<String> roles);

View file

@ -156,6 +156,13 @@ public interface RealmModel extends RoleContainerModel {
void updateDefaultRoles(String[] defaultRoles);
Set<String> getDefaultRequiredActions();
void addDefaultRequiredAction(String action);
void removeDefaultRequiredAction(String action);
void setDefaultRequiredActions(Set<String> action);
// Key is clientId
Map<String, ClientModel> getClientNameMap();

View file

@ -2,8 +2,10 @@ package org.keycloak.models.entities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -76,6 +78,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private List<IdentityProviderMapperEntity> identityProviderMappers = new ArrayList<IdentityProviderMapperEntity>();
private List<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
private List<AuthenticatorEntity> authenticators = new ArrayList<>();
private List<String> defaultRequiredActions = new ArrayList<>();
public String getName() {
@ -500,6 +503,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
public void setAuthenticators(List<AuthenticatorEntity> authenticators) {
this.authenticators = authenticators;
}
public List<String> getDefaultRequiredActions() {
return defaultRequiredActions;
}
public void setDefaultRequiredActions(List<String> defaultRequiredActions) {
this.defaultRequiredActions = defaultRequiredActions;
}
}

View file

@ -104,5 +104,7 @@ public class DefaultAuthenticationFlows {
execution.setAutheticatorFlow(false);
realm.addAuthenticatorExecution(execution);
//
}
}

View file

@ -1548,4 +1548,37 @@ public class RealmAdapter implements RealmModel {
mapper.setConfig(config);
return mapper;
}
@Override
public Set<String> getDefaultRequiredActions() {
Set<String> result = new HashSet<String>();
if (realm.getDefaultRequiredActions() != null) {
result.addAll(realm.getDefaultRequiredActions());
}
return result;
}
@Override
public void addDefaultRequiredAction(String action) {
Set<String> actions = getDefaultRequiredActions();
actions.add(action);
setDefaultRequiredActions(actions);
}
@Override
public void removeDefaultRequiredAction(String action) {
Set<String> actions = getDefaultRequiredActions();
actions.remove(action);
setDefaultRequiredActions(actions);
}
@Override
public void setDefaultRequiredActions(Set<String> action) {
List<String> result = new ArrayList<String>();
result.addAll(action);
realm.setDefaultRequiredActions(result);
}
}

View file

@ -1116,4 +1116,30 @@ public class RealmAdapter implements RealmModel {
if (updated != null) return updated.getAuthenticatorById(id);
return cached.getAuthenticators().get(id);
}
@Override
public Set<String> getDefaultRequiredActions() {
return cached.getDefaultRequiredActions();
}
@Override
public void addDefaultRequiredAction(String action) {
getDelegateForUpdate();
updated.addDefaultRequiredAction(action);
}
@Override
public void removeDefaultRequiredAction(String action) {
getDelegateForUpdate();
updated.removeDefaultRequiredAction(action);
}
@Override
public void setDefaultRequiredActions(Set<String> action) {
getDelegateForUpdate();
updated.setDefaultRequiredActions(action);
}
}

View file

@ -98,6 +98,7 @@ public class CachedRealm {
private Set<String> supportedLocales = new HashSet<String>();
private String defaultLocale;
private MultivaluedHashMap<String, IdentityProviderMapperModel> identityProviderMappers = new MultivaluedHashMap<>();
private Set<String> defaultRequiredActions = new HashSet<>();
public CachedRealm() {
}
@ -200,6 +201,7 @@ public class CachedRealm {
for (AuthenticatorModel authenticator : model.getAuthenticators()) {
authenticators.put(authenticator.getId(), authenticator);
}
this.defaultRequiredActions.addAll(model.getDefaultRequiredActions());
}
@ -438,4 +440,8 @@ public class CachedRealm {
public Map<String, AuthenticationExecutionModel> getExecutionsById() {
return executionsById;
}
public Set<String> getDefaultRequiredActions() {
return defaultRequiredActions;
}
}

View file

@ -1707,5 +1707,30 @@ public class RealmAdapter implements RealmModel {
return authenticators;
}
@Override
public Set<String> getDefaultRequiredActions() {
Set<String> result = new HashSet<String>();
result.addAll(realm.getDefaultRequiredActions());
return result;
}
@Override
public void setDefaultRequiredActions(Set<String> actions) {
realm.setDefaultRequiredActions(actions);
}
@Override
public void addDefaultRequiredAction(String action) {
realm.getDefaultRequiredActions().add(action);
}
@Override
public void removeDefaultRequiredAction(String action) {
realm.getDefaultRequiredActions().remove(action);
}
}

View file

@ -113,6 +113,12 @@ public class RealmEntity {
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
@ElementCollection
@Column(name="VALUE")
@CollectionTable(name = "DEFAULT_REQUIRED_ACTIONS", joinColumns={ @JoinColumn(name="REALM_ID") })
protected Set<String> defaultRequiredActions = new HashSet<String>();
@ElementCollection
@MapKeyColumn(name="NAME")
@Column(name="VALUE")
@ -568,5 +574,13 @@ public class RealmEntity {
public void setAuthenticationFlows(Collection<AuthenticationFlowEntity> authenticationFlows) {
this.authenticationFlows = authenticationFlows;
}
public Set<String> getDefaultRequiredActions() {
return defaultRequiredActions;
}
public void setDefaultRequiredActions(Set<String> defaultRequiredActions) {
this.defaultRequiredActions = defaultRequiredActions;
}
}

View file

@ -1590,4 +1590,32 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
mapper.setConfig(config);
return mapper;
}
@Override
public Set<String> getDefaultRequiredActions() {
Set<String> result = new HashSet<String>();
result.addAll(realm.getDefaultRequiredActions());
return result;
}
@Override
public void setDefaultRequiredActions(Set<String> actions) {
List<String> result = new ArrayList<String>();
result.addAll(actions);
getMongoEntity().setDefaultRequiredActions(result);
updateMongoEntity();
}
@Override
public void addDefaultRequiredAction(String action) {
getMongoStore().pushItemToList(getMongoEntity(), "defaultRequiredActions", action, true, invocationContext);
}
@Override
public void removeDefaultRequiredAction(String action) {
getMongoStore().pullItemFromList(getMongoEntity(), "defaultRequiredActions", action, invocationContext);
}
}

View file

@ -100,12 +100,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
}
@Override
public Action getAction() {
public String getAction() {
return entity.getAction();
}
@Override
public void setAction(Action action) {
public void setAction(String action) {
entity.setAction(action);
update();
}

View file

@ -24,7 +24,7 @@ public class ClientSessionEntity extends SessionEntity {
private int timestamp;
private ClientSessionModel.Action action;
private String action;
private Set<String> roles;
private Set<String> protocolMappers;
@ -81,11 +81,11 @@ public class ClientSessionEntity extends SessionEntity {
this.timestamp = timestamp;
}
public ClientSessionModel.Action getAction() {
public String getAction() {
return action;
}
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
this.action = action;
}

View file

@ -189,12 +189,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
}
@Override
public Action getAction() {
public String getAction() {
return entity.getAction();
}
@Override
public void setAction(Action action) {
public void setAction(String action) {
entity.setAction(action);
}

View file

@ -54,8 +54,8 @@ public class ClientSessionEntity {
@Column(name="AUTH_METHOD")
protected String authMethod;
@Column(name="ACTION")
protected ClientSessionModel.Action action;
@Column(name="CURRENT_ACTION")
protected String action;
@Column(name="AUTH_USER_ID")
protected String userId;
@ -123,11 +123,11 @@ public class ClientSessionEntity {
this.redirectUri = redirectUri;
}
public ClientSessionModel.Action getAction() {
public String getAction() {
return action;
}
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
this.action = action;
}

View file

@ -93,12 +93,12 @@ public class ClientSessionAdapter implements ClientSessionModel {
}
@Override
public ClientSessionModel.Action getAction() {
public String getAction() {
return entity.getAction();
}
@Override
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
entity.setAction(action);
}

View file

@ -24,7 +24,7 @@ public class ClientSessionEntity {
private String authMethod;
private int timestamp;
private ClientSessionModel.Action action;
private String action;
private Set<String> roles;
private Set<String> protocolMappers;
private Map<String, String> notes = new HashMap<>();
@ -78,11 +78,11 @@ public class ClientSessionEntity {
this.timestamp = timestamp;
}
public ClientSessionModel.Action getAction() {
public String getAction() {
return action;
}
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
this.action = action;
}

View file

@ -108,12 +108,12 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
}
@Override
public Action getAction() {
public String getAction() {
return entity.getAction();
}
@Override
public void setAction(Action action) {
public void setAction(String action) {
entity.setAction(action);
updateMongoEntity();
}

View file

@ -26,7 +26,7 @@ public class MongoClientSessionEntity extends AbstractIdentifiableEntity impleme
private String authMethod;
private int timestamp;
private ClientSessionModel.Action action;
private String action;
private List<String> roles;
private List<String> protocolMappers;
private Map<String, String> notes = new HashMap<String, String>();
@ -82,11 +82,11 @@ public class MongoClientSessionEntity extends AbstractIdentifiableEntity impleme
this.timestamp = timestamp;
}
public ClientSessionModel.Action getAction() {
public String getAction() {
return action;
}
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
this.action = action;
}

View file

@ -21,6 +21,7 @@ import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
@ -32,6 +33,7 @@ import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.services.ErrorPage;
import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.HttpAuthenticationManager;
@ -59,6 +61,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.PublicKey;
import java.util.List;
/**
* Resource class for the oauth/openid connect token service
@ -264,7 +267,7 @@ public class SamlService {
ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
clientSession.setRedirectUri(redirect);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
clientSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
@ -317,7 +320,22 @@ public class SamlService {
return forms.createLogin();
}
private Response buildRedirectToIdentityProvider(String providerId, String accessCode) {
logger.debug("Automatically redirect to identity provider: " + providerId);
return Response.temporaryRedirect(
Urls.identityProviderAuthnRequest(uriInfo.getBaseUri(), providerId, realm.getName(), accessCode))
.build();
}
protected Response newBrowserAuthentication(ClientSessionModel clientSession) {
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
for (IdentityProviderModel identityProvider : identityProviders) {
if (identityProvider.isAuthenticateByDefault()) {
return buildRedirectToIdentityProvider(identityProvider.getAlias(), new ClientSessionCode(realm, clientSession).getCode() );
}
}
String flowId = null;
for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
if (flow.getAlias().equals("browser")) {
@ -336,7 +354,11 @@ public class SamlService {
.setUriInfo(uriInfo)
.setRequest(request);
return processor.authenticate();
try {
return processor.authenticate();
} catch (Exception e) {
return processor.handleBrowserException(e);
}
}
@ -394,7 +416,7 @@ public class SamlService {
// remove client from logout requests
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
if (clientSession.getClient().getId().equals(client.getId())) {
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
}
}
logger.debug("browser Logout");
@ -405,7 +427,7 @@ public class SamlService {
if (clientSession == null) continue;
if (clientSession.getClient().getClientId().equals(client.getClientId())) {
// remove requesting client from logout
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
}
UserSessionModel userSession = clientSession.getUserSession();
try {

View file

@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.AuthenticationExecutionModel;
@ -15,8 +16,10 @@ 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.ErrorPage;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@ -39,6 +42,7 @@ public class AuthenticationProcessor {
protected EventBuilder event;
protected HttpRequest request;
protected String flowId;
protected String action;
protected boolean userSessionCreated;
@ -134,6 +138,11 @@ public class AuthenticationProcessor {
return this;
}
public AuthenticationProcessor setAction(String action) {
this.action = action;
return this;
}
private class Result implements AuthenticatorContext {
AuthenticatorModel model;
AuthenticationExecutionModel execution;
@ -168,6 +177,11 @@ public class AuthenticationProcessor {
this.model = model;
}
@Override
public String getAction() {
return AuthenticationProcessor.this.action;
}
@Override
public Authenticator getAuthenticator() {
return authenticator;
@ -332,6 +346,34 @@ public class AuthenticationProcessor {
return status == UserSessionModel.AuthenticatorStatus.SUCCESS;
}
public Response handleBrowserException(Exception failure) {
if (failure instanceof AuthException) {
AuthException e = (AuthException)failure;
logger.error("failed authentication: " + e.getError().toString(), e);
if (e.getError() == AuthenticationProcessor.Error.INVALID_USER) {
event.error(Errors.USER_NOT_FOUND);
return ErrorPage.error(session, Messages.INVALID_USER);
} else if (e.getError() == AuthenticationProcessor.Error.USER_DISABLED) {
event.error(Errors.USER_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
} else if (e.getError() == AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED) {
event.error(Errors.USER_TEMPORARILY_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_TEMPORARILY_DISABLED);
} else {
event.error(Errors.INVALID_USER_CREDENTIALS);
return ErrorPage.error(session, Messages.INVALID_USER);
}
} else {
logger.error("failed authentication", failure);
event.error(Errors.INVALID_USER_CREDENTIALS);
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_REQUEST);
}
}
public Response authenticate() throws AuthException {
logger.debug("AUTHENTICATE");
event.event(EventType.LOGIN);

View file

@ -31,6 +31,8 @@ public interface AuthenticatorContext {
void setAuthenticatorModel(AuthenticatorModel model);
String getAction();
Authenticator getAuthenticator();
void setAuthenticator(Authenticator authenticator);

View file

@ -0,0 +1,32 @@
package org.keycloak.authentication;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.AuthenticationExecutionModel;
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 RequiredActionContext {
EventBuilder getEvent();
UserModel getUser();
RealmModel getRealm();
ClientSessionModel getClientSession();
UserSessionModel getUserSession();
ClientConnection getConnection();
UriInfo getUriInfo();
KeycloakSession getSession();
HttpRequest getHttpRequest();
}

View file

@ -0,0 +1,14 @@
package org.keycloak.authentication;
import org.keycloak.provider.Provider;
import javax.ws.rs.core.Response;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RequiredActionProvider extends Provider {
Response invokeRequiredAction(RequiredActionContext context);
Object jaxrsService();
}

View file

@ -19,26 +19,27 @@ import java.net.URI;
* @version $Revision: 1 $
*/
public class AbstractFormAuthenticator {
protected boolean isActionUrl(AuthenticatorContext context) {
URI expected = LoginActionsService.authenticationFormProcessor(context.getUriInfo()).build(context.getRealm().getName());
String current = context.getUriInfo().getAbsolutePath().getPath();
String expectedPath = expected.getPath();
return expectedPath.equals(current);
public static final String LOGIN_FORM_ACTION = "login_form";
public static final String ACTION = "action";
protected boolean isAction(AuthenticatorContext context, String action) {
return action.equals(context.getAction());
}
protected LoginFormsProvider loginForm(AuthenticatorContext context) {
ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession());
code.setAction(ClientSessionModel.Action.AUTHENTICATE);
URI action = getActionUrl(context, code);
code.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
URI action = getActionUrl(context, code, LOGIN_FORM_ACTION);
return context.getSession().getProvider(LoginFormsProvider.class)
.setActionUri(action)
.setClientSessionCode(code.getCode());
}
public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code) {
public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code, String action) {
return LoginActionsService.authenticationFormProcessor(context.getUriInfo())
.queryParam(OAuth2Constants.CODE, code.getCode())
.queryParam(OAuth2Constants.CODE, code.getCode())
.queryParam(ACTION, action)
.build(context.getRealm().getName());
}

View file

@ -27,7 +27,7 @@ public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator {
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
if (!isAction(context, LOGIN_FORM_ACTION)) {
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
return;
}

View file

@ -9,7 +9,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@ -28,7 +27,7 @@ public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticat
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
if (!isAction(context, LOGIN_FORM_ACTION)) {
context.failure(AuthenticationProcessor.Error.INTERNAL_ERROR);
return;
}

View file

@ -33,7 +33,7 @@ public class LoginFormUsernameAuthenticator extends AbstractFormAuthenticator im
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
if (!isAction(context, LOGIN_FORM_ACTION)) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);

View file

@ -13,7 +13,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@ -26,6 +25,7 @@ import java.util.List;
* @version $Revision: 1 $
*/
public class OTPFormAuthenticator extends AbstractFormAuthenticator implements Authenticator {
public static final String TOTP_FORM_ACTION = "totp";
protected AuthenticatorModel model;
public OTPFormAuthenticator(AuthenticatorModel model) {
@ -34,7 +34,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
@Override
public void authenticate(AuthenticatorContext context) {
if (!isActionUrl(context)) {
if (!isAction(context, TOTP_FORM_ACTION)) {
Response challengeResponse = challenge(context, null);
context.challenge(challengeResponse);
return;
@ -43,7 +43,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
}
public void validateOTP(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.TOTP);
if (password == null) {
@ -70,7 +70,7 @@ public class OTPFormAuthenticator extends AbstractFormAuthenticator implements A
protected Response challenge(AuthenticatorContext context, String error) {
ClientSessionCode clientSessionCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
URI action = AbstractFormAuthenticator.getActionUrl(context, clientSessionCode);
URI action = AbstractFormAuthenticator.getActionUrl(context, clientSessionCode, TOTP_FORM_ACTION);
LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
.setActionUri(action)
.setClientSessionCode(clientSessionCode.getCode());

View file

@ -0,0 +1,48 @@
package org.keycloak.authentication.authenticators;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AuthenticationManager;
/**
* No auth, but it sets a required action.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SetRequiredActionAuthenticator implements Authenticator {
@Override
public boolean requiresUser() {
return false;
}
@Override
public void authenticate(AuthenticatorContext context) {
UserModel user = context.getUser();
if (user == null) {
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.UNKNOWN_USER);
}
user.addRequiredAction(context.getAuthenticatorModel().getConfig().get("required.action"));
context.success();
}
@Override
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
return true;
}
@Override
public String getRequiredAction() {
return null;
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,69 @@
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;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SetRequiredActionAuthenticatorFactory implements AuthenticatorFactory {
public static final String PROVIDER_ID = "auth-set-required-action";
static SetRequiredActionAuthenticator SINGLETON = new SetRequiredActionAuthenticator();
@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 PROVIDER_ID;
}
@Override
public String getDisplayCategory() {
return "Action";
}
@Override
public String getDisplayType() {
return "Set Required Action";
}
@Override
public String getHelpText() {
return "Doesn't do any authentication. Instead it just sets a configured required action for the user.";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return null;
}
}

View file

@ -130,7 +130,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
ClientSessionModel clientSession = accessCode.getClientSession();
String redirect = clientSession.getRedirectUri();
String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, accessCode.getCode());
log.debugv("redirectAccessCode: state: {0}", state);
if (state != null)

View file

@ -220,7 +220,7 @@ public class AuthorizationEndpoint {
clientSession = session.sessions().createClientSession(realm, client);
clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
clientSession.setRedirectUri(redirectUri);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, responseType);
clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUriParam);
@ -277,7 +277,12 @@ public class AuthorizationEndpoint {
.setUriInfo(uriInfo)
.setRequest(request);
Response challenge = processor.authenticateOnly();
Response challenge = null;
try {
challenge = processor.authenticateOnly();
} catch (Exception e) {
return processor.handleBrowserException(e);
}
if (challenge != null && prompt != null && prompt.equals("none")) {
if (processor.isUserSessionCreated()) {

View file

@ -191,7 +191,7 @@ public class TokenEndpoint {
ClientSessionModel clientSession = accessCode.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN)) {
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
event.error(Errors.INVALID_CODE);
throw new ErrorResponseException("invalid_grant", "Code is expired", Response.Status.BAD_REQUEST);
}

View file

@ -148,7 +148,7 @@ public class AuthenticationManager {
public static void backchannelLogoutClientSession(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession, UserSessionModel userSession, UriInfo uriInfo, HttpHeaders headers) {
ClientModel client = clientSession.getClient();
if (client instanceof ClientModel && !client.isFrontchannelLogout() && clientSession.getAction() != ClientSessionModel.Action.LOGGED_OUT) {
if (client instanceof ClientModel && !client.isFrontchannelLogout() && !ClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) {
String authMethod = clientSession.getAuthMethod();
if (authMethod == null) return; // must be a keycloak service like account
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
@ -156,7 +156,7 @@ public class AuthenticationManager {
.setHttpHeaders(headers)
.setUriInfo(uriInfo);
protocol.backchannelLogout(userSession, clientSession);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
}
}
@ -188,7 +188,7 @@ public class AuthenticationManager {
List<ClientSessionModel> redirectClients = new LinkedList<ClientSessionModel>();
for (ClientSessionModel clientSession : userSession.getClientSessions()) {
ClientModel client = clientSession.getClient();
if (clientSession.getAction() == ClientSessionModel.Action.LOGGED_OUT) continue;
if (ClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) continue;
if (client.isFrontchannelLogout()) {
String authMethod = clientSession.getAuthMethod();
if (authMethod == null) continue; // must be a keycloak service like account
@ -205,7 +205,7 @@ public class AuthenticationManager {
try {
logger.debugv("backchannel logout to: {0}", client.getClientId());
protocol.backchannelLogout(userSession, clientSession);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
} catch (Exception e) {
logger.warn("Failed to logout client, continuing", e);
}
@ -219,7 +219,7 @@ public class AuthenticationManager {
.setHttpHeaders(headers)
.setUriInfo(uriInfo);
// setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not
nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT);
nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT.name());
try {
logger.debugv("frontchannel logout to: {0}", nextRedirectClient.getClient().getClientId());
Response response = protocol.frontchannelLogout(userSession, nextRedirectClient);
@ -476,7 +476,7 @@ public class AuthenticationManager {
}
if (client.isConsentRequired()) {
accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT.name());
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());

View file

@ -80,8 +80,8 @@ public class ClientSessionCode {
return clientSession;
}
public boolean isValid(ClientSessionModel.Action requestedAction) {
ClientSessionModel.Action action = clientSession.getAction();
public boolean isValid(String requestedAction) {
String action = clientSession.getAction();
if (action == null) {
return false;
}
@ -93,18 +93,14 @@ public class ClientSessionCode {
}
int lifespan;
switch (action) {
case CODE_TO_TOKEN:
lifespan = realm.getAccessCodeLifespan();
break;
case AUTHENTICATE:
lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
break;
default:
lifespan = realm.getAccessCodeLifespanUserAction();
break;
}
if (action.equals(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
lifespan = realm.getAccessCodeLifespan();
} else if (action.equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
} else {
lifespan = realm.getAccessCodeLifespanUserAction();
}
return timestamp + lifespan > Time.currentTime();
}
@ -132,7 +128,7 @@ public class ClientSessionCode {
return requestedProtocolMappers;
}
public void setAction(ClientSessionModel.Action action) {
public void setAction(String action) {
clientSession.setAction(action);
clientSession.setNote(ACTION_KEY, UUID.randomUUID().toString());
clientSession.setTimestamp(Time.currentTime());
@ -142,16 +138,16 @@ public class ClientSessionCode {
setAction(convertToAction(requiredAction));
}
private ClientSessionModel.Action convertToAction(RequiredAction requiredAction) {
private String convertToAction(RequiredAction requiredAction) {
switch (requiredAction) {
case CONFIGURE_TOTP:
return ClientSessionModel.Action.CONFIGURE_TOTP;
return ClientSessionModel.Action.CONFIGURE_TOTP.name();
case UPDATE_PASSWORD:
return ClientSessionModel.Action.UPDATE_PASSWORD;
return ClientSessionModel.Action.UPDATE_PASSWORD.name();
case UPDATE_PROFILE:
return ClientSessionModel.Action.UPDATE_PROFILE;
return ClientSessionModel.Action.UPDATE_PROFILE.name();
case VERIFY_EMAIL:
return ClientSessionModel.Action.VERIFY_EMAIL;
return ClientSessionModel.Action.VERIFY_EMAIL.name();
default:
throw new IllegalArgumentException("Unknown required action " + requiredAction);
}

View file

@ -738,7 +738,7 @@ public class AccountService {
try {
ClientSessionModel clientSession = auth.getClientSession();
ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
clientSession.setRedirectUri(redirectUri);
clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, UUID.randomUUID().toString());

View file

@ -373,7 +373,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private ClientSessionCode parseClientSessionCode(String code) {
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
if (clientCode != null && clientCode.isValid(AUTHENTICATE.name())) {
ClientSessionModel clientSession = clientCode.getClientSession();
if (clientSession != null) {

View file

@ -166,7 +166,7 @@ public class LoginActionsService {
ClientSessionCode clientCode;
Response response;
boolean check(String code, ClientSessionModel.Action requiredAction) {
boolean check(String code, String requiredAction) {
if (!check(code)) {
return false;
} else if (!clientCode.isValid(requiredAction)) {
@ -178,7 +178,7 @@ public class LoginActionsService {
}
}
boolean check(String code, ClientSessionModel.Action requiredAction, ClientSessionModel.Action alternativeRequiredAction) {
boolean check(String code, String requiredAction, String alternativeRequiredAction) {
if (!check(code)) {
return false;
} else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) {
@ -231,9 +231,9 @@ public class LoginActionsService {
ClientSessionCode clientSessionCode = checks.clientCode;
ClientSessionModel clientSession = clientSessionCode.getClientSession();
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
TokenManager.dettachClientSession(session.sessions(), realm, clientSession);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
}
return session.getProvider(LoginFormsProvider.class)
@ -281,7 +281,8 @@ public class LoginActionsService {
@Path("auth-form")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response authForm(@QueryParam("code") String code) {
public Response authForm(@QueryParam("code") String code,
@QueryParam("action") String action) {
event.event(EventType.LOGIN);
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
@ -301,8 +302,8 @@ public class LoginActionsService {
ClientSessionModel clientSession = clientCode.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
return session.getProvider(LoginFormsProvider.class)
.setError(Messages.EXPIRED_CODE)
@ -338,39 +339,17 @@ public class LoginActionsService {
.setRealm(realm)
.setSession(session)
.setUriInfo(uriInfo)
.setAction(action)
.setRequest(request);
try {
return processor.authenticate();
} catch (AuthenticationProcessor.AuthException e) {
return handleError(e, code);
} catch (Exception e) {
event.error(Errors.INVALID_USER_CREDENTIALS);
logger.error("failed authentication", e);
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE);
return processor.handleBrowserException(e);
}
}
protected Response handleError(AuthenticationProcessor.AuthException e, String code) {
logger.error("failed authentication: " + e.getError().toString(), e);
if (e.getError() == AuthenticationProcessor.Error.INVALID_USER) {
event.error(Errors.USER_NOT_FOUND);
return ErrorPage.error(session, Messages.INVALID_USER);
} else if (e.getError() == AuthenticationProcessor.Error.USER_DISABLED) {
event.error(Errors.USER_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
} else if (e.getError() == AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED) {
event.error(Errors.USER_TEMPORARILY_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_TEMPORARILY_DISABLED);
} else {
event.error(Errors.INVALID_USER_CREDENTIALS);
return ErrorPage.error(session, Messages.INVALID_USER);
}
}
/**
* URL called after login page. YOU SHOULD NEVER INVOKE THIS DIRECTLY!
*
@ -402,8 +381,8 @@ public class LoginActionsService {
ClientSessionModel clientSession = clientCode.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
return session.getProvider(LoginFormsProvider.class)
.setError(Messages.EXPIRED_CODE)
@ -538,7 +517,7 @@ public class LoginActionsService {
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.INVALID_CODE);
}
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE)) {
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name())) {
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.INVALID_CODE);
}
@ -676,7 +655,7 @@ public class LoginActionsService {
String code = formData.getFirst("code");
ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT)) {
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT.name())) {
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE);
}
@ -742,7 +721,7 @@ public class LoginActionsService {
final MultivaluedMap<String, String> formData) {
event.event(EventType.UPDATE_PROFILE);
Checks checks = new Checks();
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PROFILE)) {
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PROFILE.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -804,7 +783,7 @@ public class LoginActionsService {
final MultivaluedMap<String, String> formData) {
event.event(EventType.UPDATE_TOTP);
Checks checks = new Checks();
if (!checks.check(code, ClientSessionModel.Action.CONFIGURE_TOTP)) {
if (!checks.check(code, ClientSessionModel.Action.CONFIGURE_TOTP.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -849,7 +828,7 @@ public class LoginActionsService {
final MultivaluedMap<String, String> formData) {
event.event(EventType.UPDATE_PASSWORD);
Checks checks = new Checks();
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PASSWORD, ClientSessionModel.Action.RECOVER_PASSWORD)) {
if (!checks.check(code, ClientSessionModel.Action.UPDATE_PASSWORD.name(), ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -890,7 +869,7 @@ public class LoginActionsService {
event.event(EventType.UPDATE_PASSWORD).success();
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
String actionCookieValue = getActionCookie();
if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) {
return session.getProvider(LoginFormsProvider.class)
@ -911,7 +890,7 @@ public class LoginActionsService {
event.event(EventType.VERIFY_EMAIL);
if (key != null) {
Checks checks = new Checks();
if (!checks.check(key, ClientSessionModel.Action.VERIFY_EMAIL)) {
if (!checks.check(key, ClientSessionModel.Action.VERIFY_EMAIL.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -937,7 +916,7 @@ public class LoginActionsService {
return redirectOauth(user, accessCode, clientSession, userSession);
} else {
Checks checks = new Checks();
if (!checks.check(code, ClientSessionModel.Action.VERIFY_EMAIL)) {
if (!checks.check(code, ClientSessionModel.Action.VERIFY_EMAIL.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -960,7 +939,7 @@ public class LoginActionsService {
event.event(EventType.RESET_PASSWORD);
if (key != null) {
Checks checks = new Checks();
if (!checks.check(key, ClientSessionModel.Action.RECOVER_PASSWORD)) {
if (!checks.check(key, ClientSessionModel.Action.RECOVER_PASSWORD.name())) {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
@ -1038,7 +1017,7 @@ public class LoginActionsService {
event.session(userSession);
TokenManager.attachClientSession(userSession, clientSession);
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD.name());
try {
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());

View file

@ -788,7 +788,7 @@ public class UsersResource {
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD.name());
try {
UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
@ -838,7 +838,7 @@ public class UsersResource {
ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL);
accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL.name());
try {
UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());

View file

@ -4,3 +4,4 @@ org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory
org.keycloak.authentication.authenticators.LoginFormUsernameAuthenticatorFactory
org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory
org.keycloak.authentication.authenticators.SpnegoAuthenticatorFactory
org.keycloak.authentication.authenticators.SetRequiredActionAuthenticatorFactory

View file

@ -166,7 +166,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
private ClientSessionCode parseClientSessionCode(String code) {
ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realm);
if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
if (clientCode != null && clientCode.isValid(AUTHENTICATE.name())) {
ClientSessionModel clientSession = clientCode.getClientSession();
if (clientSession != null) {

View file

@ -117,14 +117,14 @@ public class UserSessionProviderTest {
int time = clientSession.getTimestamp();
assertEquals(null, clientSession.getAction());
clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
clientSession.setTimestamp(time + 10);
kc.stopSession(session, true);
session = kc.startSession();
ClientSessionModel updated = session.sessions().getClientSession(realm, id);
assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN, updated.getAction());
assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN.name(), updated.getAction());
assertEquals(time + 10, updated.getTimestamp());
}