keycloak-uncached

verify clientsession actions

6/15/2015 7:04:55 PM

Changes

services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java 186(+0 -186)

Details

diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index a557b5a..bc1e1bd 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -1,7 +1,6 @@
 package org.keycloak.protocol.saml;
 
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.HttpResponse;
 import org.keycloak.ClientConnection;
@@ -17,7 +16,6 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.login.LoginFormsProvider;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
@@ -30,14 +28,11 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.saml.common.constants.GeneralConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
-import org.keycloak.saml.common.exceptions.ConfigurationException;
-import org.keycloak.saml.common.exceptions.ProcessingException;
 import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
 import org.keycloak.services.ErrorPage;
 import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.services.managers.HttpAuthenticationManager;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.RealmsResource;
 import org.keycloak.util.StreamUtil;
@@ -52,13 +47,10 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
-import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.Providers;
-import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.security.PublicKey;
@@ -291,36 +283,6 @@ public class SamlService {
             return newBrowserAuthentication(clientSession);
         }
 
-        private Response oldBrowserAuthentication(ClientSessionModel clientSession) {
-            Response response = authManager.checkNonFormAuthentication(session, clientSession, realm, uriInfo, request, clientConnection, headers, event);
-            if (response != null) return response;
-
-            // SPNEGO/Kerberos authentication TODO: This should be somehow pluggable instead of hardcoded this way (Authentication interceptors?)
-            HttpAuthenticationManager httpAuthManager = new HttpAuthenticationManager(session, clientSession, realm, uriInfo, request, clientConnection, event);
-            HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate(headers);
-            if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse();
-
-            LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class)
-                    .setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode());
-
-            // Attach state from SPNEGO authentication
-            if (httpAuthOutput.getChallenge() != null) {
-                httpAuthOutput.getChallenge().sendChallenge(forms);
-            }
-
-            String rememberMeUsername = AuthenticationManager.getRememberMeUsername(realm, headers);
-
-            if (rememberMeUsername != null) {
-                MultivaluedMap<String, String> formData = new MultivaluedMapImpl<String, String>();
-                formData.add(AuthenticationManager.FORM_USERNAME, rememberMeUsername);
-                formData.add("rememberMe", "on");
-
-                forms.setFormData(formData);
-            }
-
-            return forms.createLogin();
-        }
-
         private Response buildRedirectToIdentityProvider(String providerId, String accessCode) {
             logger.debug("Automatically redirect to identity provider: " + providerId);
             return Response.temporaryRedirect(
diff --git a/services/src/main/java/org/keycloak/authentication/actions/TermsAndConditions.java b/services/src/main/java/org/keycloak/authentication/actions/TermsAndConditions.java
index 3c0769e..5c6157c 100755
--- a/services/src/main/java/org/keycloak/authentication/actions/TermsAndConditions.java
+++ b/services/src/main/java/org/keycloak/authentication/actions/TermsAndConditions.java
@@ -1,37 +1,25 @@
 package org.keycloak.authentication.actions;
 
 import org.keycloak.Config;
-import org.keycloak.Version;
 import org.keycloak.authentication.RequiredActionContext;
 import org.keycloak.authentication.RequiredActionFactory;
 import org.keycloak.authentication.RequiredActionProvider;
 import org.keycloak.events.Errors;
-import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
 import org.keycloak.freemarker.FreeMarkerException;
-import org.keycloak.freemarker.FreeMarkerUtil;
-import org.keycloak.freemarker.Theme;
-import org.keycloak.freemarker.ThemeProvider;
 import org.keycloak.login.LoginFormsProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.protocol.LoginProtocol;
-import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.ClientSessionCode;
 
 import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
 import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashMap;
-import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -86,6 +74,14 @@ public class TermsAndConditions implements RequiredActionProvider, RequiredActio
         return PROVIDER_ID;
     }
 
+
+    @Override
+    public String getProviderId() {
+        return getId();
+    }
+
+
+
     @Override
     public void evaluateTriggers(RequiredActionContext context) {
 
@@ -94,7 +90,7 @@ public class TermsAndConditions implements RequiredActionProvider, RequiredActio
     @Override
     public Response invokeRequiredAction(RequiredActionContext context) {
         return context.getSession().getProvider(LoginFormsProvider.class)
-                .setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode())
+                .setClientSessionCode(context.generateAccessCode(getProviderId()))
                 .setUser(context.getUser())
                 .createForm("terms.ftl", new HashMap<String, Object>());
     }
diff --git a/services/src/main/java/org/keycloak/authentication/actions/UpdatePassword.java b/services/src/main/java/org/keycloak/authentication/actions/UpdatePassword.java
index 57ff72b..ae4a380 100755
--- a/services/src/main/java/org/keycloak/authentication/actions/UpdatePassword.java
+++ b/services/src/main/java/org/keycloak/authentication/actions/UpdatePassword.java
@@ -51,10 +51,9 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
 
     @Override
     public Response invokeRequiredAction(RequiredActionContext context) {
-        ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
-        accessCode.setAction(ClientSessionModel.Action.UPDATE_PASSWORD.name());
-
-        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode())
+        LoginFormsProvider loginFormsProvider = context.getSession()
+                .getProvider(LoginFormsProvider.class)
+                .setClientSessionCode(context.generateAccessCode(getProviderId()))
                 .setUser(context.getUser());
         return loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
     }
@@ -96,4 +95,10 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
     public String getId() {
         return UserModel.RequiredAction.UPDATE_PASSWORD.name();
     }
