Merge pull request #1413 from patriot1burke/master
refactor auth spi into additional form spi
This commit is contained in:
commit
2e5704c6b4
39 changed files with 847 additions and 235 deletions
|
@ -12,6 +12,16 @@
|
|||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<addColumn tableName="AUTHENTICATION_FLOW">
|
||||
<column name="PROVIDER_ID" type="VARCHAR(36)" defaultValue="basic-flow">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<addColumn tableName="AUTHENTICATION_EXECUTION">
|
||||
<column name="AUTH_FLOW_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<dropColumn tableName="AUTHENTICATOR" columnName="PROVIDER_ID"/>
|
||||
<renameTable oldTableName="AUTHENTICATOR_CONFIG" newTableName="AUTHENTICATOR_CONFIG_ENTRY"/>
|
||||
<renameTable oldTableName="AUTHENTICATOR" newTableName="AUTHENTICATOR_CONFIG"/>
|
||||
|
|
|
@ -22,6 +22,7 @@ public class AuthenticationExecutionModel implements Serializable {
|
|||
private String id;
|
||||
private String authenticatorConfig;
|
||||
private String authenticator;
|
||||
private String flowId;
|
||||
private boolean autheticatorFlow;
|
||||
private Requirement requirement;
|
||||
private boolean userSetupAllowed;
|
||||
|
@ -84,6 +85,19 @@ public class AuthenticationExecutionModel implements Serializable {
|
|||
this.parentFlow = parentFlow;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this execution is a flow, this is the flowId pointing to an AuthenticationFlowModel
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
|
||||
public void setFlowId(String flowId) {
|
||||
this.flowId = flowId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the referenced authenticator a flow?
|
||||
*
|
||||
|
|
|
@ -12,6 +12,7 @@ public class AuthenticationFlowModel implements Serializable {
|
|||
private String id;
|
||||
private String alias;
|
||||
private String description;
|
||||
private String providerId;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -36,4 +37,12 @@ public class AuthenticationFlowModel implements Serializable {
|
|||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
public void setProviderId(String providerId) {
|
||||
this.providerId = providerId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public interface ClientSessionModel {
|
|||
public String getNote(String name);
|
||||
public void setNote(String name, String value);
|
||||
public void removeNote(String name);
|
||||
public Map<String, String> getNotes();
|
||||
|
||||
/**
|
||||
* These are notes you want applied to the UserSessionModel when the client session is attached to it.
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
public class AuthenticationExecutionEntity {
|
||||
protected String id;
|
||||
protected String authenticator;
|
||||
protected String flowId;
|
||||
protected AuthenticationExecutionModel.Requirement requirement;
|
||||
protected int priority;
|
||||
private boolean userSetupAllowed;
|
||||
|
@ -71,4 +72,12 @@ public class AuthenticationExecutionEntity {
|
|||
public void setParentFlow(String parentFlow) {
|
||||
this.parentFlow = parentFlow;
|
||||
}
|
||||
|
||||
public String getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
|
||||
public void setFlowId(String flowId) {
|
||||
this.flowId = flowId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ public class AuthenticationFlowEntity {
|
|||
protected String id;
|
||||
protected String alias;
|
||||
protected String description;
|
||||
protected String providerId;
|
||||
|
||||
List<AuthenticationExecutionEntity> executions = new ArrayList<AuthenticationExecutionEntity>();
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -44,4 +46,12 @@ public class AuthenticationFlowEntity {
|
|||
public void setExecutions(List<AuthenticationExecutionEntity> executions) {
|
||||
this.executions = executions;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
public void setProviderId(String providerId) {
|
||||
this.providerId = providerId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ public class DefaultAuthenticationFlows {
|
|||
AuthenticationFlowModel browser = new AuthenticationFlowModel();
|
||||
browser.setAlias(BROWSER_FLOW);
|
||||
browser.setDescription("browser based authentication");
|
||||
browser.setProviderId("basic-flow");
|
||||
browser = realm.addAuthenticationFlow(browser);
|
||||
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(browser.getId());
|
||||
|
@ -40,11 +41,12 @@ public class DefaultAuthenticationFlows {
|
|||
AuthenticationFlowModel forms = new AuthenticationFlowModel();
|
||||
forms.setAlias(FORMS_FLOW);
|
||||
forms.setDescription("Username, password, otp and other auth forms.");
|
||||
forms.setProviderId("basic-flow");
|
||||
forms = realm.addAuthenticationFlow(forms);
|
||||
execution = new AuthenticationExecutionModel();
|
||||
execution.setParentFlow(browser.getId());
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
|
||||
execution.setAuthenticator(forms.getId());
|
||||
execution.setFlowId(forms.getId());
|
||||
execution.setPriority(30);
|
||||
execution.setUserSetupAllowed(false);
|
||||
execution.setAutheticatorFlow(true);
|
||||
|
|
|
@ -1233,6 +1233,7 @@ public class RealmAdapter implements RealmModel {
|
|||
model.setId(entity.getId());
|
||||
model.setAlias(entity.getAlias());
|
||||
model.setDescription(entity.getDescription());
|
||||
model.setProviderId(entity.getProviderId());
|
||||
return model;
|
||||
}
|
||||
|
||||
|
@ -1266,6 +1267,7 @@ public class RealmAdapter implements RealmModel {
|
|||
if (toUpdate == null) return;
|
||||
toUpdate.setAlias(model.getAlias());
|
||||
toUpdate.setDescription(model.getDescription());
|
||||
toUpdate.setProviderId(model.getProviderId());
|
||||
|
||||
}
|
||||
|
||||
|
@ -1275,6 +1277,7 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setAlias(model.getAlias());
|
||||
entity.setDescription(model.getDescription());
|
||||
entity.setProviderId(model.getProviderId());
|
||||
realm.getAuthenticationFlows().add(entity);
|
||||
model.setId(entity.getId());
|
||||
return model;
|
||||
|
@ -1303,6 +1306,7 @@ public class RealmAdapter implements RealmModel {
|
|||
model.setPriority(entity.getPriority());
|
||||
model.setAuthenticator(entity.getAuthenticator());
|
||||
model.setParentFlow(entity.getParentFlow());
|
||||
model.setFlowId(entity.getFlowId());
|
||||
model.setAutheticatorFlow(entity.isAuthenticatorFlow());
|
||||
return model;
|
||||
}
|
||||
|
@ -1334,6 +1338,7 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setRequirement(model.getRequirement());
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
entity.setAuthenticatorFlow(model.isAutheticatorFlow());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
AuthenticationFlowEntity flow = getFlowEntity(model.getId());
|
||||
flow.getExecutions().add(entity);
|
||||
model.setId(entity.getId());
|
||||
|
@ -1355,6 +1360,7 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setAuthenticator(model.getAuthenticator());
|
||||
entity.setPriority(model.getPriority());
|
||||
entity.setRequirement(model.getRequirement());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
}
|
||||
|
||||
|
|
|
@ -1542,6 +1542,7 @@ public class RealmAdapter implements RealmModel {
|
|||
AuthenticationFlowModel model = new AuthenticationFlowModel();
|
||||
model.setId(entity.getId());
|
||||
model.setAlias(entity.getAlias());
|
||||
model.setProviderId(entity.getProviderId());
|
||||
model.setDescription(entity.getDescription());
|
||||
return model;
|
||||
}
|
||||
|
@ -1567,6 +1568,7 @@ public class RealmAdapter implements RealmModel {
|
|||
if (entity == null) return;
|
||||
entity.setAlias(model.getAlias());
|
||||
entity.setDescription(model.getDescription());
|
||||
entity.setProviderId(model.getProviderId());
|
||||
|
||||
}
|
||||
|
||||
|
@ -1576,6 +1578,7 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setAlias(model.getAlias());
|
||||
entity.setDescription(model.getDescription());
|
||||
entity.setProviderId(model.getProviderId());
|
||||
entity.setRealm(realm);
|
||||
realm.getAuthenticationFlows().add(entity);
|
||||
em.persist(entity);
|
||||
|
@ -1589,7 +1592,7 @@ public class RealmAdapter implements RealmModel {
|
|||
TypedQuery<AuthenticationExecutionEntity> query = em.createNamedQuery("getAuthenticationExecutionsByFlow", AuthenticationExecutionEntity.class);
|
||||
AuthenticationFlowEntity flow = em.getReference(AuthenticationFlowEntity.class, flowId);
|
||||
query.setParameter("realm", realm);
|
||||
query.setParameter("flow", flow);
|
||||
query.setParameter("parentFlow", flow);
|
||||
List<AuthenticationExecutionEntity> queryResult = query.getResultList();
|
||||
List<AuthenticationExecutionModel> executions = new LinkedList<>();
|
||||
for (AuthenticationExecutionEntity entity : queryResult) {
|
||||
|
@ -1607,7 +1610,8 @@ public class RealmAdapter implements RealmModel {
|
|||
model.setRequirement(entity.getRequirement());
|
||||
model.setPriority(entity.getPriority());
|
||||
model.setAuthenticator(entity.getAuthenticator());
|
||||
model.setParentFlow(entity.getFlow().getId());
|
||||
model.setFlowId(entity.getFlowId());
|
||||
model.setParentFlow(entity.getParentFlow().getId());
|
||||
model.setAutheticatorFlow(entity.isAutheticatorFlow());
|
||||
return model;
|
||||
}
|
||||
|
@ -1625,9 +1629,10 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setAuthenticator(model.getAuthenticator());
|
||||
entity.setPriority(model.getPriority());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
entity.setRequirement(model.getRequirement());
|
||||
AuthenticationFlowEntity flow = em.find(AuthenticationFlowEntity.class, model.getParentFlow());
|
||||
entity.setFlow(flow);
|
||||
entity.setParentFlow(flow);
|
||||
flow.getExecutions().add(entity);
|
||||
entity.setRealm(realm);
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
|
@ -1648,6 +1653,7 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setPriority(model.getPriority());
|
||||
entity.setRequirement(model.getRequirement());
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
em.flush();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ import javax.persistence.Table;
|
|||
@Table(name="AUTHENTICATION_EXECUTION")
|
||||
@Entity
|
||||
@NamedQueries({
|
||||
@NamedQuery(name="getAuthenticationExecutionsByFlow", query="select authenticator from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.flow = :flow"),
|
||||
@NamedQuery(name="getAuthenticationExecutionsByFlow", query="select authenticator from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.parentFlow = :parentFlow"),
|
||||
@NamedQuery(name="deleteAuthenticationExecutionsByRealm", query="delete from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm"),
|
||||
@NamedQuery(name="deleteAuthenticationExecutionsByRealmAndFlow", query="delete from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.flow = :flow"),
|
||||
@NamedQuery(name="deleteAuthenticationExecutionsByRealmAndFlow", query="delete from AuthenticationExecutionEntity authenticator where authenticator.realm = :realm and authenticator.parentFlow = :parentFlow"),
|
||||
})
|
||||
public class AuthenticationExecutionEntity {
|
||||
@Id
|
||||
|
@ -34,11 +34,14 @@ public class AuthenticationExecutionEntity {
|
|||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "FLOW_ID")
|
||||
protected AuthenticationFlowEntity flow;
|
||||
protected AuthenticationFlowEntity parentFlow;
|
||||
|
||||
@Column(name="AUTHENTICATOR")
|
||||
protected String authenticator;
|
||||
|
||||
@Column(name="AUTH_FLOW_ID")
|
||||
protected String flowId;
|
||||
|
||||
@Column(name="REQUIREMENT")
|
||||
protected AuthenticationExecutionModel.Requirement requirement;
|
||||
|
||||
|
@ -107,11 +110,19 @@ public class AuthenticationExecutionEntity {
|
|||
this.autheticatorFlow = autheticatorFlow;
|
||||
}
|
||||
|
||||
public AuthenticationFlowEntity getFlow() {
|
||||
return flow;
|
||||
public AuthenticationFlowEntity getParentFlow() {
|
||||
return parentFlow;
|
||||
}
|
||||
|
||||
public void setFlow(AuthenticationFlowEntity flow) {
|
||||
this.flow = flow;
|
||||
public void setParentFlow(AuthenticationFlowEntity flow) {
|
||||
this.parentFlow = flow;
|
||||
}
|
||||
|
||||
public String getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
|
||||
public void setFlowId(String flowId) {
|
||||
this.flowId = flowId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,10 +36,13 @@ public class AuthenticationFlowEntity {
|
|||
@Column(name="ALIAS")
|
||||
protected String alias;
|
||||
|
||||
@Column(name="PROVIDER_ID")
|
||||
protected String providerId;
|
||||
|
||||
@Column(name="DESCRIPTION")
|
||||
protected String description;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "flow")
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "parentFlow")
|
||||
Collection<AuthenticationExecutionEntity> executions = new ArrayList<AuthenticationExecutionEntity>();
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -80,4 +83,12 @@ public class AuthenticationFlowEntity {
|
|||
public void setExecutions(Collection<AuthenticationExecutionEntity> executions) {
|
||||
this.executions = executions;
|
||||
}
|
||||
|
||||
public String getProviderId() {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
public void setProviderId(String providerId) {
|
||||
this.providerId = providerId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1341,6 +1341,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
if (toUpdate == null) return;
|
||||
toUpdate.setAlias(model.getAlias());
|
||||
toUpdate.setDescription(model.getDescription());
|
||||
toUpdate.setProviderId(model.getProviderId());
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
|
@ -1350,6 +1351,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setAlias(model.getAlias());
|
||||
entity.setDescription(model.getDescription());
|
||||
entity.setProviderId(model.getProviderId());
|
||||
getMongoEntity().getAuthenticationFlows().add(entity);
|
||||
model.setId(entity.getId());
|
||||
updateMongoEntity();
|
||||
|
@ -1378,6 +1380,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
model.setRequirement(entity.getRequirement());
|
||||
model.setPriority(entity.getPriority());
|
||||
model.setAuthenticator(entity.getAuthenticator());
|
||||
model.setFlowId(entity.getFlowId());
|
||||
model.setParentFlow(entity.getParentFlow());
|
||||
model.setAutheticatorFlow(entity.isAuthenticatorFlow());
|
||||
return model;
|
||||
|
@ -1410,6 +1413,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
entity.setRequirement(model.getRequirement());
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
entity.setAuthenticatorFlow(model.isAutheticatorFlow());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
entity.setParentFlow(model.getParentFlow());
|
||||
AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
|
||||
flow.getExecutions().add(entity);
|
||||
|
@ -1433,6 +1437,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
entity.setAuthenticator(model.getAuthenticator());
|
||||
entity.setPriority(model.getPriority());
|
||||
entity.setRequirement(model.getRequirement());
|
||||
entity.setFlowId(model.getFlowId());
|
||||
entity.setUserSetupAllowed(model.isUserSetupAllowed());
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
|
|
@ -165,6 +165,14 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getNotes() {
|
||||
if (entity.getNotes() == null || entity.getNotes().isEmpty()) return Collections.emptyMap();
|
||||
Map<String, String> copy = new HashMap<>();
|
||||
copy.putAll(entity.getNotes());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserSessionNote(String name, String value) {
|
||||
if (entity.getUserSessionNotes() == null) {
|
||||
|
|
|
@ -81,6 +81,16 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getNotes() {
|
||||
Map<String, String> copy = new HashMap<>();
|
||||
for (ClientSessionNoteEntity attr : entity.getNotes()) {
|
||||
copy.put(attr.getName(), attr.getValue());
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserSessionNote(String name, String value) {
|
||||
for (ClientUserSessionNoteEntity attr : entity.getUserSessionNotes()) {
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.keycloak.models.UserSessionModel;
|
|||
import org.keycloak.models.sessions.mem.entities.ClientSessionEntity;
|
||||
import org.keycloak.models.sessions.mem.entities.UserSessionEntity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -136,6 +138,14 @@ public class ClientSessionAdapter implements ClientSessionModel {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getNotes() {
|
||||
if (entity.getNotes() == null || entity.getNotes().isEmpty()) return Collections.emptyMap();
|
||||
Map<String, String> copy = new HashMap<>();
|
||||
copy.putAll(entity.getNotes());
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserSessionNote(String name, String value) {
|
||||
entity.getUserSessionNotes().put(name, value);
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.keycloak.models.UserSessionModel;
|
|||
import org.keycloak.models.sessions.mongo.entities.MongoClientSessionEntity;
|
||||
import org.keycloak.models.sessions.mongo.entities.MongoUserSessionEntity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
@ -157,6 +158,15 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
|
|||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getNotes() {
|
||||
if (entity.getNotes() == null || entity.getNotes().isEmpty()) return Collections.emptyMap();
|
||||
Map<String, String> copy = new HashMap<>();
|
||||
copy.putAll(entity.getNotes());
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setUserSessionNote(String name, String value) {
|
||||
entity.getUserSessionNotes().put(name, value);
|
||||
|
|
12
services/src/main/java/org/keycloak/authentication/AuthenticationFlow.java
Executable file
12
services/src/main/java/org/keycloak/authentication/AuthenticationFlow.java
Executable file
|
@ -0,0 +1,12 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface AuthenticationFlow {
|
||||
Response processAction(String actionExecution);
|
||||
Response processFlow();
|
||||
}
|
|
@ -26,7 +26,6 @@ import org.keycloak.util.Time;
|
|||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -64,6 +63,7 @@ public class AuthenticationProcessor {
|
|||
ATTEMPTED
|
||||
|
||||
}
|
||||
|
||||
public static enum Error {
|
||||
EXPIRED_CODE,
|
||||
INVALID_CLIENT_SESSION,
|
||||
|
@ -229,12 +229,14 @@ public class AuthenticationProcessor {
|
|||
this.challenge = challenge;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceChallenge(Response challenge) {
|
||||
this.status = Status.FORCE_CHALLENGE;
|
||||
this.challenge = challenge;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failureChallenge(Error error, Response challenge) {
|
||||
this.error = error;
|
||||
|
@ -242,6 +244,7 @@ public class AuthenticationProcessor {
|
|||
this.challenge = challenge;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(Error error, Response challenge) {
|
||||
this.error = error;
|
||||
|
@ -264,7 +267,8 @@ public class AuthenticationProcessor {
|
|||
@Override
|
||||
public void setUser(UserModel user) {
|
||||
UserModel previousUser = getUser();
|
||||
if (previousUser != null && !user.getId().equals(previousUser.getId())) throw new AuthException(Error.USER_CONFLICT);
|
||||
if (previousUser != null && !user.getId().equals(previousUser.getId()))
|
||||
throw new AuthException(Error.USER_CONFLICT);
|
||||
validateUser(user);
|
||||
getClientSession().setAuthenticatedUser(user);
|
||||
}
|
||||
|
@ -325,6 +329,16 @@ public class AuthenticationProcessor {
|
|||
clientSession.setTimestamp(Time.currentTime());
|
||||
return accessCode.getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getChallenge() {
|
||||
return challenge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Error getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AuthException extends RuntimeException {
|
||||
|
@ -372,15 +386,6 @@ public class AuthenticationProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean isProcessed(AuthenticationExecutionModel model) {
|
||||
if (model.isDisabled()) return true;
|
||||
ClientSessionModel.ExecutionStatus status = clientSession.getExecutionStatus().get(model.getId());
|
||||
if (status == null) return false;
|
||||
return status == ClientSessionModel.ExecutionStatus.SUCCESS || status == ClientSessionModel.ExecutionStatus.SKIPPED
|
||||
|| status == ClientSessionModel.ExecutionStatus.ATTEMPTED
|
||||
|| status == ClientSessionModel.ExecutionStatus.SETUP_REQUIRED;
|
||||
}
|
||||
|
||||
public boolean isSuccessful(AuthenticationExecutionModel model) {
|
||||
ClientSessionModel.ExecutionStatus status = clientSession.getExecutionStatus().get(model.getId());
|
||||
if (status == null) return false;
|
||||
|
@ -389,7 +394,7 @@ public class AuthenticationProcessor {
|
|||
|
||||
public Response handleBrowserException(Exception failure) {
|
||||
if (failure instanceof AuthException) {
|
||||
AuthException e = (AuthException)failure;
|
||||
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);
|
||||
|
@ -405,11 +410,11 @@ public class AuthenticationProcessor {
|
|||
event.error(Errors.INVALID_CODE);
|
||||
return ErrorPage.error(session, Messages.INVALID_CODE);
|
||||
|
||||
} else if (e.getError() == Error.EXPIRED_CODE) {
|
||||
} else if (e.getError() == Error.EXPIRED_CODE) {
|
||||
event.error(Errors.EXPIRED_CODE);
|
||||
return ErrorPage.error(session, Messages.EXPIRED_CODE);
|
||||
|
||||
}else {
|
||||
} else {
|
||||
event.error(Errors.INVALID_USER_CREDENTIALS);
|
||||
return ErrorPage.error(session, Messages.INVALID_USER);
|
||||
}
|
||||
|
@ -422,15 +427,22 @@ public class AuthenticationProcessor {
|
|||
|
||||
}
|
||||
|
||||
public FlowExecution createFlowExecution(String flowId) {
|
||||
public AuthenticationFlow createFlowExecution(String flowId, AuthenticationExecutionModel execution) {
|
||||
AuthenticationFlowModel flow = realm.getAuthenticationFlowById(flowId);
|
||||
if (flow == null) {
|
||||
logger.error("Unknown flow to execute with");
|
||||
throw new AuthException(Error.INTERNAL_ERROR);
|
||||
}
|
||||
FlowExecution flowExecution = new FlowExecution();
|
||||
flowExecution.executions = realm.getAuthenticationExecutions(flow.getId()).iterator();
|
||||
return flowExecution;
|
||||
if (flow.getProviderId() == null || flow.getProviderId().equals("basic-flow")) {
|
||||
DefaultAuthenticationFlow flowExecution = new DefaultAuthenticationFlow(this);
|
||||
flowExecution.executions = realm.getAuthenticationExecutions(flow.getId()).iterator();
|
||||
return flowExecution;
|
||||
|
||||
} else if (flow.getProviderId().equals("form-flow")) {
|
||||
FormAuthenticationFlow flowExecution = new FormAuthenticationFlow(this, execution);
|
||||
return flowExecution;
|
||||
}
|
||||
throw new AuthException("Unknown flow provider type", Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
public Response authenticate() throws AuthException {
|
||||
|
@ -446,8 +458,8 @@ public class AuthenticationProcessor {
|
|||
}
|
||||
UserModel authUser = clientSession.getAuthenticatedUser();
|
||||
validateUser(authUser);
|
||||
FlowExecution flowExecution = createFlowExecution(this.flowId);
|
||||
Response challenge = flowExecution.processFlow();
|
||||
AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, null);
|
||||
Response challenge = authenticationFlow.processFlow();
|
||||
if (challenge != null) return challenge;
|
||||
if (clientSession.getAuthenticatedUser() == null) {
|
||||
throw new AuthException(Error.UNKNOWN_USER);
|
||||
|
@ -455,7 +467,7 @@ public class AuthenticationProcessor {
|
|||
return authenticationComplete();
|
||||
}
|
||||
|
||||
public static void resetFlow(ClientSessionModel clientSession) {
|
||||
public static void resetFlow(ClientSessionModel clientSession) {
|
||||
clientSession.setAuthenticatedUser(null);
|
||||
clientSession.clearExecutionStatus();
|
||||
clientSession.clearUserSessionNotes();
|
||||
|
@ -486,13 +498,9 @@ public class AuthenticationProcessor {
|
|||
if (authType != null) {
|
||||
event.detail(Details.AUTH_TYPE, authType);
|
||||
}
|
||||
AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getAuthenticator());
|
||||
Authenticator authenticator = factory.create();
|
||||
Result context = new Result(model, authenticator);
|
||||
authenticator.action(context);
|
||||
|
||||
FlowExecution flowExecution = createFlowExecution(this.flowId);
|
||||
Response challenge = flowExecution.action(execution, context);
|
||||
AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, model);
|
||||
Response challenge = authenticationFlow.processAction(execution);
|
||||
if (challenge != null) return challenge;
|
||||
if (clientSession.getAuthenticatedUser() == null) {
|
||||
throw new AuthException(Error.UNKNOWN_USER);
|
||||
|
@ -523,8 +531,8 @@ public class AuthenticationProcessor {
|
|||
}
|
||||
UserModel authUser = clientSession.getAuthenticatedUser();
|
||||
validateUser(authUser);
|
||||
FlowExecution flowExecution = createFlowExecution(this.flowId);
|
||||
Response challenge = flowExecution.processFlow();
|
||||
AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, null);
|
||||
Response challenge = authenticationFlow.processFlow();
|
||||
if (challenge != null) return challenge;
|
||||
|
||||
String username = clientSession.getAuthenticatedUser().getUsername();
|
||||
|
@ -572,175 +580,16 @@ public class AuthenticationProcessor {
|
|||
}
|
||||
TokenManager.attachClientSession(userSession, clientSession);
|
||||
event.user(userSession.getUser())
|
||||
.detail(Details.USERNAME, username)
|
||||
.session(userSession);
|
||||
.detail(Details.USERNAME, username)
|
||||
.session(userSession);
|
||||
|
||||
return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, connection, request, uriInfo, event);
|
||||
|
||||
}
|
||||
|
||||
class FlowExecution {
|
||||
Response alternativeChallenge = null;
|
||||
AuthenticationExecutionModel challengedAlternativeExecution = null;
|
||||
boolean alternativeSuccessful = false;
|
||||
Iterator<AuthenticationExecutionModel> executions;
|
||||
|
||||
public Response action(String actionExecution, Result actionResult) {
|
||||
while (executions.hasNext()) {
|
||||
AuthenticationExecutionModel model = executions.next();
|
||||
if (isProcessed(model)) {
|
||||
logger.debug("execution is processed");
|
||||
if (!alternativeSuccessful && model.isAlternative() && isSuccessful(model)) alternativeSuccessful = true;
|
||||
continue;
|
||||
}
|
||||
if (!model.getId().equals(actionExecution)) {
|
||||
if (model.isAutheticatorFlow()) {
|
||||
FlowExecution flowExecution = createFlowExecution(model.getAuthenticator());
|
||||
return flowExecution.action(actionExecution, actionResult);
|
||||
} else {
|
||||
throw new AuthException("action is not current execution", Error.INTERNAL_ERROR);
|
||||
}
|
||||
} else { // we found the action
|
||||
Response response = processResult(actionResult);
|
||||
if (response == null) return processFlow();
|
||||
else return response;
|
||||
}
|
||||
}
|
||||
throw new AuthException("action is not in current execution", Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
public Response processFlow() {
|
||||
while (executions.hasNext()) {
|
||||
AuthenticationExecutionModel model = executions.next();
|
||||
if (isProcessed(model)) {
|
||||
logger.debug("execution is processed");
|
||||
if (!alternativeSuccessful && model.isAlternative() && isSuccessful(model)) alternativeSuccessful = true;
|
||||
continue;
|
||||
}
|
||||
if (model.isAlternative() && alternativeSuccessful) {
|
||||
clientSession.setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
if (model.isAutheticatorFlow()) {
|
||||
FlowExecution flowExecution = createFlowExecution(model.getAuthenticator());
|
||||
Response flowResponse = flowExecution.processFlow();
|
||||
if (flowResponse == null) {
|
||||
clientSession.setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
|
||||
if (model.isAlternative()) alternativeSuccessful = true;
|
||||
continue;
|
||||
} else {
|
||||
return flowResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getAuthenticator());
|
||||
Authenticator authenticator = factory.create();
|
||||
logger.debugv("authenticator: {0}", factory.getId());
|
||||
UserModel authUser = clientSession.getAuthenticatedUser();
|
||||
|
||||
if (authenticator.requiresUser() && authUser == null){
|
||||
if (alternativeChallenge != null) {
|
||||
clientSession.setExecutionStatus(challengedAlternativeExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return alternativeChallenge;
|
||||
}
|
||||
throw new AuthException("authenticator: " + factory.getId(), Error.UNKNOWN_USER);
|
||||
}
|
||||
boolean configuredFor = false;
|
||||
if (authenticator.requiresUser() && authUser != null) {
|
||||
configuredFor = authenticator.configuredFor(session, realm, authUser);
|
||||
if (!configuredFor) {
|
||||
if (model.isRequired()) {
|
||||
if (model.isUserSetupAllowed()) {
|
||||
logger.debugv("authenticator SETUP_REQUIRED: {0}", factory.getId());
|
||||
clientSession.setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED);
|
||||
authenticator.setRequiredActions(session, realm, clientSession.getAuthenticatedUser());
|
||||
continue;
|
||||
} else {
|
||||
throw new AuthException(Error.CREDENTIAL_SETUP_REQUIRED);
|
||||
}
|
||||
} else if (model.isOptional()) {
|
||||
clientSession.setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Result context = new Result(model, authenticator);
|
||||
authenticator.authenticate(context);
|
||||
Response response = processResult(context);
|
||||
if (response != null) return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Response processResult(Result result) {
|
||||
AuthenticationExecutionModel execution = result.getExecution();
|
||||
Status status = result.getStatus();
|
||||
if (status == Status.SUCCESS){
|
||||
logger.debugv("authenticator SUCCESS: {0}", execution.getAuthenticator());
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
|
||||
if (execution.isAlternative()) alternativeSuccessful = true;
|
||||
return null;
|
||||
} else if (status == Status.FAILED) {
|
||||
logger.debugv("authenticator FAILED: {0}", execution.getAuthenticator());
|
||||
logFailure();
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
|
||||
if (result.challenge != null) {
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
throw new AuthException(result.error);
|
||||
} else if (status == Status.FORCE_CHALLENGE) {
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == Status.CHALLENGE) {
|
||||
logger.debugv("authenticator CHALLENGE: {0}", execution.getAuthenticator());
|
||||
if (execution.isRequired()) {
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
UserModel authenticatedUser = clientSession.getAuthenticatedUser();
|
||||
if (execution.isOptional() && authenticatedUser != null && result.getAuthenticator().configuredFor(session, realm, authenticatedUser)) {
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
if (execution.isAlternative()) {
|
||||
alternativeChallenge = result.challenge;
|
||||
challengedAlternativeExecution = execution;
|
||||
} else {
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
}
|
||||
return null;
|
||||
} else if (status == Status.FAILURE_CHALLENGE) {
|
||||
logger.debugv("authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator());
|
||||
logFailure();
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == Status.ATTEMPTED) {
|
||||
logger.debugv("authenticator ATTEMPTED: {0}", execution.getAuthenticator());
|
||||
if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
|
||||
throw new AuthException(Error.INVALID_CREDENTIALS);
|
||||
}
|
||||
clientSession.setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
|
||||
return null;
|
||||
} else {
|
||||
logger.debugv("authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator());
|
||||
logger.error("Unknown result status");
|
||||
throw new AuthException(Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Response sendChallenge(Result result, AuthenticationExecutionModel execution) {
|
||||
clientSession.setNote(CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
|
||||
return result.challenge;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public AuthenticatorContext createAuthenticatorContext(AuthenticationExecutionModel model, Authenticator authenticator) {
|
||||
return new Result(model, authenticator);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import org.keycloak.provider.Provider;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface Authenticator extends Provider {
|
||||
boolean requiresUser();
|
||||
void authenticate(AuthenticatorContext context);
|
||||
boolean requiresUser();
|
||||
boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user);
|
||||
|
||||
/**
|
||||
|
|
|
@ -77,4 +77,8 @@ public interface AuthenticatorContext {
|
|||
* @return
|
||||
*/
|
||||
String generateAccessCode();
|
||||
|
||||
Response getChallenge();
|
||||
|
||||
AuthenticationProcessor.Error getError();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class AuthenticatorUtil {
|
|||
for (AuthenticationExecutionModel model : realm.getAuthenticationExecutions(flowId)) {
|
||||
executions.add(model);
|
||||
if (model.isAutheticatorFlow() && model.isEnabled()) {
|
||||
recurseExecutions(realm, model.getAuthenticator(), executions);
|
||||
recurseExecutions(realm, model.getFlowId(), executions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public class AuthenticatorUtil {
|
|||
public static AuthenticationExecutionModel findExecutionByAuthenticator(RealmModel realm, String flowId, String authProviderId) {
|
||||
for (AuthenticationExecutionModel model : realm.getAuthenticationExecutions(flowId)) {
|
||||
if (model.isAutheticatorFlow()) {
|
||||
AuthenticationExecutionModel recurse = findExecutionByAuthenticator(realm, model.getAuthenticator(), authProviderId);
|
||||
AuthenticationExecutionModel recurse = findExecutionByAuthenticator(realm, model.getFlowId(), authProviderId);
|
||||
if (recurse != null) return recurse;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DefaultAuthenticationFlow implements AuthenticationFlow {
|
||||
Response alternativeChallenge = null;
|
||||
AuthenticationExecutionModel challengedAlternativeExecution = null;
|
||||
boolean alternativeSuccessful = false;
|
||||
Iterator<AuthenticationExecutionModel> executions;
|
||||
AuthenticationProcessor processor;
|
||||
|
||||
public DefaultAuthenticationFlow(AuthenticationProcessor processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
protected boolean isProcessed(AuthenticationExecutionModel model) {
|
||||
if (model.isDisabled()) return true;
|
||||
ClientSessionModel.ExecutionStatus status = processor.getClientSession().getExecutionStatus().get(model.getId());
|
||||
if (status == null) return false;
|
||||
return status == ClientSessionModel.ExecutionStatus.SUCCESS || status == ClientSessionModel.ExecutionStatus.SKIPPED
|
||||
|| status == ClientSessionModel.ExecutionStatus.ATTEMPTED
|
||||
|| status == ClientSessionModel.ExecutionStatus.SETUP_REQUIRED;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Response processAction(String actionExecution) {
|
||||
while (executions.hasNext()) {
|
||||
AuthenticationExecutionModel model = executions.next();
|
||||
if (isProcessed(model)) {
|
||||
AuthenticationProcessor.logger.debug("execution is processed");
|
||||
if (!alternativeSuccessful && model.isAlternative() && processor.isSuccessful(model))
|
||||
alternativeSuccessful = true;
|
||||
continue;
|
||||
}
|
||||
if (!model.getId().equals(actionExecution)) {
|
||||
if (model.isAutheticatorFlow()) {
|
||||
AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model);
|
||||
return authenticationFlow.processAction(actionExecution);
|
||||
} else {
|
||||
throw new AuthenticationProcessor.AuthException("action is not current execution", AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
}
|
||||
} else { // we found the action
|
||||
AuthenticatorFactory factory = (AuthenticatorFactory) processor.getSession().getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getAuthenticator());
|
||||
Authenticator authenticator = factory.create();
|
||||
AuthenticatorContext result = processor.createAuthenticatorContext(model, authenticator);
|
||||
authenticator.action(result);
|
||||
Response response = processResult(result);
|
||||
if (response == null) return processFlow();
|
||||
else return response;
|
||||
}
|
||||
}
|
||||
throw new AuthenticationProcessor.AuthException("action is not in current execution", AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response processFlow() {
|
||||
while (executions.hasNext()) {
|
||||
AuthenticationExecutionModel model = executions.next();
|
||||
if (isProcessed(model)) {
|
||||
AuthenticationProcessor.logger.debug("execution is processed");
|
||||
if (!alternativeSuccessful && model.isAlternative() && processor.isSuccessful(model))
|
||||
alternativeSuccessful = true;
|
||||
continue;
|
||||
}
|
||||
if (model.isAlternative() && alternativeSuccessful) {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
if (model.isAutheticatorFlow()) {
|
||||
AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model);
|
||||
Response flowChallenge = authenticationFlow.processFlow();
|
||||
if (flowChallenge == null) {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
|
||||
if (model.isAlternative()) alternativeSuccessful = true;
|
||||
continue;
|
||||
} else {
|
||||
if (model.isAlternative()) {
|
||||
alternativeChallenge = flowChallenge;
|
||||
challengedAlternativeExecution = model;
|
||||
} else if (model.isRequired()) {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return flowChallenge;
|
||||
} else if (model.isOptional()) {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
} else {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
return flowChallenge;
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticatorFactory factory = (AuthenticatorFactory) processor.getSession().getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getAuthenticator());
|
||||
Authenticator authenticator = factory.create();
|
||||
AuthenticationProcessor.logger.debugv("authenticator: {0}", factory.getId());
|
||||
UserModel authUser = processor.getClientSession().getAuthenticatedUser();
|
||||
|
||||
if (authenticator.requiresUser() && authUser == null) {
|
||||
if (alternativeChallenge != null) {
|
||||
processor.getClientSession().setExecutionStatus(challengedAlternativeExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return alternativeChallenge;
|
||||
}
|
||||
throw new AuthenticationProcessor.AuthException("authenticator: " + factory.getId(), AuthenticationProcessor.Error.UNKNOWN_USER);
|
||||
}
|
||||
boolean configuredFor = false;
|
||||
if (authenticator.requiresUser() && authUser != null) {
|
||||
configuredFor = authenticator.configuredFor(processor.getSession(), processor.getRealm(), authUser);
|
||||
if (!configuredFor) {
|
||||
if (model.isRequired()) {
|
||||
if (model.isUserSetupAllowed()) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator SETUP_REQUIRED: {0}", factory.getId());
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED);
|
||||
authenticator.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getClientSession().getAuthenticatedUser());
|
||||
continue;
|
||||
} else {
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.CREDENTIAL_SETUP_REQUIRED);
|
||||
}
|
||||
} else if (model.isOptional()) {
|
||||
processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
AuthenticatorContext context = processor.createAuthenticatorContext(model, authenticator);
|
||||
authenticator.authenticate(context);
|
||||
Response response = processResult(context);
|
||||
if (response != null) return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Response processResult(AuthenticatorContext result) {
|
||||
AuthenticationExecutionModel execution = result.getExecution();
|
||||
AuthenticationProcessor.Status status = result.getStatus();
|
||||
if (status == AuthenticationProcessor.Status.SUCCESS) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator SUCCESS: {0}", execution.getAuthenticator());
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
|
||||
if (execution.isAlternative()) alternativeSuccessful = true;
|
||||
return null;
|
||||
} else if (status == AuthenticationProcessor.Status.FAILED) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator FAILED: {0}", execution.getAuthenticator());
|
||||
processor.logFailure();
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
|
||||
if (result.getChallenge() != null) {
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
throw new AuthenticationProcessor.AuthException(result.getError());
|
||||
} else if (status == AuthenticationProcessor.Status.FORCE_CHALLENGE) {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == AuthenticationProcessor.Status.CHALLENGE) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator CHALLENGE: {0}", execution.getAuthenticator());
|
||||
if (execution.isRequired()) {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
UserModel authenticatedUser = processor.getClientSession().getAuthenticatedUser();
|
||||
if (execution.isOptional() && authenticatedUser != null && result.getAuthenticator().configuredFor(processor.getSession(), processor.getRealm(), authenticatedUser)) {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
if (execution.isAlternative()) {
|
||||
alternativeChallenge = result.getChallenge();
|
||||
challengedAlternativeExecution = execution;
|
||||
} else {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
}
|
||||
return null;
|
||||
} else if (status == AuthenticationProcessor.Status.FAILURE_CHALLENGE) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator());
|
||||
processor.logFailure();
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == AuthenticationProcessor.Status.ATTEMPTED) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator ATTEMPTED: {0}", execution.getAuthenticator());
|
||||
if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INVALID_CREDENTIALS);
|
||||
}
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
|
||||
return null;
|
||||
} else {
|
||||
AuthenticationProcessor.logger.debugv("authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator());
|
||||
AuthenticationProcessor.logger.error("Unknown result status");
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Response sendChallenge(AuthenticatorContext result, AuthenticationExecutionModel execution) {
|
||||
processor.getClientSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
|
||||
return result.getChallenge();
|
||||
}
|
||||
|
||||
|
||||
}
|
24
services/src/main/java/org/keycloak/authentication/FormAction.java
Executable file
24
services/src/main/java/org/keycloak/authentication/FormAction.java
Executable file
|
@ -0,0 +1,24 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
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 FormAction extends Provider {
|
||||
void authenticate(FormContext context);
|
||||
|
||||
boolean requiresUser();
|
||||
boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user);
|
||||
|
||||
/**
|
||||
* Set actions to configure authenticator
|
||||
*
|
||||
*/
|
||||
void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user);
|
||||
|
||||
}
|
10
services/src/main/java/org/keycloak/authentication/FormActionFactory.java
Executable file
10
services/src/main/java/org/keycloak/authentication/FormActionFactory.java
Executable file
|
@ -0,0 +1,10 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface FormActionFactory extends ProviderFactory<FormAction> {
|
||||
}
|
32
services/src/main/java/org/keycloak/authentication/FormActionSpi.java
Executable file
32
services/src/main/java/org/keycloak/authentication/FormActionSpi.java
Executable file
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class FormActionSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "form-action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return FormAction.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return FormActionFactory.class;
|
||||
}
|
||||
|
||||
}
|
290
services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
Executable file
290
services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
Executable file
|
@ -0,0 +1,290 @@
|
|||
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.AuthenticatorConfigModel;
|
||||
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;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class FormAuthenticationFlow implements AuthenticationFlow {
|
||||
AuthenticationProcessor processor;
|
||||
AuthenticationExecutionModel execution;
|
||||
|
||||
|
||||
public FormAuthenticationFlow(AuthenticationProcessor processor, AuthenticationExecutionModel execution) {
|
||||
this.processor = processor;
|
||||
this.execution = execution;
|
||||
}
|
||||
|
||||
private static class FormActionResult implements FormContext {
|
||||
AuthenticatorContext delegate;
|
||||
FormAuthenticator authenticator;
|
||||
|
||||
FormActionResult(AuthenticatorContext delegate, FormAuthenticator authenticator) {
|
||||
this.delegate = delegate;
|
||||
this.authenticator = authenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormAuthenticator getFormAuthenticator() {
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder getEvent() {
|
||||
return delegate.getEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel getExecution() {
|
||||
return delegate.getExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecution(AuthenticationExecutionModel execution) {
|
||||
delegate.setExecution(execution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatorConfigModel getAuthenticatorConfig() {
|
||||
return delegate.getAuthenticatorConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAction() {
|
||||
return delegate.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator getAuthenticator() {
|
||||
return delegate.getAuthenticator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticator(Authenticator authenticator) {
|
||||
delegate.setAuthenticator(authenticator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProcessor.Status getStatus() {
|
||||
return delegate.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUser() {
|
||||
return delegate.getUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUser(UserModel user) {
|
||||
delegate.setUser(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return delegate.getRealm();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientSessionModel getClientSession() {
|
||||
return delegate.getClientSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachUserSession(UserSessionModel userSession) {
|
||||
delegate.attachUserSession(userSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientConnection getConnection() {
|
||||
return delegate.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriInfo getUriInfo() {
|
||||
return delegate.getUriInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getSession() {
|
||||
return delegate.getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequest getHttpRequest() {
|
||||
return delegate.getHttpRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BruteForceProtector getProtector() {
|
||||
return delegate.getProtector();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void success() {
|
||||
delegate.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(AuthenticationProcessor.Error error) {
|
||||
delegate.failure(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(AuthenticationProcessor.Error error, Response response) {
|
||||
delegate.failure(error, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void challenge(Response challenge) {
|
||||
delegate.challenge(challenge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceChallenge(Response challenge) {
|
||||
delegate.forceChallenge(challenge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failureChallenge(AuthenticationProcessor.Error error, Response challenge) {
|
||||
delegate.failureChallenge(error, challenge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attempted() {
|
||||
delegate.attempted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForwardedErrorMessage() {
|
||||
return delegate.getForwardedErrorMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateAccessCode() {
|
||||
return delegate.generateAccessCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getChallenge() {
|
||||
return delegate.getChallenge();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProcessor.Error getError() {
|
||||
return delegate.getError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Response processAction(String actionExecution) {
|
||||
if (!actionExecution.equals(execution.getId())) {
|
||||
throw new AuthenticationProcessor.AuthException("action is not current execution", AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
}
|
||||
FormAuthenticator authenticator = processor.getSession().getProvider(FormAuthenticator.class, execution.getAuthenticator());
|
||||
for (AuthenticationExecutionModel formActionExecution : processor.getRealm().getAuthenticationExecutions(execution.getFlowId())) {
|
||||
FormAction action = processor.getSession().getProvider(FormAction.class, execution.getAuthenticator());
|
||||
|
||||
UserModel authUser = processor.getClientSession().getAuthenticatedUser();
|
||||
if (action.requiresUser() && authUser == null) {
|
||||
throw new AuthenticationProcessor.AuthException("form action: " + execution.getAuthenticator() + " requires user", AuthenticationProcessor.Error.UNKNOWN_USER);
|
||||
}
|
||||
boolean configuredFor = false;
|
||||
if (action.requiresUser() && authUser != null) {
|
||||
configuredFor = action.configuredFor(processor.getSession(), processor.getRealm(), authUser);
|
||||
if (!configuredFor) {
|
||||
if (formActionExecution.isRequired()) {
|
||||
if (formActionExecution.isUserSetupAllowed()) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator SETUP_REQUIRED: {0}", execution.getAuthenticator());
|
||||
processor.getClientSession().setExecutionStatus(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED);
|
||||
action.setRequiredActions(processor.getSession(), processor.getRealm(), authUser);
|
||||
continue;
|
||||
} else {
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.CREDENTIAL_SETUP_REQUIRED);
|
||||
}
|
||||
} else if (formActionExecution.isOptional()) {
|
||||
processor.getClientSession().setExecutionStatus(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FormActionResult result = new FormActionResult(processor.createAuthenticatorContext(formActionExecution, null), authenticator);
|
||||
action.authenticate(result);
|
||||
return processResult(result, formActionExecution);
|
||||
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response processFlow() {
|
||||
FormAuthenticator authenticator = processor.getSession().getProvider(FormAuthenticator.class, execution.getAuthenticator());
|
||||
AuthenticatorContext context = processor.createAuthenticatorContext(execution, null);
|
||||
authenticator.authenticate(context);
|
||||
return processResult(context, execution);
|
||||
}
|
||||
|
||||
|
||||
public Response processResult(AuthenticatorContext result, AuthenticationExecutionModel execution) {
|
||||
AuthenticationProcessor.Status status = result.getStatus();
|
||||
if (status == AuthenticationProcessor.Status.SUCCESS) {
|
||||
return null;
|
||||
} else if (status == AuthenticationProcessor.Status.FAILED) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator FAILED: {0}", execution.getAuthenticator());
|
||||
processor.logFailure();
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
|
||||
if (result.getChallenge() != null) {
|
||||
return sendChallenge(result, execution);
|
||||
}
|
||||
throw new AuthenticationProcessor.AuthException(result.getError());
|
||||
} else if (status == AuthenticationProcessor.Status.FORCE_CHALLENGE) {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == AuthenticationProcessor.Status.CHALLENGE) {
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == AuthenticationProcessor.Status.FAILURE_CHALLENGE) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator());
|
||||
processor.logFailure();
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
|
||||
return sendChallenge(result, execution);
|
||||
} else if (status == AuthenticationProcessor.Status.ATTEMPTED) {
|
||||
AuthenticationProcessor.logger.debugv("authenticator ATTEMPTED: {0}", execution.getAuthenticator());
|
||||
if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INVALID_CREDENTIALS);
|
||||
}
|
||||
processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
|
||||
return null;
|
||||
} else {
|
||||
AuthenticationProcessor.logger.debugv("authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator());
|
||||
AuthenticationProcessor.logger.error("Unknown result status");
|
||||
throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Response sendChallenge(AuthenticatorContext result, AuthenticationExecutionModel execution) {
|
||||
processor.getClientSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
|
||||
return result.getChallenge();
|
||||
}
|
||||
|
||||
|
||||
}
|
14
services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
Executable file
14
services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
Executable 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 FormAuthenticator extends Provider {
|
||||
void authenticate(AuthenticatorContext context);
|
||||
Response createChallenge(FormContext context, String... errorMessages);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface FormAuthenticatorFactory extends ProviderFactory<FormAuthenticator> {
|
||||
}
|
32
services/src/main/java/org/keycloak/authentication/FormAuthenticatorSpi.java
Executable file
32
services/src/main/java/org/keycloak/authentication/FormAuthenticatorSpi.java
Executable file
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class FormAuthenticatorSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "form-authenticator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return FormAuthenticator.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return FormAuthenticatorFactory.class;
|
||||
}
|
||||
|
||||
}
|
9
services/src/main/java/org/keycloak/authentication/FormContext.java
Executable file
9
services/src/main/java/org/keycloak/authentication/FormContext.java
Executable file
|
@ -0,0 +1,9 @@
|
|||
package org.keycloak.authentication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface FormContext extends AuthenticatorContext {
|
||||
FormAuthenticator getFormAuthenticator();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
|
@ -6,13 +6,11 @@ import org.keycloak.authentication.RequiredActionContext;
|
|||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.login.LoginFormsProvider;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
import org.keycloak.util.Time;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
|
@ -6,13 +6,9 @@ import org.keycloak.authentication.RequiredActionContext;
|
|||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
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.UserModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
|
@ -6,19 +6,13 @@ import org.keycloak.authentication.RequiredActionContext;
|
|||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
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.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
import org.keycloak.util.Time;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
|
@ -8,13 +8,11 @@ import org.keycloak.authentication.RequiredActionProvider;
|
|||
import org.keycloak.events.Details;
|
||||
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.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
import org.keycloak.services.resources.LoginActionsService;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
import org.keycloak.util.Time;
|
|
@ -300,7 +300,6 @@ public class LoginActionsService {
|
|||
*/
|
||||
@Path("authenticate")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response authenticateForm(@QueryParam("code") String code,
|
||||
@QueryParam("execution") String execution) {
|
||||
event.event(EventType.LOGIN);
|
||||
|
|
|
@ -124,7 +124,7 @@ public class AuthenticationManagementResource {
|
|||
rep.setSubFlow(false);
|
||||
rep.setRequirementChoices(new LinkedList<String>());
|
||||
if (execution.isAutheticatorFlow()) {
|
||||
AuthenticationFlowModel flowRef = realm.getAuthenticationFlowById(execution.getAuthenticator());
|
||||
AuthenticationFlowModel flowRef = realm.getAuthenticationFlowById(execution.getFlowId());
|
||||
rep.setReferenceType(flowRef.getAlias());
|
||||
rep.setExecution(execution.getId());
|
||||
rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
org.keycloak.authentication.actions.UpdatePassword
|
||||
org.keycloak.authentication.actions.UpdateProfile
|
||||
org.keycloak.authentication.actions.UpdateTotp
|
||||
org.keycloak.authentication.actions.VerifyEmail
|
||||
org.keycloak.authentication.actions.TermsAndConditions
|
||||
org.keycloak.authentication.requiredactions.UpdatePassword
|
||||
org.keycloak.authentication.requiredactions.UpdateProfile
|
||||
org.keycloak.authentication.requiredactions.UpdateTotp
|
||||
org.keycloak.authentication.requiredactions.VerifyEmail
|
||||
org.keycloak.authentication.requiredactions.TermsAndConditions
|
|
@ -4,4 +4,6 @@ org.keycloak.exportimport.ClientImportSpi
|
|||
org.keycloak.wellknown.WellKnownSpi
|
||||
org.keycloak.messages.MessagesSpi
|
||||
org.keycloak.authentication.AuthenticatorSpi
|
||||
org.keycloak.authentication.RequiredActionSpi
|
||||
org.keycloak.authentication.RequiredActionSpi
|
||||
org.keycloak.authentication.FormAuthenticatorSpi
|
||||
org.keycloak.authentication.FormActionSpi
|
||||
|
|
Loading…
Reference in a new issue