keycloak-aplcache

form action refactor

7/1/2015 3:07:02 PM

Changes

Details

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..f5d2110 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,7 @@ 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=Recaptcha Failed
 
 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..a892722 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,7 @@ codeSuccessTitle=Success code
 codeErrorTitle=Error code\: {0}
 termsTitle=Terms and Conditions
 termsTitleHtml=Terms and Conditions
+recaptchaFailed=Recaptcha Failed
 
 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..43d6ab4 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,7 @@ 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=Recaptcha Failed
 
 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..495480f 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,7 @@ 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=Recaptcha Failed
 
 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/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java
index 3f2a103..3909efb 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
@@ -34,7 +34,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 +49,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 +58,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 +67,23 @@ 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);
 
         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);
         realm.addAuthenticatorExecution(execution);
 
 
+
     }
 
     public static void browserFlow(RealmModel realm) {
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..8df839c 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,7 @@ 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 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