keycloak-aplcache
Changes
forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java 24(+20 -4)
model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java 11(+11 -0)
model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java 3(+2 -1)
model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java 3(+2 -1)
model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java 3(+2 -1)
model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java 3(+2 -1)
Details
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
index f5f0195..80b2460 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
@@ -22,6 +22,9 @@
<column name="AUTH_FLOW_ID" type="VARCHAR(36)">
<constraints nullable="true"/>
</column>
+ <column name="AUTH_CONFIG" type="VARCHAR(36)">
+ <constraints nullable="true"/>
+ </column>
</addColumn>
<addColumn tableName="USER_ATTRIBUTE">
<column name="ID" type="VARCHAR(36)">
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_de.properties
index 6cbb05d..4fe6ab3 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_de.properties
@@ -13,6 +13,8 @@ kerberosNotConfigured=Kerberos Not Configured
kerberosNotConfiguredTitle=Kerberos Not Configured
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
kerberosNotSetUp=Kerberos is not set up. You cannot login.
+recaptchaFailed=Invalid Recaptcha
+recaptchaNotConfigured=Recaptcha is required, but not configured
registerWithTitle=Registrierung bei {0}
registerWithTitleHtml=Registrierung bei <strong>{0}</strong>
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
index 7a5237d..3fdb91c 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -30,6 +30,8 @@ codeSuccessTitle=Success code
codeErrorTitle=Error code\: {0}
termsTitle=Terms and Conditions
termsTitleHtml=Terms and Conditions
+recaptchaFailed=Invalid Recaptcha
+recaptchaNotConfigured=Recaptcha is required, but not configured
noAccount=New user?
username=Username
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_it.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_it.properties
index 5049b68..b239ecc 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_it.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_it.properties
@@ -13,6 +13,8 @@ bypassKerberos=Your browser is not set up for Kerberos login. Please click cont
kerberosNotSetUp=Kerberos is not set up. You cannot login.
kerberosNotConfigured=Kerberos Not Configured
kerberosNotConfiguredTitle=Kerberos Not Configured
+recaptchaFailed=Invalid Recaptcha
+recaptchaNotConfigured=Recaptcha is required, but not configured
registerWithTitle=Registrati come {0}
registerWithTitleHtml=Registrati come <strong>{0}</strong>
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
index 4959003..85b28fd 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
@@ -13,6 +13,8 @@ bypassKerberos=Your browser is not set up for Kerberos login. Please click cont
kerberosNotSetUp=Kerberos is not set up. You cannot login.
kerberosNotConfigured=Kerberos Not Configured
kerberosNotConfiguredTitle=Kerberos Not Configured
+recaptchaFailed=Invalid Recaptcha
+recaptchaNotConfigured=Recaptcha is required, but not configured
registerWithTitle=Registre-se com {0}
registerWithTitleHtml=Registre-se com <strong>{0}</strong>
diff --git a/forms/common-themes/src/main/resources/theme/base/login/register.ftl b/forms/common-themes/src/main/resources/theme/base/login/register.ftl
index 1927378..75a48fc 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/register.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/register.ftl
@@ -107,7 +107,13 @@
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.country" name="user.attributes.country"/>
</div>
</div>
-
+ <#if recaptchaRequired??>
+ <div class="form-group">
+ <div class="${properties.kcInputWrapperClass!}">
+ <div class="g-recaptcha" data-sitekey="${recaptchaSiteKey}"></div>
+ </div>
+ </div>
+ </#if>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
diff --git a/forms/common-themes/src/main/resources/theme/base/login/template.ftl b/forms/common-themes/src/main/resources/theme/base/login/template.ftl
old mode 100644
new mode 100755
index 34b2d4a..aca358f
--- a/forms/common-themes/src/main/resources/theme/base/login/template.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/template.ftl
@@ -21,6 +21,11 @@
<script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
</#list>
</#if>
+ <#if scripts??>
+ <#list scripts as script>
+ <script src="${script}" type="text/javascript"></script>
+ </#list>
+ </#if>
</head>
<body class="${properties.kcBodyClass!}">
diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
index f176555..dd5bc60 100755
--- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
+++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
@@ -63,6 +63,8 @@ public interface LoginFormsProvider extends Provider {
*/
public LoginFormsProvider setErrors(List<FormMessage> messages);
+ LoginFormsProvider addError(FormMessage errorMessage);
+
public LoginFormsProvider setSuccess(String message, Object ... parameters);
public LoginFormsProvider setUser(UserModel user);
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index 413c701..2f74db9 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -3,7 +3,6 @@ package org.keycloak.login.freemarker;
import org.jboss.logging.Logger;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.keycloak.OAuth2Constants;
-import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
@@ -39,8 +38,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
-import org.keycloak.services.messages.Messages;
import org.keycloak.services.Urls;
+import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
@@ -52,6 +51,7 @@ import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -61,7 +61,7 @@ import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
- public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
+public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private static final Logger logger = Logger.getLogger(FreeMarkerLoginFormsProvider.class);
@@ -445,13 +445,29 @@ import java.util.concurrent.TimeUnit;
@Override
public LoginFormsProvider setErrors(List<FormMessage> messages) {
+ if (messages == null) return this;
this.messageType = MessageType.ERROR;
this.messages = new ArrayList<>(messages);
return this;
}
@Override
- public FreeMarkerLoginFormsProvider setSuccess(String message, Object ... parameters) {
+ public LoginFormsProvider addError(FormMessage errorMessage) {
+ if (this.messageType != MessageType.ERROR) {
+ this.messageType = null;
+ this.messages = null;
+ }
+ if (messages == null) {
+ this.messageType = MessageType.ERROR;
+ this.messages = new LinkedList<>();
+ }
+ this.messages.add(errorMessage);
+ return this;
+
+ }
+
+ @Override
+ public FreeMarkerLoginFormsProvider setSuccess(String message, Object... parameters) {
setMessage(MessageType.SUCCESS, message, parameters);
return this;
}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
index 123e625..d4b21ee 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
@@ -10,6 +10,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
public class AuthenticationExecutionEntity {
protected String id;
protected String authenticator;
+ private String authenticatorConfig;
protected String flowId;
protected AuthenticationExecutionModel.Requirement requirement;
protected int priority;
@@ -80,4 +81,12 @@ public class AuthenticationExecutionEntity {
public void setFlowId(String flowId) {
this.flowId = flowId;
}
+
+ public String getAuthenticatorConfig() {
+ return authenticatorConfig;
+ }
+
+ public void setAuthenticatorConfig(String authenticatorConfig) {
+ this.authenticatorConfig = authenticatorConfig;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
index 3f2a103..dc7a44a 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
@@ -2,8 +2,12 @@ package org.keycloak.models.utils;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.RealmModel;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -34,7 +38,9 @@ public class DefaultAuthenticationFlows {
registrationFormFlow.setProviderId("form-flow");
registrationFormFlow = realm.addAuthenticationFlow(registrationFormFlow);
- AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
+ AuthenticationExecutionModel execution;
+
+ execution = new AuthenticationExecutionModel();
execution.setParentFlow(registrationFlow.getId());
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
execution.setAuthenticator("registration-page-form");
@@ -47,7 +53,7 @@ public class DefaultAuthenticationFlows {
execution = new AuthenticationExecutionModel();
execution.setParentFlow(registrationFormFlow.getId());
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
- execution.setAuthenticator("username-validation-action");
+ execution.setAuthenticator("registration-user-creation");
execution.setPriority(20);
execution.setUserSetupAllowed(false);
execution.setAutheticatorFlow(false);
@@ -56,8 +62,8 @@ public class DefaultAuthenticationFlows {
execution = new AuthenticationExecutionModel();
execution.setParentFlow(registrationFormFlow.getId());
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
- execution.setAuthenticator("profile-validation-action");
- execution.setPriority(30);
+ execution.setAuthenticator("registration-profile-action");
+ execution.setPriority(40);
execution.setUserSetupAllowed(false);
execution.setAutheticatorFlow(false);
realm.addAuthenticatorExecution(execution);
@@ -65,22 +71,31 @@ public class DefaultAuthenticationFlows {
execution = new AuthenticationExecutionModel();
execution.setParentFlow(registrationFormFlow.getId());
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
- execution.setAuthenticator("password-validation-action");
- execution.setPriority(40);
+ execution.setAuthenticator("registration-password-action");
+ execution.setPriority(50);
execution.setUserSetupAllowed(false);
execution.setAutheticatorFlow(false);
realm.addAuthenticatorExecution(execution);
+ //AuthenticatorConfigModel captchaConfig = new AuthenticatorConfigModel();
+ //captchaConfig.setAlias("Recaptcha Config");
+ //Map<String, String> config = new HashMap<>();
+ //config.put("site.key", "6LcFEAkTAAAAAOaY-5RJk3zIYw4AalNtqfac27Bn");
+ //config.put("secret", "6LcFEAkTAAAAAM0SErEs9NlfhYpOTRj_vOVJSAMI");
+ //captchaConfig.setConfig(config);
+ //captchaConfig = realm.addAuthenticatorConfig(captchaConfig);
execution = new AuthenticationExecutionModel();
execution.setParentFlow(registrationFormFlow.getId());
- execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED);
- execution.setAuthenticator("registration-user-creation");
- execution.setPriority(50);
+ execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED);
+ execution.setAuthenticator("registration-recaptcha-action");
+ execution.setPriority(60);
execution.setUserSetupAllowed(false);
execution.setAutheticatorFlow(false);
+ //execution.setAuthenticatorConfig(captchaConfig.getId());
realm.addAuthenticatorExecution(execution);
+
}
public static void browserFlow(RealmModel realm) {
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 7df3f6f..45f3c09 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
@@ -1308,6 +1308,7 @@ public class RealmAdapter implements RealmModel {
model.setParentFlow(entity.getParentFlow());
model.setFlowId(entity.getFlowId());
model.setAutheticatorFlow(entity.isAuthenticatorFlow());
+ model.setAuthenticatorConfig(entity.getAuthenticatorConfig());
return model;
}
@@ -1339,6 +1340,7 @@ public class RealmAdapter implements RealmModel {
entity.setUserSetupAllowed(model.isUserSetupAllowed());
entity.setAuthenticatorFlow(model.isAutheticatorFlow());
entity.setFlowId(model.getFlowId());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
AuthenticationFlowEntity flow = getFlowEntity(model.getId());
flow.getExecutions().add(entity);
model.setId(entity.getId());
@@ -1362,6 +1364,7 @@ public class RealmAdapter implements RealmModel {
entity.setRequirement(model.getRequirement());
entity.setFlowId(model.getFlowId());
entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
index b27659f..c5e9019 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java
@@ -39,6 +39,9 @@ public class AuthenticationExecutionEntity {
@Column(name="AUTHENTICATOR")
protected String authenticator;
+ @Column(name="AUTH_CONFIG")
+ protected String authenticatorConfig;
+
@Column(name="AUTH_FLOW_ID")
protected String flowId;
@@ -125,4 +128,12 @@ public class AuthenticationExecutionEntity {
public void setFlowId(String flowId) {
this.flowId = flowId;
}
+
+ public String getAuthenticatorConfig() {
+ return authenticatorConfig;
+ }
+
+ public void setAuthenticatorConfig(String authenticatorConfig) {
+ this.authenticatorConfig = authenticatorConfig;
+ }
}
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 eec43ba..5ccf6c1 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
@@ -1613,6 +1613,7 @@ public class RealmAdapter implements RealmModel {
model.setFlowId(entity.getFlowId());
model.setParentFlow(entity.getParentFlow().getId());
model.setAutheticatorFlow(entity.isAutheticatorFlow());
+ model.setAuthenticatorConfig(entity.getAuthenticatorConfig());
return model;
}
@@ -1631,6 +1632,7 @@ public class RealmAdapter implements RealmModel {
entity.setPriority(model.getPriority());
entity.setFlowId(model.getFlowId());
entity.setRequirement(model.getRequirement());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
AuthenticationFlowEntity flow = em.find(AuthenticationFlowEntity.class, model.getParentFlow());
entity.setParentFlow(flow);
flow.getExecutions().add(entity);
@@ -1653,6 +1655,7 @@ public class RealmAdapter implements RealmModel {
entity.setPriority(model.getPriority());
entity.setRequirement(model.getRequirement());
entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
entity.setFlowId(model.getFlowId());
em.flush();
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 935746e..cb5cab9 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
@@ -1383,6 +1383,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
model.setFlowId(entity.getFlowId());
model.setParentFlow(entity.getParentFlow());
model.setAutheticatorFlow(entity.isAuthenticatorFlow());
+ model.setAuthenticatorConfig(entity.getAuthenticatorConfig());
return model;
}
@@ -1415,6 +1416,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setAuthenticatorFlow(model.isAutheticatorFlow());
entity.setFlowId(model.getFlowId());
entity.setParentFlow(model.getParentFlow());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
flow.getExecutions().add(entity);
updateMongoEntity();
@@ -1439,6 +1441,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setRequirement(model.getRequirement());
entity.setFlowId(model.getFlowId());
entity.setUserSetupAllowed(model.isUserSetupAllowed());
+ entity.setAuthenticatorConfig(model.getAuthenticatorConfig());
updateMongoEntity();
}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
index af9f436..66b7592 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientSessionAdapter.java
@@ -227,7 +227,8 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setAuthenticatedUser(UserModel user) {
- entity.setAuthUserId(user.getId());
+ if (user == null) entity.setAuthUserId(null);
+ else entity.setAuthUserId(user.getId());
update();
}
diff --git a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
index 4c340c5..e76811e 100755
--- a/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
+++ b/model/sessions-jpa/src/main/java/org/keycloak/models/sessions/jpa/ClientSessionAdapter.java
@@ -306,6 +306,7 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setAuthenticatedUser(UserModel user) {
- entity.setUserId(user.getId());
+ if (user == null) entity.setUserId(null);
+ else entity.setUserId(user.getId());
}
}
diff --git a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
index 7fcd35f..458278a 100755
--- a/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
+++ b/model/sessions-mem/src/main/java/org/keycloak/models/sessions/mem/ClientSessionAdapter.java
@@ -193,7 +193,8 @@ public class ClientSessionAdapter implements ClientSessionModel {
@Override
public void setAuthenticatedUser(UserModel user) {
- entity.setAuthUserId(user.getId());
+ if (user == null) entity.setAuthUserId(null);
+ else entity.setAuthUserId(user.getId());
}
}
diff --git a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
index 2120044..55013ed 100755
--- a/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
+++ b/model/sessions-mongo/src/main/java/org/keycloak/models/sessions/mongo/ClientSessionAdapter.java
@@ -210,7 +210,8 @@ public class ClientSessionAdapter extends AbstractMongoAdapter<MongoClientSessio
@Override
public void setAuthenticatedUser(UserModel user) {
- entity.setAuthUserId(user.getId());
+ if (user == null) entity.setAuthUserId(null);
+ else entity.setAuthUserId(user.getId());
updateMongoEntity();
}
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 472f62f..8474239 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -45,7 +45,6 @@ public class AuthenticationProcessor {
protected EventBuilder event;
protected HttpRequest request;
protected String flowId;
- protected String action;
/**
* This could be an error message forwarded from brokering when the broker failed authentication
* and we want to continue authentication locally. forwardedErrorMessage can then be displayed by
@@ -151,16 +150,39 @@ public class AuthenticationProcessor {
return this;
}
- public AuthenticationProcessor setAction(String action) {
- this.action = action;
- return this;
- }
-
public AuthenticationProcessor setForwardedErrorMessage(String forwardedErrorMessage) {
this.forwardedErrorMessage = forwardedErrorMessage;
return this;
}
+ public String generateCode() {
+ ClientSessionCode accessCode = new ClientSessionCode(getRealm(), getClientSession());
+ clientSession.setTimestamp(Time.currentTime());
+ return accessCode.getCode();
+ }
+
+ public EventBuilder newEvent() {
+ this.event = new EventBuilder(realm, session, connection);
+ return this.event;
+ }
+
+ public EventBuilder getEvent() {
+ return event;
+ }
+
+ public HttpRequest getRequest() {
+ return request;
+ }
+
+ public void setAutheticatedUser(UserModel user) {
+ UserModel previousUser = clientSession.getAuthenticatedUser();
+ if (previousUser != null && !user.getId().equals(previousUser.getId()))
+ throw new AuthException(Error.USER_CONFLICT);
+ validateUser(user);
+ getClientSession().setAuthenticatedUser(user);
+ }
+
+
private class Result implements AuthenticatorContext {
AuthenticatorConfigModel authenticatorConfig;
AuthenticationExecutionModel execution;
@@ -178,8 +200,7 @@ public class AuthenticationProcessor {
@Override
public EventBuilder newEvent() {
- AuthenticationProcessor.this.event = new EventBuilder(realm, session, connection);
- return AuthenticationProcessor.this.event;
+ return AuthenticationProcessor.this.newEvent();
}
@Override
@@ -214,11 +235,6 @@ public class AuthenticationProcessor {
}
@Override
- public String getAction() {
- return AuthenticationProcessor.this.action;
- }
-
- @Override
public Authenticator getAuthenticator() {
return authenticator;
}
@@ -288,11 +304,7 @@ public class AuthenticationProcessor {
@Override
public void setUser(UserModel user) {
- UserModel previousUser = getUser();
- if (previousUser != null && !user.getId().equals(previousUser.getId()))
- throw new AuthException(Error.USER_CONFLICT);
- validateUser(user);
- getClientSession().setAuthenticatedUser(user);
+ setAutheticatedUser(user);
}
@Override
@@ -347,11 +359,10 @@ public class AuthenticationProcessor {
@Override
public String generateAccessCode() {
- ClientSessionCode accessCode = new ClientSessionCode(getRealm(), getClientSession());
- clientSession.setTimestamp(Time.currentTime());
- return accessCode.getCode();
+ return generateCode();
}
+
@Override
public Response getChallenge() {
return challenge;
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
index 80654c7..6da5e54 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
@@ -27,17 +27,7 @@ public interface AuthenticatorContext {
void setExecution(AuthenticationExecutionModel execution);
- AuthenticatorConfigModel getAuthenticatorConfig();
-
- String getAction();
-
- Authenticator getAuthenticator();
-
- void setAuthenticator(Authenticator authenticator);
-
- AuthenticationProcessor.Status getStatus();
-
- UserModel getUser();
+ UserModel getUser();
void setUser(UserModel user);
@@ -55,17 +45,6 @@ public interface AuthenticatorContext {
HttpRequest getHttpRequest();
BruteForceProtector getProtector();
- AuthenticationExecutionModel.Requirement getCategoryRequirementFromCurrentFlow(String authenticatorCategory);
-
- void success();
- void failure(AuthenticationProcessor.Error error);
- void failure(AuthenticationProcessor.Error error, Response response);
- void challenge(Response challenge);
-
- void forceChallenge(Response challenge);
-
- void failureChallenge(AuthenticationProcessor.Error error, Response challenge);
- void attempted();
/**
* This could be an error message forwarded from brokering when the broker failed authentication
@@ -81,6 +60,27 @@ public interface AuthenticatorContext {
*/
String generateAccessCode();
+ AuthenticatorConfigModel getAuthenticatorConfig();
+
+ Authenticator getAuthenticator();
+
+ void setAuthenticator(Authenticator authenticator);
+
+ AuthenticationProcessor.Status getStatus();
+
+ AuthenticationExecutionModel.Requirement getCategoryRequirementFromCurrentFlow(String authenticatorCategory);
+
+ void success();
+ void failure(AuthenticationProcessor.Error error);
+ void failure(AuthenticationProcessor.Error error, Response response);
+ void challenge(Response challenge);
+
+ void forceChallenge(Response challenge);
+
+ void failureChallenge(AuthenticationProcessor.Error error, Response challenge);
+ void attempted();
+
+
Response getChallenge();
AuthenticationProcessor.Error getError();
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java
index 302fcf8..19f0f3e 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordForm.java
@@ -48,10 +48,6 @@ public class UsernamePasswordForm extends AbstractFormAuthenticator implements A
@Override
public void authenticate(AuthenticatorContext context) {
- if (REGISTRATION_FORM_ACTION.equals(context.getAction()) && context.getUser() != null) {
- context.success();
- return;
- }
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
String loginHint = context.getClientSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
diff --git a/services/src/main/java/org/keycloak/authentication/FormAction.java b/services/src/main/java/org/keycloak/authentication/FormAction.java
index b231829..a02b2fe 100755
--- a/services/src/main/java/org/keycloak/authentication/FormAction.java
+++ b/services/src/main/java/org/keycloak/authentication/FormAction.java
@@ -1,5 +1,6 @@
package org.keycloak.authentication;
+import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@@ -10,7 +11,8 @@ import org.keycloak.provider.Provider;
* @version $Revision: 1 $
*/
public interface FormAction extends Provider {
- void authenticate(FormActionContext context);
+ void validate(ValidationContext context);
+ void success(FormContext context);
boolean requiresUser();
boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user);
@@ -21,4 +23,6 @@ public interface FormAction extends Provider {
*/
void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user);
+ void buildPage(FormContext context, LoginFormsProvider form);
+
}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
index ab40717..8cd6751 100755
--- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
@@ -2,7 +2,9 @@ package org.keycloak.authentication;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
+import org.keycloak.OAuth2Constants;
import org.keycloak.events.EventBuilder;
+import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.ClientSessionModel;
@@ -10,10 +12,14 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.resources.LoginActionsService;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
+import java.net.URI;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -37,183 +43,99 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
formAuthenticator = processor.getSession().getProvider(FormAuthenticator.class, execution.getAuthenticator());
}
- private class FormContext implements FormActionContext {
- protected AuthenticatorContext delegate;
+ private class FormContextImpl implements FormContext {
+ AuthenticationExecutionModel executionModel;
+ AuthenticatorConfigModel authenticatorConfig;
- private FormContext(AuthenticatorContext delegate) {
- this.delegate = delegate;
+ private FormContextImpl(AuthenticationExecutionModel executionModel) {
+ this.executionModel = executionModel;
}
@Override
public EventBuilder newEvent() {
- return delegate.newEvent();
+ return processor.newEvent();
}
- @Override
- public FormAuthenticator getFormAuthenticator() {
- return formAuthenticator;
- }
-
- @Override
- public AuthenticationExecutionModel getFormExecution() {
- return formExecution;
- }
-
- @Override
+ @Override
public EventBuilder getEvent() {
- return delegate.getEvent();
+ return processor.getEvent();
}
@Override
public AuthenticationExecutionModel getExecution() {
- return delegate.getExecution();
- }
-
- @Override
- public void setExecution(AuthenticationExecutionModel execution) {
- delegate.setExecution(execution);
+ return executionModel;
}
@Override
public AuthenticatorConfigModel getAuthenticatorConfig() {
- return delegate.getAuthenticatorConfig();
- }
-
- @Override
- public String getAction() {
- return delegate.getAction();
- }
-
- @Override
- public Authenticator getAuthenticator() {
- return delegate.getAuthenticator();
- }
-
- @Override
- public void setAuthenticator(Authenticator authenticator) {
- delegate.setAuthenticator(authenticator);
- }
-
- @Override
- public AuthenticationProcessor.Status getStatus() {
- return delegate.getStatus();
+ if (executionModel.getAuthenticatorConfig() == null) return null;
+ if (authenticatorConfig != null) return authenticatorConfig;
+ authenticatorConfig = getRealm().getAuthenticatorConfigById(executionModel.getAuthenticatorConfig());
+ return authenticatorConfig;
}
@Override
public UserModel getUser() {
- return delegate.getUser();
+ return getClientSession().getAuthenticatedUser();
}
@Override
public void setUser(UserModel user) {
- delegate.setUser(user);
+ processor.setAutheticatedUser(user);
}
@Override
public RealmModel getRealm() {
- return delegate.getRealm();
+ return processor.getRealm();
}
@Override
public ClientSessionModel getClientSession() {
- return delegate.getClientSession();
- }
-
- @Override
- public void attachUserSession(UserSessionModel userSession) {
- delegate.attachUserSession(userSession);
+ return processor.getClientSession();
}
@Override
public ClientConnection getConnection() {
- return delegate.getConnection();
+ return processor.getConnection();
}
@Override
public UriInfo getUriInfo() {
- return delegate.getUriInfo();
+ return processor.getUriInfo();
}
@Override
public KeycloakSession getSession() {
- return delegate.getSession();
+ return processor.getSession();
}
@Override
public HttpRequest getHttpRequest() {
- return delegate.getHttpRequest();
- }
-
- @Override
- public BruteForceProtector getProtector() {
- return delegate.getProtector();
- }
-
- @Override
- public AuthenticationExecutionModel.Requirement getCategoryRequirementFromCurrentFlow(String authenticatorCategory) {
- for (AuthenticationExecutionModel formActionExecution : formActionExecutions) {
- FormActionFactory factory = (FormActionFactory) getSession().getKeycloakSessionFactory().getProviderFactory(FormAction.class, formActionExecution.getAuthenticator());
- if (factory != null && authenticatorCategory.equals(factory.getReferenceCategory())) {
- return formActionExecution.getRequirement();
- }
-
- }
- return null;
- }
-
- @Override
- public void success() {
- delegate.success();
- }
-
- @Override
- public void failure(AuthenticationProcessor.Error error) {
- delegate.failure(error);
+ return processor.getRequest();
}
- @Override
- public void failure(AuthenticationProcessor.Error error, Response response) {
- delegate.failure(error, response);
- }
-
- @Override
- public void challenge(Response challenge) {
- delegate.challenge(challenge);
- }
-
- @Override
- public void forceChallenge(Response challenge) {
- delegate.forceChallenge(challenge);
- }
-
- @Override
- public void failureChallenge(AuthenticationProcessor.Error error, Response challenge) {
- delegate.failureChallenge(error, challenge);
- }
-
- @Override
- public void attempted() {
- delegate.attempted();
- }
+ }
- @Override
- public String getForwardedErrorMessage() {
- return delegate.getForwardedErrorMessage();
- }
+ private class ValidationContextImpl extends FormContextImpl implements ValidationContext {
+ FormAction action;
- @Override
- public String generateAccessCode() {
- return delegate.generateAccessCode();
+ private ValidationContextImpl(AuthenticationExecutionModel executionModel, FormAction action) {
+ super(executionModel);
+ this.action = action;
}
+ boolean success;
+ List<FormMessage> errors = null;
+ MultivaluedMap<String, String> formData = null;
@Override
- public Response getChallenge() {
- return delegate.getChallenge();
+ public void validationError(MultivaluedMap<String, String> formData, List<FormMessage> errors) {
+ this.errors = errors;
+ this.formData = formData;
}
@Override
- public AuthenticationProcessor.Error getError() {
- return delegate.getError();
+ public void success() {
+ success = true;
}
}
@@ -224,7 +146,12 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
}
Map<String, ClientSessionModel.ExecutionStatus> executionStatus = new HashMap<>();
List<FormAction> requiredActions = new LinkedList<>();
+ List<ValidationContextImpl> successes = new LinkedList<>();
for (AuthenticationExecutionModel formActionExecution : formActionExecutions) {
+ if (!formActionExecution.isEnabled()) {
+ executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ continue;
+ }
FormAction action = processor.getSession().getProvider(FormAction.class, formActionExecution.getAuthenticator());
UserModel authUser = processor.getClientSession().getAuthenticatedUser();
@@ -251,12 +178,20 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
}
}
- AuthenticatorContext delegate = processor.createAuthenticatorContext(formActionExecution, null, formActionExecutions);
- FormActionContext result = new FormContext(delegate);
- action.authenticate(result);
- Response challenge = processResult(executionStatus, result, formActionExecution);
- if (challenge != null) return challenge;
- executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+ ValidationContextImpl result = new ValidationContextImpl(formActionExecution, action);
+ action.validate(result);
+ if (result.success) {
+ executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+ successes.add(result);
+ } else {
+ processor.logFailure();
+ executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ return renderForm(result.formData, result.errors);
+ }
+ }
+
+ for (ValidationContextImpl context : successes) {
+ context.action.success(context);
}
// set status and required actions only if form is fully successful
for (Map.Entry<String, ClientSessionModel.ExecutionStatus> entry : executionStatus.entrySet()) {
@@ -270,63 +205,36 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
}
- @Override
- public Response processFlow() {
- AuthenticatorContext delegate = processor.createAuthenticatorContext(formExecution, null, formActionExecutions);
- FormActionContext result = new FormContext(delegate);
- formAuthenticator.authenticate(result);
- Map<String, ClientSessionModel.ExecutionStatus> executionStatus = new HashMap<>();
- Response response = processResult(executionStatus, result, formExecution);
- for (Map.Entry<String, ClientSessionModel.ExecutionStatus> entry : executionStatus.entrySet()) {
- processor.getClientSession().setExecutionStatus(entry.getKey(), entry.getValue());
- }
- return response;
+ public URI getActionUrl(String executionId, String code) {
+ return LoginActionsService.registrationFormProcessor(processor.getUriInfo())
+ .queryParam(OAuth2Constants.CODE, code)
+ .queryParam("execution", executionId)
+ .build(processor.getRealm().getName());
}
- public Response processResult(Map<String, ClientSessionModel.ExecutionStatus> executionStatus, AuthenticatorContext result, AuthenticationExecutionModel execution) {
- AuthenticationProcessor.Status status = result.getStatus();
- if (status == AuthenticationProcessor.Status.SUCCESS) {
- executionStatus.put(execution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
- return null;
- } else if (status == AuthenticationProcessor.Status.FAILED) {
- AuthenticationProcessor.logger.debugv("authenticator FAILED: {0}", execution.getAuthenticator());
- processor.logFailure();
- executionStatus.put(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
- if (result.getChallenge() != null) {
- return sendChallenge(result);
- }
- throw new AuthenticationProcessor.AuthException(result.getError());
- } else if (status == AuthenticationProcessor.Status.FORCE_CHALLENGE) {
- executionStatus.put(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
- return sendChallenge(result);
- } else if (status == AuthenticationProcessor.Status.CHALLENGE) {
- processor.getClientSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
- return sendChallenge(result);
- } else if (status == AuthenticationProcessor.Status.FAILURE_CHALLENGE) {
- AuthenticationProcessor.logger.debugv("authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator());
- processor.logFailure();
- executionStatus.put(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
- return sendChallenge(result);
- } else if (status == AuthenticationProcessor.Status.ATTEMPTED) {
- AuthenticationProcessor.logger.debugv("authenticator ATTEMPTED: {0}", execution.getAuthenticator());
- if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
- throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INVALID_CREDENTIALS);
- }
- executionStatus.put(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
- return null;
- } else {
- AuthenticationProcessor.logger.debugv("authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator());
- AuthenticationProcessor.logger.error("Unknown result status");
- throw new AuthenticationProcessor.AuthException(AuthenticationProcessor.Error.INTERNAL_ERROR);
- }
-
+ @Override
+ public Response processFlow() {
+ return renderForm(null, null);
}
- public Response sendChallenge(AuthenticatorContext result) {
- processor.getClientSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, formExecution.getId());
- return result.getChallenge();
+ public Response renderForm(MultivaluedMap<String, String> formData, List<FormMessage> errors) {
+ String executionId = formExecution.getId();
+ processor.getClientSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, executionId);
+ String code = processor.generateCode();
+ URI actionUrl = getActionUrl(executionId, code);
+ LoginFormsProvider form = processor.getSession().getProvider(LoginFormsProvider.class)
+ .setActionUri(actionUrl)
+ .setClientSessionCode(code)
+ .setFormData(formData)
+ .setErrors(errors);
+ for (AuthenticationExecutionModel formActionExecution : formActionExecutions) {
+ if (!formActionExecution.isEnabled()) continue;
+ FormAction action = processor.getSession().getProvider(FormAction.class, formActionExecution.getAuthenticator());
+ FormContext result = new FormContextImpl(formActionExecution);
+ action.buildPage(result, form);
+ }
+ FormContext context = new FormContextImpl(formExecution);
+ return formAuthenticator.render(context, form);
}
-
-
}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
index f33843e..02efebe 100755
--- a/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticator.java
@@ -1,5 +1,6 @@
package org.keycloak.authentication;
+import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.Provider;
@@ -12,6 +13,5 @@ import java.util.List;
* @version $Revision: 1 $
*/
public interface FormAuthenticator extends Provider {
- void authenticate(AuthenticatorContext context);
- Response createChallenge(FormActionContext context, MultivaluedMap<String, String> formData, List<FormMessage> errorMessages);
+ Response render(FormContext context, LoginFormsProvider form);
}
diff --git a/services/src/main/java/org/keycloak/authentication/FormContext.java b/services/src/main/java/org/keycloak/authentication/FormContext.java
new file mode 100755
index 0000000..f135945
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/FormContext.java
@@ -0,0 +1,33 @@
+package org.keycloak.authentication;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.ClientConnection;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticatorConfigModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import javax.ws.rs.core.UriInfo;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public interface FormContext {
+ EventBuilder getEvent();
+ EventBuilder newEvent();
+ AuthenticationExecutionModel getExecution();
+ UserModel getUser();
+ void setUser(UserModel user);
+ RealmModel getRealm();
+ ClientSessionModel getClientSession();
+ ClientConnection getConnection();
+ UriInfo getUriInfo();
+ KeycloakSession getSession();
+ HttpRequest getHttpRequest();
+ AuthenticatorConfigModel getAuthenticatorConfig();
+
+}
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java
index 0fa38c5..c527ea4 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java
@@ -1,23 +1,15 @@
package org.keycloak.authentication.forms;
import org.keycloak.Config;
-import org.keycloak.OAuth2Constants;
-import org.keycloak.authentication.AuthenticatorContext;
-import org.keycloak.authentication.FormActionContext;
import org.keycloak.authentication.FormAuthenticator;
import org.keycloak.authentication.FormAuthenticatorFactory;
+import org.keycloak.authentication.FormContext;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.utils.FormMessage;
-import org.keycloak.services.resources.LoginActionsService;
-import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
-import java.net.URI;
-import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -35,38 +27,8 @@ public class RegistrationPage implements FormAuthenticator, FormAuthenticatorFac
public static final String PROVIDER_ID = "registration-page-form";
@Override
- public void authenticate(AuthenticatorContext context) {
- LoginFormsProvider registrationPage = createForm(context, context.getExecution().getId());
- context.challenge(registrationPage.createRegistration());
-
- }
- public URI getActionUrl(AuthenticatorContext context, String executionId, String code) {
- return LoginActionsService.registrationFormProcessor(context.getUriInfo())
- .queryParam(OAuth2Constants.CODE, code)
- .queryParam(EXECUTION, executionId)
- .build(context.getRealm().getName());
- }
-
-
- @Override
- public Response createChallenge(FormActionContext context, MultivaluedMap<String, String> formData, List<FormMessage> errorMessages) {
- LoginFormsProvider registrationPage = createForm(context, context.getFormExecution().getId());
- if (formData != null) registrationPage.setFormData(formData);
- if (errorMessages != null) {
- registrationPage.setErrors(errorMessages);
- }
- return registrationPage.createRegistration();
- }
-
- public LoginFormsProvider createForm(AuthenticatorContext context, String executionId) {
- AuthenticationExecutionModel.Requirement categoryRequirement = context.getCategoryRequirementFromCurrentFlow(UserCredentialModel.PASSWORD);
- boolean passwordRequired = categoryRequirement != null && categoryRequirement != AuthenticationExecutionModel.Requirement.DISABLED;
- String code = context.generateAccessCode();
- URI actionUrl = getActionUrl(context, executionId, code);
- return context.getSession().getProvider(LoginFormsProvider.class)
- .setAttribute("passwordRequired", passwordRequired)
- .setActionUri(actionUrl)
- .setClientSessionCode(code);
+ public Response render(FormContext context, LoginFormsProvider form) {
+ return form.createRegistration();
}
@Override
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
index e218c54..c8716f7 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
@@ -1,27 +1,28 @@
package org.keycloak.authentication.forms;
import org.keycloak.Config;
-import org.keycloak.authentication.AuthenticatorContext;
import org.keycloak.authentication.FormAction;
-import org.keycloak.authentication.FormActionContext;
import org.keycloak.authentication.FormActionFactory;
-import org.keycloak.authentication.FormAuthenticator;
+import org.keycloak.authentication.FormContext;
+import org.keycloak.authentication.ValidationContext;
import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.FormMessage;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.AttributeFormDataProcessor;
import org.keycloak.services.validation.Validation;
import javax.ws.rs.core.MultivaluedMap;
+import java.util.ArrayList;
+import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -32,7 +33,67 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
public static final String PROVIDER_ID = "registration-user-creation";
@Override
- public void authenticate(FormActionContext context) {
+ public void validate(ValidationContext context) {
+ MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
+ List<FormMessage> errors = new ArrayList<>();
+ context.getEvent().detail(Details.REGISTER_METHOD, "form");
+
+ String email = formData.getFirst(Validation.FIELD_EMAIL);
+ String username = formData.getFirst(RegistrationPage.FIELD_USERNAME);
+ context.getEvent().detail(Details.USERNAME, username);
+ context.getEvent().detail(Details.EMAIL, email);
+
+ String usernameField = RegistrationPage.FIELD_USERNAME;
+ if (context.getRealm().isRegistrationEmailAsUsername()) {
+ username = email;
+ context.getEvent().detail(Details.USERNAME, username);
+ usernameField = RegistrationPage.FIELD_EMAIL;
+ if (Validation.isBlank(email)) {
+ errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.MISSING_EMAIL));
+ } else if (!Validation.isEmailValid(email)) {
+ errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.INVALID_EMAIL));
+ formData.remove(Validation.FIELD_EMAIL);
+ }
+ if (errors.size() > 0) {
+ context.getEvent().error(Errors.INVALID_REGISTRATION);
+ context.validationError(formData, errors);
+ return;
+ }
+ if (email != null && context.getSession().users().getUserByEmail(email, context.getRealm()) != null) {
+ context.getEvent().error(Errors.USERNAME_IN_USE);
+ formData.remove(Validation.FIELD_EMAIL);
+ errors.add(new FormMessage(RegistrationPage.FIELD_EMAIL, Messages.USERNAME_EXISTS));
+ context.validationError(formData, errors);
+ return;
+ }
+ } else {
+ if (Validation.isBlank(username)) {
+ context.getEvent().error(Errors.INVALID_REGISTRATION);
+ errors.add(new FormMessage(RegistrationPage.FIELD_USERNAME, Messages.MISSING_USERNAME));
+ context.validationError(formData, errors);
+ return;
+ }
+
+ }
+ if (context.getSession().users().getUserByUsername(username, context.getRealm()) != null) {
+ context.getEvent().error(Errors.USERNAME_IN_USE);
+ errors.add(new FormMessage(usernameField, Messages.USERNAME_EXISTS));
+ formData.remove(Validation.FIELD_USERNAME);
+ formData.remove(Validation.FIELD_EMAIL);
+ context.validationError(formData, errors);
+ return;
+
+ }
+ context.success();
+ }
+
+ @Override
+ public void buildPage(FormContext context, LoginFormsProvider form) {
+
+ }
+
+ @Override
+ public void success(FormContext context) {
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
String email = formData.getFirst(Validation.FIELD_EMAIL);
String username = formData.getFirst(RegistrationPage.FIELD_USERNAME);
@@ -45,29 +106,12 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
;
UserModel user = context.getSession().users().addUser(context.getRealm(), username);
user.setEnabled(true);
- user.setFirstName(formData.getFirst("firstName"));
- user.setLastName(formData.getFirst("lastName"));
user.setEmail(email);
context.getClientSession().setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
AttributeFormDataProcessor.process(formData, context.getRealm(), user);
context.setUser(user);
- AuthenticationExecutionModel.Requirement categoryRequirement = context.getCategoryRequirementFromCurrentFlow(UserCredentialModel.PASSWORD);
- boolean passwordRequired = categoryRequirement != null && categoryRequirement != AuthenticationExecutionModel.Requirement.DISABLED;
- if (passwordRequired) {
- String password = formData.getFirst(RegistrationPage.FIELD_PASSWORD);
- UserCredentialModel credentials = new UserCredentialModel();
- credentials.setType(CredentialRepresentation.PASSWORD);
- credentials.setValue(password);
-
- try {
- context.getSession().users().updateCredential(context.getRealm(), user, UserCredentialModel.password(formData.getFirst("password")));
- } catch (Exception me) {
- user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
- }
- }
context.getEvent().user(user);
- context.success();
context.getEvent().success();
context.newEvent().event(EventType.LOGIN);
context.getEvent().client(context.getClientSession().getClient().getClientId())
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index 9f9070a..e9b7fa0 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -57,6 +57,8 @@ public class Messages {
public static final String INVALID_TOTP = "invalidTotpMessage";
public static final String USERNAME_EXISTS = "usernameExistsMessage";
+ public static final String RECAPTCHA_FAILED = "recaptchaFailed";
+ public static final String RECAPTCHA_NOT_CONFIGURED = "recaptchaNotConfigured";
public static final String EMAIL_EXISTS = "emailExistsMessage";
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.FormActionFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.FormActionFactory
index 47a023c..b0240f3 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.FormActionFactory
+++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.FormActionFactory
@@ -1,4 +1,4 @@
-org.keycloak.authentication.forms.RegistrationPasswordValidation
-org.keycloak.authentication.forms.RegistrationProfileValidation
+org.keycloak.authentication.forms.RegistrationPassword
+org.keycloak.authentication.forms.RegistrationProfile
org.keycloak.authentication.forms.RegistrationUserCreation
-org.keycloak.authentication.forms.RegistrationUsernameValidation
\ No newline at end of file
+org.keycloak.authentication.forms.RegistrationRecaptcha
\ No newline at end of file