keycloak-memoizeit

Added realm registration

8/15/2013 7:31:10 AM

Details

diff --git a/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json b/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json
index 2fa8a91..2a711d0 100755
--- a/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json
+++ b/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json
@@ -5,6 +5,7 @@
     "accessCodeLifespan": 10,
     "sslNotRequired": true,
     "cookieLoginAllowed": true,
+    "registrationAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 524fb88..1586236 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -103,6 +103,7 @@ public class RealmManager {
         newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
         newRealm.setSslNotRequired(rep.isSslNotRequired());
         newRealm.setCookieLoginAllowed(rep.isCookieLoginAllowed());
+        newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
         if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
             generateRealmKeys(newRealm);
         } else {
diff --git a/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
index a72bcba..de99a7c 100755
--- a/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
@@ -62,19 +62,19 @@ public class RequiredCredentialModel {
         PASSWORD.setType(CredentialRepresentation.PASSWORD);
         PASSWORD.setInput(true);
         PASSWORD.setSecret(true);
-        PASSWORD.setFormLabel("Password");
+        PASSWORD.setFormLabel("password");
         map.put(PASSWORD.getType(), PASSWORD);
         TOTP = new RequiredCredentialModel();
         TOTP.setType(CredentialRepresentation.TOTP);
         TOTP.setInput(true);
         TOTP.setSecret(false);
-        TOTP.setFormLabel("Authenticator Code");
+        TOTP.setFormLabel("authenticatorCode");
         map.put(TOTP.getType(), TOTP);
         CLIENT_CERT = new RequiredCredentialModel();
         CLIENT_CERT.setType(CredentialRepresentation.CLIENT_CERT);
         CLIENT_CERT.setInput(false);
         CLIENT_CERT.setSecret(false);
-        CLIENT_CERT.setFormLabel("Client Certificate");
+        CLIENT_CERT.setFormLabel("clientCertificate");
         map.put(CLIENT_CERT.getType(), CLIENT_CERT);
         BUILT_IN = Collections.unmodifiableMap(map);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
new file mode 100644
index 0000000..67f6a99
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
@@ -0,0 +1,28 @@
+package org.keycloak.services.resources.flows;
+
+import javax.ws.rs.core.UriInfo;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.TokenManager;
+import org.keycloak.services.models.RealmModel;
+
+public class Flows {
+
+    private Flows() {
+    }
+
+    public static PageFlows pages(HttpRequest request) {
+        return new PageFlows(request);
+    }
+
+    public static FormFlows forms(RealmModel realm, HttpRequest request) {
+        return new FormFlows(realm, request);
+    }
+
+    public static OAuthFlows oauth(RealmModel realm, HttpRequest request, UriInfo uriInfo, AuthenticationManager authManager,
+            TokenManager tokenManager) {
+        return new OAuthFlows(realm, request, uriInfo, authManager, tokenManager);
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java
new file mode 100644
index 0000000..4c65dbb
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/flows/FormFlows.java
@@ -0,0 +1,61 @@
+package org.keycloak.services.resources.flows;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.services.models.RealmModel;
+import org.picketlink.idm.model.sample.Realm;
+
+public class FormFlows {
+
+    public static final String REALM = Realm.class.getName();
+    public static final String ERROR_MESSAGE = "KEYCLOAK_FORMS_ERROR_MESSAGE";
+    public static final String DATA = "KEYCLOAK_FORMS_DATA";
+
+    private MultivaluedMap<String, String> formData;
+    private String error;
+
+    private RealmModel realm;
+
+    private HttpRequest request;
+
+    FormFlows(RealmModel realm, HttpRequest request) {
+        this.realm = realm;
+        this.request = request;
+    }
+
+    public FormFlows setFormData(MultivaluedMap<String, String> formData) {
+        this.formData = formData;
+        return this;
+    }
+
+    public FormFlows setError(String error) {
+        this.error = error;
+        return this;
+    }
+
+    public Response forwardToLogin() {
+        return forwardToForm(Pages.LOGIN);
+    }
+
+    public Response forwardToRegistration() {
+        return forwardToForm(Pages.REGISTER);
+    }
+
+    private Response forwardToForm(String form) {
+        request.setAttribute(REALM, realm);
+
+        if (error != null) {
+            request.setAttribute(ERROR_MESSAGE, error);
+        }
+
+        if (formData != null) {
+            request.setAttribute(DATA, formData);
+        }
+
+        request.forward(form);
+        return null;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/PageFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/PageFlows.java
new file mode 100644
index 0000000..b63b232
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/flows/PageFlows.java
@@ -0,0 +1,28 @@
+package org.keycloak.services.resources.flows;
+
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.logging.Logger;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.services.JspRequestParameters;
+
+public class PageFlows {
+
+    private static final Logger log = Logger.getLogger(PageFlows.class);
+
+    private HttpRequest request;
+
+    PageFlows(HttpRequest request) {
+        this.request = request;
+    }
+
+    public Response forwardToSecurityFailure(String message) {
+        log.error(message);
+
+        request.setAttribute(JspRequestParameters.KEYCLOAK_SECURITY_FAILURE_MESSAGE, message);
+
+        request.forward(Pages.SECURITY_FAILURE);
+        return null;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Pages.java b/services/src/main/java/org/keycloak/services/resources/flows/Pages.java
new file mode 100644
index 0000000..bb41513
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Pages.java
@@ -0,0 +1,13 @@
+package org.keycloak.services.resources.flows;
+
+public class Pages {
+
+    public final static String LOGIN = "/sdk/login.xhtml";
+
+    public final static String OAUTH_GRANT = "/saas/oauthGrantForm.jsp";
+
+    public final static String REGISTER = "/sdk/register.xhtml";
+
+    public final static String SECURITY_FAILURE = "/saas/securityFailure.jsp";
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
new file mode 100644
index 0000000..e20f974
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
@@ -0,0 +1,71 @@
+package org.keycloak.services.resources.flows;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.services.resources.SaasService;
+import org.keycloak.services.resources.SocialResource;
+import org.keycloak.services.resources.TokenService;
+
+public class Urls {
+
+    private static UriBuilder realmBase(URI baseUri) {
+        return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
+    }
+
+    private static UriBuilder tokenBase(URI baseUri) {
+        return realmBase(baseUri).path(RealmsResource.class, "getTokenService");
+    }
+
+    public static URI realmLoginAction(URI baseUri, String realmId) {
+        return tokenBase(baseUri).path(TokenService.class, "processLogin").build(realmId);
+    }
+
+    public static URI realmLoginPage(URI baseUri, String realmId) {
+        return tokenBase(baseUri).path(TokenService.class, "loginPage").build(realmId);
+    }
+
+    public static URI realmRegisterAction(URI baseUri, String realmId) {
+        return tokenBase(baseUri).path(TokenService.class, "processRegister").build(realmId);
+    }
+
+    public static URI realmRegisterPage(URI baseUri, String realmId) {
+        return tokenBase(baseUri).path(TokenService.class, "registerPage").build(realmId);
+    }
+
+    private static UriBuilder saasBase(URI baseUri) {
+        return UriBuilder.fromUri(baseUri).path(SaasService.class);
+    }
+
+    public static URI saasLoginAction(URI baseUri) {
+        return saasBase(baseUri).path(SaasService.class, "processLogin").build();
+    }
+
+    public static URI saasLoginPage(URI baseUri) {
+        return saasBase(baseUri).path(SaasService.class, "loginPage").build();
+    }
+
+    public static URI saasRegisterAction(URI baseUri) {
+        return saasBase(baseUri).path(SaasService.class, "processRegister").build();
+    }
+
+    public static URI saasRegisterPage(URI baseUri) {
+        return saasBase(baseUri).path(SaasService.class, "registerPage").build();
+    }
+
+    private static UriBuilder socialBase(URI baseUri) {
+        return UriBuilder.fromUri(baseUri).path(SocialResource.class);
+    }
+
+    public static URI socialCallback(URI baseUri) {
+        return socialBase(baseUri).path(SocialResource.class, "callback").build();
+    }
+
+    public static URI socialRedirectToProviderAuth(URI baseUri, String realmId) {
+        return socialBase(baseUri).path(SocialResource.class, "redirectToProviderAuth")
+                .build(realmId);
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/SaasService.java b/services/src/main/java/org/keycloak/services/resources/SaasService.java
index af8b1aa..0a54871 100755
--- a/services/src/main/java/org/keycloak/services/resources/SaasService.java
+++ b/services/src/main/java/org/keycloak/services/resources/SaasService.java
@@ -14,9 +14,11 @@ import org.keycloak.services.models.RoleModel;
 import org.keycloak.services.models.UserCredentialModel;
 import org.keycloak.services.models.UserModel;
 import org.keycloak.services.resources.admin.RealmsAdminResource;
+import org.keycloak.services.resources.flows.Flows;
 
 import javax.ws.rs.*;
 import javax.ws.rs.core.*;
+
 import java.net.URI;
 import java.util.StringTokenizer;
 
@@ -81,7 +83,8 @@ public class SaasService {
             public Response callImpl() {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
-                if (realm == null) throw new NotFoundException();
+                if (realm == null)
+                    throw new NotFoundException();
                 UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
                 if (user == null) {
                     return Response.status(401).build();
@@ -102,7 +105,8 @@ public class SaasService {
             public Response callImpl() {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
-                if (realm == null) throw new NotFoundException();
+                if (realm == null)
+                    throw new NotFoundException();
                 UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
                 if (user == null) {
                     return Response.status(401).build();
@@ -137,7 +141,6 @@ public class SaasService {
         }.call();
     }
 
-
     public static UriBuilder contextRoot(UriInfo uriInfo) {
         return UriBuilder.fromUri(uriInfo.getBaseUri()).replacePath("/auth-server");
     }
@@ -153,7 +156,8 @@ public class SaasService {
             protected RealmsAdminResource callImpl() {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel saasRealm = realmManager.defaultRealm();
-                if (saasRealm == null) throw new NotFoundException();
+                if (saasRealm == null)
+                    throw new NotFoundException();
                 UserModel admin = authManager.authenticateSaasIdentity(saasRealm, uriInfo, headers);
                 if (admin == null) {
                     throw new NotAuthorizedException("Bearer");
@@ -178,7 +182,8 @@ public class SaasService {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
                 authManager.expireSaasIdentityCookie(uriInfo);
-                forwardToLoginForm(realm, null, null);
+
+                Flows.forms(realm, request).forwardToLogin();
             }
         }.run();
     }
@@ -193,7 +198,8 @@ public class SaasService {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
                 authManager.expireSaasIdentityCookie(uriInfo);
-                forwardToRegisterForm(realm, null, null);
+
+                Flows.forms(realm, request).forwardToRegistration();
             }
         }.run();
     }
@@ -208,12 +214,12 @@ public class SaasService {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
                 authManager.expireSaasIdentityCookie(uriInfo);
-                forwardToLoginForm(realm, null, null);
+
+                Flows.forms(realm, request).forwardToLogin();
             }
         }.run();
     }
 
-
     @Path("logout-cookie")
     @GET
     @NoCache
@@ -227,45 +233,6 @@ public class SaasService {
         }.run();
     }
 
-    protected void forwardToLoginForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
-        if (error != null) {
-            request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
-        }
-
-        if (formData != null) {
-            request.setAttribute("KEYCLOAK_FORM_DATA", formData);
-        }
-
-        forwardToForm(realm, Pages.loginForm);
-    }
-
-    protected void forwardToRegisterForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
-        if (error != null) {
-            request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
-        }
-
-        if (formData != null) {
-            request.setAttribute("KEYCLOAK_FORM_DATA", formData);
-        }
-
-        forwardToForm(realm, Pages.registerForm);
-    }
-
-    protected void forwardToForm(RealmModel realm, String form) {
-        request.setAttribute(RealmModel.class.getName(), realm);
-
-        request.setAttribute("KEYCLOAK_LOGIN_PAGE", Urls.saasLoginPage(uriInfo));
-        request.setAttribute("KEYCLOAK_LOGIN_ACTION", Urls.saasLoginAction(uriInfo));
-
-        request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", Urls.saasRegisterPage(uriInfo));
-        request.setAttribute("KEYCLOAK_REGISTRATION_ACTION", Urls.saasRegisterAction(uriInfo));
-
-        request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", Urls.socialRedirectToProviderAuth(uriInfo, realm.getId()));
-
-        request.forward(form);
-    }
-
-
     @Path("login")
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@@ -276,7 +243,8 @@ public class SaasService {
             protected Response callImpl() {
                 RealmManager realmManager = new RealmManager(session);
                 RealmModel realm = realmManager.defaultRealm();
-                if (realm == null) throw new NotFoundException();
+                if (realm == null)
+                    throw new NotFoundException();
 
                 if (!realm.isEnabled()) {
                     throw new NotImplementedYetException();
@@ -285,26 +253,27 @@ public class SaasService {
                 UserModel user = realm.getUser(username);
                 if (user == null) {
                     logger.info("Not Authenticated! Incorrect user name");
-                    forwardToLoginForm(realm, "Invalid username or password", formData);
-                    return null;
+
+                    return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
+                            .forwardToLogin();
                 }
                 if (!user.isEnabled()) {
                     logger.info("NAccount is disabled, contact admin.");
-                    forwardToLoginForm(realm, "Account is disabled, contact admin.", formData);
-                    return null;
+
+                    return Flows.forms(realm, request).setError("Invalid username or password")
+                            .setFormData(formData).forwardToLogin();
                 }
 
                 boolean authenticated = authManager.authenticateForm(realm, user, formData);
                 if (!authenticated) {
                     logger.info("Not Authenticated! Invalid credentials");
-                    forwardToLoginForm(realm, "Invalid username or password", formData);
-                    return null;
+
+                    return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
+                            .forwardToLogin();
                 }
 
                 NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
-                return Response.status(302)
-                        .cookie(cookie)
-                        .location(contextRoot(uriInfo).path(adminPath).build()).build();
+                return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
             }
         }.call();
     }
@@ -340,8 +309,8 @@ public class SaasService {
 
                 String error = validateRegistrationForm(formData);
                 if (error != null) {
-                    forwardToRegisterForm(defaultRealm, error, formData);
-                    return null;
+                    return Flows.forms(defaultRealm, request).setError(error).setFormData(formData)
+                            .forwardToRegistration();
                 }
 
                 UserRepresentation newUser = new UserRepresentation();
@@ -366,16 +335,16 @@ public class SaasService {
                             last = token;
                         }
                     }
-                    if (first == null) first = new StringBuffer();
+                    if (first == null)
+                        first = new StringBuffer();
                     newUser.setFirstName(first.toString());
                     newUser.setLastName(last);
                 }
                 newUser.credential(CredentialRepresentation.PASSWORD, formData.getFirst("password"));
                 UserModel user = registerMe(defaultRealm, newUser);
                 if (user == null) {
-                    request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Username already exists.");
-                    forwardToRegisterForm(defaultRealm, "Username already exists.", formData);
-                    return null;
+                    return Flows.forms(defaultRealm, request).setError("Username already exists.")
+                            .setFormData(formData).forwardToRegistration();
 
                 }
                 NewCookie cookie = authManager.createSaasIdentityCookie(defaultRealm, user, uriInfo);
@@ -384,7 +353,6 @@ public class SaasService {
         }.call();
     }
 
-
     protected UserModel registerMe(RealmModel defaultRealm, UserRepresentation newUser) {
         if (!defaultRealm.isEnabled()) {
             throw new ForbiddenException();
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
index 35ed9ab..f29f908 100644
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
@@ -16,7 +16,6 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
 import org.jboss.resteasy.logging.Logger;
@@ -25,7 +24,11 @@ import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.models.RealmModel;
+import org.keycloak.services.models.RoleModel;
 import org.keycloak.services.models.UserModel;
+import org.keycloak.services.resources.flows.Flows;
+import org.keycloak.services.resources.flows.OAuthFlows;
+import org.keycloak.services.resources.flows.Urls;
 import org.keycloak.social.AuthCallback;
 import org.keycloak.social.AuthRequest;
 import org.keycloak.social.RequestDetails;
@@ -61,19 +64,6 @@ public class SocialResource {
         this.socialRequestManager = socialRequestManager;
     }
 
-    public static UriBuilder socialServiceBaseUrl(UriInfo uriInfo) {
-        UriBuilder base = uriInfo.getBaseUriBuilder().path(SocialResource.class);
-        return base;
-    }
-
-    public static UriBuilder redirectToProviderAuthUrl(UriInfo uriInfo) {
-        return socialServiceBaseUrl(uriInfo).path(SocialResource.class, "redirectToProviderAuth");
-    }
-
-    public static UriBuilder callbackUrl(UriInfo uriInfo) {
-        return socialServiceBaseUrl(uriInfo).path(SocialResource.class, "callback");
-    }
-
     @GET
     @Path("callback")
     public Response callback() throws URISyntaxException {
@@ -86,41 +76,42 @@ public class SocialResource {
 
                 String realmId = requestData.getClientAttribute("realmId");
 
-                String key = System.getProperty("keycloak.social." + requestData.getProviderId() + ".key");
-                String secret = System.getProperty("keycloak.social." + requestData.getProviderId() + ".secret");
-                String callbackUri = callbackUrl(uriInfo).build().toString();
-
-                SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
+                RealmManager realmManager = new RealmManager(session);
+                RealmModel realm = realmManager.getRealm(realmId);
 
-                AuthCallback callback = new AuthCallback(requestData.getSocialAttributes(), queryParams);
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
 
-                SocialUser socialUser = null;
-                try {
-                    socialUser = provider.processCallback(config, callback);
-                } catch (SocialProviderException e) {
-                    logger.warn("Failed to process social callback", e);
-                    OAuthUtil.securityFailureForward(request, "Failed to process social callback");
-                    return null;
+                if (!realm.isEnabled()) {
+                    return oauth.forwardToSecurityFailure("Realm not enabled.");
                 }
 
-                RealmManager realmManager = new RealmManager(session);
-                RealmModel realm = realmManager.getRealm(realmId);
-
                 if (!realm.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Realm not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Realm not enabled.");
                 }
 
                 String clientId = requestData.getClientAttributes().get("clientId");
 
                 UserModel client = realm.getUser(clientId);
                 if (client == null) {
-                    OAuthUtil.securityFailureForward(request, "Unknown login requester.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Unknown login requester.");
                 }
                 if (!client.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Login requester not enabled.");
+                }
+
+                String key = System.getProperty("keycloak.social." + requestData.getProviderId() + ".key");
+                String secret = System.getProperty("keycloak.social." + requestData.getProviderId() + ".secret");
+                String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
+                SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
+
+                AuthCallback callback = new AuthCallback(requestData.getSocialAttributes(), queryParams);
+
+                SocialUser socialUser = null;
+                try {
+                    socialUser = provider.processCallback(config, callback);
+                } catch (SocialProviderException e) {
+                    logger.warn("Failed to process social callback", e);
+                    return oauth.forwardToSecurityFailure("Failed to process social callback");
                 }
 
                 // TODO Lookup user based on attribute for provider id - this is so a user can have a friendly username + link a
@@ -133,20 +124,20 @@ public class SocialResource {
                     user.setAttribute(provider.getId() + ".id", socialUser.getId());
 
                     // TODO Grant default roles for realm when available
-                    realm.grantRole(user, realm.getRole("user"));
+                    RoleModel defaultRole = realm.getRole("user");
+
+                    realm.grantRole(user, defaultRole);
                 }
 
                 if (!user.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Your account is not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Your account is not enabled.");
                 }
 
                 String scope = requestData.getClientAttributes().get("scope");
                 String state = requestData.getClientAttributes().get("state");
                 String redirectUri = requestData.getClientAttributes().get("redirectUri");
 
-                return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scope, state,
-                        redirectUri, client, user);
+                return oauth.processAccessCode(scope, state, redirectUri, client, user);
             }
         }.call();
     }
@@ -159,13 +150,12 @@ public class SocialResource {
             @QueryParam("redirect_uri") final String redirectUri) {
         SocialProvider provider = getProvider(providerId);
         if (provider == null) {
-            OAuthUtil.securityFailureForward(request, "Social provider not found");
-            return null;
+            return Flows.pages(request).forwardToSecurityFailure("Social provider not found");
         }
 
         String key = System.getProperty("keycloak.social." + providerId + ".key");
         String secret = System.getProperty("keycloak.social." + providerId + ".secret");
-        String callbackUri = callbackUrl(uriInfo).build().toString();
+        String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
 
         SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
 
@@ -181,9 +171,7 @@ public class SocialResource {
 
             return Response.status(Status.FOUND).location(authRequest.getAuthUri()).build();
         } catch (Throwable t) {
-            logger.error("Failed to redirect to social auth", t);
-            OAuthUtil.securityFailureForward(request, "Failed to redirect to social auth");
-            return null;
+            return Flows.pages(request).forwardToSecurityFailure("Failed to redirect to social auth");
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index a9b1e8f..65b30ef 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -10,6 +10,8 @@ import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.HttpResponse;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.SkeletonKeyToken;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.AccessCodeEntry;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.RealmManager;
@@ -17,9 +19,13 @@ import org.keycloak.services.managers.ResourceAdminManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.RoleModel;
+import org.keycloak.services.models.UserCredentialModel;
 import org.keycloak.services.models.UserModel;
+import org.keycloak.services.resources.flows.Flows;
+import org.keycloak.services.resources.flows.OAuthFlows;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
 import javax.ws.rs.GET;
 import javax.ws.rs.NotAuthorizedException;
 import javax.ws.rs.POST;
@@ -30,14 +36,17 @@ 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.NewCookie;
 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.security.PrivateKey;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.StringTokenizer;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -72,8 +81,7 @@ public class TokenService {
     }
 
     public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
-        UriBuilder base = uriInfo.getBaseUriBuilder()
-                .path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
+        UriBuilder base = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
         return base;
     }
 
@@ -104,7 +112,6 @@ public class TokenService {
         return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
     }
 
-
     @Path("grants/identity-token")
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@@ -174,52 +181,126 @@ public class TokenService {
     @Path("auth/request/login")
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public Response processLogin(final MultivaluedMap<String, String> formData) {
+    public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam,
+            @QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect,
+            final MultivaluedMap<String, String> formData) {
         return new Transaction() {
             protected Response callImpl() {
-                String clientId = formData.getFirst("client_id");
-                String scopeParam = formData.getFirst("scope");
-                String state = formData.getFirst("state");
-                String redirect = formData.getFirst("redirect_uri");
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
 
                 if (!realm.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Realm not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Realm not enabled.");
                 }
                 UserModel client = realm.getUser(clientId);
                 if (client == null) {
-                    OAuthUtil.securityFailureForward(request, "Unknown login requester.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Unknown login requester.");
                 }
                 if (!client.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Login requester not enabled.");
                 }
                 String username = formData.getFirst("username");
                 UserModel user = realm.getUser(username);
                 if (user == null) {
                     logger.error("Incorrect user name.");
-                    request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
-                    request.setAttribute("KEYCLOAK_FORM_DATA", formData);
-                    OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
-                    return null;
+
+                    return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
+                            .forwardToLogin();
                 }
                 if (!user.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Your account is not enabled.");
-                    return null;
+                    return oauth.forwardToSecurityFailure("Your account is not enabled.");
                 }
                 boolean authenticated = authManager.authenticateForm(realm, user, formData);
                 if (!authenticated) {
                     logger.error("Authentication failed");
-                    request.setAttribute("username", username);
-                    request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
-                    request.setAttribute("KEYCLOAK_FORM_DATA", formData);
-                    OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
-                    return null;
+
+                    return Flows.forms(realm, request).setError("Invalid username or password").setFormData(formData)
+                            .forwardToLogin();
                 }
 
-                return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scopeParam, state,
-                        redirect, client, user);
+                return oauth.processAccessCode(scopeParam, state, redirect, client, user);
+            }
+        }.call();
+    }
+
+    @Path("registrations")
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response processRegister(@QueryParam("client_id") final String clientId,
+            @QueryParam("scope") final String scopeParam, @QueryParam("state") final String state,
+            @QueryParam("redirect_uri") final String redirect, final MultivaluedMap<String, String> formData) {
+        return new Transaction() {
+            @Override
+            protected Response callImpl() {
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
+
+                if (!realm.isEnabled()) {
+                    return oauth.forwardToSecurityFailure("Realm not enabled");
+                }
+                UserModel client = realm.getUser(clientId);
+                if (client == null) {
+                    return oauth.forwardToSecurityFailure("Unknown login requester.");
+                }
+
+                if (!client.isEnabled()) {
+                    return oauth.forwardToSecurityFailure("Login requester not enabled.");
+                }
+
+                if (!realm.isRegistrationAllowed()) {
+                    return oauth.forwardToSecurityFailure("Registration not allowed");
+                }
+
+                String error = validateRegistrationForm(formData);
+                if (error != null) {
+                    return Flows.forms(realm, request).setError(error).setFormData(formData).forwardToRegistration();
+                }
+
+                String username = formData.getFirst("username");
+
+                UserModel user = realm.getUser(username);
+                if (user != null) {
+                    return Flows.forms(realm, request).setError("Username already exists.").setFormData(formData)
+                            .forwardToRegistration();
+                }
+
+                user = realm.addUser(username);
+
+                String fullname = formData.getFirst("name");
+                if (fullname != null) {
+                    StringTokenizer tokenizer = new StringTokenizer(fullname, " ");
+                    StringBuffer first = null;
+                    String last = "";
+                    while (tokenizer.hasMoreTokens()) {
+                        String token = tokenizer.nextToken();
+                        if (tokenizer.hasMoreTokens()) {
+                            if (first == null) {
+                                first = new StringBuffer();
+                            } else {
+                                first.append(" ");
+                            }
+                            first.append(token);
+                        } else {
+                            last = token;
+                        }
+                    }
+                    if (first == null)
+                        first = new StringBuffer();
+                    user.setFirstName(first.toString());
+                    user.setLastName(last);
+                }
+
+                user.setEmail(formData.getFirst("email"));
+
+                UserCredentialModel credentials = new UserCredentialModel();
+                credentials.setType(CredentialRepresentation.PASSWORD);
+                credentials.setValue(formData.getFirst("password"));
+                realm.updateCredential(user, credentials);
+
+                // TODO Grant default roles for realm when available
+                RoleModel defaultRole = realm.getRole("user");
+                
+                realm.grantRole(user, defaultRole);
+
+                return processLogin(clientId, scopeParam, state, redirect, formData);
             }
         }.call();
     }
@@ -276,7 +357,6 @@ public class TokenService {
                     return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
                 }
 
-
                 JWSInput input = new JWSInput(code, providers);
                 boolean verifiedCode = false;
                 try {
@@ -288,7 +368,8 @@ public class TokenService {
                     Map<String, String> res = new HashMap<String, String>();
                     res.put("error", "invalid_grant");
                     res.put("error_description", "Unable to verify code signature");
-                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+                            .build();
                 }
                 String key = input.readContent(String.class);
                 AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
@@ -296,25 +377,29 @@ public class TokenService {
                     Map<String, String> res = new HashMap<String, String>();
                     res.put("error", "invalid_grant");
                     res.put("error_description", "Code not found");
-                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+                            .build();
                 }
                 if (accessCode.isExpired()) {
                     Map<String, String> res = new HashMap<String, String>();
                     res.put("error", "invalid_grant");
                     res.put("error_description", "Code is expired");
-                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+                            .build();
                 }
                 if (!accessCode.getToken().isActive()) {
                     Map<String, String> res = new HashMap<String, String>();
                     res.put("error", "invalid_grant");
                     res.put("error_description", "Token expired");
-                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+                            .build();
                 }
                 if (!client.getLoginName().equals(accessCode.getClient().getLoginName())) {
                     Map<String, String> res = new HashMap<String, String>();
                     res.put("error", "invalid_grant");
                     res.put("error_description", "Auth error");
-                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+                    return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+                            .build();
                 }
                 logger.info("accessRequest SUCCESS");
                 AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
@@ -331,9 +416,7 @@ public class TokenService {
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
-        String encodedToken = new JWSBuilder()
-                .content(tokenBytes)
-                .rsa256(privateKey);
+        String encodedToken = new JWSBuilder().content(tokenBytes).rsa256(privateKey);
 
         return accessTokenResponse(token, encodedToken);
     }
@@ -352,25 +435,25 @@ public class TokenService {
     @Path("login")
     @GET
     public Response loginPage(final @QueryParam("response_type") String responseType,
-                              final @QueryParam("redirect_uri") String redirect,
-                              final @QueryParam("client_id") String clientId,
-                              final @QueryParam("scope") String scopeParam,
-                              final @QueryParam("state") String state) {
+            final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
+            final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
         return new Transaction() {
             protected Response callImpl() {
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
+
                 if (!realm.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Realm not enabled");
+                    oauth.forwardToSecurityFailure("Realm not enabled");
                     return null;
                 }
                 UserModel client = realm.getUser(clientId);
                 if (client == null) {
-                    OAuthUtil.securityFailureForward(request, "Unknown login requester.");
+                    oauth.forwardToSecurityFailure("Unknown login requester.");
                     transaction.rollback();
                     return null;
                 }
 
                 if (!client.isEnabled()) {
-                    OAuthUtil.securityFailureForward(request, "Login requester not enabled.");
+                    oauth.forwardToSecurityFailure("Login requester not enabled.");
                     transaction.rollback();
                     session.close();
                     return null;
@@ -380,7 +463,7 @@ public class TokenService {
                 RoleModel identityRequestRole = realm.getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
                 boolean isResource = realm.hasRole(client, resourceRole);
                 if (!isResource && !realm.hasRole(client, identityRequestRole)) {
-                    OAuthUtil.securityFailureForward(request, "Login requester not allowed to request login.");
+                    oauth.forwardToSecurityFailure("Login requester not allowed to request login.");
                     transaction.rollback();
                     session.close();
                     return null;
@@ -389,12 +472,42 @@ public class TokenService {
                 UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
                 if (user != null) {
                     logger.info(user.getLoginName() + " already logged in.");
-                    return OAuthUtil.processAccessCode(realm, tokenManager, authManager, request, uriInfo, scopeParam, state,
-                            redirect, client, user);
+                    return oauth.processAccessCode(scopeParam, state, redirect, client, user);
                 }
 
-                OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
-                return null;
+                return Flows.forms(realm, request).forwardToLogin();
+            }
+        }.call();
+    }
+
+    @Path("registrations")
+    @GET
+    public Response registerPage(final @QueryParam("response_type") String responseType,
+            final @QueryParam("redirect_uri") String redirect, final @QueryParam("client_id") String clientId,
+            final @QueryParam("scope") String scopeParam, final @QueryParam("state") String state) {
+        return new Transaction() {
+            protected Response callImpl() {
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
+
+                if (!realm.isEnabled()) {
+                    return oauth.forwardToSecurityFailure("Realm not enabled");
+                }
+                UserModel client = realm.getUser(clientId);
+                if (client == null) {
+                    return oauth.forwardToSecurityFailure("Unknown login requester.");
+                }
+
+                if (!client.isEnabled()) {
+                    return oauth.forwardToSecurityFailure("Login requester not enabled.");
+                }
+
+                if (!realm.isRegistrationAllowed()) {
+                    return oauth.forwardToSecurityFailure("Registration not allowed");
+                }
+
+                authManager.expireIdentityCookie(realm, uriInfo);
+
+                return Flows.forms(realm, request).forwardToRegistration();
             }
         }.call();
     }
@@ -425,6 +538,8 @@ public class TokenService {
     public Response processOAuth(final MultivaluedMap<String, String> formData) {
         return new Transaction() {
             protected Response callImpl() {
+                OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
+
                 String code = formData.getFirst("code");
                 JWSInput input = new JWSInput(code, providers);
                 boolean verifiedCode = false;
@@ -434,16 +549,12 @@ public class TokenService {
                     logger.debug("Failed to verify signature", ignored);
                 }
                 if (!verifiedCode) {
-                    OAuthUtil.securityFailureForward(request, "Illegal access code.");
-                    session.close();
-                    return null;
+                    return oauth.forwardToSecurityFailure("Illegal access code.");
                 }
                 String key = input.readContent(String.class);
                 AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
                 if (accessCodeEntry == null) {
-                    OAuthUtil.securityFailureForward(request, "Unknown access code.");
-                    session.close();
-                    return null;
+                    return oauth.forwardToSecurityFailure("Unknown access code.");
                 }
 
                 String redirect = accessCodeEntry.getRedirectUri();
@@ -453,16 +564,45 @@ public class TokenService {
                     return redirectAccessDenied(redirect, state);
                 }
 
-                return OAuthUtil.redirectAccessCode(realm, authManager, uriInfo, accessCodeEntry, state, redirect);
+                return oauth.redirectAccessCode(accessCodeEntry, state, redirect);
             }
         }.call();
     }
 
     protected Response redirectAccessDenied(String redirect, String state) {
         UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", "access_denied");
-        if (state != null) redirectUri.queryParam("state", state);
+        if (state != null)
+            redirectUri.queryParam("state", state);
         Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
         return location.build();
     }
 
+    private String validateRegistrationForm(MultivaluedMap<String, String> formData) {
+        if (isEmpty(formData.getFirst("name"))) {
+            return "Please specify full name";
+        }
+
+        if (isEmpty(formData.getFirst("email"))) {
+            return "Please specify email";
+        }
+
+        if (isEmpty(formData.getFirst("username"))) {
+            return "Please specify username";
+        }
+
+        if (isEmpty(formData.getFirst("password"))) {
+            return "Please specify password";
+        }
+
+        if (!formData.getFirst("password").equals(formData.getFirst("password-confirm"))) {
+            return "Password confirmation doesn't match.";
+        }
+
+        return null;
+    }
+
+    private boolean isEmpty(String s) {
+        return s == null || s.length() == 0;
+    }
+
 }