+
+    @Override
+    public String getProviderId() {
+        return getId();
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/authentication/actions/UpdateProfile.java b/services/src/main/java/org/keycloak/authentication/actions/UpdateProfile.java
index d9aaa73..7117ae3 100755
--- a/services/src/main/java/org/keycloak/authentication/actions/UpdateProfile.java
+++ b/services/src/main/java/org/keycloak/authentication/actions/UpdateProfile.java
@@ -32,10 +32,8 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
 
     @Override
     public Response invokeRequiredAction(RequiredActionContext context) {
-        ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
-        accessCode.setAction(ClientSessionModel.Action.UPDATE_PROFILE.name());
-
-        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode())
+        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class)
+                .setClientSessionCode(context.generateAccessCode(getProviderId()))
                 .setUser(context.getUser());
         return loginFormsProvider.createResponse(UserModel.RequiredAction.UPDATE_PROFILE);
     }
@@ -78,4 +76,10 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
     public String getId() {
         return UserModel.RequiredAction.UPDATE_PROFILE.name();
     }
+
+    @Override
+    public String getProviderId() {
+        return getId();
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/authentication/actions/UpdateTotp.java b/services/src/main/java/org/keycloak/authentication/actions/UpdateTotp.java
index e378942..6f79d51 100755
--- a/services/src/main/java/org/keycloak/authentication/actions/UpdateTotp.java
+++ b/services/src/main/java/org/keycloak/authentication/actions/UpdateTotp.java
@@ -40,10 +40,8 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
 
     @Override
     public Response invokeRequiredAction(RequiredActionContext context) {
-        ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
-        accessCode.setAction(ClientSessionModel.Action.CONFIGURE_TOTP.name());
-
-        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode())
+         LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class)
+                 .setClientSessionCode(context.generateAccessCode(getProviderId()))
                 .setUser(context.getUser());
         return loginFormsProvider.createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
     }
@@ -87,4 +85,10 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
         return UserModel.RequiredAction.CONFIGURE_TOTP.name();
     }
 
+    @Override
+    public String getProviderId() {
+        return getId();
+    }
+
+
 }
diff --git a/services/src/main/java/org/keycloak/authentication/actions/VerifyEmail.java b/services/src/main/java/org/keycloak/authentication/actions/VerifyEmail.java
index 9d337f9..fa284bd 100755
--- a/services/src/main/java/org/keycloak/authentication/actions/VerifyEmail.java
+++ b/services/src/main/java/org/keycloak/authentication/actions/VerifyEmail.java
@@ -59,12 +59,11 @@ public class VerifyEmail implements RequiredActionProvider, RequiredActionFactor
             return null;
         }
 
-        ClientSessionCode accessCode = new ClientSessionCode(context.getRealm(), context.getClientSession());
-        accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL.name());
         context.getEvent().clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, context.getUser().getEmail()).success();
         LoginActionsService.createActionCookie(context.getRealm(), context.getUriInfo(), context.getConnection(), context.getUserSession().getId());
 
-        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode())
+        LoginFormsProvider loginFormsProvider = context.getSession().getProvider(LoginFormsProvider.class)
+                .setClientSessionCode(context.generateAccessCode(getProviderId()))
                 .setUser(context.getUser());
         return loginFormsProvider.createResponse(UserModel.RequiredAction.VERIFY_EMAIL);
     }
@@ -107,4 +106,10 @@ public class VerifyEmail implements RequiredActionProvider, RequiredActionFactor
         return UserModel.RequiredAction.VERIFY_EMAIL.name();
     }
 
