keycloak-aplcache
Changes
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java 33(+33 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java 104(+104 -0)
model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java 117(+117 -0)
model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java 244(+244 -0)
services/src/main/java/org/keycloak/authentication/authenticators/AuthenticationFlow.java 60(+60 -0)
services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java 26(+25 -1)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java 9(+7 -2)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java 70(+70 -0)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java 10(+8 -2)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java 70(+70 -0)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java 34(+28 -6)
services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java 70(+70 -0)
Details
diff --git a/connections/jpa/src/main/resources/META-INF/persistence.xml b/connections/jpa/src/main/resources/META-INF/persistence.xml
index 5bcb77e..6399049 100755
--- a/connections/jpa/src/main/resources/META-INF/persistence.xml
+++ b/connections/jpa/src/main/resources/META-INF/persistence.xml
@@ -24,6 +24,9 @@
<class>org.keycloak.models.jpa.entities.UserConsentEntity</class>
<class>org.keycloak.models.jpa.entities.UserConsentRoleEntity</class>
<class>org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity</class>
+ <class>org.keycloak.models.jpa.entities.AuthenticationFlowEntity</class>
+ <class>org.keycloak.models.jpa.entities.AuthenticationExecutionEntity</class>
+ <class>org.keycloak.models.jpa.entities.AuthenticatorEntity</class>
<!-- JpaUserSessionProvider -->
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionEntity</class>
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
index 27869eb..516b9f4 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
@@ -21,6 +21,44 @@
<column name="REPRESENTATION" type="VARCHAR(25500)"/>
<column name="ERROR" type="VARCHAR(255)"/>
</createTable>
+ <createTable tableName="AUTHENTICATOR">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="ALIAS" type="VARCHAR(255)"/>
+ <column name="REALM_ID" type="VARCHAR(36)"/>
+ <column name="PROVIDER_ID" type="VARCHAR(36)"/>
+ </createTable>
+ <createTable tableName="AUTHENTICATION_FLOW">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="ALIAS" type="VARCHAR(255)"/>
+ <column name="DESCRIPTION" type="VARCHAR(255)"/>
+ <column name="REALM_ID" type="VARCHAR(36)"/>
+ </createTable>
+ <createTable tableName="AUTHENTICATION_EXECUTION">
+ <column name="ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="ALIAS" type="VARCHAR(255)"/>
+ <column name="AUTHENTICATOR" type="VARCHAR(36)"/>
+ <column name="REALM_ID" type="VARCHAR(36)"/>
+ <column name="FLOW_ID" type="VARCHAR(36)"/>
+ <column name="REQUIREMENT" type="INT"/>
+ <column name="PRIORITY" type="INT"/>
+ <column name="USER_SETUP_ALLOWED" type="BOOLEAN" defaultValueBoolean="false"/>
+ <column name="AUTHENTICATOR_FLOW" type="BOOLEAN" defaultValueBoolean="false"/>
+ </createTable>
+ <createTable tableName="AUTHENTICATOR_CONFIG">
+ <column name="AUTHENTICATOR_ID" type="VARCHAR(36)">
+ <constraints nullable="false"/>
+ </column>
+ <column name="VALUE" type="CLOB"/>
+ <column name="NAME" type="VARCHAR(255)">
+ <constraints nullable="false"/>
+ </column>
+ </createTable>
<addColumn tableName="REALM">
<column name="ADMIN_EVENTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
@@ -30,7 +68,7 @@
</column>
</addColumn>
<createTable tableName="CLIENT_SESSION_AUTH_STATUS">
- <column name="AUTHENTICATOR" type="VARCHAR(32)">
+ <column name="AUTHENTICATOR" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="STATUS" type="INT"/>
@@ -39,10 +77,10 @@
</column>
</createTable>
<addColumn tableName="CLIENT_SESSION">
- <column name="AUTH_USER_ID" type="VARCHAR(32)"/>
+ <column name="AUTH_USER_ID" type="VARCHAR(36)"/>
</addColumn>
<addColumn tableName="USER_REQUIRED_ACTION">
- <column name="REQUIRED_ACTION" type="VARCHAR(32)">
+ <column name="REQUIRED_ACTION" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
</addColumn>
@@ -63,10 +101,18 @@
<column name="REQUIRED_ACTION" value="UPDATE_PASSWORD"/>
<where>ACTION = 3</where>
</update>
+ <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_AUTHENTICATOR_PK" tableName="AUTHENTICATOR"/>
+ <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_AUTHENTICATION_FLOW_PK" tableName="AUTHENTICATION_FLOW"/>
+ <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_AUTHENTICATION_EXECUTION_PK" tableName="AUTHENTICATION_EXECUTION"/>
+ <addPrimaryKey columnNames="AUTHENTICATOR_ID, NAME" constraintName="CONSTRAINT_AUTHENTICATOR_CONFIG_PK" tableName="AUTHENTICATOR_CONFIG"/>
<dropPrimaryKey constraintName="CONSTRAINT_2" tableName="USER_REQUIRED_ACTION"/>
<dropColumn tableName="USER_REQUIRED_ACTION" columnName="ACTION"/>
<addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTRAINT_REQUIRED_ACTION" tableName="USER_REQUIRED_ACTION"/>
<addPrimaryKey columnNames="CLIENT_SESSION, AUTHENTICATOR" constraintName="CONSTRAINT_AUTH_STATUS_PK" tableName="CLIENT_SESSION_AUTH_STATUS"/>
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_AUTH_STATUS" constraintName="AUTH_STATUS_CONSTRAINT" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
+ <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATOR" constraintName="FK_AUTHENTICATOR_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
+ <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATION_FLOW" constraintName="FK_AUTHENTICATION_FLOW_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
+ <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="AUTHENTICATION_EXECUTION" constraintName="FK_AUTHENTICATION_EXECUTION_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
+ <addForeignKeyConstraint baseColumnNames="FLOW_ID" baseTableName="AUTHENTICATION_EXECUTION" constraintName="FK_AUTHENTICATION_EXECUTION_FLOW" referencedColumnNames="ID" referencedTableName="AUTHENTICATION_FLOW"/>
</changeSet>
</databaseChangeLog>
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
new file mode 100755
index 0000000..8cea65b
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java
@@ -0,0 +1,83 @@
+package org.keycloak.models;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public class AuthenticationExecutionModel {
+
+ private String id;
+ private String authenticator;
+ private boolean autheticatorFlow;
+ private Requirement requirement;
+ private boolean userSetupAllowed;
+ private int priority;
+ private String parentFlow;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAuthenticator() {
+ return authenticator;
+ }
+
+ public void setAuthenticator(String authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ public Requirement getRequirement() {
+ return requirement;
+ }
+
+ public void setRequirement(Requirement requirement) {
+ this.requirement = requirement;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public boolean isUserSetupAllowed() {
+ return userSetupAllowed;
+ }
+
+ public void setUserSetupAllowed(boolean userSetupAllowed) {
+ this.userSetupAllowed = userSetupAllowed;
+ }
+
+ public String getParentFlow() {
+ return parentFlow;
+ }
+
+ public void setParentFlow(String parentFlow) {
+ this.parentFlow = parentFlow;
+ }
+
+ /**
+ * Is the referenced authenticator a flow?
+ *
+ * @return
+ */
+ public boolean isAutheticatorFlow() {
+ return autheticatorFlow;
+ }
+
+ public void setAutheticatorFlow(boolean autheticatorFlow) {
+ this.autheticatorFlow = autheticatorFlow;
+ }
+
+ public enum Requirement {
+ REQUIRED,
+ OPTIONAL,
+ ALTERNATIVE
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
new file mode 100755
index 0000000..b9e5322
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticationFlowModel.java
@@ -0,0 +1,35 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthenticationFlowModel {
+ private String id;
+ private String alias;
+ private String description;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticatorModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticatorModel.java
index 0ca9322..0a6cacd 100755
--- a/model/api/src/main/java/org/keycloak/models/AuthenticatorModel.java
+++ b/model/api/src/main/java/org/keycloak/models/AuthenticatorModel.java
@@ -9,23 +9,9 @@ import java.util.Map;
*/
public class AuthenticatorModel {
- public enum Requirement {
- REQUIRED,
- OPTIONAL,
- ALTERNATIVE
- }
-
private String id;
private String alias;
private String providerId;
- private boolean masterAuthenticator;
- private boolean formBased;
- private String inputPage;
- private String actionUrl;
- private String setupUrl;
- private Requirement requirement;
- private boolean userSetupAllowed;
- private int priority;
private Map<String, String> config = new HashMap<String, String>();
@@ -53,70 +39,6 @@ public class AuthenticatorModel {
this.providerId = providerId;
}
- public boolean isFormBased() {
- return formBased;
- }
-
- public void setFormBased(boolean formBased) {
- this.formBased = formBased;
- }
-
- public String getInputPage() {
- return inputPage;
- }
-
- public void setInputPage(String inputPage) {
- this.inputPage = inputPage;
- }
-
- public String getActionUrl() {
- return actionUrl;
- }
-
- public void setActionUrl(String actionUrl) {
- this.actionUrl = actionUrl;
- }
-
- public String getSetupUrl() {
- return setupUrl;
- }
-
- public void setSetupUrl(String setupUrl) {
- this.setupUrl = setupUrl;
- }
-
- public Requirement getRequirement() {
- return requirement;
- }
-
- public void setRequirement(Requirement requirement) {
- this.requirement = requirement;
- }
-
- public int getPriority() {
- return priority;
- }
-
- public void setPriority(int priority) {
- this.priority = priority;
- }
-
- public boolean isUserSetupAllowed() {
- return userSetupAllowed;
- }
-
- public void setUserSetupAllowed(boolean userSetupAllowed) {
- this.userSetupAllowed = userSetupAllowed;
- }
-
- public boolean isMasterAuthenticator() {
- return masterAuthenticator;
- }
-
- public void setMasterAuthenticator(boolean masterAuthenticator) {
- this.masterAuthenticator = masterAuthenticator;
- }
-
public Map<String, String> getConfig() {
return config;
}
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
new file mode 100755
index 0000000..c90a657
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
@@ -0,0 +1,74 @@
+package org.keycloak.models.entities;
+
+import org.keycloak.models.AuthenticationExecutionModel;
+
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthenticationExecutionEntity {
+ protected String id;
+ protected String authenticator;
+ protected AuthenticationExecutionModel.Requirement requirement;
+ protected int priority;
+ private boolean userSetupAllowed;
+ private boolean autheticatorFlow;
+ private String parentFlow;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAuthenticator() {
+ return authenticator;
+ }
+
+ public void setAuthenticator(String authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ public AuthenticationExecutionModel.Requirement getRequirement() {
+ return requirement;
+ }
+
+ public void setRequirement(AuthenticationExecutionModel.Requirement requirement) {
+ this.requirement = requirement;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public boolean isUserSetupAllowed() {
+ return userSetupAllowed;
+ }
+
+ public void setUserSetupAllowed(boolean userSetupAllowed) {
+ this.userSetupAllowed = userSetupAllowed;
+ }
+
+ public boolean isAutheticatorFlow() {
+ return autheticatorFlow;
+ }
+
+ public void setAutheticatorFlow(boolean autheticatorFlow) {
+ this.autheticatorFlow = autheticatorFlow;
+ }
+
+ public String getParentFlow() {
+ return parentFlow;
+ }
+
+ public void setParentFlow(String parentFlow) {
+ this.parentFlow = parentFlow;
+ }
+}
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
new file mode 100755
index 0000000..b79d1a5
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationFlowEntity.java
@@ -0,0 +1,47 @@
+package org.keycloak.models.entities;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthenticationFlowEntity {
+ protected String id;
+ protected String alias;
+ protected String description;
+ List<AuthenticationExecutionEntity> executions = new ArrayList<AuthenticationExecutionEntity>();
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public List<AuthenticationExecutionEntity> getExecutions() {
+ return executions;
+ }
+
+ public void setExecutions(List<AuthenticationExecutionEntity> executions) {
+ this.executions = executions;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/AuthenticatorEntity.java b/model/api/src/main/java/org/keycloak/models/entities/AuthenticatorEntity.java
new file mode 100755
index 0000000..c9077c0
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticatorEntity.java
@@ -0,0 +1,46 @@
+package org.keycloak.models.entities;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthenticatorEntity {
+ protected String id;
+ protected String alias;
+ protected String providerId;
+ private Map<String, String> config;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getProviderId() {
+ return providerId;
+ }
+
+ public void setProviderId(String providerId) {
+ this.providerId = providerId;
+ }
+
+ public Map<String, String> getConfig() {
+ return config;
+ }
+
+ public void setConfig(Map<String, String> config) {
+ this.config = config;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index 718a1c5..822edc4 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -73,6 +73,8 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private List<String> supportedLocales = new ArrayList<String>();
private String defaultLocale;
private List<IdentityProviderMapperEntity> identityProviderMappers = new ArrayList<IdentityProviderMapperEntity>();
+ private List<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
+ private List<AuthenticatorEntity> authenticators = new ArrayList<>();
public String getName() {
@@ -473,6 +475,22 @@ public class RealmEntity extends AbstractIdentifiableEntity {
public void setIdentityProviderMappers(List<IdentityProviderMapperEntity> identityProviderMappers) {
this.identityProviderMappers = identityProviderMappers;
}
+
+ public List<AuthenticationFlowEntity> getAuthenticationFlows() {
+ return authenticationFlows;
+ }
+
+ public void setAuthenticationFlows(List<AuthenticationFlowEntity> authenticationFlows) {
+ this.authenticationFlows = authenticationFlows;
+ }
+
+ public List<AuthenticatorEntity> getAuthenticators() {
+ return authenticators;
+ }
+
+ public void setAuthenticators(List<AuthenticatorEntity> authenticators) {
+ this.authenticators = authenticators;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index dca2067..90afbb3 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -168,6 +168,25 @@ public interface RealmModel extends RoleContainerModel {
void setSmtpConfig(Map<String, String> smtpConfig);
+ List<AuthenticationFlowModel> getAuthenticationFlows();
+ AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model);
+ AuthenticationFlowModel getAuthenticationFlowById(String id);
+ void removeAuthenticationFlow(AuthenticationFlowModel model);
+ void updateAuthenticationFlow(AuthenticationFlowModel model);
+
+ List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId);
+ AuthenticationExecutionModel getAuthenticationExecutionById(String id);
+ AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model);
+ void updateAuthenticatorExecution(AuthenticationExecutionModel model);
+ void removeAuthenticatorExecution(AuthenticationExecutionModel model);
+
+
+ List<AuthenticatorModel> getAuthenticators();
+ AuthenticatorModel addAuthenticator(AuthenticatorModel model);
+ void updateAuthenticator(AuthenticatorModel model);
+ void removeAuthenticator(AuthenticatorModel model);
+ AuthenticatorModel getAuthenticatorById(String id);
+
List<IdentityProviderModel> getIdentityProviders();
IdentityProviderModel getIdentityProviderByAlias(String alias);
void addIdentityProvider(IdentityProviderModel identityProvider);
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 d835102..feae198 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
@@ -18,6 +18,9 @@ package org.keycloak.models.file.adapter;
import org.keycloak.connections.file.InMemoryModel;
import org.keycloak.enums.SslRequired;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
@@ -29,6 +32,9 @@ import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.entities.AuthenticationExecutionEntity;
+import org.keycloak.models.entities.AuthenticationFlowEntity;
+import org.keycloak.models.entities.AuthenticatorEntity;
import org.keycloak.models.entities.ClientEntity;
import org.keycloak.models.entities.IdentityProviderMapperEntity;
import org.keycloak.models.entities.RealmEntity;
@@ -1184,4 +1190,232 @@ public class RealmAdapter implements RealmModel {
return mapping;
}
+ @Override
+ public List<AuthenticationFlowModel> getAuthenticationFlows() {
+ List<AuthenticationFlowEntity> flows = realm.getAuthenticationFlows();
+ if (flows.size() == 0) return Collections.EMPTY_LIST;
+ List<AuthenticationFlowModel> models = new LinkedList<>();
+ for (AuthenticationFlowEntity entity : flows) {
+ AuthenticationFlowModel model = entityToModel(entity);
+ models.add(model);
+ }
+ return models;
+ }
+
+ protected AuthenticationFlowModel entityToModel(AuthenticationFlowEntity entity) {
+ AuthenticationFlowModel model = new AuthenticationFlowModel();
+ model.setId(entity.getId());
+ model.setAlias(entity.getAlias());
+ model.setDescription(entity.getDescription());
+ return model;
+ }
+
+ @Override
+ public AuthenticationFlowModel getAuthenticationFlowById(String id) {
+ for (AuthenticationFlowModel model : getAuthenticationFlows()) {
+ if (model.getId().equals(id)) return model;
+ }
+ return null;
+ }
+
+ protected AuthenticationFlowEntity getFlowEntity(String id) {
+ List<AuthenticationFlowEntity> flows = realm.getAuthenticationFlows();
+ for (AuthenticationFlowEntity entity : flows) {
+ if (id.equals(entity.getId())) return entity;
+ }
+ return null;
+
+ }
+
+ @Override
+ public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity toDelete = getFlowEntity(model.getId());
+ if (toDelete == null) return;
+ realm.getAuthenticationFlows().remove(toDelete);
+ }
+
+ @Override
+ public void updateAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity toUpdate = getFlowEntity(model.getId());
+ if (toUpdate == null) return;
+ toUpdate.setAlias(model.getAlias());
+ toUpdate.setDescription(model.getDescription());
+
+ }
+
+ @Override
+ public AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity entity = new AuthenticationFlowEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAlias(model.getAlias());
+ entity.setDescription(model.getDescription());
+ realm.getAuthenticationFlows().add(entity);
+ model.setId(entity.getId());
+ return model;
+ }
+
+ @Override
+ public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
+ AuthenticationFlowEntity flow = getFlowEntity(flowId);
+ if (flow == null) return Collections.EMPTY_LIST;
+
+ List<AuthenticationExecutionEntity> queryResult = flow.getExecutions();
+ List<AuthenticationExecutionModel> executions = new LinkedList<>();
+ for (AuthenticationExecutionEntity entity : queryResult) {
+ AuthenticationExecutionModel model = entityToModel(entity);
+ executions.add(model);
+ }
+ return executions;
+ }
+
+ public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) {
+ AuthenticationExecutionModel model = new AuthenticationExecutionModel();
+ model.setId(entity.getId());
+ model.setUserSetupAllowed(entity.isUserSetupAllowed());
+ model.setRequirement(entity.getRequirement());
+ model.setPriority(entity.getPriority());
+ model.setAuthenticator(entity.getAuthenticator());
+ model.setParentFlow(entity.getParentFlow());
+ model.setAutheticatorFlow(entity.isAutheticatorFlow());
+ return model;
+ }
+
+ @Override
+ public AuthenticationExecutionModel getAuthenticationExecutionById(String id) {
+ AuthenticationExecutionEntity execution = getAuthenticationExecutionEntity(id);
+ return entityToModel(execution);
+ }
+
+ public AuthenticationExecutionEntity getAuthenticationExecutionEntity(String id) {
+ List<AuthenticationFlowEntity> flows = realm.getAuthenticationFlows();
+ for (AuthenticationFlowEntity entity : flows) {
+ for (AuthenticationExecutionEntity exe : entity.getExecutions()) {
+ if (exe.getId().equals(id)) {
+ return exe;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = new AuthenticationExecutionEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ AuthenticationFlowEntity flow = getFlowEntity(model.getId());
+ flow.getExecutions().add(entity);
+ model.setId(entity.getId());
+ return model;
+
+ }
+
+ @Override
+ public void updateAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = null;
+ AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
+ for (AuthenticationExecutionEntity exe : flow.getExecutions()) {
+ if (exe.getId().equals(model.getId())) {
+ entity = exe;
+ }
+ }
+ if (entity == null) return;
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ }
+
+ @Override
+ public void removeAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = null;
+ AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
+ for (AuthenticationExecutionEntity exe : flow.getExecutions()) {
+ if (exe.getId().equals(model.getId())) {
+ entity = exe;
+ }
+ }
+ if (entity == null) return;
+ flow.getExecutions().remove(entity);
+
+ }
+
+ @Override
+ public List<AuthenticatorModel> getAuthenticators() {
+ List<AuthenticatorModel> authenticators = new LinkedList<>();
+ for (AuthenticatorEntity entity : realm.getAuthenticators()) {
+ authenticators.add(entityToModel(entity));
+ }
+ return authenticators;
+ }
+
+ @Override
+ public AuthenticatorModel addAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity auth = new AuthenticatorEntity();
+ auth.setId(KeycloakModelUtils.generateId());
+ auth.setAlias(model.getAlias());
+ auth.setProviderId(model.getProviderId());
+ auth.setConfig(model.getConfig());
+ realm.getAuthenticators().add(auth);
+ model.setId(auth.getId());
+ return model;
+ }
+
+ @Override
+ public void removeAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(model.getId());
+ if (entity == null) return;
+ realm.getAuthenticators().remove(entity);
+
+ }
+
+ @Override
+ public AuthenticatorModel getAuthenticatorById(String id) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(id);
+ if (entity == null) return null;
+ return entityToModel(entity);
+ }
+
+ public AuthenticatorEntity getAuthenticatorEntity(String id) {
+ AuthenticatorEntity entity = null;
+ for (AuthenticatorEntity auth : realm.getAuthenticators()) {
+ if (auth.getId().equals(id)) {
+ entity = auth;
+ break;
+ }
+ }
+ return entity;
+ }
+
+ public AuthenticatorModel entityToModel(AuthenticatorEntity entity) {
+ AuthenticatorModel model = new AuthenticatorModel();
+ model.setId(entity.getId());
+ model.setProviderId(entity.getProviderId());
+ model.setAlias(entity.getAlias());
+ Map<String, String> config = new HashMap<>();
+ if (entity.getConfig() != null) config.putAll(entity.getConfig());
+ model.setConfig(config);
+ return model;
+ }
+
+ @Override
+ public void updateAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(model.getId());
+ if (entity == null) return;
+ entity.setAlias(model.getAlias());
+ entity.setProviderId(model.getProviderId());
+ if (entity.getConfig() == null) {
+ entity.setConfig(model.getConfig());
+ } else {
+ entity.getConfig().clear();
+ entity.getConfig().putAll(model.getConfig());
+ }
+ }
+
+
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 22f57a9..5329a9c 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -1,6 +1,9 @@
package org.keycloak.models.cache.entities;
import org.keycloak.enums.SslRequired;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
@@ -74,6 +77,10 @@ public class CachedRealm {
private Map<String, String> browserSecurityHeaders = new HashMap<String, String>();
private Map<String, String> smtpConfig = new HashMap<String, String>();
+ private Map<String, AuthenticationFlowModel> authenticationFlows = new HashMap<>();
+ private Map<String, AuthenticatorModel> authenticators = new HashMap<>();
+ private MultivaluedHashMap<String, AuthenticationExecutionModel> authenticationExecutions = new MultivaluedHashMap<>();
+ private Map<String, AuthenticationExecutionModel> executionsById = new HashMap<>();
private boolean eventsEnabled;
private long eventsExpiration;
@@ -178,6 +185,16 @@ public class CachedRealm {
internationalizationEnabled = model.isInternationalizationEnabled();
supportedLocales.addAll(model.getSupportedLocales());
defaultLocale = model.getDefaultLocale();
+ for (AuthenticationFlowModel flow : model.getAuthenticationFlows()) {
+ authenticationFlows.put(flow.getId(), flow);
+ for (AuthenticationExecutionModel execution : model.getAuthenticationExecutions(flow.getId())) {
+ authenticationExecutions.add(flow.getId(), execution);
+ executionsById.put(execution.getId(), execution);
+ }
+ }
+ for (AuthenticatorModel authenticator : model.getAuthenticators()) {
+ authenticators.put(authenticator.getId(), authenticator);
+ }
}
@@ -396,4 +413,20 @@ public class CachedRealm {
public MultivaluedHashMap<String, IdentityProviderMapperModel> getIdentityProviderMappers() {
return identityProviderMappers;
}
+
+ public Map<String, AuthenticationFlowModel> getAuthenticationFlows() {
+ return authenticationFlows;
+ }
+
+ public Map<String, AuthenticatorModel> getAuthenticators() {
+ return authenticators;
+ }
+
+ public MultivaluedHashMap<String, AuthenticationExecutionModel> getAuthenticationExecutions() {
+ return authenticationExecutions;
+ }
+
+ public Map<String, AuthenticationExecutionModel> getExecutionsById() {
+ return executionsById;
+ }
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index 33f2356..2f6f8d6 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -2,6 +2,9 @@ package org.keycloak.models.cache;
import org.keycloak.Config;
import org.keycloak.enums.SslRequired;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
@@ -17,6 +20,7 @@ import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -948,4 +952,104 @@ public class RealmAdapter implements RealmModel {
return null;
}
+ @Override
+ public List<AuthenticationFlowModel> getAuthenticationFlows() {
+ if (updated != null) return updated.getAuthenticationFlows();
+ List<AuthenticationFlowModel> models = new ArrayList<>();
+ models.addAll(cached.getAuthenticationFlows().values());
+ return models;
+ }
+
+ @Override
+ public AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model) {
+ getDelegateForUpdate();
+ return updated.addAuthenticationFlow(model);
+ }
+
+ @Override
+ public AuthenticationFlowModel getAuthenticationFlowById(String id) {
+ if (updated != null) return updated.getAuthenticationFlowById(id);
+ return cached.getAuthenticationFlows().get(id);
+ }
+
+ @Override
+ public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+ getDelegateForUpdate();
+ updated.removeAuthenticationFlow(model);
+
+ }
+
+ @Override
+ public void updateAuthenticationFlow(AuthenticationFlowModel model) {
+ getDelegateForUpdate();
+ updated.updateAuthenticationFlow(model);
+
+ }
+
+ @Override
+ public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
+ if (updated != null) return updated.getAuthenticationExecutions(flowId);
+ List<AuthenticationExecutionModel> models = new ArrayList<>();
+ return cached.getAuthenticationExecutions().get(flowId);
+ }
+
+ @Override
+ public AuthenticationExecutionModel getAuthenticationExecutionById(String id) {
+ if (updated != null) return updated.getAuthenticationExecutionById(id);
+ return cached.getExecutionsById().get(id);
+ }
+
+ @Override
+ public AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model) {
+ getDelegateForUpdate();
+ return updated.addAuthenticatorExecution(model);
+ }
+
+ @Override
+ public void updateAuthenticatorExecution(AuthenticationExecutionModel model) {
+ getDelegateForUpdate();
+ updated.updateAuthenticatorExecution(model);
+
+ }
+
+ @Override
+ public void removeAuthenticatorExecution(AuthenticationExecutionModel model) {
+ getDelegateForUpdate();
+ updated.removeAuthenticatorExecution(model);
+
+ }
+
+ @Override
+ public List<AuthenticatorModel> getAuthenticators() {
+ if (updated != null) return updated.getAuthenticators();
+ List<AuthenticatorModel> models = new ArrayList<>();
+ models.addAll(cached.getAuthenticators().values());
+ return models;
+ }
+
+ @Override
+ public AuthenticatorModel addAuthenticator(AuthenticatorModel model) {
+ getDelegateForUpdate();
+ return updated.addAuthenticator(model);
+ }
+
+ @Override
+ public void updateAuthenticator(AuthenticatorModel model) {
+ getDelegateForUpdate();
+ updated.updateAuthenticator(model);
+
+ }
+
+ @Override
+ public void removeAuthenticator(AuthenticatorModel model) {
+ getDelegateForUpdate();
+ updated.removeAuthenticator(model);
+
+ }
+
+ @Override
+ public AuthenticatorModel getAuthenticatorById(String id) {
+ if (updated != null) return updated.getAuthenticatorById(id);
+ return cached.getAuthenticators().get(id);
+ }
}
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
new file mode 100755
index 0000000..be8720a
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
@@ -0,0 +1,117 @@
+package org.keycloak.models.jpa.entities;
+
+import org.keycloak.models.AuthenticationExecutionModel;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@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="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"),
+})
+public class AuthenticationExecutionEntity {
+ @Id
+ @Column(name="ID", length = 36)
+ protected String id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "REALM_ID")
+ protected RealmEntity realm;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "FLOW_ID")
+ protected AuthenticationFlowEntity flow;
+
+ @Column(name="AUTHENTICATOR")
+ protected String authenticator;
+
+ @Column(name="REQUIREMENT")
+ protected AuthenticationExecutionModel.Requirement requirement;
+
+ @Column(name="PRIORITY")
+ protected int priority;
+
+ @Column(name="USER_SETUP_ALLOWED")
+ private boolean userSetupAllowed;
+
+ @Column(name="AUTHENTICATOR_FLOW")
+ private boolean autheticatorFlow;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+
+ public String getAuthenticator() {
+ return authenticator;
+ }
+
+ public void setAuthenticator(String authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ public AuthenticationExecutionModel.Requirement getRequirement() {
+ return requirement;
+ }
+
+ public void setRequirement(AuthenticationExecutionModel.Requirement requirement) {
+ this.requirement = requirement;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public boolean isUserSetupAllowed() {
+ return userSetupAllowed;
+ }
+
+ public void setUserSetupAllowed(boolean userSetupAllowed) {
+ this.userSetupAllowed = userSetupAllowed;
+ }
+
+ public boolean isAutheticatorFlow() {
+ return autheticatorFlow;
+ }
+
+ public void setAutheticatorFlow(boolean autheticatorFlow) {
+ this.autheticatorFlow = autheticatorFlow;
+ }
+
+ public AuthenticationFlowEntity getFlow() {
+ return flow;
+ }
+
+ public void setFlow(AuthenticationFlowEntity flow) {
+ this.flow = flow;
+ }
+}
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
new file mode 100755
index 0000000..464fb4a
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationFlowEntity.java
@@ -0,0 +1,89 @@
+package org.keycloak.models.jpa.entities;
+
+import org.keycloak.models.AuthenticatorModel;
+
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Table(name="AUTHENTICATION_FLOW")
+@Entity
+@NamedQueries({
+ @NamedQuery(name="getAuthenticationFlowsByRealm", query="select flow from AuthenticationFlowEntity flow where flow.realm = :realm"),
+ @NamedQuery(name="deleteAuthenticationFlowByRealm", query="delete from AuthenticationFlowEntity flow where flow.realm = :realm")
+})
+public class AuthenticationFlowEntity {
+ @Id
+ @Column(name="ID", length = 36)
+ protected String id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "REALM_ID")
+ protected RealmEntity realm;
+
+ @Column(name="ALIAS")
+ protected String alias;
+
+ @Column(name="DESCRIPTION")
+ protected String description;
+
+ @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "flow")
+ Collection<AuthenticationExecutionEntity> executions = new ArrayList<AuthenticationExecutionEntity>();
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Collection<AuthenticationExecutionEntity> getExecutions() {
+ return executions;
+ }
+
+ public void setExecutions(Collection<AuthenticationExecutionEntity> executions) {
+ this.executions = executions;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticatorEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticatorEntity.java
new file mode 100755
index 0000000..1e97cd2
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticatorEntity.java
@@ -0,0 +1,89 @@
+package org.keycloak.models.jpa.entities;
+
+import org.keycloak.models.AuthenticatorModel;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Table(name="AUTHENTICATOR")
+@Entity
+@NamedQueries({
+ @NamedQuery(name="deleteAuthenticatorsByRealm", query="delete from AuthenticatorEntity authenticator where authenticator.realm = :realm"),})
+public class AuthenticatorEntity {
+ @Id
+ @Column(name="ID", length = 36)
+ protected String id;
+
+ @Column(name="ALIAS")
+ protected String alias;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "REALM_ID")
+ protected RealmEntity realm;
+
+ @Column(name="PROVIDER_ID")
+ protected String providerId;
+
+ @ElementCollection
+ @MapKeyColumn(name="NAME")
+ @Column(name="VALUE")
+ @CollectionTable(name="AUTHENTICATOR_CONFIG", joinColumns={ @JoinColumn(name="AUTHENTICATOR_ID") })
+ private Map<String, String> config;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getProviderId() {
+ return providerId;
+ }
+
+ public void setProviderId(String providerId) {
+ this.providerId = providerId;
+ }
+
+ public RealmEntity getRealm() {
+ return realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+
+ public Map<String, String> getConfig() {
+ return config;
+ }
+
+ public void setConfig(Map<String, String> config) {
+ this.config = config;
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index cdf314c..9ac1c3e 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -151,6 +151,12 @@ public class RealmEntity {
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<IdentityProviderMapperEntity> identityProviderMappers = new ArrayList<IdentityProviderMapperEntity>();
+ @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
+ Collection<AuthenticatorEntity> authenticators = new ArrayList<>();
+
+ @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
+ Collection<AuthenticationFlowEntity> authenticationFlows = new ArrayList<>();
+
@Column(name="INTERNATIONALIZATION_ENABLED")
@@ -535,5 +541,21 @@ public class RealmEntity {
public void setIdentityProviderMappers(Collection<IdentityProviderMapperEntity> identityProviderMappers) {
this.identityProviderMappers = identityProviderMappers;
}
+
+ public Collection<AuthenticatorEntity> getAuthenticators() {
+ return authenticators;
+ }
+
+ public void setAuthenticators(Collection<AuthenticatorEntity> authenticators) {
+ this.authenticators = authenticators;
+ }
+
+ public Collection<AuthenticationFlowEntity> getAuthenticationFlows() {
+ return authenticationFlows;
+ }
+
+ public void setAuthenticationFlows(Collection<AuthenticationFlowEntity> authenticationFlows) {
+ this.authenticationFlows = authenticationFlows;
+ }
}
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 66b94d0..9a7eb97 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
@@ -1,6 +1,9 @@
package org.keycloak.models.jpa;
import org.keycloak.enums.SslRequired;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
@@ -10,6 +13,9 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.jpa.entities.AuthenticationExecutionEntity;
+import org.keycloak.models.jpa.entities.AuthenticationFlowEntity;
+import org.keycloak.models.jpa.entities.AuthenticatorEntity;
import org.keycloak.models.jpa.entities.ClientEntity;
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity;
@@ -1351,4 +1357,207 @@ public class RealmAdapter implements RealmModel {
return mapping;
}
+ @Override
+ public List<AuthenticationFlowModel> getAuthenticationFlows() {
+ TypedQuery<AuthenticationFlowEntity> query = em.createNamedQuery("getAuthenticationFlowsByRealm", AuthenticationFlowEntity.class);
+ query.setParameter("realm", realm);
+ List<AuthenticationFlowEntity> flows = query.getResultList();
+ if (flows.size() == 0) return Collections.EMPTY_LIST;
+ List<AuthenticationFlowModel> models = new LinkedList<>();
+ for (AuthenticationFlowEntity entity : flows) {
+ AuthenticationFlowModel model = entityToModel(entity);
+ models.add(model);
+ }
+ return models;
+ }
+
+ protected AuthenticationFlowModel entityToModel(AuthenticationFlowEntity entity) {
+ AuthenticationFlowModel model = new AuthenticationFlowModel();
+ model.setId(entity.getId());
+ model.setAlias(entity.getAlias());
+ model.setDescription(entity.getDescription());
+ return model;
+ }
+
+ @Override
+ public AuthenticationFlowModel getAuthenticationFlowById(String id) {
+ AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, id);
+ if (entity == null) return null;
+ return entityToModel(entity);
+ }
+
+ @Override
+ public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, model.getId());
+ if (entity == null) return;
+ em.remove(entity);
+ em.flush();
+ }
+
+ @Override
+ public void updateAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, model.getId());
+ if (entity == null) return;
+ entity.setAlias(model.getAlias());
+ entity.setDescription(model.getDescription());
+
+ }
+
+ @Override
+ public AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity entity = new AuthenticationFlowEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAlias(model.getAlias());
+ entity.setDescription(model.getDescription());
+ entity.setRealm(realm);
+ realm.getAuthenticationFlows().add(entity);
+ em.persist(entity);
+ em.flush();
+ model.setId(entity.getId());
+ return model;
+ }
+
+ @Override
+ public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
+ TypedQuery<AuthenticationExecutionEntity> query = em.createNamedQuery("getAuthenticationExecutionsByFlow", AuthenticationExecutionEntity.class);
+ AuthenticationFlowEntity flow = em.getReference(AuthenticationFlowEntity.class, flowId);
+ query.setParameter("realm", realm);
+ query.setParameter("flow", flow);
+ List<AuthenticationExecutionEntity> queryResult = query.getResultList();
+ List<AuthenticationExecutionModel> executions = new LinkedList<>();
+ for (AuthenticationExecutionEntity entity : queryResult) {
+ AuthenticationExecutionModel model = entityToModel(entity);
+ executions.add(model);
+ }
+ return executions;
+ }
+
+ public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) {
+ AuthenticationExecutionModel model = new AuthenticationExecutionModel();
+ model.setId(entity.getId());
+ model.setUserSetupAllowed(entity.isUserSetupAllowed());
+ model.setRequirement(entity.getRequirement());
+ model.setPriority(entity.getPriority());
+ model.setAuthenticator(entity.getAuthenticator());
+ model.setParentFlow(entity.getFlow().getId());
+ model.setAutheticatorFlow(entity.isAutheticatorFlow());
+ return model;
+ }
+
+ @Override
+ public AuthenticationExecutionModel getAuthenticationExecutionById(String id) {
+ AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, id);
+ if (entity == null) return null;
+ return entityToModel(entity);
+ }
+
+ @Override
+ public AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = new AuthenticationExecutionEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ AuthenticationFlowEntity flow = em.find(AuthenticationFlowEntity.class, model.getParentFlow());
+ entity.setFlow(flow);
+ flow.getExecutions().add(entity);
+ entity.setRealm(realm);
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ em.persist(entity);
+ em.flush();
+ model.setId(entity.getId());
+ return model;
+
+ }
+
+ @Override
+ public void updateAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, model.getId());
+ if (entity == null) return;
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ em.flush();
+ }
+
+ @Override
+ public void removeAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, model.getId());
+ if (entity == null) return;
+ em.remove(entity);
+ em.flush();
+
+ }
+
+ @Override
+ public AuthenticatorModel addAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity auth = new AuthenticatorEntity();
+ auth.setId(KeycloakModelUtils.generateId());
+ auth.setAlias(model.getAlias());
+ auth.setRealm(realm);
+ auth.setProviderId(model.getProviderId());
+ auth.setConfig(model.getConfig());
+ realm.getAuthenticators().add(auth);
+ em.persist(auth);
+ em.flush();
+ model.setId(auth.getId());
+ return model;
+ }
+
+ @Override
+ public void removeAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = em.find(AuthenticatorEntity.class, model.getId());
+ if (entity == null) return;
+ em.remove(entity);
+ em.flush();
+
+ }
+
+ @Override
+ public AuthenticatorModel getAuthenticatorById(String id) {
+ AuthenticatorEntity entity = em.find(AuthenticatorEntity.class, id);
+ if (entity == null) return null;
+ return entityToModel(entity);
+ }
+
+ public AuthenticatorModel entityToModel(AuthenticatorEntity entity) {
+ AuthenticatorModel model = new AuthenticatorModel();
+ model.setId(entity.getId());
+ model.setProviderId(entity.getProviderId());
+ model.setAlias(entity.getAlias());
+ Map<String, String> config = new HashMap<>();
+ if (entity.getConfig() != null) config.putAll(entity.getConfig());
+ model.setConfig(config);
+ return model;
+ }
+
+ @Override
+ public void updateAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = em.find(AuthenticatorEntity.class, model.getId());
+ if (entity == null) return;
+ entity.setAlias(model.getAlias());
+ entity.setProviderId(model.getProviderId());
+ if (entity.getConfig() == null) {
+ entity.setConfig(model.getConfig());
+ } else {
+ entity.getConfig().clear();
+ entity.getConfig().putAll(model.getConfig());
+ }
+ em.flush();
+
+ }
+
+ @Override
+ public List<AuthenticatorModel> getAuthenticators() {
+ List<AuthenticatorModel> authenticators = new LinkedList<>();
+ for (AuthenticatorEntity entity : realm.getAuthenticators()) {
+ authenticators.add(entityToModel(entity));
+ }
+ return authenticators;
+ }
+
+
}
\ No newline at end of file
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 d797de9..579aea0 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
@@ -5,6 +5,9 @@ import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.enums.SslRequired;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
@@ -15,6 +18,9 @@ import org.keycloak.models.RealmProvider;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.entities.AuthenticationExecutionEntity;
+import org.keycloak.models.entities.AuthenticationFlowEntity;
+import org.keycloak.models.entities.AuthenticatorEntity;
import org.keycloak.models.entities.IdentityProviderEntity;
import org.keycloak.models.entities.IdentityProviderMapperEntity;
import org.keycloak.models.entities.RequiredCredentialEntity;
@@ -1169,6 +1175,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
if (toDelete != null) {
this.realm.getIdentityProviderMappers().remove(toDelete);
}
+ updateMongoEntity();
}
@@ -1213,4 +1220,241 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
return mapping;
}
+ @Override
+ public List<AuthenticationFlowModel> getAuthenticationFlows() {
+ List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
+ if (flows.size() == 0) return Collections.EMPTY_LIST;
+ List<AuthenticationFlowModel> models = new LinkedList<>();
+ for (AuthenticationFlowEntity entity : flows) {
+ AuthenticationFlowModel model = entityToModel(entity);
+ models.add(model);
+ }
+ return models;
+ }
+
+ protected AuthenticationFlowModel entityToModel(AuthenticationFlowEntity entity) {
+ AuthenticationFlowModel model = new AuthenticationFlowModel();
+ model.setId(entity.getId());
+ model.setAlias(entity.getAlias());
+ model.setDescription(entity.getDescription());
+ return model;
+ }
+
+ @Override
+ public AuthenticationFlowModel getAuthenticationFlowById(String id) {
+ for (AuthenticationFlowModel model : getAuthenticationFlows()) {
+ if (model.getId().equals(id)) return model;
+ }
+ return null;
+ }
+
+ protected AuthenticationFlowEntity getFlowEntity(String id) {
+ List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
+ for (AuthenticationFlowEntity entity : flows) {
+ if (id.equals(entity.getId())) return entity;
+ }
+ return null;
+
+ }
+
+ @Override
+ public void removeAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity toDelete = getFlowEntity(model.getId());
+ if (toDelete == null) return;
+ getMongoEntity().getAuthenticationFlows().remove(toDelete);
+ updateMongoEntity();
+ }
+
+ @Override
+ public void updateAuthenticationFlow(AuthenticationFlowModel model) {
+ List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
+ AuthenticationFlowEntity toUpdate = getFlowEntity(model.getId());;
+ if (toUpdate == null) return;
+ toUpdate.setAlias(model.getAlias());
+ toUpdate.setDescription(model.getDescription());
+ updateMongoEntity();
+ }
+
+ @Override
+ public AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model) {
+ AuthenticationFlowEntity entity = new AuthenticationFlowEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAlias(model.getAlias());
+ entity.setDescription(model.getDescription());
+ getMongoEntity().getAuthenticationFlows().add(entity);
+ model.setId(entity.getId());
+ updateMongoEntity();
+ return model;
+ }
+
+ @Override
+ public List<AuthenticationExecutionModel> getAuthenticationExecutions(String flowId) {
+ AuthenticationFlowEntity flow = getFlowEntity(flowId);
+ if (flow == null) return Collections.EMPTY_LIST;
+
+ List<AuthenticationExecutionEntity> queryResult = flow.getExecutions();
+ List<AuthenticationExecutionModel> executions = new LinkedList<>();
+ for (AuthenticationExecutionEntity entity : queryResult) {
+ AuthenticationExecutionModel model = entityToModel(entity);
+ executions.add(model);
+ }
+ return executions;
+ }
+
+ public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) {
+ AuthenticationExecutionModel model = new AuthenticationExecutionModel();
+ model.setId(entity.getId());
+ model.setUserSetupAllowed(entity.isUserSetupAllowed());
+ model.setRequirement(entity.getRequirement());
+ model.setPriority(entity.getPriority());
+ model.setAuthenticator(entity.getAuthenticator());
+ model.setParentFlow(entity.getParentFlow());
+ model.setAutheticatorFlow(entity.isAutheticatorFlow());
+ return model;
+ }
+
+ @Override
+ public AuthenticationExecutionModel getAuthenticationExecutionById(String id) {
+ AuthenticationExecutionEntity execution = getAuthenticationExecutionEntity(id);
+ return entityToModel(execution);
+ }
+
+ public AuthenticationExecutionEntity getAuthenticationExecutionEntity(String id) {
+ List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
+ for (AuthenticationFlowEntity entity : flows) {
+ for (AuthenticationExecutionEntity exe : entity.getExecutions()) {
+ if (exe.getId().equals(id)) {
+ return exe;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public AuthenticationExecutionModel addAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = new AuthenticationExecutionEntity();
+ entity.setId(KeycloakModelUtils.generateId());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ AuthenticationFlowEntity flow = getFlowEntity(model.getId());
+ flow.getExecutions().add(entity);
+ updateMongoEntity();
+ model.setId(entity.getId());
+ return model;
+
+ }
+
+ @Override
+ public void updateAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = null;
+ AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
+ for (AuthenticationExecutionEntity exe : flow.getExecutions()) {
+ if (exe.getId().equals(model.getId())) {
+ entity = exe;
+ }
+ }
+ if (entity == null) return;
+ entity.setAutheticatorFlow(model.isAutheticatorFlow());
+ entity.setAuthenticator(model.getAuthenticator());
+ entity.setPriority(model.getPriority());
+ entity.setRequirement(model.getRequirement());
+ entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ updateMongoEntity();
+ }
+
+ @Override
+ public void removeAuthenticatorExecution(AuthenticationExecutionModel model) {
+ AuthenticationExecutionEntity entity = null;
+ AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
+ for (AuthenticationExecutionEntity exe : flow.getExecutions()) {
+ if (exe.getId().equals(model.getId())) {
+ entity = exe;
+ }
+ }
+ if (entity == null) return;
+ flow.getExecutions().remove(entity);
+ updateMongoEntity();
+
+ }
+
+ @Override
+ public List<AuthenticatorModel> getAuthenticators() {
+ List<AuthenticatorModel> authenticators = new LinkedList<>();
+ for (AuthenticatorEntity entity : getMongoEntity().getAuthenticators()) {
+ authenticators.add(entityToModel(entity));
+ }
+ return authenticators;
+ }
+
+ @Override
+ public AuthenticatorModel addAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity auth = new AuthenticatorEntity();
+ auth.setId(KeycloakModelUtils.generateId());
+ auth.setAlias(model.getAlias());
+ auth.setProviderId(model.getProviderId());
+ auth.setConfig(model.getConfig());
+ realm.getAuthenticators().add(auth);
+ model.setId(auth.getId());
+ updateMongoEntity();
+ return model;
+ }
+
+ @Override
+ public void removeAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(model.getId());
+ if (entity == null) return;
+ getMongoEntity().getAuthenticators().remove(entity);
+ updateMongoEntity();
+
+ }
+
+ @Override
+ public AuthenticatorModel getAuthenticatorById(String id) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(id);
+ if (entity == null) return null;
+ return entityToModel(entity);
+ }
+
+ public AuthenticatorEntity getAuthenticatorEntity(String id) {
+ AuthenticatorEntity entity = null;
+ for (AuthenticatorEntity auth : getMongoEntity().getAuthenticators()) {
+ if (auth.getId().equals(id)) {
+ entity = auth;
+ break;
+ }
+ }
+ return entity;
+ }
+
+ public AuthenticatorModel entityToModel(AuthenticatorEntity entity) {
+ AuthenticatorModel model = new AuthenticatorModel();
+ model.setId(entity.getId());
+ model.setProviderId(entity.getProviderId());
+ model.setAlias(entity.getAlias());
+ Map<String, String> config = new HashMap<>();
+ if (entity.getConfig() != null) config.putAll(entity.getConfig());
+ model.setConfig(config);
+ return model;
+ }
+
+ @Override
+ public void updateAuthenticator(AuthenticatorModel model) {
+ AuthenticatorEntity entity = getAuthenticatorEntity(model.getId());
+ if (entity == null) return;
+ entity.setAlias(model.getAlias());
+ entity.setProviderId(model.getProviderId());
+ if (entity.getConfig() == null) {
+ entity.setConfig(model.getConfig());
+ } else {
+ entity.getConfig().clear();
+ entity.getConfig().putAll(model.getConfig());
+ }
+ updateMongoEntity();
+ }
+
+
}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 6f63004..5b20edf 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -3,6 +3,7 @@ package org.keycloak.authentication;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.events.EventBuilder;
+import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
@@ -52,7 +53,7 @@ public class AuthenticationProcessor {
protected ClientConnection connection;
protected UriInfo uriInfo;
protected KeycloakSession session;
- protected List<AuthenticatorModel> authenticators;
+ protected List<AuthenticationExecutionModel> executions;
protected BruteForceProtector protector;
protected EventBuilder eventBuilder;
protected HttpRequest request;
@@ -160,6 +161,13 @@ public class AuthenticationProcessor {
this.challenge = challenge;
}
+ @Override
+ public void failure(Error error, Response challenge) {
+ this.error = error;
+ this.status = Status.FAILED;
+ this.challenge = challenge;
+
+ }
@Override
public void attempted() {
@@ -264,28 +272,29 @@ public class AuthenticationProcessor {
validateUser(authUser);
Response challenge = null;
Map<String, UserSessionModel.AuthenticatorStatus> previousAttempts = clientSession.getAuthenticators();
- for (AuthenticatorModel model : authenticators) {
- UserSessionModel.AuthenticatorStatus oldStatus = previousAttempts.get(model.getAlias());
+ for (AuthenticationExecutionModel model : executions) {
+ UserSessionModel.AuthenticatorStatus oldStatus = previousAttempts.get(model.getId());
if (isProcessed(oldStatus)) continue;
- AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, model.getProviderId());
- Authenticator authenticator = factory.create(model);
+ AuthenticatorModel authenticatorModel = realm.getAuthenticatorById(model.getAuthenticator());
+ AuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, authenticatorModel.getProviderId());
+ Authenticator authenticator = factory.create(authenticatorModel);
if (authenticator.requiresUser() && authUser == null){
if ( authenticator.requiresUser()) {
if (challenge != null) return challenge;
throw new AuthException(Error.UNKNOWN_USER);
}
}
- if (authUser != null && model.getRequirement() == AuthenticatorModel.Requirement.ALTERNATIVE) {
- clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SKIPPED);
+ if (authUser != null && model.getRequirement() == AuthenticationExecutionModel.Requirement.ALTERNATIVE) {
+ clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SKIPPED);
continue;
}
authUser = clientSession.getAuthenticatedUser();
if (authenticator.requiresUser() && authUser != null && !authenticator.configuredFor(authUser)) {
- if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) {
+ if (model.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
if (model.isUserSetupAllowed()) {
- clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED);
+ clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SETUP_REQUIRED);
authUser.addRequiredAction(authenticator.getRequiredAction());
} else {
@@ -294,25 +303,26 @@ public class AuthenticationProcessor {
}
continue;
}
- Result context = new Result(model, authenticator);
+ Result context = new Result(authenticatorModel, authenticator);
authenticator.authenticate(context);
Status result = context.getStatus();
if (result == Status.SUCCESS){
- clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.SUCCESS);
- if (model.isMasterAuthenticator()) return authenticationComplete();
+ clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.SUCCESS);
+ //if (model.isMasterAuthenticator()) return authenticationComplete();
continue;
} else if (result == Status.FAILED) {
+ if (context.challenge != null) return context.challenge;
throw new AuthException(context.error);
} else if (result == Status.CHALLENGE) {
- if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) return context.challenge;
+ if (model.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) return context.challenge;
if (challenge != null) challenge = context.challenge;
continue;
} else if (result == Status.FAILURE_CHALLENGE) {
logUserFailure();
return context.challenge;
} else if (result == Status.ATTEMPTED) {
- if (model.getRequirement() == AuthenticatorModel.Requirement.REQUIRED) throw new AuthException(Error.INVALID_CREDENTIALS);
- clientSession.setAuthenticatorStatus(model.getAlias(), UserSessionModel.AuthenticatorStatus.ATTEMPTED);
+ if (model.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) throw new AuthException(Error.INVALID_CREDENTIALS);
+ clientSession.setAuthenticatorStatus(model.getId(), UserSessionModel.AuthenticatorStatus.ATTEMPTED);
continue;
}
}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
index 162c9b6..8a91d5e 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
@@ -9,6 +9,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.managers.ClientSessionCode;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -48,6 +49,7 @@ public interface AuthenticatorContext {
void success();
void failure(AuthenticationProcessor.Error error);
+ void failure(AuthenticationProcessor.Error error, Response response);
void challenge(Response challenge);
void failureChallenge(AuthenticationProcessor.Error error, Response challenge);
void attempted();
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java
index 28290fc..04b445e 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java
@@ -1,13 +1,16 @@
package org.keycloak.authentication;
import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.provider.ConfiguredProvider;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public interface AuthenticatorFactory extends ProviderFactory<Authenticator> {
+public interface AuthenticatorFactory extends ProviderFactory<Authenticator>, ConfiguredProvider {
Authenticator create(AuthenticatorModel model);
+ String getDisplayCategory();
+ String getDisplayType();
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/AuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/authenticators/AuthenticationFlow.java
new file mode 100755
index 0000000..98e5826
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/AuthenticationFlow.java
@@ -0,0 +1,60 @@
+package org.keycloak.authentication.authenticators;
+
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticatorModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthenticationFlow {
+
+ /**
+ * Hardcoded models just to test this stuff. It is temporary
+ */
+ static List<AuthenticationExecutionModel> hardcoded = new ArrayList<>();
+
+ /*
+ static {
+ AuthenticationExecutionModel model = new AuthenticationExecutionModel();
+ model.setId("1");
+ model.setAlias("cookie");
+ model.setMasterAuthenticator(true);
+ model.setProviderId(CookieAuthenticatorFactory.PROVIDER_ID);
+ model.setPriority(0);
+ model.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE);
+ model.setUserSetupAllowed(false);
+ hardcoded.add(model);
+ model = new AuthenticatorModel();
+ model.setId("2");
+ model.setAlias("user form");
+ model.setMasterAuthenticator(false);
+ model.setProviderId(LoginFormUsernameAuthenticatorFactory.PROVIDER_ID);
+ model.setPriority(1);
+ model.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
+ model.setUserSetupAllowed(false);
+ hardcoded.add(model);
+ model = new AuthenticatorModel();
+ model.setId("3");
+ model.setAlias("password form");
+ model.setMasterAuthenticator(false);
+ model.setProviderId(LoginFormUsernameAuthenticatorFactory.PROVIDER_ID);
+ model.setPriority(2);
+ model.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
+ model.setUserSetupAllowed(false);
+ hardcoded.add(model);
+ model = new AuthenticatorModel();
+ model.setId("4");
+ model.setAlias("otp form");
+ model.setMasterAuthenticator(false);
+ model.setProviderId(OTPFormAuthenticatorFactory.PROVIDER_ID);
+ model.setPriority(3);
+ model.setRequirement(AuthenticationExecutionModel.Requirement.OPTIONAL);
+ model.setUserSetupAllowed(false);
+ hardcoded.add(model);
+ }
+ */
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java
index ab50b3d..0f2ec07 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/CookieAuthenticatorFactory.java
@@ -6,12 +6,16 @@ import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CookieAuthenticatorFactory implements AuthenticatorFactory {
+ public static final String PROVIDER_ID = "auth-cookie";
static CookieAuthenticator SINGLETON = new CookieAuthenticator();
@Override
public Authenticator create(AuthenticatorModel model) {
@@ -40,6 +44,26 @@ public class CookieAuthenticatorFactory implements AuthenticatorFactory {
@Override
public String getId() {
- return "auth-cookie";
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Complete Authenticator";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Cookie Authenticator";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Validates the SSO cookie set by the auth server.";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return null;
}
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java
index 7cf5b71..f2f2ef2 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticator.java
@@ -6,6 +6,7 @@ import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -31,19 +32,23 @@ public class LoginFormOTPAuthenticator extends LoginFormUsernameAuthenticator {
validateOTP(context);
}
+ protected Response badPassword(AuthenticatorContext context) {
+ return loginForm(context).setError(Messages.INVALID_USER).createLogin();
+ }
+
public void validateOTP(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.TOTP);
if (password == null) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = badPassword(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
credentials.add(UserCredentialModel.totp(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
if (!valid) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = badPassword(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java
new file mode 100755
index 0000000..ef240cb
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormOTPAuthenticatorFactory.java
@@ -0,0 +1,70 @@
+package org.keycloak.authentication.authenticators;
+
+import org.keycloak.Config;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.authentication.AuthenticatorFactory;
+import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class LoginFormOTPAuthenticatorFactory implements AuthenticatorFactory {
+
+ public static final String PROVIDER_ID = "auth-login-form-otp";
+
+ @Override
+ public Authenticator create(AuthenticatorModel model) {
+ return new LoginFormOTPAuthenticator(model);
+ }
+
+ @Override
+ public Authenticator create(KeycloakSession session) {
+ throw new IllegalStateException("illegal call");
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Credential Validation";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Login Form OTP";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Validates an OTP that is specified on the login page.";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java
index 1aae3b2..bcc4c5e 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticator.java
@@ -6,6 +6,7 @@ import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -31,19 +32,24 @@ public class LoginFormPasswordAuthenticator extends LoginFormUsernameAuthenticat
validatePassword(context);
}
+ protected Response badPassword(AuthenticatorContext context) {
+ return loginForm(context).setError(Messages.INVALID_USER).createLogin();
+ }
+
+
public void validatePassword(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
List<UserCredentialModel> credentials = new LinkedList<>();
String password = inputData.getFirst(CredentialRepresentation.PASSWORD);
if (password == null) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = badPassword(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
credentials.add(UserCredentialModel.password(password));
boolean valid = context.getSession().users().validCredentials(context.getRealm(), context.getUser(), credentials);
if (!valid) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = badPassword(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_CREDENTIALS, challengeResponse);
return;
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java
new file mode 100755
index 0000000..5da119e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormPasswordAuthenticatorFactory.java
@@ -0,0 +1,70 @@
+package org.keycloak.authentication.authenticators;
+
+import org.keycloak.Config;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.authentication.AuthenticatorFactory;
+import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class LoginFormPasswordAuthenticatorFactory implements AuthenticatorFactory {
+
+ public static final String PROVIDER_ID = "auth-login-form-password";
+
+ @Override
+ public Authenticator create(AuthenticatorModel model) {
+ return new LoginFormPasswordAuthenticator(model);
+ }
+
+ @Override
+ public Authenticator create(KeycloakSession session) {
+ throw new IllegalStateException("illegal call");
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Credential Validation";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Login Form Password";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Validates a user password that is specified on the login page.";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
index 1d1f73f..78b9096 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticator.java
@@ -6,11 +6,13 @@ import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import javax.ws.rs.core.MultivaluedMap;
@@ -59,19 +61,37 @@ public class LoginFormUsernameAuthenticator implements Authenticator {
}
protected Response challenge(AuthenticatorContext context, MultivaluedMap<String, String> formData) {
- LoginFormsProvider forms = context.getSession().getProvider(LoginFormsProvider.class)
- .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode());
+ LoginFormsProvider forms = loginForm(context);
if (formData.size() > 0) forms.setFormData(formData);
return forms.createLogin();
}
+ protected LoginFormsProvider loginForm(AuthenticatorContext context) {
+ ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession());
+ code.setAction(ClientSessionModel.Action.AUTHENTICATE);
+ return context.getSession().getProvider(LoginFormsProvider.class)
+ .setClientSessionCode(code.getCode());
+ }
+
+ protected Response invalidUser(AuthenticatorContext context) {
+ return loginForm(context).setError(Messages.INVALID_USER).createLogin();
+ }
+
+ protected Response disabledUser(AuthenticatorContext context) {
+ return loginForm(context).setError(Messages.ACCOUNT_DISABLED).createLogin();
+ }
+
+ protected Response temporarilyDisabledUser(AuthenticatorContext context) {
+ return loginForm(context).setError(Messages.ACCOUNT_TEMPORARILY_DISABLED).createLogin();
+ }
+
public void validateUser(AuthenticatorContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getFormParameters();
String username = inputData.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = invalidUser(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
return;
}
@@ -82,17 +102,19 @@ public class LoginFormUsernameAuthenticator implements Authenticator {
public boolean invalidUser(AuthenticatorContext context, UserModel user) {
if (user == null) {
- Response challengeResponse = challenge(context);
+ Response challengeResponse = invalidUser(context);
context.failureChallenge(AuthenticationProcessor.Error.INVALID_USER, challengeResponse);
return true;
}
if (!user.isEnabled()) {
- context.failure(AuthenticationProcessor.Error.USER_DISABLED);
+ Response challengeResponse = disabledUser(context);
+ context.failureChallenge(AuthenticationProcessor.Error.USER_DISABLED, challengeResponse);
return true;
}
if (context.getRealm().isBruteForceProtected()) {
if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user.getUsername())) {
- context.failure(AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED);
+ Response challengeResponse = temporarilyDisabledUser(context);
+ context.failureChallenge(AuthenticationProcessor.Error.USER_TEMPORARILY_DISABLED, challengeResponse);
return true;
}
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java
new file mode 100755
index 0000000..de86b08
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/LoginFormUsernameAuthenticatorFactory.java
@@ -0,0 +1,70 @@
+package org.keycloak.authentication.authenticators;
+
+import org.keycloak.Config;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.authentication.AuthenticatorFactory;
+import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class LoginFormUsernameAuthenticatorFactory implements AuthenticatorFactory {
+
+ public static final String PROVIDER_ID = "auth-login-form-username";
+
+ @Override
+ public Authenticator create(AuthenticatorModel model) {
+ return new LoginFormUsernameAuthenticator(model);
+ }
+
+ @Override
+ public Authenticator create(KeycloakSession session) {
+ throw new IllegalStateException("illegal call");
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "User Validation";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Login Form Username";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Validates a username that is specified on the login page.";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java
new file mode 100755
index 0000000..f5fe0e7
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/OTPFormAuthenticatorFactory.java
@@ -0,0 +1,70 @@
+package org.keycloak.authentication.authenticators;
+
+import org.keycloak.Config;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.authentication.AuthenticatorFactory;
+import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OTPFormAuthenticatorFactory implements AuthenticatorFactory {
+
+ public static final String PROVIDER_ID = "auth-otp-form";
+
+ @Override
+ public Authenticator create(AuthenticatorModel model) {
+ return new OTPFormAuthenticator(model);
+ }
+
+ @Override
+ public Authenticator create(KeycloakSession session) {
+ throw new IllegalStateException("illegal call");
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Credential Validation";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "OTP Form";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Validates a OTP on a separate OTP form.";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java
new file mode 100755
index 0000000..684d074
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java
@@ -0,0 +1,33 @@
+package org.keycloak.authentication;
+
+import org.keycloak.protocol.ProtocolMapper;
+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 AuthenticatorSpi implements Spi {
+
+ @Override
+ public boolean isPrivate() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "authenticator";
+ }
+
+ @Override
+ public Class<? extends Provider> getProviderClass() {
+ return Authenticator.class;
+ }
+
+ @Override
+ public Class<? extends ProviderFactory> getProviderFactoryClass() {
+ return AuthenticatorFactory.class;
+ }
+
+}
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory
new file mode 100755
index 0000000..20dff3b
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory
@@ -0,0 +1,5 @@
+org.keycloak.authentication.authenticators.CookieAuthenticatorFactory
+org.keycloak.authentication.authenticators.LoginFormOTPAuthenticatorFactory
+org.keycloak.authentication.authenticators.LoginFormPasswordAuthenticatorFactory
+org.keycloak.authentication.authenticators.LoginFormUsernameAuthenticatorFactory
+org.keycloak.authentication.authenticators.OTPFormAuthenticatorFactory
\ No newline at end of file