keycloak-aplcache
Changes
model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java 25(+18 -7)
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java 8(+8 -0)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java 10(+10 -0)
model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java 10(+10 -0)
model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java 10(+10 -0)
services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java 2(+1 -1)
Details
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
index 3134b12..ff0311d 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
@@ -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"/>
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
index 15a599f..3b959d9 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
@@ -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;
@@ -85,6 +86,19 @@ public class AuthenticationExecutionModel implements Serializable {
}
/**
+ * 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?
*
* @return
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
index 194a6b3..db5970a 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
@@ -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;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/ClientSessionModel.java b/model/api/src/main/java/org/keycloak/models/ClientSessionModel.java
index 0a9744c..8531b5d 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientSessionModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientSessionModel.java
@@ -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.
diff --git a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
index e98b371..123e625 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
@@ -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;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationFlowEntity.java b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationFlowEntity.java
index b79d1a5..0db9560 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationFlowEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationFlowEntity.java
@@ -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;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
index df2e677..7512422 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
@@ -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);
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index 1dc6fab..7df3f6f 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -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());
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
index be8720a..b27659f 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
@@ -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 setParentFlow(AuthenticationFlowEntity flow) {
+ this.parentFlow = flow;
+ }
+
+ public String getFlowId() {
+ return flowId;
}
- public void setFlow(AuthenticationFlowEntity flow) {
- this.flow = flow;
+ public void setFlowId(String flowId) {
+ this.flowId = flowId;
}
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
index 1a60832..2db9722 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
@@ -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;
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index de47499..eec43ba 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -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();
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index dee96e2..935746e 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -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();
}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
index 32a2df6..af9f436 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
@@ -166,6 +166,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) {
entity.setUserSessionNotes(new HashMap<String, String>());
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
index 979e610..4c340c5 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
@@ -82,6 +82,16 @@ public class ClientSessionAdapter implements ClientSessionModel {
}
@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()) {
if (attr.getName().equals(name)) {
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
index 2c344f6..7fcd35f 100755
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
@@ -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;
@@ -137,6 +139,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);
}
diff --git a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
index 1313d36..2120044 100755
--- a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
+++ b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
@@ -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;
@@ -158,6 +159,15 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
}
@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);
updateMongoEntity();
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/AuthenticationFlow.java
new file mode 100755
index 0000000..d77772e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationFlow.java
@@ -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();
+}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 509e5c5..f5ff56e 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -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);
+ }
}
diff --git a/services/src/main/java/org/keycloak/authentication/Authenticator.java b/services/src/main/java/org/keycloak/authentication/Authenticator.java
index 36e6d52..ddde806 100755
--- a/services/src/main/java/org/keycloak/authentication/Authenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/Authenticator.java
@@ -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);
/**
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
index 49e663c..07a3fd1 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
@@ -77,4 +77,8 @@ public interface AuthenticatorContext {
* @return
*/
String generateAccessCode();
+
+ Response getChallenge();
+
+ AuthenticationProcessor.Error getError();
}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java
index 591ca4b..04962dd 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java
@@ -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;
}
diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
new file mode 100755
index 0000000..8aaaa64
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
@@ -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();
+ }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAction.java b/services/src/main/java/org/keycloak/authentication/FormAction.java
new file mode 100755
index 0000000..90bd084
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormAction.java
@@ -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);
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormActionFactory.java b/services/src/main/java/org/keycloak/authentication/FormActionFactory.java
new file mode 100755
index 0000000..cbac58b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormActionFactory.java
@@ -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> {
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormActionSpi.java b/services/src/main/java/org/keycloak/authentication/FormActionSpi.java
new file mode 100755
index 0000000..125ffdc
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormActionSpi.java
@@ -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;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
new file mode 100755
index 0000000..b8bb691
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
@@ -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();
+ }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
new file mode 100755
index 0000000..4804e92
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
@@ -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);
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticatorFactory.java
new file mode 100755
index 0000000..5b99f1a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticatorFactory.java
@@ -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> {
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticatorSpi.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticatorSpi.java
new file mode 100755
index 0000000..18303f0
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticatorSpi.java
@@ -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;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/FormContext.java b/services/src/main/java/org/keycloak/authentication/FormContext.java
new file mode 100755
index 0000000..24c46a7
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormContext.java
@@ -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();
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
index d048a57..7f1edbd 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
@@ -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());
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 20023c6..44910cb 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -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);
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
index 8106ec7..a72fdd9 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
+++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory
@@ -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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 050fef2..43d8d10 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -4,4 +4,6 @@ org.keycloak.exportimport.ClientImportSpi
org.keycloak.wellknown.WellKnownSpi
org.keycloak.messages.MessagesSpi
org.keycloak.authentication.AuthenticatorSpi
-org.keycloak.authentication.RequiredActionSpi
\ No newline at end of file
+org.keycloak.authentication.RequiredActionSpi
+org.keycloak.authentication.FormAuthenticatorSpi
+org.keycloak.authentication.FormActionSpi