+    @Override
+    public String getProviderId() {
+        return getId();
+    }
+
+
 }
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 473bc4f..af6a671 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -43,6 +43,12 @@ public class AuthenticationProcessor {
     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
+     * whatever form is challenging.
+     */
+    protected String forwardedErrorMessage;
     protected boolean userSessionCreated;
 
 
@@ -56,6 +62,7 @@ public class AuthenticationProcessor {
 
     }
     public static enum Error {
+        INVALID_CLIENT_SESSION,
         INVALID_USER,
         INVALID_CREDENTIALS,
         CREDENTIAL_SETUP_REQUIRED,
@@ -144,6 +151,11 @@ public class AuthenticationProcessor {
         return this;
     }
 
+    public AuthenticationProcessor setForwardedErrorMessage(String forwardedErrorMessage) {
+        this.forwardedErrorMessage = forwardedErrorMessage;
+        return this;
+    }
+
     private class Result implements AuthenticatorContext {
         AuthenticatorModel model;
         AuthenticationExecutionModel execution;
@@ -300,6 +312,11 @@ public class AuthenticationProcessor {
         public EventBuilder getEvent() {
             return AuthenticationProcessor.this.event;
         }
+
+        @Override
+        public String getForwardedErrorMessage() {
+            return AuthenticationProcessor.this.forwardedErrorMessage;
+        }
     }
 
     public static class AuthException extends RuntimeException {
@@ -367,7 +384,11 @@ public class AuthenticationProcessor {
                 event.error(Errors.USER_TEMPORARILY_DISABLED);
                 return ErrorPage.error(session, Messages.ACCOUNT_TEMPORARILY_DISABLED);
 
-            } else {
+            } else if (e.getError() == Error.INVALID_CLIENT_SESSION) {
+                event.error(Errors.INVALID_CODE);
+                return ErrorPage.error(session, Messages.INVALID_CODE);
+
+            }else {
                 event.error(Errors.INVALID_USER_CREDENTIALS);
                 return ErrorPage.error(session, Messages.INVALID_USER);
             }
@@ -382,6 +403,9 @@ public class AuthenticationProcessor {
 
 
     public Response authenticate() throws AuthException {
+        if (!ClientSessionModel.Action.AUTHENTICATE.name().equals(clientSession.getAction())) {
+            throw new AuthException(Error.INVALID_CLIENT_SESSION);
+        }
         logger.debug("AUTHENTICATE");
         event.event(EventType.LOGIN);
         event.client(clientSession.getClient().getClientId())
@@ -402,6 +426,9 @@ public class AuthenticationProcessor {
     }
 
     public Response authenticateOnly() throws AuthException {
+        if (!ClientSessionModel.Action.AUTHENTICATE.name().equals(clientSession.getAction())) {
+            throw new AuthException(Error.INVALID_CLIENT_SESSION);
+        }
         event.event(EventType.LOGIN);
         event.client(clientSession.getClient().getClientId())
                 .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
@@ -585,11 +612,6 @@ public class AuthenticationProcessor {
              .detail(Details.USERNAME, username)
              .session(userSession);
 
-        return processRequiredActions();
-
-    }
-
-    public Response processRequiredActions() {
         return AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, connection, request, uriInfo, event);
 
     }
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
index 248eb7a..a8f5aad 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorContext.java
@@ -66,4 +66,11 @@ public interface AuthenticatorContext {
 
     void failureChallenge(AuthenticationProcessor.Error error, Response challenge);
     void attempted();
+
+    /**
+     * 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
+     * whatever form is challenging.
+     */
+    String getForwardedErrorMessage();
 }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java
index 4463662..44d11fd 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/AbstractFormAuthenticator.java
@@ -32,10 +32,14 @@ public class AbstractFormAuthenticator {
         ClientSessionCode code = new ClientSessionCode(context.getRealm(), context.getClientSession());
         code.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
         URI action = getActionUrl(context, code, LOGIN_FORM_ACTION);
-        return context.getSession().getProvider(LoginFormsProvider.class)
+        LoginFormsProvider provider = context.getSession().getProvider(LoginFormsProvider.class)
                     .setUser(context.getUser())
                     .setActionUri(action)
                     .setClientSessionCode(code.getCode());
+        if (context.getForwardedErrorMessage() != null) {
+            provider.setError(context.getForwardedErrorMessage());
+        }
+        return provider;
     }
 
     public static URI getActionUrl(AuthenticatorContext context, ClientSessionCode code, String action) {
diff --git a/services/src/main/java/org/keycloak/authentication/RequiredActionContext.java b/services/src/main/java/org/keycloak/authentication/RequiredActionContext.java
index 62d4a93..dc630a8 100755
--- a/services/src/main/java/org/keycloak/authentication/RequiredActionContext.java
+++ b/services/src/main/java/org/keycloak/authentication/RequiredActionContext.java
@@ -11,6 +11,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.services.managers.BruteForceProtector;
+import org.keycloak.services.managers.ClientSessionCode;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
@@ -29,4 +30,5 @@ public interface RequiredActionContext {
     UriInfo getUriInfo();
     KeycloakSession getSession();
     HttpRequest getHttpRequest();
+    String generateAccessCode(String action);
 }
diff --git a/services/src/main/java/org/keycloak/authentication/RequiredActionProvider.java b/services/src/main/java/org/keycloak/authentication/RequiredActionProvider.java
index e6ff488..628f5c7 100755
--- a/services/src/main/java/org/keycloak/authentication/RequiredActionProvider.java
+++ b/services/src/main/java/org/keycloak/authentication/RequiredActionProvider.java
@@ -12,4 +12,5 @@ public interface RequiredActionProvider extends Provider {
     void evaluateTriggers(RequiredActionContext context);
     Response invokeRequiredAction(RequiredActionContext context);
     Object jaxrsService(RequiredActionContext context);
+    String getProviderId();
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 5b15cb8..e29649f 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -1,7 +1,6 @@
 package org.keycloak.protocol.oidc.endpoints;
 
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.ClientConnection;
 import org.keycloak.OAuth2Constants;
@@ -18,7 +17,6 @@ import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.utils.DefaultAuthenticationFlows;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -26,7 +24,6 @@ import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.services.ErrorPageException;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.services.managers.HttpAuthenticationManager;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.Urls;
 
@@ -248,10 +245,10 @@ public class AuthorizationEndpoint {
             return buildRedirectToIdentityProvider(idpHint, accessCode);
         }
 
-        return newBrowserAuthentication(accessCode);
+        return browserAuthentication(accessCode);
     }
 
-    protected Response newBrowserAuthentication(String accessCode) {
+    protected Response browserAuthentication(String accessCode) {
         List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
         for (IdentityProviderModel identityProvider : identityProviders) {
             if (identityProvider.isAuthenticateByDefault()) {
@@ -295,65 +292,6 @@ public class AuthorizationEndpoint {
         }
     }
 
-    protected Response oldBrowserAuthentication(String accessCode) {
-        Response response = authManager.checkNonFormAuthentication(session, clientSession, realm, uriInfo, request, clientConnection, headers, event);
-        if (response != null) return response;
-
-        // SPNEGO/Kerberos authentication TODO: This should be somehow pluggable instead of hardcoded this way (Authentication interceptors?)
-        HttpAuthenticationManager httpAuthManager = new HttpAuthenticationManager(session, clientSession, realm, uriInfo, request, clientConnection, event);
-        HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate(headers);
-        if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse();
-
-        if (prompt != null && prompt.equals("none")) {
-            OIDCLoginProtocol oauth = new OIDCLoginProtocol(session, realm, uriInfo, headers, event);
-            return oauth.cancelLogin(clientSession);
-        }
-
-        List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
-        for (IdentityProviderModel identityProvider : identityProviders) {
-            if (identityProvider.isAuthenticateByDefault()) {
-                return buildRedirectToIdentityProvider(identityProvider.getAlias(), accessCode);
-            }
-        }
-
-        List<RequiredCredentialModel> requiredCredentials = realm.getRequiredCredentials();
-        if (requiredCredentials.isEmpty()) {
-            if (!identityProviders.isEmpty()) {
-                if (identityProviders.size() == 1) {
-                    return buildRedirectToIdentityProvider(identityProviders.get(0).getAlias(), accessCode);
-                }
-
-                return session.getProvider(LoginFormsProvider.class).setError(Messages.IDENTITY_PROVIDER_NOT_UNIQUE, realm.getName()).createErrorPage();
-            }
-
-            return session.getProvider(LoginFormsProvider.class).setError(Messages.REALM_SUPPORTS_NO_CREDENTIALS, realm.getName()).createErrorPage();
-        }
-
-        LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode);
-
-        // Attach state from SPNEGO authentication
-        if (httpAuthOutput.getChallenge() != null) {
-            httpAuthOutput.getChallenge().sendChallenge(forms);
-        }
-
-        String rememberMeUsername = AuthenticationManager.getRememberMeUsername(realm, headers);
-
-        if (loginHint != null || rememberMeUsername != null) {
-            MultivaluedMap<String, String> formData = new MultivaluedMapImpl<String, String>();
-
-            if (loginHint != null) {
-                formData.add(AuthenticationManager.FORM_USERNAME, loginHint);
-            } else {
-                formData.add(AuthenticationManager.FORM_USERNAME, rememberMeUsername);
-                formData.add("rememberMe", "on");
-            }
-
-            forms.setFormData(formData);
-        }
-
-        return forms.createLogin();
-    }
-
     private Response buildRegister() {
         authManager.expireIdentityCookie(realm, uriInfo, clientConnection);
 
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index a4b0276..56aface 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -379,22 +379,6 @@ public class AuthenticationManager {
         return authResult;
     }
 
-    public Response checkNonFormAuthentication(KeycloakSession session, ClientSessionModel clientSession, RealmModel realm, UriInfo uriInfo,
-                                               HttpRequest request,
-                                               ClientConnection clientConnection, HttpHeaders headers,
-                                               EventBuilder event) {
-        AuthResult authResult = authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, true);
-        if (authResult != null) {
-            UserModel user = authResult.getUser();
-            UserSessionModel userSession = authResult.getSession();
-            TokenManager.attachClientSession(userSession, clientSession);
-            event.user(user).session(userSession).detail(Details.AUTH_METHOD, "sso");
-            return nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
-        }
-        return null;
-    }
-
-
 
     public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
                                                 ClientSessionModel clientSession,
@@ -442,11 +426,6 @@ public class AuthenticationManager {
                                                          final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
         final RealmModel realm = clientSession.getRealm();
         final UserModel user = userSession.getUser();
-        /*
-        isForcePasswordUpdateRequired(realm, user);
-        isTotpConfigurationRequired(realm, user);
-        isEmailVerificationRequired(realm, user);
-        */
         final ClientModel client = clientSession.getClient();
 
         RequiredActionContext context = new RequiredActionContext() {
@@ -494,6 +473,13 @@ public class AuthenticationManager {
             public HttpRequest getHttpRequest() {
                 return request;
             }
+
+            @Override
+            public String generateAccessCode(String action) {
+                ClientSessionCode code = new ClientSessionCode(getRealm(), getClientSession());
+                code.setAction(action);
+                return code.getCode();
+            }
         };
 
         // see if any required actions need triggering, i.e. an expired password
@@ -502,7 +488,6 @@ public class AuthenticationManager {
             provider.evaluateTriggers(context);
         }
 
-        ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
 
         logger.debugv("processAccessCode: go to oauth page?: {0}", client.isConsentRequired());
 
@@ -512,7 +497,9 @@ public class AuthenticationManager {
         for (String action : requiredActions) {
             RequiredActionProvider actionProvider = session.getProvider(RequiredActionProvider.class, action);
             Response challenge = actionProvider.invokeRequiredAction(context);
-            if (challenge != null) return challenge;
+            if (challenge != null) {
+                return challenge;
+            }
 
         }
         if (client.isConsentRequired()) {
@@ -521,6 +508,7 @@ public class AuthenticationManager {
 
             List<RoleModel> realmRoles = new LinkedList<>();
             MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<>();
+            ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
             for (RoleModel r : accessCode.getRequestedRoles()) {
 
                 // Consent already granted by user
@@ -564,47 +552,6 @@ public class AuthenticationManager {
     }
 
 
-
-    private static void isForcePasswordUpdateRequired(RealmModel realm, UserModel user) {
-        int daysToExpirePassword = realm.getPasswordPolicy().getDaysToExpirePassword();
-        if(daysToExpirePassword != -1) {
-            for (UserCredentialValueModel entity : user.getCredentialsDirectly()) {
-                if (entity.getType().equals(UserCredentialModel.PASSWORD)) {
-                    
-                    if(entity.getCreatedDate() == null) {
-                        user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-                        logger.debug("User is required to update password");
-                    } else {
-                        long timeElapsed = Time.toMillis(Time.currentTime()) - entity.getCreatedDate();
-                        long timeToExpire = TimeUnit.DAYS.toMillis(daysToExpirePassword);
-                    
-                        if(timeElapsed > timeToExpire) {
-                            user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-                            logger.debug("User is required to update password");
-                        }
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    protected static void isTotpConfigurationRequired(RealmModel realm, UserModel user) {
-        for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
-            if (c.getType().equals(CredentialRepresentation.TOTP) && !user.isTotp()) {
-                user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
-                logger.debug("User is required to configure totp");
-            }
-        }
-    }
-
-    protected static void isEmailVerificationRequired(RealmModel realm, UserModel user) {
-        if (realm.isVerifyEmail() && !user.isEmailVerified()) {
-            user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
-            logger.debug("User is required to verify email");
-        }
-    }
-
     protected static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) {
         try {
             AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), checkActive);
diff --git a/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java b/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
index 8ddc02f..d203218 100755
--- a/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
+++ b/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
@@ -81,22 +81,18 @@ public class ClientSessionCode {
     }
 
     public boolean isValid(String requestedAction) {
-        String action = clientSession.getAction();
-        if (action == null) {
-            return false;
-        }
+        if (!isValidAction(requestedAction)) return false;
+        return isActionActive(requestedAction);
+    }
 
+    public boolean isActionActive(String requestedAction) {
         int timestamp = clientSession.getTimestamp();
 
-        if (!action.equals(requestedAction)) {
-            return false;
-        }
-
         int lifespan;
-        if (action.equals(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
+        if (requestedAction.equals(ClientSessionModel.Action.CODE_TO_TOKEN.name())) {
             lifespan = realm.getAccessCodeLifespan();
 
-        } else if (action.equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
+        } else if (requestedAction.equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
             lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
         } else {
             lifespan = realm.getAccessCodeLifespanUserAction();
@@ -104,6 +100,18 @@ public class ClientSessionCode {
         return timestamp + lifespan > Time.currentTime();
     }
 
+    public boolean isValidAction(String requestedAction) {
+        String action = clientSession.getAction();
+        if (action == null) {
+            return false;
+        }
+        if (!action.equals(requestedAction)) {
+            return false;
+        }
+        return true;
+    }
+
+
     public Set<RoleModel> getRequestedRoles() {
         Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
         for (String roleId : clientSession.getRoles()) {
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index d45e706..57b16a7 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -21,6 +21,7 @@ import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.ClientConnection;
+import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
@@ -31,7 +32,7 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.login.LoginFormsProvider;
+import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.Constants;
@@ -44,6 +45,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.AccessToken;
@@ -51,6 +53,7 @@ import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.AuthenticationManager.AuthResult;
+import org.keycloak.services.managers.BruteForceProtector;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.ErrorResponse;
@@ -112,11 +115,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
     private EventBuilder event;
 
-    public IdentityBrokerService(RealmModel realmModel) {
+    private BruteForceProtector protector;
+
+    public IdentityBrokerService(RealmModel realmModel, BruteForceProtector protector) {
         if (realmModel == null) {
             throw new IllegalArgumentException("Realm can not be null.");
         }
-
+        this.protector = protector;
         this.realmModel = realmModel;
     }
 
@@ -317,12 +322,21 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
     @Override
     public Response cancelled(String code) {
-        return session.getProvider(LoginFormsProvider.class).setClientSessionCode(code).createLogin();
+        ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
+        if (clientCode.getClientSession() == null || !clientCode.isValid(AUTHENTICATE.name())) {
+            return redirectToErrorPage(Messages.INVALID_CODE);
+        }
+
+        return browserAuthentication(clientCode.getClientSession(), null);
     }
 
     @Override
     public Response error(String code, String message) {
-        return session.getProvider(LoginFormsProvider.class).setClientSessionCode(code).setError(message).createLogin();
+        ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
+        if (clientCode.getClientSession() == null || !clientCode.isValid(AUTHENTICATE.name())) {
+            return redirectToErrorPage(Messages.INVALID_CODE);
+        }
+        return browserAuthentication(clientCode.getClientSession(), message);
     }
 
     private Response performAccountLinking(ClientSessionModel clientSession, BrokeredIdentityContext context, FederatedIdentityModel federatedIdentityModel, UserModel federatedUser) {
@@ -448,12 +462,32 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         }
 
         fireErrorEvent(message);
-        return session.getProvider(LoginFormsProvider.class)
-                .setClientSessionCode(clientCode.getCode())
-                .setError(message)
-                .createLogin();
+        return browserAuthentication(clientCode.getClientSession(), message);
     }
 
+    protected Response browserAuthentication(ClientSessionModel clientSession, String errorMessage) {
+        AuthenticationFlowModel flow = realmModel.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW);
+        String flowId = flow.getId();
+        AuthenticationProcessor processor = new AuthenticationProcessor();
+        processor.setClientSession(clientSession)
+                .setFlowId(flowId)
+                .setConnection(clientConnection)
+                .setEventBuilder(event)
+                .setProtector(protector)
+                .setRealm(realmModel)
+                .setSession(session)
+                .setUriInfo(uriInfo)
+                .setRequest(request);
+        if (errorMessage != null) processor.setForwardedErrorMessage(errorMessage);
+
+        try {
+            return processor.authenticate();
+        } catch (Exception e) {
+            return processor.handleBrowserException(e);
+        }
+    }
+
+
     private Response badRequest(String message) {
         fireErrorEvent(message);
         return ErrorResponse.error(message, Status.BAD_REQUEST);
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index fae9564..b3716b9 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -36,9 +36,7 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.login.LoginFormsProvider;
-import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
@@ -48,20 +46,17 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelException;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.DefaultAuthenticationFlows;
 import org.keycloak.models.utils.FormMessage;
-import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.representations.PasswordToken;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
@@ -137,16 +132,6 @@ public class LoginActionsService {
         return baseUriBuilder.path(RealmsResource.class).path(RealmsResource.class, "getLoginActionsService");
     }
 
-    public static UriBuilder processLoginUrl(UriInfo uriInfo) {
-        UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
-        return processLoginUrl(baseUriBuilder);
-    }
-
-    public static UriBuilder processLoginUrl(UriBuilder baseUriBuilder) {
-        UriBuilder uriBuilder = loginActionsBaseUrl(baseUriBuilder);
-        return uriBuilder.path(OIDCLoginProtocolService.class, "processLogin");
-    }
-
     public static UriBuilder processOAuthUrl(UriInfo uriInfo) {
         UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
         return processOAuthUrl(baseUriBuilder);
@@ -179,10 +164,16 @@ public class LoginActionsService {
         boolean check(String code, String requiredAction) {
             if (!check(code)) {
                 return false;
-            } else if (!clientCode.isValid(requiredAction)) {
+            } else if (!clientCode.isValidAction(requiredAction)) {
+                event.client(clientCode.getClientSession().getClient());
                 event.error(Errors.INVALID_CODE);
                 response = ErrorPage.error(session, Messages.INVALID_CODE);
                 return false;
+            } else if (!clientCode.isActionActive(requiredAction)) {
+                event.client(clientCode.getClientSession().getClient());
+                event.error(Errors.EXPIRED_CODE);
+                response = ErrorPage.error(session, Messages.INVALID_CODE);
+                return false;
             } else {
                 return true;
             }
@@ -191,10 +182,16 @@ public class LoginActionsService {
         boolean check(String code, String requiredAction, String alternativeRequiredAction) {
             if (!check(code)) {
                 return false;
-            } else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) {
+            } else if (!(clientCode.isValidAction(requiredAction) || clientCode.isValidAction(alternativeRequiredAction))) {
+                event.client(clientCode.getClientSession().getClient());
                 event.error(Errors.INVALID_CODE);
                 response = ErrorPage.error(session, Messages.INVALID_CODE);
                 return false;
+            } else if (!(clientCode.isActionActive(requiredAction) || clientCode.isActionActive(alternativeRequiredAction))) {
+                event.client(clientCode.getClientSession().getClient());
+                event.error(Errors.EXPIRED_CODE);
+                response = ErrorPage.error(session, Messages.INVALID_CODE);
+                return false;
             } else {
                 return true;
             }
@@ -217,6 +214,21 @@ public class LoginActionsService {
                 response = ErrorPage.error(session, Messages.INVALID_CODE);
                 return false;
             }
+            ClientSessionModel clientSession = clientCode.getClientSession();
+            event.detail(Details.CODE_ID, clientSession.getId());
+            ClientModel client = clientSession.getClient();
+            if (client == null) {
+                event.error(Errors.CLIENT_NOT_FOUND);
+                response = ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
+                return false;
+            }
+            session.getContext().setClient(client);
+
+            if (!client.isEnabled()) {
+                event.error(Errors.CLIENT_NOT_FOUND);
+                response = ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
+                return false;
+            }
             session.getContext().setClient(clientCode.getClientSession().getClient());
             return true;
         }
@@ -246,9 +258,24 @@ public class LoginActionsService {
             clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
         }
 
-        return session.getProvider(LoginFormsProvider.class)
-                .setClientSessionCode(clientSessionCode.getCode())
-                .createLogin();
+        AuthenticationFlowModel flow = realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW);
+        String flowId = flow.getId();
+        AuthenticationProcessor processor = new AuthenticationProcessor();
+        processor.setClientSession(clientSession)
+                .setFlowId(flowId)
+                .setConnection(clientConnection)
+                .setEventBuilder(event)
+                .setProtector(authManager.getProtector())
+                .setRealm(realm)
+                .setSession(session)
+                .setUriInfo(uriInfo)
+                .setRequest(request);
+
+        try {
+            return processor.authenticate();
+        } catch (Exception e) {
+            return processor.handleBrowserException(e);
+        }
     }
 
     /**
@@ -283,7 +310,7 @@ public class LoginActionsService {
                 .createRegistration();
     }
 
-        /**
+    /**
      * URL called after login page.  YOU SHOULD NEVER INVOKE THIS DIRECTLY!
      *
      * @param code
@@ -295,51 +322,18 @@ public class LoginActionsService {
     public Response authForm(@QueryParam("code") String code,
                              @QueryParam("action") String action) {
         event.event(EventType.LOGIN);
-        if (!checkSsl()) {
-            event.error(Errors.SSL_REQUIRED);
-            return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
-        }
-
-        if (!realm.isEnabled()) {
-            event.error(Errors.REALM_DISABLED);
-            return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
-        }
-        ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
-        if (clientCode == null) {
-            event.error(Errors.INVALID_CODE);
-            return ErrorPage.error(session, Messages.INVALID_CODE);
-        }
-
-        ClientSessionModel clientSession = clientCode.getClientSession();
-        event.detail(Details.CODE_ID, clientSession.getId());
-
-        if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
-            event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
-            return ErrorPage.error(session, Messages.EXPIRED_CODE);
-        }
-
-        ClientModel client = clientSession.getClient();
-        if (client == null) {
-            event.error(Errors.CLIENT_NOT_FOUND);
-            return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
-        }
-        session.getContext().setClient(client);
-
-        if (!client.isEnabled()) {
-            event.error(Errors.CLIENT_DISABLED);
-            return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
+        Checks checks = new Checks();
+        if (!checks.check(code, ClientSessionModel.Action.AUTHENTICATE.name())) {
+            return checks.response;
         }
+        final ClientSessionCode clientCode = checks.clientCode;
+        final ClientSessionModel clientSession = clientCode.getClientSession();
 
-        String flowId = null;
-        for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
-            if (flow.getAlias().equals("browser")) {
-                flowId = flow.getId();
-                break;
-            }
-        }
+        String flowAlias = DefaultAuthenticationFlows.BROWSER_FLOW;
+        AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias);
         AuthenticationProcessor processor = new AuthenticationProcessor();
         processor.setClientSession(clientSession)
-                .setFlowId(flowId)
+                .setFlowId(flow.getId())
                 .setConnection(clientConnection)
                 .setEventBuilder(event)
                 .setProtector(authManager.getProtector())
@@ -358,142 +352,6 @@ public class LoginActionsService {
     }
 
     /**
-     * URL called after login page.  YOU SHOULD NEVER INVOKE THIS DIRECTLY!
-     *
-     * @param code
-     * @param formData
-     * @return
-     */
-    @Path("request/login")
-    @POST
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public Response processLogin(@QueryParam("code") String code,
-                                 final MultivaluedMap<String, String> formData) {
-        event.event(EventType.LOGIN);
-        if (!checkSsl()) {
-            event.error(Errors.SSL_REQUIRED);
-            return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
-        }
-
-        if (!realm.isEnabled()) {
-            event.error(Errors.REALM_DISABLED);
-            return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
-        }
-        ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
-        if (clientCode == null) {
-            event.error(Errors.INVALID_CODE);
-            return ErrorPage.error(session, Messages.INVALID_CODE);
-        }
-
-        ClientSessionModel clientSession = clientCode.getClientSession();
-        event.detail(Details.CODE_ID, clientSession.getId());
-
-        if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
-            clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
-            event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
-            return session.getProvider(LoginFormsProvider.class)
-                    .setError(Messages.EXPIRED_CODE)
-                    .setClientSessionCode(clientCode.getCode())
-                    .createLogin();
-        }
-
-        String username = formData.getFirst(AuthenticationManager.FORM_USERNAME);
-
-        String rememberMe = formData.getFirst("rememberMe");
-        boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on");
-
-        event.client(clientSession.getClient().getClientId())
-                .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
-                .detail(Details.RESPONSE_TYPE, "code")
-                .detail(Details.AUTH_METHOD, "form")
-                .detail(Details.USERNAME, username);
-
-        if (remember) {
-            event.detail(Details.REMEMBER_ME, "true");
-        }
-
-        ClientModel client = clientSession.getClient();
-        if (client == null) {
-            event.error(Errors.CLIENT_NOT_FOUND);
-            return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
-        }
-        if (!client.isEnabled()) {
-            event.error(Errors.CLIENT_DISABLED);
-            return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
-        }
-
-        session.getContext().setClient(clientSession.getClient());
-
-        if (formData.containsKey("cancel")) {
-            event.error(Errors.REJECTED_BY_USER);
-            LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
-            protocol.setRealm(realm)
-                    .setHttpHeaders(headers)
-                    .setUriInfo(uriInfo);
-            return protocol.cancelLogin(clientSession);
-        }
-
-        AuthenticationManager.AuthenticationStatus status = authManager.authenticateForm(session, clientConnection, realm, formData);
-
-        if (remember) {
-            authManager.createRememberMeCookie(realm, username, uriInfo, clientConnection);
-        } else {
-            authManager.expireRememberMeCookie(realm, uriInfo, clientConnection);
-        }
-
-        UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username);
-        if (user != null) {
-            event.user(user);
-        }
-
-        switch (status) {
-            case SUCCESS:
-            case ACTIONS_REQUIRED:
-                UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "form", remember, null, null);
-                TokenManager.attachClientSession(userSession, clientSession);
-                event.session(userSession);
-                return authManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
-            case ACCOUNT_TEMPORARILY_DISABLED:
-                event.error(Errors.USER_TEMPORARILY_DISABLED);
-                return session.getProvider(LoginFormsProvider.class)
-                        .setError(Messages.ACCOUNT_TEMPORARILY_DISABLED)
-                        .setFormData(formData)
-                        .setClientSessionCode(clientCode.getCode())
-                        .createLogin();
-            case ACCOUNT_DISABLED:
-                event.error(Errors.USER_DISABLED);
-                return session.getProvider(LoginFormsProvider.class)
-                        .setError(Messages.ACCOUNT_DISABLED)
-                        .setClientSessionCode(clientCode.getCode())
-                        .setFormData(formData).createLogin();
-            case MISSING_TOTP:
-                formData.remove(CredentialRepresentation.PASSWORD);
-
-                String passwordToken = new JWSBuilder().jsonContent(new PasswordToken(realm.getName(), user.getId())).rsa256(realm.getPrivateKey());
-                formData.add(CredentialRepresentation.PASSWORD_TOKEN, passwordToken);
-
-                return session.getProvider(LoginFormsProvider.class)
-                        .setFormData(formData)
-                        .setClientSessionCode(clientCode.getCode())
-                        .createLoginTotp();
-            case INVALID_USER:
-                event.error(Errors.USER_NOT_FOUND);
-                return session.getProvider(LoginFormsProvider.class)
-                        .setError(Messages.INVALID_USER)
-                        .setFormData(formData)
-                        .setClientSessionCode(clientCode.getCode())
-                        .createLogin();
-            default:
-                event.error(Errors.INVALID_USER_CREDENTIALS);
-                return session.getProvider(LoginFormsProvider.class)
-                        .setError(Messages.INVALID_USER)
-                        .setFormData(formData)
-                        .setClientSessionCode(clientCode.getCode())
-                        .createLogin();
-        }
-    }
-
-    /**
      * Registration
      *
      * @param code
@@ -993,19 +851,14 @@ public class LoginActionsService {
     public Response sendPasswordReset(@QueryParam("code") String code,
                                       final MultivaluedMap<String, String> formData) {
         event.event(EventType.SEND_RESET_PASSWORD);
-        if (!checkSsl()) {
-            return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
-        }
-        if (!realm.isEnabled()) {
-            event.error(Errors.REALM_DISABLED);
-            return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
-        }
-        ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
-        if (accessCode == null) {
-            event.error(Errors.INVALID_CODE);
-            return ErrorPage.error(session, Messages.INVALID_CODE);
+        Checks checks = new Checks();
+        if (!checks.check(code)) {
+            return checks.response;
         }
-        ClientSessionModel clientSession = accessCode.getClientSession();
+        final ClientSessionCode accessCode = checks.clientCode;
+        final ClientSessionModel clientSession = accessCode.getClientSession();
+        ClientModel client = clientSession.getClient();
+
 
         String username = formData.getFirst("username");
         if(username == null || username.isEmpty()) {
@@ -1016,16 +869,6 @@ public class LoginActionsService {
                     .createPasswordReset();
         }
 
-        ClientModel client = clientSession.getClient();
-        if (client == null) {
-            return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
-        }
-        if (!client.isEnabled()) {
-            return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
-        }
-
-        session.getContext().setClient(client);
-
         event.client(client.getClientId())
                 .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
                 .detail(Details.RESPONSE_TYPE, "code")
@@ -1114,43 +957,6 @@ public class LoginActionsService {
     public Object requiredAction(@QueryParam("code") String code,
                                  @PathParam("action") String action) {
         event.event(EventType.LOGIN);
-        if (!checkSsl()) {
-            event.error(Errors.SSL_REQUIRED);
-            throw new WebApplicationException(ErrorPage.error(session, Messages.HTTPS_REQUIRED));
-        }
-
-        if (!realm.isEnabled()) {
-            event.error(Errors.REALM_DISABLED);
-            return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
-        }
-        ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
-        if (clientCode == null) {
-            event.error(Errors.INVALID_CODE);
-            throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
-        }
-
-        final ClientSessionModel clientSession = clientCode.getClientSession();
-        event.detail(Details.CODE_ID, clientSession.getId());
-
-        /*
-        if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
-            event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
-            throw new WebApplicationException(ErrorPage.error(session, Messages.EXPIRED_CODE));
-        }
-        */
-
-        ClientModel client = clientSession.getClient();
-        if (client == null) {
-            event.error(Errors.CLIENT_NOT_FOUND);
-            throw new WebApplicationException( ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER));
-        }
-        session.getContext().setClient(client);
-
-        if (!client.isEnabled()) {
-            event.error(Errors.CLIENT_NOT_FOUND);
-            throw new WebApplicationException( ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED));
-        }
-
         if (action == null) {
             logger.error("required action was null");
             event.error(Errors.INVALID_CODE);
@@ -1164,6 +970,20 @@ public class LoginActionsService {
             event.error(Errors.INVALID_CODE);
             throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
         }
+        Checks checks = new Checks();
+        if (!checks.check(code, action)) {
+            return checks.response;
+        }
+        final ClientSessionCode clientCode = checks.clientCode;
+        final ClientSessionModel clientSession = clientCode.getClientSession();
+
+        if (clientSession.getUserSession() == null) {
+            logger.error("user session was null");
+            event.error(Errors.USER_SESSION_NOT_FOUND);
+            throw new WebApplicationException(ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE));
+        }
+
+
         RequiredActionContext context = new RequiredActionContext() {
             @Override
             public EventBuilder getEvent() {
@@ -1209,7 +1029,14 @@ public class LoginActionsService {
             public HttpRequest getHttpRequest() {
                 return request;
             }
-        };
+
+            @Override
+            public String generateAccessCode(String action) {
+                ClientSessionCode code = new ClientSessionCode(getRealm(), getClientSession());
+                code.setAction(action);
+                return code.getCode();
+            }
+       };
         return provider.jaxrsService(context);
 
 
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index dc674f7..656c4dc 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -161,7 +161,7 @@ public class RealmsResource {
     public IdentityBrokerService getBrokerService(final @PathParam("realm") String name) {
         RealmModel realm = init(name);
 
-        IdentityBrokerService brokerService = new IdentityBrokerService(realm);
+        IdentityBrokerService brokerService = new IdentityBrokerService(realm, protector);
         ResteasyProviderFactory.getInstance().injectProperties(brokerService);
 
         brokerService.init();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index f180530..e6851b5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -334,7 +334,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
             Assert.assertThat(actual.getSessionId(), sessionId);
 
             if (details == null || details.isEmpty()) {
-                Assert.assertNull(actual.getDetails());
+//                Assert.assertNull(actual.getDetails());
             } else {
                 Assert.assertNotNull(actual.getDetails());
                 for (Map.Entry<String, Matcher<String>> d : details.entrySet()) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 26b1f79..087f6c3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -178,7 +178,7 @@ public class ResetPasswordTest {
 
         loginPage.login("login@test.com", "password");
 
-        Event loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "login@test.com").assertEvent();
+        Event loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent();
 
         String code = oauth.getCurrentQuery().get("code");
         OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
@@ -372,7 +372,7 @@ public class ResetPasswordTest {
 
             assertEquals("An error occurred, please login again through your application.", errorPage.getError());
 
-            events.expectRequiredAction(EventType.RESET_PASSWORD).error("invalid_code").client((String) null).user((String) null).session((String) null).clearDetails().assertEvent();
+            events.expectRequiredAction(EventType.RESET_PASSWORD).error("expired_code").client("test-app").user((String) null).session((String) null).clearDetails().assertEvent();
         } finally {
             Time.setOffset(0);
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
index cdf61d0..d5d7296 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
@@ -152,20 +152,6 @@ public class AccessTokenPerfTest {
             return b.build(realm).toString();
         }
 
-        public String getProcessLoginUrl(String state) {
-            UriBuilder b = LoginActionsService.processLoginUrl(UriBuilder.fromUri(baseUrl));
-            if (clientId != null) {
-                b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
-            }
-            if (redirectUri != null) {
-                b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
-            }
-            if (state != null) {
-                b.queryParam(OAuth2Constants.STATE, state);
-            }
-            return b.build(realm).toString();
-        }
-
         static Pattern actionParser = Pattern.compile("action=\"([^\"]+)\"");
 
         public void run() {