keycloak-uncached

Changes

integration/pom.xml 21(+21 -0)

pom.xml 12(+12 -0)

services/pom.xml 36(+36 -0)

services/src/main/java/org/keycloak/services/resources/SkeletonKeyApplication.java 55(+0 -55)

Details

diff --git a/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java b/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
index 3bca480..9b83907 100755
--- a/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
+++ b/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
@@ -36,7 +36,7 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
    @Override
    public ObjectMapper getContext(Class<?> type)
    {
-      if (type.getPackage().getName().startsWith("org.jboss.resteasy.skeleton.key")) return mapper;
+      if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
       return null;
    }
 }
diff --git a/integration/as7-eap6/adapter/pom.xml b/integration/as7-eap6/adapter/pom.xml
new file mode 100755
index 0000000..b4ad78f
--- /dev/null
+++ b/integration/as7-eap6/adapter/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<project>
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-alpha-1</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-as7-adapter</artifactId>
+    <name>Keycloak AS7 Integration</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <version>3.1.2.GA</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>jose-jwt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+            <version>1.0.0.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-client</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jboss.web</groupId>
+            <artifactId>jbossweb</artifactId>
+            <version>7.0.17.Final</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.as</groupId>
+            <artifactId>jboss-as-web</artifactId>
+            <version>7.1.2.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.picketbox</groupId>
+            <artifactId>picketbox</artifactId>
+            <scope>provided</scope>
+            <version>4.0.7.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java
new file mode 100755
index 0000000..65c9ddb
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java
@@ -0,0 +1,14 @@
+package org.keycloak.adapters.as7;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface Actions
+{
+   public static final String J_OAUTH_ADMIN_FORCED_LOGOUT = "j_oauth_admin_forced_logout";
+   public static final String J_OAUTH_LOGOUT = "j_oauth_logout";
+   public static final String J_OAUTH_RESOLVE_ACCESS_CODE = "j_oauth_resolve_access_code";
+   public static final String J_OAUTH_REMOTE_LOGOUT = "j_oauth_remote_logout";
+   public static final String J_OAUTH_TOKEN_GRANT = "j_oauth_token_grant";
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
new file mode 100755
index 0000000..2f7e95c
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
@@ -0,0 +1,87 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.authenticator.AuthenticatorBase;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.jboss.logging.Logger;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Uses a configured remote auth server to do Bearer token authentication only.  SkeletonKeyTokens are used
+ * to provide user data and role mappings.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements LifecycleListener
+{
+   private static final Logger log = Logger.getLogger(BearerTokenAuthenticatorValve.class);
+   protected ManagedResourceConfig remoteSkeletonKeyConfig;
+   protected ResourceMetadata resourceMetadata;
+
+   @Override
+   public void start() throws LifecycleException
+   {
+      super.start();
+      StandardContext standardContext = (StandardContext)context;
+      standardContext.addLifecycleListener(this);
+   }
+
+   @Override
+   public void lifecycleEvent(LifecycleEvent event)
+   {
+      if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+   }
+
+   protected void init()
+   {
+      ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
+      resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
+      remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
+   }
+
+   @Override
+   public void invoke(Request request, Response response) throws IOException, ServletException
+   {
+      try
+      {
+         super.invoke(request, response);
+      }
+      finally
+      {
+         ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+      }
+   }
+
+   @Override
+   protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+   {
+      try
+      {
+         CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true);
+         if (bearer.login(request, response))
+         {
+            return true;
+       }
+         return false;
+      }
+      catch (LoginException e)
+      {
+      }
+      return false;
+   }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
new file mode 100755
index 0000000..7d14c1d
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
@@ -0,0 +1,163 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.connector.Request;
+import org.jboss.logging.Logger;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeyPrincipal;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.VerificationException;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CatalinaBearerTokenAuthenticator
+{
+   protected ResourceMetadata resourceMetadata;
+   protected boolean challenge;
+   protected Logger log = Logger.getLogger(CatalinaBearerTokenAuthenticator.class);
+   protected String tokenString;
+   protected SkeletonKeyToken token;
+   private Principal principal;
+   protected boolean propagateToken;
+
+   public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge)
+   {
+      this.resourceMetadata = resourceMetadata;
+      this.challenge = challenge;
+      this.propagateToken = propagateToken;
+   }
+
+   public ResourceMetadata getResourceMetadata()
+   {
+      return resourceMetadata;
+   }
+
+   public String getTokenString()
+   {
+      return tokenString;
+   }
+
+   public SkeletonKeyToken getToken()
+   {
+      return token;
+   }
+
+   public Principal getPrincipal()
+   {
+      return principal;
+   }
+
+   public boolean login(Request request, HttpServletResponse response) throws LoginException, IOException
+   {
+      String authHeader = request.getHeader("Authorization");
+      if (authHeader == null)
+      {
+         if (challenge)
+         {
+            challengeResponse(response, null, null);
+            return false;
+         }
+         else
+         {
+            return false;
+         }
+      }
+
+      String[] split = authHeader.trim().split("\\s+");
+      if (split == null || split.length != 2) challengeResponse(response, null, null);
+      if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(response, null, null);
+
+
+      tokenString = split[1];
+
+      try
+      {
+         token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata);
+      }
+      catch (VerificationException e)
+      {
+         log.error("Failed to verify token", e);
+         challengeResponse(response, "invalid_token", e.getMessage());
+      }
+      boolean verifyCaller = false;
+      Set<String> roles = null;
+      if (resourceMetadata.getResourceName() != null)
+      {
+         SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
+         if (access != null) roles = access.getRoles();
+         verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
+      }
+      else
+      {
+         verifyCaller = token.isVerifyCaller();
+         SkeletonKeyToken.Access access = token.getRealmAccess();
+         if (access != null) roles = access.getRoles();
+      }
+      String surrogate = null;
+      if (verifyCaller)
+      {
+         if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0)
+         {
+            response.sendError(400);
+            throw new LoginException("No trusted certificates in token");
+         }
+         // for now, we just make sure JBoss Web did two-way SSL
+         // assume JBoss Web verifies the client cert
+         X509Certificate[] chain = request.getCertificateChain();
+         if (chain == null || chain.length == 0)
+         {
+            response.sendError(400);
+            throw new LoginException("No certificates provided by jboss web to verify the caller");
+         }
+         surrogate = chain[0].getSubjectX500Principal().getName();
+      }
+      SkeletonKeyPrincipal skeletonKeyPrincipal = new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
+      principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
+      request.setUserPrincipal(principal);
+      request.setAuthType("OAUTH_BEARER");
+      if (propagateToken)
+      {
+         SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
+         request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+         ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+      }
+
+      return true;
+   }
+
+
+   protected void challengeResponse(HttpServletResponse response, String error, String description) throws LoginException
+   {
+      StringBuilder header = new StringBuilder("Bearer realm=\"");
+      header.append(resourceMetadata.getRealm()).append("\"");
+      if (error != null)
+      {
+         header.append(", error=\"").append(error).append("\"");
+      }
+      if (description != null)
+      {
+         header.append(", error_description=\"").append(description).append("\"");
+      }
+      response.setHeader("WWW-Authenticate", header.toString());
+      try
+      {
+         response.sendError(401);
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);
+      }
+      throw new LoginException("Challenged");
+   }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java
new file mode 100755
index 0000000..bf783bd
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java
@@ -0,0 +1,138 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Realm;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.as.web.security.JBossGenericPrincipal;
+import org.jboss.security.NestableGroup;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContext;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CatalinaSecurityContextHelper
+{
+   public GenericPrincipal createPrincipal(Realm realm, Principal identity, Collection<String> roleSet)
+   {
+      Subject subject = new Subject();
+      String credentials = "";
+      Set<Principal> principals = subject.getPrincipals();
+      principals.add(identity);
+      Group[] roleSets = getRoleSets(roleSet);
+      for(int g = 0; g < roleSets.length; g ++)
+      {
+         Group group = roleSets[g];
+         String name = group.getName();
+         Group subjectGroup = createGroup(name, principals);
+         if( subjectGroup instanceof NestableGroup)
+         {
+            /* A NestableGroup only allows Groups to be added to it so we
+            need to add a SimpleGroup to subjectRoles to contain the roles
+            */
+            SimpleGroup tmp = new SimpleGroup("Roles");
+            subjectGroup.addMember(tmp);
+            subjectGroup = tmp;
+         }
+         // Copy the group members to the Subject group
+         Enumeration<? extends Principal> members = group.members();
+         while( members.hasMoreElements() )
+         {
+            Principal role = (Principal) members.nextElement();
+            subjectGroup.addMember(role);
+         }
+      }
+      // add the CallerPrincipal group if none has been added in getRoleSets
+      Group callerGroup = new SimpleGroup(SecurityConstants.CALLER_PRINCIPAL_GROUP);
+      callerGroup.addMember(identity);
+      principals.add(callerGroup);
+      SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+      Principal userPrincipal = getPrincipal(subject);
+      sc.getUtil().createSubjectInfo(userPrincipal, credentials, subject);
+      List<String> rolesAsStringList = new ArrayList<String>();
+      rolesAsStringList.addAll(roleSet);
+      return  new JBossGenericPrincipal(realm, userPrincipal.getName(), null, rolesAsStringList,
+              userPrincipal, null, credentials, null, subject);
+
+   }
+   /**
+    * Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is
+    * considered or the single principal inside the CallerPrincipal group.
+    *
+    * @param subject
+    * @return the authenticated principal
+    */
+   protected Principal getPrincipal(Subject subject) {
+      Principal principal = null;
+      Principal callerPrincipal = null;
+      if (subject != null) {
+         Set<Principal> principals = subject.getPrincipals();
+         if (principals != null && !principals.isEmpty()) {
+            for (Principal p : principals) {
+               if (!(p instanceof Group) && principal == null) {
+                  principal = p;
+               }
+               if (p instanceof Group) {
+                  Group g = Group.class.cast(p);
+                  if (g.getName().equals(SecurityConstants.CALLER_PRINCIPAL_GROUP) && callerPrincipal == null) {
+                     Enumeration<? extends Principal> e = g.members();
+                     if (e.hasMoreElements())
+                        callerPrincipal = e.nextElement();
+                  }
+               }
+            }
+         }
+      }
+      return callerPrincipal == null ? principal : callerPrincipal;
+   }
+
+   protected Group createGroup(String name, Set<Principal> principals)
+   {
+      Group roles = null;
+      Iterator<Principal> iter = principals.iterator();
+      while( iter.hasNext() )
+      {
+         Object next = iter.next();
+         if( (next instanceof Group) == false )
+            continue;
+         Group grp = (Group) next;
+         if( grp.getName().equals(name) )
+         {
+            roles = grp;
+            break;
+         }
+      }
+      // If we did not find a group create one
+      if( roles == null )
+      {
+         roles = new SimpleGroup(name);
+         principals.add(roles);
+      }
+      return roles;
+   }
+
+   protected Group[] getRoleSets(Collection<String> roleSet)
+   {
+      SimpleGroup roles = new SimpleGroup("Roles");
+      Group[] roleSets = {roles};
+      for (String role : roleSet)
+      {
+         roles.addMember(new SimplePrincipal(role));
+      }
+      return roleSets;
+   }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java
new file mode 100755
index 0000000..73372e3
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java
@@ -0,0 +1,279 @@
+package org.keycloak.adapters.as7.config;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthServerConfig
+{
+   @JsonProperty("realm")
+   protected String realm;
+
+   @JsonProperty("realm-private-key")
+   protected String realmPrivateKey;
+
+   @JsonProperty("realm-public-key")
+   protected String realmPublicKey;
+
+   @JsonProperty("realm-keystore")
+   protected String realmKeyStore;
+
+   @JsonProperty("realm-keystore-password")
+   protected String realmKeystorePassword;
+
+   @JsonProperty("realm-key-alias")
+   protected String realmKeyAlias;
+
+   @JsonProperty("realm-private-key-password")
+   protected String realmPrivateKeyPassword;
+
+   @JsonProperty("access-code-lifetime")
+   protected int accessCodeLifetime;
+
+   @JsonProperty("token-lifetime")
+   protected int tokenLifetime;
+
+   @JsonProperty("admin-role")
+   protected String adminRole;
+
+   @JsonProperty("login-role")
+   protected String loginRole;
+
+   @JsonProperty("oauth-client-role")
+   protected String clientRole;
+
+   @JsonProperty("wildcard-role")
+   protected String wildcardRole;
+
+   @JsonProperty("cancel-propagation")
+   protected boolean cancelPropagation;
+
+   @JsonProperty("sso-disabled")
+   protected boolean ssoDisabled;
+
+   // these properties are optional and used to provide connection metadata when the server wants to make
+   // remote SSL connections
+
+   protected String truststore;
+   @JsonProperty("truststore-password")
+   protected String truststorePassword;
+   @JsonProperty("client-keystore")
+   protected String clientKeystore;
+   @JsonProperty("client-keystore-password")
+   protected String clientKeystorePassword;
+   @JsonProperty("client-key-password")
+   protected String clientKeyPassword;
+
+   protected List<String> resources = new ArrayList<String>();
+
+
+   public String getRealm()
+   {
+      return realm;
+   }
+
+   public void setRealm(String realm)
+   {
+      this.realm = realm;
+   }
+
+   public String getRealmPrivateKey()
+   {
+      return realmPrivateKey;
+   }
+
+   public void setRealmPrivateKey(String realmPrivateKey)
+   {
+      this.realmPrivateKey = realmPrivateKey;
+   }
+
+   public String getRealmPublicKey()
+   {
+      return realmPublicKey;
+   }
+
+   public void setRealmPublicKey(String realmPublicKey)
+   {
+      this.realmPublicKey = realmPublicKey;
+   }
+
+   public int getAccessCodeLifetime()
+   {
+      return accessCodeLifetime;
+   }
+
+   public void setAccessCodeLifetime(int accessCodeLifetime)
+   {
+      this.accessCodeLifetime = accessCodeLifetime;
+   }
+
+   public String getTruststore()
+   {
+      return truststore;
+   }
+
+   public void setTruststore(String truststore)
+   {
+      this.truststore = truststore;
+   }
+
+   public String getTruststorePassword()
+   {
+      return truststorePassword;
+   }
+
+   public void setTruststorePassword(String truststorePassword)
+   {
+      this.truststorePassword = truststorePassword;
+   }
+
+   public String getClientKeystore()
+   {
+      return clientKeystore;
+   }
+
+   public void setClientKeystore(String clientKeystore)
+   {
+      this.clientKeystore = clientKeystore;
+   }
+
+   public String getClientKeystorePassword()
+   {
+      return clientKeystorePassword;
+   }
+
+   public void setClientKeystorePassword(String clientKeystorePassword)
+   {
+      this.clientKeystorePassword = clientKeystorePassword;
+   }
+
+   public String getClientKeyPassword()
+   {
+      return clientKeyPassword;
+   }
+
+   public void setClientKeyPassword(String clientKeyPassword)
+   {
+      this.clientKeyPassword = clientKeyPassword;
+   }
+
+   public boolean isCancelPropagation()
+   {
+      return cancelPropagation;
+   }
+
+   public void setCancelPropagation(boolean cancelPropagation)
+   {
+      this.cancelPropagation = cancelPropagation;
+   }
+
+   public boolean isSsoDisabled()
+   {
+      return ssoDisabled;
+   }
+
+   public void setSsoDisabled(boolean ssoDisabled)
+   {
+      this.ssoDisabled = ssoDisabled;
+   }
+
+   public List<String> getResources()
+   {
+      return resources;
+   }
+
+   public String getAdminRole()
+   {
+      return adminRole;
+   }
+
+   public void setAdminRole(String adminRole)
+   {
+      this.adminRole = adminRole;
+   }
+
+   public String getLoginRole()
+   {
+      return loginRole;
+   }
+
+   public void setLoginRole(String loginRole)
+   {
+      this.loginRole = loginRole;
+   }
+
+   public String getClientRole()
+   {
+      return clientRole;
+   }
+
+   public void setClientRole(String clientRole)
+   {
+      this.clientRole = clientRole;
+   }
+
+   public String getWildcardRole()
+   {
+      return wildcardRole;
+   }
+
+   public void setWildcardRole(String wildcardRole)
+   {
+      this.wildcardRole = wildcardRole;
+   }
+
+   public String getRealmKeyStore()
+   {
+      return realmKeyStore;
+   }
+
+   public void setRealmKeyStore(String realmKeyStore)
+   {
+      this.realmKeyStore = realmKeyStore;
+   }
+
+   public String getRealmKeystorePassword()
+   {
+      return realmKeystorePassword;
+   }
+
+   public void setRealmKeystorePassword(String realmKeystorePassword)
+   {
+      this.realmKeystorePassword = realmKeystorePassword;
+   }
+
+   public String getRealmKeyAlias()
+   {
+      return realmKeyAlias;
+   }
+
+   public void setRealmKeyAlias(String realmKeyAlias)
+   {
+      this.realmKeyAlias = realmKeyAlias;
+   }
+
+   public String getRealmPrivateKeyPassword()
+   {
+      return realmPrivateKeyPassword;
+   }
+
+   public void setRealmPrivateKeyPassword(String realmPrivateKeyPassword)
+   {
+      this.realmPrivateKeyPassword = realmPrivateKeyPassword;
+   }
+
+   public int getTokenLifetime()
+   {
+      return tokenLifetime;
+   }
+
+   public void setTokenLifetime(int tokenLifetime)
+   {
+      this.tokenLifetime = tokenLifetime;
+   }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
new file mode 100755
index 0000000..e1bef4b
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
@@ -0,0 +1,213 @@
+package org.keycloak.adapters.as7.config;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.annotate.JsonPropertyOrder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@JsonPropertyOrder({"realm", "resource", "realm-public-key", "admin-role", "auth-url", "code-url", "truststore", "truststore-password", "client-id", "client-credentials"})
+public class ManagedResourceConfig
+{
+   @JsonProperty("realm")
+   protected String realm;
+   @JsonProperty("resource")
+   protected String resource;
+
+   @JsonProperty("realm-public-key")
+   protected String realmKey;
+
+   @JsonProperty("admin-role")
+   protected String adminRole;
+
+   @JsonProperty("auth-url")
+   protected String authUrl;
+   @JsonProperty("code-url")
+   protected String codeUrl;
+
+   @JsonProperty("allow-any-hostname")
+   protected boolean allowAnyHostname;
+
+   @JsonProperty("truststore")
+   protected String truststore;
+
+   @JsonProperty("truststore-password")
+   protected String truststorePassword;
+   @JsonProperty("client-id")
+   protected String clientId;
+   @JsonProperty("client-keystore")
+   protected String clientKeystore;
+   @JsonProperty("client-keystore-password")
+   protected String clientKeystorePassword;
+   @JsonProperty("client-key-password")
+   protected String clientKeyPassword;
+
+   @JsonProperty("client-credentials")
+   protected Map<String, String> clientCredentials = new HashMap<String, String>();
+
+   @JsonProperty("connection-pool-size")
+   protected int connectionPoolSize;
+
+   @JsonProperty("cancel-propagation")
+   protected boolean cancelPropagation;
+
+
+   public String getRealm()
+   {
+      return realm;
+   }
+
+   public void setRealm(String realm)
+   {
+      this.realm = realm;
+   }
+
+   public String getResource()
+   {
+      return resource;
+   }
+
+   public void setResource(String resource)
+   {
+      this.resource = resource;
+   }
+
+   public String getRealmKey()
+   {
+      return realmKey;
+   }
+
+   public void setRealmKey(String realmKey)
+   {
+      this.realmKey = realmKey;
+   }
+
+   public String getAuthUrl()
+   {
+      return authUrl;
+   }
+
+   public void setAuthUrl(String authUrl)
+   {
+      this.authUrl = authUrl;
+   }
+
+   public String getCodeUrl()
+   {
+      return codeUrl;
+   }
+
+   public void setCodeUrl(String codeUrl)
+   {
+      this.codeUrl = codeUrl;
+   }
+
+   public boolean isAllowAnyHostname()
+   {
+      return allowAnyHostname;
+   }
+
+   public void setAllowAnyHostname(boolean allowAnyHostname)
+   {
+      this.allowAnyHostname = allowAnyHostname;
+   }
+
+   public String getTruststore()
+   {
+      return truststore;
+   }
+
+   public void setTruststore(String truststore)
+   {
+      this.truststore = truststore;
+   }
+
+   public String getTruststorePassword()
+   {
+      return truststorePassword;
+   }
+
+   public void setTruststorePassword(String truststorePassword)
+   {
+      this.truststorePassword = truststorePassword;
+   }
+
+   public String getClientId()
+   {
+      return clientId;
+   }
+
+   public void setClientId(String clientId)
+   {
+      this.clientId = clientId;
+   }
+
+   public Map<String, String> getClientCredentials()
+   {
+      return clientCredentials;
+   }
+
+   public String getClientKeystore()
+   {
+      return clientKeystore;
+   }
+
+   public void setClientKeystore(String clientKeystore)
+   {
+      this.clientKeystore = clientKeystore;
+   }
+
+   public String getClientKeystorePassword()
+   {
+      return clientKeystorePassword;
+   }
+
+   public void setClientKeystorePassword(String clientKeystorePassword)
+   {
+      this.clientKeystorePassword = clientKeystorePassword;
+   }
+
+   public String getClientKeyPassword()
+   {
+      return clientKeyPassword;
+   }
+
+   public void setClientKeyPassword(String clientKeyPassword)
+   {
+      this.clientKeyPassword = clientKeyPassword;
+   }
+
+   public int getConnectionPoolSize()
+   {
+      return connectionPoolSize;
+   }
+
+   public void setConnectionPoolSize(int connectionPoolSize)
+   {
+      this.connectionPoolSize = connectionPoolSize;
+   }
+
+   public boolean isCancelPropagation()
+   {
+      return cancelPropagation;
+   }
+
+   public void setCancelPropagation(boolean cancelPropagation)
+   {
+      this.cancelPropagation = cancelPropagation;
+   }
+
+   public String getAdminRole()
+   {
+      return adminRole;
+   }
+
+   public void setAdminRole(String adminRole)
+   {
+      this.adminRole = adminRole;
+   }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
new file mode 100755
index 0000000..75339d1
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
@@ -0,0 +1,139 @@
+package org.keycloak.adapters.as7.config;
+
+import org.apache.catalina.Context;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.logging.Logger;
+import org.keycloak.EnvUtil;
+import org.keycloak.PemUtils;
+import org.keycloak.ResourceMetadata;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.PublicKey;
+
+public class ManagedResourceConfigLoader
+{
+   static final Logger log = Logger.getLogger(ManagedResourceConfigLoader.class);
+   protected ManagedResourceConfig remoteSkeletonKeyConfig;
+   protected ResourceMetadata resourceMetadata;
+
+   public ManagedResourceConfigLoader(Context context)
+   {
+      ObjectMapper mapper = new ObjectMapper();
+      mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+      InputStream is = null;
+      String path = context.getServletContext().getInitParameter("skeleton.key.config.file");
+      if (path == null)
+      {
+         is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
+      }
+      else
+      {
+         try
+         {
+            is = new FileInputStream(path);
+         }
+         catch (FileNotFoundException e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      remoteSkeletonKeyConfig = null;
+      try
+      {
+         remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);
+      }
+
+      String name = remoteSkeletonKeyConfig.getResource();
+      String realm = remoteSkeletonKeyConfig.getRealm();
+      if (realm == null) throw new RuntimeException("Must set 'realm' in config");
+
+      String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
+      if (realmKeyPem == null)
+      {
+         throw new IllegalArgumentException("You must set the realm-public-key");
+      }
+
+      PublicKey realmKey = null;
+      try
+      {
+         realmKey = PemUtils.decodePublicKey(realmKeyPem);
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException(e);
+      }
+      resourceMetadata = new ResourceMetadata();
+      resourceMetadata.setRealm(realm);
+      resourceMetadata.setResourceName(name);
+      resourceMetadata.setRealmKey(realmKey);
+
+
+      String truststore = remoteSkeletonKeyConfig.getTruststore();
+      if (truststore != null)
+      {
+         truststore = EnvUtil.replace(truststore);
+         String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
+         KeyStore trust = null;
+         try
+         {
+            trust = loadKeyStore(truststore, truststorePassword);
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failed to load truststore", e);
+         }
+         resourceMetadata.setTruststore(trust);
+      }
+      String clientKeystore = remoteSkeletonKeyConfig.getClientKeystore();
+      String clientKeyPassword = null;
+      if (clientKeystore != null)
+      {
+         clientKeystore = EnvUtil.replace(clientKeystore);
+         String clientKeystorePassword = remoteSkeletonKeyConfig.getClientKeystorePassword();
+         KeyStore serverKS = null;
+         try
+         {
+            serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failed to load keystore", e);
+         }
+         resourceMetadata.setClientKeystore(serverKS);
+         clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
+         resourceMetadata.setClientKeyPassword(clientKeyPassword);
+      }
+
+   }
+   public static KeyStore loadKeyStore(String filename, String password) throws Exception
+   {
+      KeyStore trustStore = KeyStore.getInstance(KeyStore
+              .getDefaultType());
+      File truststoreFile = new File(filename);
+      FileInputStream trustStream = new FileInputStream(truststoreFile);
+      trustStore.load(trustStream, password.toCharArray());
+      trustStream.close();
+      return trustStore;
+   }
+
+   public ManagedResourceConfig getRemoteSkeletonKeyConfig()
+   {
+      return remoteSkeletonKeyConfig;
+   }
+
+   public ResourceMetadata getResourceMetadata()
+   {
+      return resourceMetadata;
+   }
+
+}
\ No newline at end of file
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java
new file mode 100755
index 0000000..abc1dca
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java
@@ -0,0 +1,1050 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.FormAuthenticator;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.bouncycastle.openssl.PEMWriter;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.jose.jws.JWSBuilder;
+import org.jboss.resteasy.jose.jws.JWSInput;
+import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
+import org.jboss.resteasy.jwt.JsonSerialization;
+import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
+import org.jboss.resteasy.plugins.server.servlet.ServletUtil;
+import org.keycloak.EnvUtil;
+import org.keycloak.PemUtils;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.as7.config.AuthServerConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.jboss.resteasy.spi.ResteasyUriInfo;
+import org.jboss.resteasy.util.BasicAuthHelper;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriBuilder;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Turns a web deployment into an authentication server that follwos the OAuth 2 protocol and Skeleton Key bearer tokens.
+ * Authentication store is backed by a JBoss security domain.
+ * <p/>
+ * Servlet FORM authentication that uses the local security domain to authenticate and for role mappings.
+ * <p/>
+ * Supports bearer token creation and authentication.  The client asking for access must be set up as a valid user
+ * within the security domain.
+ * <p/>
+ * If no an OAuth access request, this works like normal FORM authentication and authorization.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthAuthenticationServerValve extends FormAuthenticator implements LifecycleListener
+{
+
+
+   public static class AccessCode
+   {
+      protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
+      protected long expiration;
+      protected SkeletonKeyToken token;
+      protected String client;
+      protected boolean sso;
+      protected String redirect;
+
+      public boolean isExpired()
+      {
+         return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
+      }
+
+      public String getId()
+      {
+         return id;
+      }
+
+      public long getExpiration()
+      {
+         return expiration;
+      }
+
+      public void setExpiration(long expiration)
+      {
+         this.expiration = expiration;
+      }
+
+      public SkeletonKeyToken getToken()
+      {
+         return token;
+      }
+
+      public void setToken(SkeletonKeyToken token)
+      {
+         this.token = token;
+      }
+
+      public String getClient()
+      {
+         return client;
+      }
+
+      public void setClient(String client)
+      {
+         this.client = client;
+      }
+
+      public boolean isSso()
+      {
+         return sso;
+      }
+
+      public void setSso(boolean sso)
+      {
+         this.sso = sso;
+      }
+
+      public String getRedirect()
+      {
+         return redirect;
+      }
+
+      public void setRedirect(String redirect)
+      {
+         this.redirect = redirect;
+      }
+   }
+
+   protected ConcurrentHashMap<String, AccessCode> accessCodeMap = new ConcurrentHashMap<String, AccessCode>();
+   private static final Logger log = Logger.getLogger(OAuthAuthenticationServerValve.class);
+
+   private static AtomicLong counter = new AtomicLong(1);
+
+   private static String generateId()
+   {
+      return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
+   }
+
+   protected AuthServerConfig skeletonKeyConfig;
+   protected PrivateKey realmPrivateKey;
+   protected PublicKey realmPublicKey;
+   protected String realmPublicKeyPem;
+   protected ResteasyProviderFactory providers;
+   protected ResourceMetadata resourceMetadata;
+   protected UserSessionManagement userSessionManagement = new UserSessionManagement();
+   protected ObjectMapper mapper;
+   protected ObjectWriter accessTokenResponseWriter;
+   protected ObjectWriter mapWriter;
+
+   private static KeyStore loadKeyStore(String filename, String password) throws Exception
+   {
+      KeyStore trustStore = KeyStore.getInstance(KeyStore
+              .getDefaultType());
+      File truststoreFile = new File(filename);
+      FileInputStream trustStream = new FileInputStream(truststoreFile);
+      trustStore.load(trustStream, password.toCharArray());
+      trustStream.close();
+      return trustStore;
+   }
+
+   @Override
+   public void start() throws LifecycleException
+   {
+      super.start();
+      StandardContext standardContext = (StandardContext) context;
+      standardContext.addLifecycleListener(this);
+   }
+
+   @Override
+   public void lifecycleEvent(LifecycleEvent event)
+   {
+      if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+   }
+
+   protected void init()
+   {
+      mapper = new ObjectMapper();
+      mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+      accessTokenResponseWriter = mapper.writerWithType(AccessTokenResponse.class);
+      mapWriter = mapper.writerWithType(mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));
+
+      InputStream is = null;
+      String path = context.getServletContext().getInitParameter("skeleton.key.config.file");
+      if (path == null)
+      {
+         is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
+      }
+      else
+      {
+         try
+         {
+            is = new FileInputStream(path);
+         }
+         catch (FileNotFoundException e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      try
+      {
+         skeletonKeyConfig = mapper.readValue(is, AuthServerConfig.class);
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);
+      }
+      if (skeletonKeyConfig.getLoginRole() == null)
+      {
+         throw new RuntimeException("You must define the login-role in your config file");
+      }
+      if (skeletonKeyConfig.getClientRole() == null)
+      {
+         throw new RuntimeException("You must define the oauth-client-role in your config file");
+      }
+      if (skeletonKeyConfig.getRealmPrivateKey() != null)
+      {
+         try
+         {
+            realmPrivateKey = PemUtils.decodePrivateKey(skeletonKeyConfig.getRealmPrivateKey());
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      if (skeletonKeyConfig.getRealmPublicKey() != null)
+      {
+         try
+         {
+            realmPublicKey = PemUtils.decodePublicKey(skeletonKeyConfig.getRealmPublicKey());
+            realmPublicKeyPem = skeletonKeyConfig.getRealmPublicKey();
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      if (skeletonKeyConfig.getRealmKeyStore() != null)
+      {
+         if (skeletonKeyConfig.getRealmKeyAlias() == null) throw new RuntimeException("Must define realm-key-alias");
+         String keystorePath = EnvUtil.replace(skeletonKeyConfig.getRealmKeyStore());
+         try
+         {
+            KeyStore ks = loadKeyStore(keystorePath, skeletonKeyConfig.getRealmKeystorePassword());
+            if (realmPrivateKey == null)
+            {
+               realmPrivateKey = (PrivateKey) ks.getKey(skeletonKeyConfig.getRealmKeyAlias(), skeletonKeyConfig.getRealmPrivateKeyPassword().toCharArray());
+            }
+            if (realmPublicKey == null)
+            {
+               Certificate cert = ks.getCertificate(skeletonKeyConfig.getRealmKeyAlias());
+               realmPublicKey = cert.getPublicKey();
+            }
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException(e);
+         }
+      }
+      if (realmPublicKey == null) throw new RuntimeException("You have not declared a keystore or public key");
+      if (realmPrivateKey == null) throw new RuntimeException("You have not declared a keystore or private key");
+      if (realmPublicKeyPem == null)
+      {
+         StringWriter sw = new StringWriter();
+         PEMWriter writer = new PEMWriter(sw);
+         try
+         {
+            writer.writeObject(realmPublicKey);
+            writer.flush();
+         }
+         catch (IOException e)
+         {
+            throw new RuntimeException(e);
+         }
+         realmPublicKeyPem = sw.toString();
+         realmPublicKeyPem = PemUtils.removeBeginEnd(realmPublicKeyPem);
+      }
+      providers = new ResteasyProviderFactory();
+      ClassLoader old = Thread.currentThread().getContextClassLoader();
+      Thread.currentThread().setContextClassLoader(OAuthAuthenticationServerValve.class.getClassLoader());
+      try
+      {
+         ResteasyProviderFactory.getInstance(); // initialize builtins
+         RegisterBuiltin.register(providers);
+      }
+      finally
+      {
+         Thread.currentThread().setContextClassLoader(old);
+      }
+      resourceMetadata = new ResourceMetadata();
+      resourceMetadata.setRealm(skeletonKeyConfig.getRealm());
+      resourceMetadata.setRealmKey(realmPublicKey);
+      String truststore = skeletonKeyConfig.getTruststore();
+      if (truststore != null)
+      {
+         truststore = EnvUtil.replace(truststore);
+         String truststorePassword = skeletonKeyConfig.getTruststorePassword();
+         KeyStore trust = null;
+         try
+         {
+            trust = loadKeyStore(truststore, truststorePassword);
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failed to load truststore", e);
+         }
+         resourceMetadata.setTruststore(trust);
+      }
+      String clientKeystore = skeletonKeyConfig.getClientKeystore();
+      String clientKeyPassword = null;
+      if (clientKeystore != null)
+      {
+         clientKeystore = EnvUtil.replace(clientKeystore);
+         String clientKeystorePassword = skeletonKeyConfig.getClientKeystorePassword();
+         KeyStore serverKS = null;
+         try
+         {
+            serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
+         }
+         catch (Exception e)
+         {
+            throw new RuntimeException("Failed to load keystore", e);
+         }
+         resourceMetadata.setClientKeystore(serverKS);
+         clientKeyPassword = skeletonKeyConfig.getClientKeyPassword();
+         resourceMetadata.setClientKeyPassword(clientKeyPassword);
+      }
+   }
+
+   @Override
+   public void invoke(Request request, Response response) throws IOException, ServletException
+   {
+      try
+      {
+         String contextPath = request.getContextPath();
+         String requestURI = request.getDecodedRequestURI();
+         log.debug("--- invoke: " + requestURI);
+         if (request.getMethod().equalsIgnoreCase("GET")
+                 && context.getLoginConfig().getLoginPage().equals(request.getRequestPathMB().toString()))
+         {
+            if (handleLoginPage(request, response)) return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("GET")
+                 && requestURI.endsWith(Actions.J_OAUTH_LOGOUT))
+         {
+            logoutCurrentUser(request, response);
+            return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("POST")
+                 && requestURI.endsWith(Actions.J_OAUTH_ADMIN_FORCED_LOGOUT))
+         {
+            adminLogout(request, response);
+            return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("POST")
+                 && requestURI.startsWith(contextPath) &&
+                 requestURI.endsWith(Constants.FORM_ACTION)
+                 && request.getParameter("client_id") != null)
+         {
+            handleOAuth(request, response);
+            return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("POST")
+                 && requestURI.endsWith(Actions.J_OAUTH_TOKEN_GRANT))
+         {
+            tokenGrant(request, response);
+            return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("POST")
+                 && requestURI.startsWith(contextPath) &&
+                 requestURI.endsWith(Actions.J_OAUTH_RESOLVE_ACCESS_CODE))
+         {
+            resolveAccessCode(request, response);
+            return;
+         }
+         else if (request.getMethod().equalsIgnoreCase("GET")
+                 && requestURI.startsWith(contextPath) &&
+                 requestURI.endsWith("j_oauth_realm_info.html"))
+         {
+            publishRealmInfoHtml(request, response);
+            return;
+         }
+         // propagate the skeleton key token string?
+         if (!skeletonKeyConfig.isCancelPropagation())
+         {
+            if (request.getAttribute(SkeletonKeySession.class.getName()) == null && request.getSessionInternal() != null)
+            {
+               SkeletonKeySession skSession = (SkeletonKeySession) request.getSessionInternal().getNote(SkeletonKeySession.class.getName());
+               if (skSession != null)
+               {
+                  request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+                  ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+               }
+            }
+         }
+         request.setAttribute("OAUTH_FORM_ACTION", "j_security_check");
+         super.invoke(request, response);
+      }
+      finally
+      {
+         ResteasyProviderFactory.clearContextData();  // to clear push of SkeletonKeySession
+      }
+   }
+
+   protected boolean handleLoginPage(Request request, Response response) throws IOException, ServletException
+   {
+      String client_id = request.getParameter("client_id");
+      // if this is not an OAUTH redirect, just return and let the default flow happen
+      if (client_id == null) return false;
+
+      String redirect_uri = request.getParameter("redirect_uri");
+      String state = request.getParameter("state");
+
+      if (redirect_uri == null)
+      {
+         response.sendError(400, "No oauth redirect query parameter set");
+         return true;
+      }
+      // only bypass authentication if our session is authenticated,
+      // the login query parameter is on request URL,
+      // and we have configured the login-role
+      else if (!skeletonKeyConfig.isSsoDisabled()
+              && request.getSessionInternal() != null
+              && request.getSessionInternal().getPrincipal() != null
+              && request.getParameter("login") != null)
+      {
+         log.debug("We're ALREADY LOGGED IN!!!");
+         GenericPrincipal gp = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+         redirectAccessCode(true, response, redirect_uri, client_id, state, gp);
+      }
+      else
+      {
+         UriBuilder builder = UriBuilder.fromUri("j_security_check")
+                 .queryParam("redirect_uri", redirect_uri)
+                 .queryParam("client_id", client_id);
+         if (state != null) builder.queryParam("state", state);
+         String loginAction = builder.build().toString();
+         request.setAttribute("OAUTH_FORM_ACTION", loginAction);
+         getNext().invoke(request, response);
+      }
+      return true;
+   }
+
+   protected GenericPrincipal checkLoggedIn(Request request, HttpServletResponse response)
+   {
+      if (request.getPrincipal() != null)
+      {
+         return (GenericPrincipal) request.getPrincipal();
+      }
+      else if (request.getSessionInternal() != null && request.getSessionInternal().getPrincipal() != null)
+      {
+         return (GenericPrincipal) request.getSessionInternal().getPrincipal();
+      }
+      return null;
+   }
+
+
+   protected void adminLogout(Request request, HttpServletResponse response) throws IOException
+   {
+      log.debug("<< adminLogout");
+      GenericPrincipal gp = checkLoggedIn(request, response);
+      if (gp == null)
+      {
+         if (bearer(request, response, false))
+         {
+            gp = (GenericPrincipal) request.getPrincipal();
+         }
+         else
+         {
+            response.sendError(403);
+            return;
+         }
+      }
+      if (!gp.hasRole(skeletonKeyConfig.getAdminRole()))
+      {
+         response.sendError(403);
+         return;
+      }
+      String logoutUser = request.getParameter("user");
+      if (logoutUser != null)
+      {
+         userSessionManagement.logout(logoutUser);
+         logoutResources(logoutUser, gp.getName());
+      }
+      else
+      {
+         userSessionManagement.logoutAllBut(gp.getName());
+         logoutResources(null, gp.getName());
+      }
+      String forwardTo = request.getParameter("forward");
+      if (forwardTo == null)
+      {
+         response.setStatus(204);
+         return;
+      }
+      RequestDispatcher disp =
+              context.getServletContext().getRequestDispatcher(forwardTo);
+      try
+      {
+         disp.forward(request.getRequest(), response);
+      }
+      catch (Throwable t)
+      {
+         request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
+         response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 "failed to forward");
+      }
+
+
+   }
+
+
+   protected void logoutCurrentUser(Request request, HttpServletResponse response) throws IOException
+   {
+      if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
+      {
+         redirectToWelcomePage(request, response);
+         return;
+      }
+      GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+      String username = principal.getName();
+      String admin = username;
+      userSessionManagement.logout(username);
+      request.setUserPrincipal(null);
+      request.setAuthType(null);
+      // logout user on all declared authenticated resources
+      logoutResources(username, admin);
+      redirectToWelcomePage(request, response);
+   }
+
+   protected void logoutResources(String username, String admin)
+   {
+      if (skeletonKeyConfig.getResources().size() != 0)
+      {
+         SkeletonKeyToken token = new SkeletonKeyToken();
+         token.id(generateId());
+         token.principal(admin);
+         token.audience(skeletonKeyConfig.getRealm());
+         SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access();
+         realmAccess.addRole(skeletonKeyConfig.getAdminRole());
+         token.setRealmAccess(realmAccess);
+         String tokenString = buildTokenString(realmPrivateKey, token);
+         ResteasyClient client = new ResteasyClientBuilder()
+                 .providerFactory(providers)
+                 .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
+                 .trustStore(resourceMetadata.getTruststore())
+                 .keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
+                 .build();
+         try
+         {
+            for (String resource : skeletonKeyConfig.getResources())
+            {
+               try
+               {
+                  log.debug("logging out: " + resource);
+                  WebTarget target = client.target(resource).path(Actions.J_OAUTH_REMOTE_LOGOUT);
+                  if (username != null) target = target.queryParam("user", username);
+                  javax.ws.rs.core.Response response = target.request()
+                          .header("Authorization", "Bearer " + tokenString)
+                          .put(null);
+                  if (response.getStatus() != 204) log.error("Failed to log out");
+                  response.close();
+               }
+               catch (Exception ignored)
+               {
+                  log.error("Failed to log out", ignored);
+               }
+            }
+         }
+         finally
+         {
+            client.close();
+         }
+      }
+   }
+
+   protected void redirectToWelcomePage(Request request, HttpServletResponse response) throws IOException
+   {
+      ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
+      String[] welcomes = context.findWelcomeFiles();
+      if (welcomes.length > 0)
+      {
+         UriBuilder welcome = uriInfo.getBaseUriBuilder().path(welcomes[0]);
+         response.sendRedirect(welcome.toTemplate());
+      }
+      else
+      {
+         response.setStatus(204);
+      }
+   }
+
+
+   protected void publishRealmInfoHtml(Request request, HttpServletResponse response) throws IOException
+   {
+      ManagedResourceConfig rep = getRealmRepresentation(request);
+      StringWriter writer;
+      String json;
+
+      ObjectMapper mapper = new ObjectMapper();
+      mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+      mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
+
+      StringBuffer html = new StringBuffer();
+      html.append("<html><body bgcolor=\"#CED8F6\">");
+      html.append("<h1>Realm: ").append(rep.getRealm()).append("</h1>");
+
+      ManagedResourceConfig bearer = new ManagedResourceConfig();
+      bearer.setRealm(rep.getRealm());
+      bearer.setRealmKey(rep.getRealmKey());
+      writer = new StringWriter();
+      mapper.writeValue(writer, bearer);
+      json = writer.toString();
+
+      html.append("<h3>BearerTokenAuthValve Json Config</h3>");
+      html.append("<form><textarea rows=\"7\" cols=\"80\">").append(json).append("</textarea></form>");
+
+      html.append("<br>");
+
+      writer = new StringWriter();
+      rep.getClientCredentials().put("password", "REQUIRED");
+      rep.setClientId("REQUIRED");
+      rep.setTruststore("REQUIRED");
+      rep.setTruststorePassword("REQUIRED");
+      mapper.writeValue(writer, rep);
+      json = writer.toString();
+      html.append("<h3>OAuthManagedResourceValve Json Config</h3>");
+      html.append("<form><textarea rows=\"20\" cols=\"80\">").append(json).append("</textarea></form>");
+
+      html.append("</body></html>");
+
+      response.setStatus(200);
+      response.setContentType("text/html");
+      response.getOutputStream().println(html.toString());
+      response.getOutputStream().flush();
+
+   }
+
+
+   protected ManagedResourceConfig getRealmRepresentation(Request request)
+   {
+      ManagedResourceConfig rep = new ManagedResourceConfig();
+      ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
+      UriBuilder authUrl = uriInfo.getBaseUriBuilder().path(context.getLoginConfig().getLoginPage());
+      UriBuilder codeUrl = uriInfo.getBaseUriBuilder().path(Actions.J_OAUTH_RESOLVE_ACCESS_CODE);
+      rep.setRealm(skeletonKeyConfig.getRealm());
+      rep.setRealmKey(realmPublicKeyPem);
+      rep.setAuthUrl(authUrl.toTemplate());
+      rep.setCodeUrl(codeUrl.toTemplate());
+      rep.setAdminRole(skeletonKeyConfig.getAdminRole());
+      return rep;
+   }
+
+   public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException
+   {
+      if (request.getHeader("Authorization") != null)
+      {
+         CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false);
+         try
+         {
+            if (bearer.login(request, response))
+            {
+               return true;
+            }
+         }
+         catch (LoginException e)
+         {
+         }
+      }
+      return false;
+   }
+
+   @Override
+   protected void register(Request request, HttpServletResponse response, Principal principal, String authType, String username, String password)
+   {
+      super.register(request, response, principal, authType, username, password);
+      log.debug("authenticate userSessionManage.login(): " + principal.getName());
+      userSessionManagement.login(request.getSessionInternal(), principal.getName());
+      if (!skeletonKeyConfig.isCancelPropagation())
+      {
+         GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
+         if (gp != null)
+         {
+            SkeletonKeyToken token = buildToken(gp);
+            String stringToken = buildTokenString(realmPrivateKey, token);
+            SkeletonKeySession skSession = new SkeletonKeySession(stringToken, resourceMetadata);
+            request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+            ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+            request.getSessionInternal(true).setNote(SkeletonKeySession.class.getName(), skSession);
+         }
+      }
+   }
+
+   @Override
+   public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+   {
+      if (bearer(request, response, true))
+      {
+         return true;
+      }
+      return super.authenticate(request, response, config);
+   }
+
+
+   protected void resolveAccessCode(Request request, Response response) throws IOException
+   {
+      if (!request.isSecure())
+      {
+         response.sendError(400);
+         return;
+      }
+      // always verify code and remove access code from map before authenticating user
+      // if user authentication fails, we want the code to be removed irreguardless just in case we're under attack
+      String code = request.getParameter("code");
+      JWSInput input = new JWSInput(code, providers);
+      boolean verifiedCode = false;
+      try
+      {
+         verifiedCode = RSAProvider.verify(input, realmPublicKey);
+      }
+      catch (Exception ignored)
+      {
+         log.error("Failed to verify signature", ignored);
+      }
+      if (!verifiedCode)
+      {
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Unable to verify code signature");
+         response.sendError(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      String key = input.readContent(String.class);
+      AccessCode accessCode = accessCodeMap.remove(key);
+      String redirect = request.getParameter("redirect_uri");
+
+      GenericPrincipal gp = basicAuth(request, response);
+      if (gp == null)
+      {
+         log.error("Failed to authenticate client_id");
+         return;
+      }
+      if (accessCode == null)
+      {
+         log.error("No access code: " + code);
+         response.sendError(400);
+         return;
+      }
+      if (accessCode.isExpired())
+      {
+         log.debug("Access code expired");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Code is expired");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      if (!accessCode.getToken().isActive())
+      {
+         log.debug("token not active");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Token expired");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      if (!gp.getName().equals(accessCode.getClient()))
+      {
+         log.debug("not equal client");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Auth error");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      if (!accessCode.getRedirect().equals(redirect))
+      {
+         log.debug("not equal redirect");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Auth error");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      if (accessCode.isSso() && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+      {
+         // we did not authenticate user on an access code request because a session was already established
+         // but, the client_id does not have permission to bypass this on a simple grant.  We want
+         // to always ask for credentials from a simple oath request
+
+         log.debug("does not have login permission");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Auth error");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+      }
+      else if (!gp.hasRole(skeletonKeyConfig.getClientRole()) && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+      {
+         log.debug("does not have login or client role permission for access token request");
+         Map<String, String> res = new HashMap<String, String>();
+         res.put("error", "invalid_grant");
+         res.put("error_description", "Auth error");
+         response.setStatus(400);
+         response.setContentType("application/json");
+         mapWriter.writeValue(response.getOutputStream(), res);
+         response.getOutputStream().flush();
+         return;
+
+      }
+      String wildcard = skeletonKeyConfig.getWildcardRole() == null ? "*" : skeletonKeyConfig.getWildcardRole();
+      Set<String> codeRoles = accessCode.getToken().getRealmAccess().getRoles();
+      if (codeRoles != null &&
+              (codeRoles.contains(skeletonKeyConfig.getClientRole()) || codeRoles.contains(skeletonKeyConfig.getLoginRole())))
+      {
+         // we store roles a oauth client is granted in the user role mapping, remove those roles as we don't want those clients with those
+         // permissions if they are logging in.
+         Set<String> newRoles = new HashSet<String>();
+         if (codeRoles.contains(skeletonKeyConfig.getClientRole())) newRoles.add(skeletonKeyConfig.getClientRole());
+         if (codeRoles.contains(skeletonKeyConfig.getLoginRole())) newRoles.add(skeletonKeyConfig.getLoginRole());
+         if (codeRoles.contains(wildcard)) newRoles.add(wildcard);
+         codeRoles.clear();
+         codeRoles.addAll(newRoles);
+      }
+
+      // is we have a login role, then we don't need to filter out roles, just grant all the roles the user has
+      // Also, if the client has the "wildcard" role, then we don't need to filter out roles
+      if (codeRoles != null
+              && !gp.hasRole(wildcard)
+              && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+      {
+         Set<String> clientAllowed = new HashSet<String>();
+         for (String role : gp.getRoles())
+         {
+            clientAllowed.add(role);
+         }
+         Set<String> newRoles = new HashSet<String>();
+         newRoles.addAll(codeRoles);
+         for (String role : newRoles)
+         {
+            if (!clientAllowed.contains(role))
+            {
+               codeRoles.remove(role);
+            }
+         }
+      }
+      AccessTokenResponse res = accessTokenResponse(realmPrivateKey, accessCode.getToken());
+      response.setStatus(200);
+      response.setContentType("application/json");
+      accessTokenResponseWriter.writeValue(response.getOutputStream(), res);
+      response.getOutputStream().flush();
+   }
+
+   protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token)
+   {
+      String encodedToken = buildTokenString(privateKey, token);
+
+      AccessTokenResponse res = new AccessTokenResponse();
+      res.setToken(encodedToken);
+      res.setTokenType("bearer");
+      if (token.getExpiration() != 0)
+      {
+         long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
+         res.setExpiresIn(time);
+      }
+      return res;
+   }
+
+   protected String buildTokenString(PrivateKey privateKey, SkeletonKeyToken token)
+   {
+      byte[] tokenBytes = null;
+      try
+      {
+         tokenBytes = JsonSerialization.toByteArray(token, false);
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException(e);
+      }
+      return new JWSBuilder()
+              .content(tokenBytes)
+              .rsa256(privateKey);
+   }
+
+
+   protected void handleOAuth(Request request, Response response) throws IOException
+   {
+      log.debug("<--- Begin oauthAuthenticate");
+      String redirect_uri = request.getParameter("redirect_uri");
+      String client_id = request.getParameter("client_id");
+      String state = request.getParameter("state");
+      String username = request.getParameter(Constants.FORM_USERNAME);
+      String password = request.getParameter(Constants.FORM_PASSWORD);
+      Principal principal = context.getRealm().authenticate(username, password);
+      if (principal == null)
+      {
+         UriBuilder builder = UriBuilder.fromUri(redirect_uri).queryParam("error", "unauthorized_client");
+         if (state != null) builder.queryParam("state", state);
+         response.sendRedirect(builder.toTemplate());
+         return;
+      }
+      GenericPrincipal gp = (GenericPrincipal) principal;
+      register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
+      userSessionManagement.login(request.getSessionInternal(), username);
+      redirectAccessCode(false, response, redirect_uri, client_id, state, gp);
+
+      return;
+   }
+
+   protected void tokenGrant(Request request, Response response) throws IOException
+   {
+      if (!request.isSecure())
+      {
+         response.sendError(400);
+         return;
+      }
+      GenericPrincipal gp = basicAuth(request, response);
+      if (gp == null) return;
+      SkeletonKeyToken token = buildToken(gp);
+      AccessTokenResponse res = accessTokenResponse(realmPrivateKey, token);
+      response.setStatus(200);
+      response.setContentType("application/json");
+      accessTokenResponseWriter.writeValue(response.getOutputStream(), res);
+      response.getOutputStream().flush();
+   }
+
+   protected GenericPrincipal basicAuth(Request request, Response response) throws IOException
+   {
+      String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+      if (authHeader == null)
+      {
+         basicAuthError(response);
+         return null;
+      }
+      String[] creds = BasicAuthHelper.parseHeader(authHeader);
+      if (creds == null)
+      {
+         basicAuthError(response);
+         return null;
+      }
+      String username = creds[0];
+      String password = creds[1];
+      GenericPrincipal gp = (GenericPrincipal) context.getRealm().authenticate(username, password);
+      if (gp == null)
+      {
+         basicAuthError(response);
+         return null;
+      }
+      return gp;
+   }
+
+   protected void basicAuthError(Response response) throws IOException
+   {
+      response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + context.getLoginConfig().getRealmName() + "\"");
+      response.sendError(401);
+   }
+
+   protected void redirectAccessCode(boolean sso, Response response, String redirect_uri, String client_id, String state, GenericPrincipal gp) throws IOException
+   {
+      SkeletonKeyToken token = buildToken(gp);
+      AccessCode code = new AccessCode();
+      code.setToken(token);
+      code.setClient(client_id);
+      code.setSso(sso);
+      code.setRedirect(redirect_uri);
+      int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 300 : skeletonKeyConfig.getAccessCodeLifetime();
+      code.setExpiration((System.currentTimeMillis() / 1000) + expiration);
+      accessCodeMap.put(code.getId(), code);
+      log.debug("--- sign access code");
+      String accessCode = null;
+      try
+      {
+         accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realmPrivateKey);
+      }
+      catch (UnsupportedEncodingException e)
+      {
+         throw new RuntimeException(e);
+      }
+      log.debug("--- build redirect");
+      UriBuilder redirectUri = UriBuilder.fromUri(redirect_uri).queryParam("code", accessCode);
+      if (state != null) redirectUri.queryParam("state", state);
+      response.sendRedirect(redirectUri.toTemplate());
+      log.debug("<--- end oauthAuthenticate");
+   }
+
+   protected SkeletonKeyToken buildToken(GenericPrincipal gp)
+   {
+      SkeletonKeyToken token = new SkeletonKeyToken();
+      token.id(generateId());
+      token.principal(gp.getName());
+      token.audience(skeletonKeyConfig.getRealm());
+      int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 3600 : skeletonKeyConfig.getAccessCodeLifetime();
+      if (skeletonKeyConfig.getTokenLifetime() > 0)
+      {
+         token.expiration((System.currentTimeMillis() / 1000) + expiration);
+      }
+      SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access();
+      for (String role : gp.getRoles())
+      {
+         realmAccess.addRole(role);
+      }
+      token.setRealmAccess(realmAccess);
+      return token;
+   }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
new file mode 100755
index 0000000..772607c
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
@@ -0,0 +1,303 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Session;
+import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.FormAuthenticator;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
+import org.keycloak.RealmConfiguration;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeyPrincipal;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Web deployment whose security is managed by a remote OAuth Skeleton Key authentication server
+ * <p/>
+ * Redirects browser to remote authentication server if not logged in.  Also allows OAuth Bearer Token requests
+ * that contain a Skeleton Key bearer tokens.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthManagedResourceValve extends FormAuthenticator implements LifecycleListener
+{
+   protected RealmConfiguration realmConfiguration;
+   private static final Logger log = Logger.getLogger(OAuthManagedResourceValve.class);
+   protected UserSessionManagement userSessionManagement = new UserSessionManagement();
+   protected ManagedResourceConfig remoteSkeletonKeyConfig;
+   protected ResourceMetadata resourceMetadata;
+
+
+   @Override
+   public void start() throws LifecycleException
+   {
+      super.start();
+      StandardContext standardContext = (StandardContext) context;
+      standardContext.addLifecycleListener(this);
+   }
+
+   @Override
+   public void lifecycleEvent(LifecycleEvent event)
+   {
+      if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+   }
+
+   protected void init()
+   {
+      ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
+      resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
+      remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
+      String client_id = remoteSkeletonKeyConfig.getClientId();
+      if (client_id == null)
+      {
+         throw new IllegalArgumentException("Must set client-id to use with auth server");
+      }
+      realmConfiguration = new RealmConfiguration();
+      String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
+      if (authUrl == null)
+      {
+         throw new RuntimeException("You must specify auth-url");
+      }
+      String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl();
+      if (tokenUrl == null)
+      {
+         throw new RuntimeException("You mut specify code-url");
+      }
+      realmConfiguration.setMetadata(resourceMetadata);
+      realmConfiguration.setClientId(client_id);
+
+      for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet())
+      {
+         realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue());
+      }
+      int size = 10;
+      if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize() > 0)
+         size = managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize();
+      ResteasyClientBuilder.HostnameVerificationPolicy policy = ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD;
+      if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().isAllowAnyHostname())
+         policy = ResteasyClientBuilder.HostnameVerificationPolicy.ANY;
+      ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
+      ClassLoader old = Thread.currentThread().getContextClassLoader();
+      Thread.currentThread().setContextClassLoader(OAuthManagedResourceValve.class.getClassLoader());
+      try
+      {
+         ResteasyProviderFactory.getInstance(); // initialize builtins
+         RegisterBuiltin.register(providerFactory);
+      }
+      finally
+      {
+         Thread.currentThread().setContextClassLoader(old);
+      }
+      ResteasyClient client = new ResteasyClientBuilder()
+              .providerFactory(providerFactory)
+              .connectionPoolSize(size)
+              .hostnameVerification(policy)
+              .trustStore(resourceMetadata.getTruststore())
+              .keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
+              .build();
+      realmConfiguration.setClient(client);
+      realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
+      realmConfiguration.setCodeUrl(client.target(tokenUrl));
+   }
+
+   @Override
+   public void invoke(Request request, Response response) throws IOException, ServletException
+   {
+      try
+      {
+         String requestURI = request.getDecodedRequestURI();
+         if (requestURI.endsWith("j_oauth_remote_logout"))
+         {
+            remoteLogout(request, response);
+            return;
+         }
+         super.invoke(request, response);
+      }
+      finally
+      {
+         ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+      }
+   }
+
+   @Override
+   public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+   {
+      try
+      {
+         if (bearer(false, request, response)) return true;
+         else if (checkLoggedIn(request, response))
+         {
+            if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null)
+            {
+               if (restoreRequest(request, request.getSessionInternal()))
+               {
+                  log.debug("restoreRequest");
+                  return (true);
+               }
+               else
+               {
+                  log.debug("Restore of original request failed");
+                  response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                  return (false);
+               }
+            }
+            else
+            {
+               return true;
+            }
+         }
+
+         // initiate or continue oauth2 protocol
+         oauth(request, response);
+      }
+      catch (LoginException e)
+      {
+      }
+      return false;
+   }
+
+   protected void remoteLogout(Request request, HttpServletResponse response) throws IOException
+   {
+      try
+      {
+         log.debug("->> remoteLogout: ");
+         if (!bearer(true, request, response))
+         {
+            log.debug("remoteLogout: bearer auth failed");
+            return;
+         }
+         GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
+         if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole()))
+         {
+            log.debug("remoteLogout: role failure");
+            response.sendError(403);
+            return;
+         }
+         String user = request.getParameter("user");
+         if (user != null)
+         {
+            userSessionManagement.logout(user);
+         }
+         else
+         {
+            userSessionManagement.logoutAll();
+         }
+      }
+      catch (Exception e)
+      {
+         log.error("failed to logout", e);
+      }
+      response.setStatus(204);
+   }
+
+   protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException
+   {
+      CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge);
+      if (bearer.login(request, response))
+      {
+         return true;
+      }
+      return false;
+   }
+
+   protected boolean checkLoggedIn(Request request, HttpServletResponse response)
+   {
+      if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
+         return false;
+      log.debug("remote logged in already");
+      GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+      request.setUserPrincipal(principal);
+      request.setAuthType("OAUTH");
+      Session session = request.getSessionInternal();
+      if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation())
+      {
+         SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
+         if (skSession != null)
+         {
+            request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+            ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+
+         }
+      }
+      return true;
+   }
+
+   /**
+    * This method always set the HTTP response, so do not continue after invoking
+    */
+   protected void oauth(Request request, HttpServletResponse response) throws IOException
+   {
+      ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
+      String code = oauth.getCode();
+      if (code == null)
+      {
+         String error = oauth.getError();
+         if (error != null)
+         {
+            response.sendError(400, "OAuth " + error);
+            return;
+         }
+         else
+         {
+            saveRequest(request, request.getSessionInternal(true));
+            oauth.loginRedirect();
+         }
+         return;
+      }
+      else
+      {
+         if (!oauth.resolveCode(code)) return;
+
+         SkeletonKeyToken token = oauth.getToken();
+         Set<String> roles = null;
+         if (resourceMetadata.getResourceName() != null)
+         {
+            SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
+            if (access != null) roles = access.getRoles();
+         }
+         else
+         {
+            SkeletonKeyToken.Access access = token.getRealmAccess();
+            if (access != null) roles = access.getRoles();
+         }
+         SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
+         GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);
+         Session session = request.getSessionInternal(true);
+         session.setPrincipal(principal);
+         session.setAuthType("OAUTH");
+         if (!remoteSkeletonKeyConfig.isCancelPropagation())
+         {
+            SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
+            session.setNote(SkeletonKeySession.class.getName(), skSession);
+         }
+
+         String username = token.getPrincipal();
+         log.debug("userSessionManage.login: " + username);
+         userSessionManagement.login(session, username);
+      }
+   }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
new file mode 100755
index 0000000..4a7d8c1
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
@@ -0,0 +1,320 @@
+package org.keycloak.adapters.as7;
+
+import org.jboss.logging.Logger;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.RealmConfiguration;
+import org.keycloak.VerificationException;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.util.BasicAuthHelper;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ServletOAuthLogin
+{
+   private static final Logger log = Logger.getLogger(ServletOAuthLogin.class);
+   protected HttpServletRequest request;
+   protected HttpServletResponse response;
+   protected boolean codePresent;
+   protected RealmConfiguration realmInfo;
+   protected int redirectPort;
+   protected String tokenString;
+   protected SkeletonKeyToken token;
+
+   public ServletOAuthLogin(RealmConfiguration realmInfo, HttpServletRequest request, HttpServletResponse response, int redirectPort)
+   {
+      this.request = request;
+      this.response = response;
+      this.realmInfo = realmInfo;
+      this.redirectPort = redirectPort;
+   }
+
+   public String getTokenString()
+   {
+      return tokenString;
+   }
+
+   public SkeletonKeyToken getToken()
+   {
+      return token;
+   }
+
+   public RealmConfiguration getRealmInfo()
+   {
+      return realmInfo;
+   }
+
+   protected String getDefaultCookiePath()
+   {
+      String path = request.getContextPath();
+      if ("".equals(path) || path == null) path = "/";
+      return path;
+   }
+
+   protected String getRequestUrl()
+   {
+      return request.getRequestURL().toString();
+   }
+
+   protected boolean isRequestSecure()
+   {
+      return request.isSecure();
+   }
+
+   protected void sendError(int code)
+   {
+      try
+      {
+         response.sendError(code);
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);
+      }
+   }
+
+   protected void sendRedirect(String url)
+   {
+      try
+      {
+         response.sendRedirect(url);
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException(e);
+      }
+   }
+
+   protected Cookie getCookie(String cookieName)
+   {
+      if (request.getCookies() == null) return null;
+      for (Cookie cookie : request.getCookies())
+      {
+         if (cookie.getName().equals(cookieName))
+         {
+            return cookie;
+         }
+      }
+      return null;
+   }
+
+   protected String getCookieValue(String cookieName)
+   {
+      Cookie cookie = getCookie(cookieName);
+      if (cookie == null) return null;
+      return cookie.getValue();
+   }
+
+   protected String getQueryParamValue(String paramName)
+   {
+      String query = request.getQueryString();
+      if (query == null) return null;
+      String[] params = query.split("&");
+      for (String param : params)
+      {
+         int eq = param.indexOf('=');
+         if (eq == -1) continue;
+         String name = param.substring(0, eq);
+         if (!name.equals(paramName)) continue;
+         return param.substring(eq + 1);
+      }
+      return null;
+   }
+
+   public String getError()
+   {
+      return getQueryParamValue("error");
+   }
+
+   public String getCode()
+   {
+      return getQueryParamValue("code");
+   }
+
+   protected void setCookie(String name, String value, String domain, String path, boolean secure)
+   {
+      Cookie cookie = new Cookie(name, value);
+      if (domain != null) cookie.setDomain(domain);
+      if (path != null) cookie.setPath(path);
+      if (secure) cookie.setSecure(true);
+      response.addCookie(cookie);
+   }
+
+   protected String getRedirectUri(String state)
+   {
+      String url = getRequestUrl();
+      if (!isRequestSecure() && realmInfo.isSslRequired())
+      {
+         int port = redirectPort;
+         if (port < 0)
+         {
+            // disabled?
+            return null;
+         }
+         UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1);
+         if (port != 443) secureUrl.port(port);
+         url = secureUrl.build().toString();
+      }
+      return realmInfo.getAuthUrl().clone()
+              .queryParam("client_id", realmInfo.getClientId())
+              .queryParam("redirect_uri", url)
+              .queryParam("state", state)
+              .queryParam("login", "true")
+              .build().toString();
+   }
+
+   protected static final AtomicLong counter = new AtomicLong();
+
+   protected String getStateCode()
+   {
+      return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
+   }
+
+   public void loginRedirect()
+   {
+      String state = getStateCode();
+      String redirect = getRedirectUri(state);
+      if (redirect == null)
+      {
+         sendError(Response.Status.FORBIDDEN.getStatusCode());
+         return;
+      }
+      setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired());
+      sendRedirect(redirect);
+   }
+
+   public boolean checkStateCookie()
+   {
+      Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
+
+      if (stateCookie == null)
+      {
+         sendError(400);
+         log.warn("No state cookie");
+         return false;
+      }
+      // reset the cookie
+      Cookie reset = new Cookie(stateCookie.getName(), stateCookie.getValue());
+      reset.setPath(stateCookie.getPath());
+      reset.setMaxAge(0);
+      response.addCookie(reset);
+
+      String stateCookieValue = getCookieValue(realmInfo.getStateCookieName());
+      // its ok to call request.getParameter() because this should be a redirect
+      String state = request.getParameter("state");
+      if (state == null)
+      {
+         sendError(400);
+         log.warn("state parameter was null");
+         return false;
+      }
+      if (!state.equals(stateCookieValue))
+      {
+         sendError(400);
+         log.warn("state parameter invalid");
+         log.warn("cookie: " + stateCookieValue);
+         log.warn("queryParam: " + state);
+         return false;
+      }
+      return true;
+
+   }
+
+   /**
+    * Start or continue the oauth login process.
+    *
+    * if code query parameter is not present, then browser is redirected to authUrl.  The redirect URL will be
+    * the URL of the current request.
+    *
+    * If code query parameter is present, then an access token is obtained by invoking a secure request to the codeUrl.
+    * If the access token is obtained, the browser is again redirected to the current request URL, but any OAuth
+    * protocol specific query parameters are removed.
+    *
+    * @return true if an access token was obtained
+    */
+   public boolean resolveCode(String code)
+   {
+      // abort if not HTTPS
+      if (realmInfo.isSslRequired() && !isRequestSecure())
+      {
+         log.error("SSL is required");
+         sendError(Response.Status.FORBIDDEN.getStatusCode());
+         return false;
+      }
+
+      if (!checkStateCookie()) return false;
+
+      String client_id = realmInfo.getClientId();
+      String password = realmInfo.getCredentials().asMap().getFirst("password");
+      String authHeader = BasicAuthHelper.createHeader(client_id, password);
+      String redirectUri = stripOauthParametersFromRedirect();
+      Form form = new Form();
+      form.param("grant_type", "authorization_code")
+              .param("code", code)
+              .param("redirect_uri", redirectUri);
+
+      Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form));
+      AccessTokenResponse tokenResponse;
+      try
+      {
+         if (res.getStatus() != 200)
+         {
+            log.error("failed to turn code into token");
+            sendError(Response.Status.FORBIDDEN.getStatusCode());
+            return false;
+         }
+         log.debug("media type: " + res.getMediaType());
+         log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
+         tokenResponse = res.readEntity(AccessTokenResponse.class);
+      }
+      finally
+      {
+         res.close();
+      }
+
+      tokenString = tokenResponse.getToken();
+      try
+      {
+         token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
+         log.debug("Verification succeeded!");
+      }
+      catch (VerificationException e)
+      {
+         log.error("failed verification of token");
+         sendError(Response.Status.FORBIDDEN.getStatusCode());
+         return false;
+      }
+      // redirect to URL without oauth query parameters
+      sendRedirect(redirectUri);
+      return true;
+   }
+
+   /**
+    * strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits
+    */
+   protected String stripOauthParametersFromRedirect()
+   {
+      StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString());
+      UriBuilder builder = UriBuilder.fromUri(buf.toString())
+              .replaceQueryParam("code", null)
+              .replaceQueryParam("state", null);
+      return builder.build().toString();
+   }
+
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java
new file mode 100755
index 0000000..081df77
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java
@@ -0,0 +1,111 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.logging.Logger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages relationship to users and sessions so that forced admin logout can be implemented
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserSessionManagement implements SessionListener
+{
+   private static final Logger log = Logger.getLogger(UserSessionManagement.class);
+   protected ConcurrentHashMap<String, Map<String, Session>> userSessionMap = new ConcurrentHashMap<String, Map<String, Session>>();
+
+   protected void login(Session session, String username)
+   {
+      Map<String, Session> map = userSessionMap.get(username);
+      if (map == null)
+      {
+         final Map<String, Session> value = new HashMap<String, Session>();
+         map = userSessionMap.putIfAbsent(username, value);
+         if (map == null)
+         {
+            map = value;
+         }
+      }
+      synchronized (map)
+      {
+         map.put(session.getId(), session);
+      }
+      session.addSessionListener(this);
+   }
+
+   public void logoutAll()
+   {
+      List<String> users = new ArrayList<String>();
+      users.addAll(userSessionMap.keySet());
+      for (String user : users) logout(user);
+   }
+
+   public void logoutAllBut(String but)
+   {
+      List<String> users = new ArrayList<String>();
+      users.addAll(userSessionMap.keySet());
+      for (String user : users)
+      {
+         if (!but.equals(user)) logout(user);
+      }
+   }
+
+
+   public void logout(String user)
+   {
+      log.debug("logoutUser: " + user);
+      Map<String, Session> map = userSessionMap.remove(user);
+      if (map == null)
+      {
+         log.debug("no session for user: " + user);
+         return;
+      }
+      log.debug("found session for user");
+      synchronized (map)
+      {
+         for (Session session : map.values())
+         {
+            log.debug("invalidating session for user: " + user);
+            session.setPrincipal(null);
+            session.setAuthType(null);
+            session.getSession().invalidate();
+         }
+      }
+
+   }
+
+   public void sessionEvent(SessionEvent event)
+   {
+      // We only care about session destroyed events
+      if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
+              && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
+         return;
+
+      // Look up the single session id associated with this session (if any)
+      Session session = event.getSession();
+      GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
+      if (principal == null) return;
+      session.setPrincipal(null);
+      session.setAuthType(null);
+
+      String username = principal.getUserPrincipal().getName();
+      Map<String, Session> map = userSessionMap.get(username);
+      if (map == null) return;
+      synchronized (map)
+      {
+         map.remove(session.getId());
+         if (map.isEmpty()) userSessionMap.remove(username);
+      }
+
+
+   }
+}

integration/pom.xml 21(+21 -0)

diff --git a/integration/pom.xml b/integration/pom.xml
new file mode 100755
index 0000000..5028c1d
--- /dev/null
+++ b/integration/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-alpha-1</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <name>Keycloak Integration</name>
+    <description/>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.keycloak</groupId>
+    <artifactId>integration-pom</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>as7-eap6/adapter</module>
+        <!-- <module>as7-eap6/jboss-modules</module> -->
+    </modules>
+</project>

pom.xml 12(+12 -0)

diff --git a/pom.xml b/pom.xml
index 2225e9b..bcb889c 100755
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,7 @@
     <modules>
         <module>core</module>
         <module>services</module>
+        <module>integration</module>
     </modules>
 
     <dependencyManagement>
@@ -109,6 +110,12 @@
                 <version>${resteasy.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.jboss.resteasy</groupId>
+                <artifactId>tjws</artifactId>
+                <version>${resteasy.version}</version>
+                <scope>provided</scope>
+            </dependency>
+            <dependency>
                 <groupId>org.codehaus.jackson</groupId>
                 <artifactId>jackson-core-asl</artifactId>
                 <version>1.9.12</version>
@@ -163,6 +170,11 @@
                 <artifactId>junit</artifactId>
                 <version>4.11</version>
             </dependency>
+            <dependency>
+                <groupId>org.hibernate.javax.persistence</groupId>
+                <artifactId>hibernate-jpa-2.0-api</artifactId>
+                <version>1.0.1.Final</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

services/pom.xml 36(+36 -0)

diff --git a/services/pom.xml b/services/pom.xml
index 8c097ae..5daecdd 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -43,6 +43,25 @@
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-jaxrs</artifactId>
             <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>tjws</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.resteasy</groupId>
@@ -94,6 +113,23 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.hibernate.javax.persistence</groupId>
+            <artifactId>hibernate-jpa-2.0-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.161</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-entitymanager</artifactId>
+            <version>3.6.6.Final</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java b/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java
new file mode 100755
index 0000000..dbe8461
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java
@@ -0,0 +1,38 @@
+package org.keycloak.services.filters;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.IdentitySessionFactory;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.container.PreMatching;
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@PreMatching
+public class IdentitySessionFilter implements ContainerRequestFilter, ContainerResponseFilter {
+    protected IdentitySessionFactory factory;
+
+    public IdentitySessionFilter(IdentitySessionFactory factory) {
+        this.factory = factory;
+    }
+
+    @Override
+    public void filter(ContainerRequestContext requestContext) throws IOException {
+        IdentitySession ctx = factory.createIdentitySession();
+        requestContext.setProperty(IdentitySession.class.getName(), ctx);
+        ResteasyProviderFactory.pushContext(IdentitySession.class, ctx);
+    }
+
+    @Override
+    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
+        IdentitySession ctx = (IdentitySession)requestContext.getProperty(IdentitySession.class.getName());
+        if (ctx != null) ctx.close();
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
new file mode 100755
index 0000000..d96b32b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
@@ -0,0 +1,49 @@
+package org.keycloak.services.managers;
+
+import org.keycloak.representations.SkeletonKeyToken;
+import org.picketlink.idm.model.User;
+
+import java.util.UUID;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public class AccessCodeEntry {
+    protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
+    protected long expiration;
+    protected SkeletonKeyToken token;
+    protected User client;
+
+    public boolean isExpired() {
+        return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public long getExpiration() {
+        return expiration;
+    }
+
+    public void setExpiration(long expiration) {
+        this.expiration = expiration;
+    }
+
+    public SkeletonKeyToken getToken() {
+        return token;
+    }
+
+    public void setToken(SkeletonKeyToken token) {
+        this.token = token;
+    }
+
+    public User getClient() {
+        return client;
+    }
+
+    public void setClient(User client) {
+        this.client = client;
+    }
+}
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 74fc03f..7b725da 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -24,107 +24,91 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class AuthenticationManager
-{
-   protected Logger logger = Logger.getLogger(AuthenticationManager.class);
-   public static final String FORM_USERNAME = "username";
-   protected RealmManager adapter;
+public class AuthenticationManager {
+    protected Logger logger = Logger.getLogger(AuthenticationManager.class);
+    public static final String FORM_USERNAME = "username";
 
-   public AuthenticationManager(RealmManager adapter)
-   {
-      this.adapter = adapter;
-   }
+    /**
+     * Grabs token from headers, authenticates, authorizes
+     *
+     * @param realm
+     * @param headers
+     * @return
+     */
+    public boolean isRealmAdmin(RealmModel realm, HttpHeaders headers) {
+        User user = authenticateToken(realm, headers);
+        return realm.isRealmAdmin(user);
+    }
 
-   public User authenticateToken(RealmModel realm, HttpHeaders headers)
-   {
-      String tokenString = null;
-      String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
-      if (authHeader == null)
-      {
-         throw new NotAuthorizedException("Bearer");
-      }
-      else
-      {
-         String[] split = authHeader.trim().split("\\s+");
-         if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
-         if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
-         tokenString = split[1];
-      }
+    public User authenticateToken(RealmModel realm, HttpHeaders headers) {
+        String tokenString = null;
+        String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
+        if (authHeader == null) {
+            throw new NotAuthorizedException("Bearer");
+        } else {
+            String[] split = authHeader.trim().split("\\s+");
+            if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
+            if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
+            tokenString = split[1];
+        }
 
 
-      try
-      {
-         SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
-         if (!token.isActive())
-         {
-            throw new NotAuthorizedException("token_expired");
-         }
-         User user = realm.getIdm().getUser(token.getPrincipal());
-         if (user == null || !user.isEnabled())
-         {
-            throw new NotAuthorizedException("invalid_user");
-         }
-         return user;
-      }
-      catch (VerificationException e)
-      {
-         logger.error("Failed to verify token", e);
-         throw new NotAuthorizedException("invalid_token");
-      }
-   }
-
-   public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData)
-   {
-      String username = user.getLoginName();
-      Set<String> types = new HashSet<String>();
+        try {
+            SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
+            if (!token.isActive()) {
+                throw new NotAuthorizedException("token_expired");
+            }
+            User user = realm.getIdm().getUser(token.getPrincipal());
+            if (user == null || !user.isEnabled()) {
+                throw new NotAuthorizedException("invalid_user");
+            }
+            return user;
+        } catch (VerificationException e) {
+            logger.error("Failed to verify token", e);
+            throw new NotAuthorizedException("invalid_token");
+        }
+    }
 
-      for (RequiredCredentialModel credential : realm.getRequiredCredentials())
-      {
-         types.add(credential.getType());
-      }
+    public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData) {
+        String username = user.getLoginName();
+        Set<String> types = new HashSet<String>();
 
-      if (types.contains(RequiredCredentialRepresentation.PASSWORD))
-      {
-         String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD);
-         if (password == null)
-         {
-            logger.warn("Password not provided");
-            return false;
-         }
+        for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
+            types.add(credential.getType());
+        }
 
-         if (types.contains(RequiredCredentialRepresentation.TOTP))
-         {
-            String token = formData.getFirst(RequiredCredentialRepresentation.TOTP);
-            if (token == null)
-            {
-               logger.warn("TOTP token not provided");
-               return false;
+        if (types.contains(RequiredCredentialRepresentation.PASSWORD)) {
+            String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD);
+            if (password == null) {
+                logger.warn("Password not provided");
+                return false;
             }
-            TOTPCredentials creds = new TOTPCredentials();
-            creds.setToken(token);
-            creds.setUsername(username);
-            creds.setPassword(new Password(password));
-            realm.getIdm().validateCredentials(creds);
-            if (creds.getStatus() != Credentials.Status.VALID)
-            {
-               return false;
-            }
-         }
-         else
-         {
-            UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password));
-            realm.getIdm().validateCredentials(creds);
-            if (creds.getStatus() != Credentials.Status.VALID)
-            {
-               return false;
+
+            if (types.contains(RequiredCredentialRepresentation.TOTP)) {
+                String token = formData.getFirst(RequiredCredentialRepresentation.TOTP);
+                if (token == null) {
+                    logger.warn("TOTP token not provided");
+                    return false;
+                }
+                TOTPCredentials creds = new TOTPCredentials();
+                creds.setToken(token);
+                creds.setUsername(username);
+                creds.setPassword(new Password(password));
+                realm.getIdm().validateCredentials(creds);
+                if (creds.getStatus() != Credentials.Status.VALID) {
+                    return false;
+                }
+            } else {
+                UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password));
+                realm.getIdm().validateCredentials(creds);
+                if (creds.getStatus() != Credentials.Status.VALID) {
+                    return false;
+                }
             }
-         }
-      }
-      else
-      {
-         logger.warn("Do not know how to authenticate user");
-         return false;
-      }
-      return true;
-   }
+        } else {
+            logger.warn("Do not know how to authenticate user");
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/InstallationManager.java b/services/src/main/java/org/keycloak/services/managers/InstallationManager.java
new file mode 100755
index 0000000..6154547
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/InstallationManager.java
@@ -0,0 +1,33 @@
+package org.keycloak.services.managers;
+
+import org.keycloak.services.models.RealmManager;
+import org.keycloak.services.models.RealmModel;
+import org.keycloak.services.models.RequiredCredentialModel;
+import org.keycloak.services.resources.RegistrationService;
+import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.model.SimpleRole;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InstallationManager {
+    public void install(RealmManager manager) {
+        RealmModel defaultRealm = manager.createRealm(Realm.DEFAULT_REALM, Realm.DEFAULT_REALM);
+        defaultRealm.setName(Realm.DEFAULT_REALM);
+        defaultRealm.setEnabled(true);
+        defaultRealm.setTokenLifespan(300);
+        defaultRealm.setAccessCodeLifespan(60);
+        defaultRealm.setSslNotRequired(false);
+        defaultRealm.setCookieLoginAllowed(true);
+        defaultRealm.setRegistrationAllowed(true);
+        manager.generateRealmKeys(defaultRealm);
+        defaultRealm.updateRealm();
+        defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
+        defaultRealm.getIdm().add(new SimpleRole(RegistrationService.REALM_CREATOR_ROLE));
+    }
+
+    public boolean isInstalled(RealmManager manager) {
+        return manager.defaultRealm() != null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 4d1428c..6c01504 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -21,156 +21,123 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class TokenManager
-{
-   protected RealmManager adapter;
-
-   public TokenManager(RealmManager adapter)
-   {
-      this.adapter = adapter;
-   }
-
-   public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user)
-   {
-      SkeletonKeyToken token = new SkeletonKeyToken();
-      token.id(adapter.generateId());
-      token.principal(user.getLoginName());
-      token.audience(realm.getName());
-      token.issuedNow();
-      token.issuedFor(client.getLoginName());
-      if (realm.getTokenLifespan() > 0)
-      {
-         token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
-      }
-      Map<String, ResourceModel> resourceMap = realm.getResourceMap();
-
-      for (String res : scope.keySet())
-      {
-         ResourceModel resource = resourceMap.get(res);
-         Set<String> scopeMapping = resource.getScope(client);
-         Set<String> roleMapping = resource.getRoleMappings(user);
-         SkeletonKeyToken.Access access = token.addAccess(resource.getName());
-         for (String role : scope.get(res))
-         {
-            if (!scopeMapping.contains("*") && !scopeMapping.contains(role))
-            {
-               throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+public class TokenManager {
+
+     public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
+        SkeletonKeyToken token = new SkeletonKeyToken();
+        token.id(RealmManager.generateId());
+        token.principal(user.getLoginName());
+        token.audience(realm.getName());
+        token.issuedNow();
+        token.issuedFor(client.getLoginName());
+        if (realm.getTokenLifespan() > 0) {
+            token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+        }
+        Map<String, ResourceModel> resourceMap = realm.getResourceMap();
+
+        for (String res : scope.keySet()) {
+            ResourceModel resource = resourceMap.get(res);
+            Set<String> scopeMapping = resource.getScope(client);
+            Set<String> roleMapping = resource.getRoleMappings(user);
+            SkeletonKeyToken.Access access = token.addAccess(resource.getName());
+            for (String role : scope.get(res)) {
+                if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
+                    throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+                }
+                if (!roleMapping.contains(role)) {
+                    throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+
+                }
+                access.addRole(role);
             }
-            if (!roleMapping.contains(role))
-            {
-               throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
-
+        }
+        return token;
+    }
+
+    public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) {
+        SkeletonKeyScope scope = decodeScope(scopeParam);
+        return createScopedToken(scope, realm, client, user);
+    }
+
+    public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user) {
+        Set<String> mapping = realm.getScope(client);
+        if (!mapping.contains("*")) {
+            throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
+        }
+        SkeletonKeyToken token = createAccessToken(realm, user);
+        token.issuedFor(client.getLoginName());
+        return token;
+
+    }
+
+    public SkeletonKeyScope decodeScope(String scopeParam) {
+        SkeletonKeyScope scope = null;
+        byte[] bytes = Base64Url.decode(scopeParam);
+        try {
+            scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return scope;
+    }
+
+
+    public SkeletonKeyToken createAccessToken(RealmModel realm, User user) {
+        List<ResourceModel> resources = realm.getResources();
+        SkeletonKeyToken token = new SkeletonKeyToken();
+        token.id(RealmManager.generateId());
+        token.issuedNow();
+        token.principal(user.getLoginName());
+        token.audience(realm.getId());
+        if (realm.getTokenLifespan() > 0) {
+            token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+        }
+
+        Set<String> realmMapping = realm.getRoleMappings(user);
+
+        if (realmMapping != null && realmMapping.size() > 0) {
+            SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
+            for (String role : realmMapping) {
+                access.addRole(role);
             }
-            access.addRole(role);
-         }
-      }
-      return token;
-   }
-
-   public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user)
-   {
-      SkeletonKeyScope scope = decodeScope(scopeParam);
-      return createScopedToken(scope, realm, client, user);
-   }
-
-   public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user)
-   {
-      Set<String> mapping = realm.getScope(client);
-      if (!mapping.contains("*"))
-      {
-         throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
-      }
-      SkeletonKeyToken token = createAccessToken(realm, user);
-      token.issuedFor(client.getLoginName());
-      return token;
-
-   }
-
-   public SkeletonKeyScope decodeScope(String scopeParam)
-   {
-      SkeletonKeyScope scope = null;
-      byte[] bytes = Base64Url.decode(scopeParam);
-      try
-      {
-         scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes);
-      }
-      catch (IOException e)
-      {
-         throw new RuntimeException(e);
-      }
-      return scope;
-   }
-
-
-   public SkeletonKeyToken createAccessToken(RealmModel realm, User user)
-   {
-      List<ResourceModel> resources = realm.getResources();
-      SkeletonKeyToken token = new SkeletonKeyToken();
-      token.id(adapter.generateId());
-      token.issuedNow();
-      token.principal(user.getLoginName());
-      token.audience(realm.getId());
-      if (realm.getTokenLifespan() > 0)
-      {
-         token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
-      }
-
-      Set<String> realmMapping = realm.getRoleMappings(user);
-
-      if (realmMapping != null && realmMapping.size() > 0)
-      {
-         SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
-         for (String role : realmMapping)
-         {
-            access.addRole(role);
-         }
-         token.setRealmAccess(access);
-      }
-      if (resources != null)
-      {
-         for (ResourceModel resource : resources)
-         {
-            Set<String> mapping = resource.getRoleMappings(user);
-            if (mapping == null) continue;
-            SkeletonKeyToken.Access access = token.addAccess(resource.getName())
-                    .verifyCaller(resource.isSurrogateAuthRequired());
-            for (String role : mapping)
-            {
-               access.addRole(role);
+            token.setRealmAccess(access);
+        }
+        if (resources != null) {
+            for (ResourceModel resource : resources) {
+                Set<String> mapping = resource.getRoleMappings(user);
+                if (mapping == null) continue;
+                SkeletonKeyToken.Access access = token.addAccess(resource.getName())
+                        .verifyCaller(resource.isSurrogateAuthRequired());
+                for (String role : mapping) {
+                    access.addRole(role);
+                }
             }
-         }
-      }
-      return token;
-   }
-
-   public SkeletonKeyToken createIdentityToken(RealmModel realm, String username)
-   {
-      SkeletonKeyToken token = new SkeletonKeyToken();
-      token.id(adapter.generateId());
-      token.issuedNow();
-      token.principal(username);
-      token.audience(realm.getId());
-      if (realm.getTokenLifespan() > 0)
-      {
-         token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
-      }
-      return token;
-   }
-
-   public String encodeToken(RealmModel realm, SkeletonKeyToken token)
-   {
-      byte[] tokenBytes = null;
-      try
-      {
-         tokenBytes = JsonSerialization.toByteArray(token, false);
-      }
-      catch (Exception e)
-      {
-         throw new RuntimeException(e);
-      }
-      String encodedToken = new JWSBuilder()
-              .content(tokenBytes)
-              .rsa256(realm.getPrivateKey());
-      return encodedToken;
-   }
+        }
+        return token;
+    }
+
+    public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) {
+        SkeletonKeyToken token = new SkeletonKeyToken();
+        token.id(RealmManager.generateId());
+        token.issuedNow();
+        token.principal(username);
+        token.audience(realm.getId());
+        if (realm.getTokenLifespan() > 0) {
+            token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+        }
+        return token;
+    }
+
+    public String encodeToken(RealmModel realm, SkeletonKeyToken token) {
+        byte[] tokenBytes = null;
+        try {
+            tokenBytes = JsonSerialization.toByteArray(token, false);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        String encodedToken = new JWSBuilder()
+                .content(tokenBytes)
+                .rsa256(realm.getPrivateKey());
+        return encodedToken;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/RealmManager.java b/services/src/main/java/org/keycloak/services/models/RealmManager.java
index 02485bf..6ee87ce 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmManager.java
@@ -1,49 +1,71 @@
 package org.keycloak.services.models;
 
+import org.keycloak.representations.idm.UserRepresentation;
+import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.internal.IdentityManagerFactory;
 import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.model.Role;
 import org.picketlink.idm.model.SimpleAgent;
+import org.picketlink.idm.model.SimpleUser;
+import org.picketlink.idm.model.User;
 
+import javax.ws.rs.core.Response;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class RealmManager
-{
-   private static AtomicLong counter = new AtomicLong(1);
-
-   public static String generateId()
-   {
-      return counter.getAndIncrement() + "-" + System.currentTimeMillis();
-   }
-
-   protected IdentityManagerFactory factory;
-
-   public RealmManager(IdentityManagerFactory factory)
-   {
-      this.factory = factory;
-   }
-
-   public RealmModel getRealm(String id)
-   {
-      Realm existing = factory.findRealm(id);
-      if (existing == null)
-      {
-         return null;
-      }
-      return new RealmModel(existing, factory);
-   }
-
-   public RealmModel create(String name)
-   {
-      Realm newRealm = factory.createRealm(generateId());
-      IdentityManager idm = factory.createIdentityManager(newRealm);
-      SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
-      idm.add(agent);
-      return new RealmModel(newRealm, factory);
-   }
-
-}
+public class RealmManager {
+    private static AtomicLong counter = new AtomicLong(1);
+
+    public static String generateId() {
+        return counter.getAndIncrement() + "-" + System.currentTimeMillis();
+    }
+
+    protected IdentitySession IdentitySession;
+
+    public RealmManager(IdentitySession IdentitySession) {
+        this.IdentitySession = IdentitySession;
+    }
+
+    public RealmModel defaultRealm() {
+        return getRealm(Realm.DEFAULT_REALM);
+    }
+
+    public RealmModel getRealm(String id) {
+        Realm existing = IdentitySession.findRealm(id);
+        if (existing == null) {
+            return null;
+        }
+        return new RealmModel(existing, IdentitySession);
+    }
+
+    public RealmModel createRealm(String name) {
+        return createRealm(generateId(), name);
+    }
+
+    public RealmModel createRealm(String id, String name) {
+        Realm newRealm = IdentitySession.createRealm(id);
+        IdentityManager idm = IdentitySession.createIdentityManager(newRealm);
+        SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
+        idm.add(agent);
+        RealmModel realm = new RealmModel(newRealm, IdentitySession);
+        return realm;
+    }
+
+    public void generateRealmKeys(RealmModel realm) {
+        KeyPair keyPair = null;
+        try {
+            keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+        realm.setPrivateKey(keyPair.getPrivate());
+        realm.setPublicKey(keyPair.getPublic());
+        realm.updateRealm();
+    }
+    }
diff --git a/services/src/main/java/org/keycloak/services/models/RealmModel.java b/services/src/main/java/org/keycloak/services/models/RealmModel.java
index 6028bbf..0cdf45c 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java
@@ -4,20 +4,19 @@ import org.bouncycastle.openssl.PEMWriter;
 import org.jboss.resteasy.security.PemUtils;
 import org.keycloak.representations.idm.RequiredCredentialRepresentation;
 import org.keycloak.services.models.relationships.RealmAdminRelationship;
-import org.keycloak.services.models.relationships.RealmResourceRelationship;
+import org.keycloak.services.models.relationships.ResourceRelationship;
 import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
 import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.IdentityManager;
 import org.picketlink.idm.credential.Password;
 import org.picketlink.idm.credential.TOTPCredential;
 import org.picketlink.idm.credential.X509CertificateCredentials;
-import org.picketlink.idm.internal.IdentityManagerFactory;
 import org.picketlink.idm.model.Agent;
 import org.picketlink.idm.model.Attribute;
 import org.picketlink.idm.model.Grant;
 import org.picketlink.idm.model.Realm;
 import org.picketlink.idm.model.Role;
-import org.picketlink.idm.model.SimpleAgent;
 import org.picketlink.idm.model.Tier;
 import org.picketlink.idm.model.User;
 import org.picketlink.idm.query.IdentityQuery;
@@ -39,374 +38,311 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class RealmModel
-{
-   public static final String REALM_AGENT_ID = "_realm_";
-   public static final String REALM_NAME = "name";
-   public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
-   public static final String REALM_TOKEN_LIFESPAN = "tokenLifespan";
-   public static final String REALM_PRIVATE_KEY = "privateKey";
-   public static final String REALM_PUBLIC_KEY = "publicKey";
-   public static final String REALM_IS_SSL_NOT_REQUIRED = "isSSLNotRequired";
-   public static final String REALM_IS_COOKIE_LOGIN_ALLOWED = "isCookieLoginAllowed";
-
-   protected Realm realm;
-   protected Agent realmAgent;
-   protected IdentityManagerFactory factory;
-   protected volatile transient PublicKey publicKey;
-   protected volatile transient PrivateKey privateKey;
-
-   public RealmModel(Realm realm, IdentityManagerFactory factory)
-   {
-      this.realm = realm;
-      this.factory = factory;
-      realmAgent = getIdm().getAgent(REALM_AGENT_ID);
-   }
-
-   public IdentityManager getIdm()
-   {
-      return factory.createIdentityManager(realm);
-   }
-
-   public void updateRealm()
-   {
-      getIdm().update(realmAgent);
-   }
-
-   public String getId()
-   {
-      return realm.getId();
-   }
-
-   public String getName()
-   {
-      return (String)realmAgent.getAttribute(REALM_NAME).getValue();
-   }
-
-   public void setName(String name)
-   {
-      realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
-   }
-
-   public boolean isEnabled()
-   {
-      return realmAgent.isEnabled();
-   }
-
-   public void setEnabled(boolean enabled)
-   {
-      realmAgent.setEnabled(enabled);
-   }
-
-   public boolean isSslNotRequired()
-   {
-      return (Boolean)realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
-   }
-
-   public void setSslNotRequired(boolean sslNotRequired)
-   {
-      realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
-   }
-
-   public boolean isCookieLoginAllowed()
-   {
-      return (Boolean)realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
-   }
-
-   public void setCookieLoginAllowed(boolean cookieLoginAllowed)
-   {
-      realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
-   }
-
-   public long getTokenLifespan()
-   {
-      return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
-   }
-
-   public void setTokenLifespan(long tokenLifespan)
-   {
-      realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN,tokenLifespan));
-   }
-
-   public long getAccessCodeLifespan()
-   {
-      return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
-   }
-
-   public void setAccessCodeLifespan(long accessCodeLifespan)
-   {
-      realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
-   }
-
-   public String getPublicKeyPem()
-   {
-      return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
-   }
-
-   public void setPublicKeyPem(String publicKeyPem)
-   {
-      realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
-      this.publicKey = null;
-   }
-
-   public String getPrivateKeyPem()
-   {
-      return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
-   }
-
-   public void setPrivateKeyPem(String privateKeyPem)
-   {
-      realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
-      this.privateKey = null;
-   }
-
-   public PublicKey getPublicKey()
-   {
-      if (publicKey != null) return publicKey;
-      String pem = getPublicKeyPem();
-      if (pem != null)
-      {
-         try
-         {
-            publicKey = PemUtils.decodePublicKey(pem);
-         }
-         catch (Exception e)
-         {
+public class RealmModel {
+    public static final String REALM_AGENT_ID = "_realm_";
+    public static final String REALM_NAME = "name";
+    public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
+    public static final String REALM_TOKEN_LIFESPAN = "tokenLifespan";
+    public static final String REALM_PRIVATE_KEY = "privateKey";
+    public static final String REALM_PUBLIC_KEY = "publicKey";
+    public static final String REALM_IS_SSL_NOT_REQUIRED = "isSSLNotRequired";
+    public static final String REALM_IS_COOKIE_LOGIN_ALLOWED = "isCookieLoginAllowed";
+    public static final String REALM_IS_REGISTRATION_ALLOWED = "isRegistrationAllowed";
+
+    protected Realm realm;
+    protected Agent realmAgent;
+    protected IdentitySession identitySession;
+    protected volatile transient PublicKey publicKey;
+    protected volatile transient PrivateKey privateKey;
+
+    public RealmModel(Realm realm, IdentitySession session) {
+        this.realm = realm;
+        this.identitySession = session;
+        realmAgent = getIdm().getAgent(REALM_AGENT_ID);
+    }
+
+    public IdentityManager getIdm() {
+        return identitySession.createIdentityManager(realm);
+    }
+
+    public void updateRealm() {
+        getIdm().update(realmAgent);
+    }
+
+    public String getId() {
+        return realm.getId();
+    }
+
+    public String getName() {
+        return (String) realmAgent.getAttribute(REALM_NAME).getValue();
+    }
+
+    public void setName(String name) {
+        realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
+    }
+
+    public boolean isEnabled() {
+        return realmAgent.isEnabled();
+    }
+
+    public void setEnabled(boolean enabled) {
+        realmAgent.setEnabled(enabled);
+    }
+
+    public boolean isSslNotRequired() {
+        return (Boolean) realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
+    }
+
+    public void setSslNotRequired(boolean sslNotRequired) {
+        realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
+    }
+
+    public boolean isCookieLoginAllowed() {
+        return (Boolean) realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
+    }
+
+    public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
+        realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
+    }
+
+    public boolean isRegistrationAllowed() {
+        return (Boolean) realmAgent.getAttribute(REALM_IS_REGISTRATION_ALLOWED).getValue();
+    }
+
+    public void setRegistrationAllowed(boolean registrationAllowed) {
+        realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_REGISTRATION_ALLOWED, registrationAllowed));
+    }
+
+    public long getTokenLifespan() {
+        return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
+    }
+
+    public void setTokenLifespan(long tokenLifespan) {
+        realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN, tokenLifespan));
+    }
+
+    public long getAccessCodeLifespan() {
+        return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
+    }
+
+    public void setAccessCodeLifespan(long accessCodeLifespan) {
+        realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
+    }
+
+    public String getPublicKeyPem() {
+        return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
+    }
+
+    public void setPublicKeyPem(String publicKeyPem) {
+        realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
+        this.publicKey = null;
+    }
+
+    public String getPrivateKeyPem() {
+        return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
+    }
+
+    public void setPrivateKeyPem(String privateKeyPem) {
+        realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
+        this.privateKey = null;
+    }
+
+    public PublicKey getPublicKey() {
+        if (publicKey != null) return publicKey;
+        String pem = getPublicKeyPem();
+        if (pem != null) {
+            try {
+                publicKey = PemUtils.decodePublicKey(pem);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return publicKey;
+    }
+
+    public void setPublicKey(PublicKey publicKey) {
+        this.publicKey = publicKey;
+        StringWriter writer = new StringWriter();
+        PEMWriter pemWriter = new PEMWriter(writer);
+        try {
+            pemWriter.writeObject(publicKey);
+            pemWriter.flush();
+        } catch (IOException e) {
             throw new RuntimeException(e);
-         }
-      }
-      return publicKey;
-   }
-
-   public void setPublicKey(PublicKey publicKey)
-   {
-      this.publicKey = publicKey;
-      StringWriter writer = new StringWriter();
-      PEMWriter pemWriter = new PEMWriter(writer);
-      try
-      {
-         pemWriter.writeObject(publicKey);
-         pemWriter.flush();
-      }
-      catch (IOException e)
-      {
-         throw new RuntimeException(e);
-      }
-      String s = writer.toString();
-      setPublicKeyPem(PemUtils.removeBeginEnd(s));
-   }
-
-   public PrivateKey getPrivateKey()
-   {
-      if (privateKey != null) return privateKey;
-      String pem = getPrivateKeyPem();
-      if (pem != null)
-      {
-         try
-         {
-            privateKey = PemUtils.decodePrivateKey(pem);
-         }
-         catch (Exception e)
-         {
+        }
+        String s = writer.toString();
+        setPublicKeyPem(PemUtils.removeBeginEnd(s));
+    }
+
+    public PrivateKey getPrivateKey() {
+        if (privateKey != null) return privateKey;
+        String pem = getPrivateKeyPem();
+        if (pem != null) {
+            try {
+                privateKey = PemUtils.decodePrivateKey(pem);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return privateKey;
+    }
+
+    public void setPrivateKey(PrivateKey privateKey) {
+        this.privateKey = privateKey;
+        StringWriter writer = new StringWriter();
+        PEMWriter pemWriter = new PEMWriter(writer);
+        try {
+            pemWriter.writeObject(privateKey);
+            pemWriter.flush();
+        } catch (IOException e) {
             throw new RuntimeException(e);
-         }
-      }
-      return privateKey;
-   }
-
-   public void setPrivateKey(PrivateKey privateKey)
-   {
-      this.privateKey = privateKey;
-      StringWriter writer = new StringWriter();
-      PEMWriter pemWriter = new PEMWriter(writer);
-      try
-      {
-         pemWriter.writeObject(privateKey);
-         pemWriter.flush();
-      }
-      catch (IOException e)
-      {
-         throw new RuntimeException(e);
-      }
-      String s = writer.toString();
-      setPrivateKeyPem(PemUtils.removeBeginEnd(s));
-   }
-
-   public List<RequiredCredentialModel> getRequiredCredentials()
-   {
-      IdentityManager idm = getIdm();
-      Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
-      RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
-      query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
-      List<RequiredCredentialRelationship> results = query.getResultList();
-      List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
-      for (RequiredCredentialRelationship relationship : results)
-      {
-         RequiredCredentialModel model = new RequiredCredentialModel();
-         model.setInput(relationship.isInput());
-         model.setSecret(relationship.isSecret());
-         model.setType(relationship.getCredentialType());
-         rtn.add(model);
-      }
-      return rtn;
-   }
-
-   public void addRequiredCredential(RequiredCredentialModel cred)
-   {
-      IdentityManager idm = getIdm();
-      Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
-      RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
-      relationship.setCredentialType(cred.getType());
-      relationship.setInput(cred.isInput());
-      relationship.setSecret(cred.isSecret());
-      relationship.setRealmAgent(realmAgent);
-      idm.add(relationship);
-   }
-
-   public void updateCredential(User user, UserCredentialModel cred)
-   {
-      IdentityManager idm = getIdm();
-      if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD))
-      {
-         Password password = new Password(cred.getValue());
-         idm.updateCredential(user, password);
-      }
-      else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP))
-      {
-         TOTPCredential totp = new TOTPCredential(cred.getValue());
-         idm.updateCredential(user, totp);
-      }
-      else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT))
-      {
-         X509Certificate cert = null;
-         try
-         {
-            cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
-         }
-         catch (Exception e)
-         {
-            throw new RuntimeException(e);
-         }
-         X509CertificateCredentials creds = new X509CertificateCredentials(cert);
-         idm.updateCredential(user, creds);
-      }
-   }
-
-   public List<Role> getRoles()
-   {
-      IdentityManager idm = getIdm();
-      IdentityQuery<Role> query = idm.createIdentityQuery(Role.class);
-      query.setParameter(Role.PARTITION, realm);
-      return query.getResultList();
-   }
-
-
-   protected ResourceModel loadResource(Agent resource)
-   {
-      Tier tier = factory.findTier(resource.getPartition().getId());
-      return new ResourceModel(tier, resource, this, factory);
-   }
-
-   /**
-    * Key name, value resource
-    *
-    * @return
-    */
-   public Map<String, ResourceModel> getResourceMap()
-   {
-      Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>();
-      for (ResourceModel resource : getResources())
-      {
-         resourceMap.put(resource.getName(), resource);
-      }
-      return resourceMap;
-   }
-
-   public List<ResourceModel> getResources()
-   {
-      IdentityManager idm = getIdm();
-      RelationshipQuery<RealmResourceRelationship> query = idm.createRelationshipQuery(RealmResourceRelationship.class);
-      query.setParameter(RealmResourceRelationship.REALM_AGENT, realmAgent);
-      List<RealmResourceRelationship> results = query.getResultList();
-      List<ResourceModel> resources = new ArrayList<ResourceModel>();
-      for (RealmResourceRelationship relationship : results)
-      {
-         ResourceModel model = loadResource(relationship.getResourceAgent());
-         resources.add(model);
-      }
-
-      return resources;
-   }
-
-   public ResourceModel addResource(String name)
-   {
-      Tier newTier = factory.createTier(RealmManager.generateId());
-      IdentityManager idm = factory.createIdentityManager(newTier);
-      SimpleAgent resourceAgent = new SimpleAgent(ResourceModel.RESOURCE_AGENT_ID);
-      resourceAgent.setAttribute(new Attribute<String>(ResourceModel.RESOURCE_NAME, name));
-      idm.add(resourceAgent);
-      idm = getIdm();
-      RealmResourceRelationship relationship = new RealmResourceRelationship();
-      relationship.setRealmAgent(realmAgent);
-      relationship.setResourceAgent(resourceAgent);
-      idm.add(relationship);
-      return new ResourceModel(newTier, resourceAgent, this, factory);
-   }
-
-   public Set<String> getRoleMappings(User user)
-   {
-      RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
-      query.setParameter(Grant.ASSIGNEE, user);
-      List<Grant> grants = query.getResultList();
-      HashSet<String> set = new HashSet<String>();
-      for (Grant grant : grants)
-      {
-         if (grant.getRole().getPartition().getId().equals(realm.getId()))set.add(grant.getRole().getName());
-      }
-      return set;
-   }
-
-   public void addScope(Agent agent, String roleName)
-   {
-      IdentityManager idm = getIdm();
-      Role role = idm.getRole(roleName);
-      if (role == null) throw new RuntimeException("role not found");
-      ScopeRelationship scope = new ScopeRelationship();
-      scope.setClient(agent);
-      scope.setScope(role);
-
-   }
-
-
-   public Set<String> getScope(Agent agent)
-   {
-      RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
-      query.setParameter(ScopeRelationship.CLIENT, agent);
-      List<ScopeRelationship> scope = query.getResultList();
-      HashSet<String> set = new HashSet<String>();
-      for (ScopeRelationship rel : scope)
-      {
-         if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName());
-      }
-      return set;
-   }
-
-   public boolean isRealmAdmin(Agent agent)
-   {
-      IdentityManager idm = getIdm();
-      RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
-      query.setParameter(RealmAdminRelationship.REALM, realm);
-      query.setParameter(RealmAdminRelationship.ADMIN, agent);
-      List<RealmAdminRelationship> results = query.getResultList();
-      return results.size() > 0;
-   }
-
-   public void addRealmAdmin(Agent agent)
-   {
-      IdentityManager idm = getIdm();
-      RealmAdminRelationship relationship = new RealmAdminRelationship();
-      relationship.setAdmin(agent);
-      relationship.setRealm(realm);
-      idm.add(relationship);
-   }
+        }
+        String s = writer.toString();
+        setPrivateKeyPem(PemUtils.removeBeginEnd(s));
+    }
+
+    public List<RequiredCredentialModel> getRequiredCredentials() {
+        IdentityManager idm = getIdm();
+        Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
+        RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
+        query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
+        List<RequiredCredentialRelationship> results = query.getResultList();
+        List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
+        for (RequiredCredentialRelationship relationship : results) {
+            RequiredCredentialModel model = new RequiredCredentialModel();
+            model.setInput(relationship.isInput());
+            model.setSecret(relationship.isSecret());
+            model.setType(relationship.getCredentialType());
+            rtn.add(model);
+        }
+        return rtn;
+    }
+
+    public void addRequiredCredential(RequiredCredentialModel cred) {
+        IdentityManager idm = getIdm();
+        Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
+        RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
+        relationship.setCredentialType(cred.getType());
+        relationship.setInput(cred.isInput());
+        relationship.setSecret(cred.isSecret());
+        relationship.setRealmAgent(realmAgent);
+        idm.add(relationship);
+    }
+
+    public void updateCredential(User user, UserCredentialModel cred) {
+        IdentityManager idm = getIdm();
+        if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) {
+            Password password = new Password(cred.getValue());
+            idm.updateCredential(user, password);
+        } else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) {
+            TOTPCredential totp = new TOTPCredential(cred.getValue());
+            idm.updateCredential(user, totp);
+        } else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT)) {
+            X509Certificate cert = null;
+            try {
+                cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            X509CertificateCredentials creds = new X509CertificateCredentials(cert);
+            idm.updateCredential(user, creds);
+        }
+    }
+
+    public List<Role> getRoles() {
+        IdentityManager idm = getIdm();
+        IdentityQuery<Role> query = idm.createIdentityQuery(Role.class);
+        query.setParameter(Role.PARTITION, realm);
+        return query.getResultList();
+    }
+
+
+    /**
+     * Key name, value resource
+     *
+     * @return
+     */
+    public Map<String, ResourceModel> getResourceMap() {
+        Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>();
+        for (ResourceModel resource : getResources()) {
+            resourceMap.put(resource.getName(), resource);
+        }
+        return resourceMap;
+    }
+
+    public List<ResourceModel> getResources() {
+        IdentityManager idm = getIdm();
+        RelationshipQuery<ResourceRelationship> query = idm.createRelationshipQuery(ResourceRelationship.class);
+        query.setParameter(ResourceRelationship.REALM_AGENT, realmAgent);
+        List<ResourceRelationship> results = query.getResultList();
+        List<ResourceModel> resources = new ArrayList<ResourceModel>();
+        for (ResourceRelationship relationship : results) {
+            Tier resourceTier = identitySession.findTier(relationship.getResourceId());
+            ResourceModel model = new ResourceModel(resourceTier,relationship, this, identitySession);
+            resources.add(model);
+        }
+
+        return resources;
+    }
+
+    public ResourceModel addResource(String name) {
+        Tier newTier = identitySession.createTier(RealmManager.generateId());
+        IdentityManager idm = getIdm();
+        ResourceRelationship relationship = new ResourceRelationship();
+        relationship.setResourceName(name);
+        relationship.setRealmAgent(realmAgent);
+        relationship.setResourceId(newTier.getId());
+        idm.add(relationship);
+        return new ResourceModel(newTier, relationship, this, identitySession);
+    }
+
+    public Set<String> getRoleMappings(User user) {
+        RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, user);
+        List<Grant> grants = query.getResultList();
+        HashSet<String> set = new HashSet<String>();
+        for (Grant grant : grants) {
+            if (grant.getRole().getPartition().getId().equals(realm.getId())) set.add(grant.getRole().getName());
+        }
+        return set;
+    }
+
+    public void addScope(Agent agent, String roleName) {
+        IdentityManager idm = getIdm();
+        Role role = idm.getRole(roleName);
+        if (role == null) throw new RuntimeException("role not found");
+        ScopeRelationship scope = new ScopeRelationship();
+        scope.setClient(agent);
+        scope.setScope(role);
+
+    }
+
+
+    public Set<String> getScope(Agent agent) {
+        RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
+        query.setParameter(ScopeRelationship.CLIENT, agent);
+        List<ScopeRelationship> scope = query.getResultList();
+        HashSet<String> set = new HashSet<String>();
+        for (ScopeRelationship rel : scope) {
+            if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName());
+        }
+        return set;
+    }
+
+    public boolean isRealmAdmin(Agent agent) {
+        IdentityManager idm = new RealmManager(identitySession).defaultRealm().getIdm();
+        RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
+        query.setParameter(RealmAdminRelationship.REALM, realm.getId());
+        query.setParameter(RealmAdminRelationship.ADMIN, agent);
+        List<RealmAdminRelationship> results = query.getResultList();
+        return results.size() > 0;
+    }
+
+    public void addRealmAdmin(Agent agent) {
+        IdentityManager idm = new RealmManager(identitySession).defaultRealm().getIdm();
+        RealmAdminRelationship relationship = new RealmAdminRelationship();
+        relationship.setAdmin(agent);
+        relationship.setRealm(realm.getId());
+        idm.add(relationship);
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
index cb24a98..cf68d46 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
@@ -4,6 +4,7 @@ import org.picketlink.idm.model.AbstractAttributedType;
 import org.picketlink.idm.model.Agent;
 import org.picketlink.idm.model.Realm;
 import org.picketlink.idm.model.Relationship;
+import org.picketlink.idm.model.annotation.AttributeProperty;
 import org.picketlink.idm.model.annotation.IdentityProperty;
 import org.picketlink.idm.query.RelationshipQueryParameter;
 
@@ -11,48 +12,43 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class RealmAdminRelationship extends AbstractAttributedType implements Relationship
-{
-   private static final long serialVersionUID = 1L;
-
-   public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
-
-      @Override
-      public String getName() {
-         return "realm";
-      }
-   };
-
-   public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() {
-
-      @Override
-      public String getName() {
-         return "admin";
-      }
-   };
-
-   protected Realm realm;
-   protected Agent admin;
-
-   @IdentityProperty
-   public Realm getRealm()
-   {
-      return realm;
-   }
-
-   public void setRealm(Realm realm)
-   {
-      this.realm = realm;
-   }
-
-   @IdentityProperty
-   public Agent getAdmin()
-   {
-      return admin;
-   }
-
-   public void setAdmin(Agent admin)
-   {
-      this.admin = admin;
-   }
+public class RealmAdminRelationship extends AbstractAttributedType implements Relationship {
+    private static final long serialVersionUID = 1L;
+
+    public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
+
+        @Override
+        public String getName() {
+            return "realm";
+        }
+    };
+
+    public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() {
+
+        @Override
+        public String getName() {
+            return "admin";
+        }
+    };
+
+    protected String realm;
+    protected Agent admin;
+
+    @AttributeProperty
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+
+    @IdentityProperty
+    public Agent getAdmin() {
+        return admin;
+    }
+
+    public void setAdmin(Agent admin) {
+        this.admin = admin;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
index 48a1c90..59ce02d 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
@@ -11,69 +11,59 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship
-{
-   private static final long serialVersionUID = 1L;
+public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship {
+    private static final long serialVersionUID = 1L;
 
-   public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
+    public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
 
-      @Override
-      public String getName() {
-         return "realmAgent";
-      }
-   };
+        @Override
+        public String getName() {
+            return "realmAgent";
+        }
+    };
 
 
-   protected Agent realmAgent;
-   protected String credentialType;
-   protected boolean input;
-   protected boolean secret;
+    protected Agent realmAgent;
+    protected String credentialType;
+    protected boolean input;
+    protected boolean secret;
 
-   public RequiredCredentialRelationship()
-   {
-   }
+    public RequiredCredentialRelationship() {
+    }
 
-   @IdentityProperty
-   public Agent getRealmAgent()
-   {
-      return realmAgent;
-   }
+    @IdentityProperty
+    public Agent getRealmAgent() {
+        return realmAgent;
+    }
 
-   public void setRealmAgent(Agent realmAgent)
-   {
-      this.realmAgent = realmAgent;
-   }
+    public void setRealmAgent(Agent realmAgent) {
+        this.realmAgent = realmAgent;
+    }
 
-   @AttributeProperty
-   public String getCredentialType()
-   {
-      return credentialType;
-   }
+    @AttributeProperty
+    public String getCredentialType() {
+        return credentialType;
+    }
 
-   public void setCredentialType(String credentialType)
-   {
-      this.credentialType = credentialType;
-   }
+    public void setCredentialType(String credentialType) {
+        this.credentialType = credentialType;
+    }
 
-   @AttributeProperty
-   public boolean isInput()
-   {
-      return input;
-   }
+    @AttributeProperty
+    public boolean isInput() {
+        return input;
+    }
 
-   public void setInput(boolean input)
-   {
-      this.input = input;
-   }
+    public void setInput(boolean input) {
+        this.input = input;
+    }
 
-   @AttributeProperty
-   public boolean isSecret()
-   {
-      return secret;
-   }
+    @AttributeProperty
+    public boolean isSecret() {
+        return secret;
+    }
 
-   public void setSecret(boolean secret)
-   {
-      this.secret = secret;
-   }
+    public void setSecret(boolean secret) {
+        this.secret = secret;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
index b8bea48..7221c72 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
@@ -11,40 +11,35 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class ScopeRelationship extends AbstractAttributedType implements Relationship
-{
-   private static final long serialVersionUID = 1L;
-
-   public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() {
-
-      @Override
-      public String getName() {
-         return "client";
-      }
-   };
-
-   protected Agent client;
-   protected Role scope;
-
-   @IdentityProperty
-   public Agent getClient()
-   {
-      return client;
-   }
-
-   public void setClient(Agent client)
-   {
-      this.client = client;
-   }
-
-   @IdentityProperty
-   public Role getScope()
-   {
-      return scope;
-   }
-
-   public void setScope(Role scope)
-   {
-      this.scope = scope;
-   }
+public class ScopeRelationship extends AbstractAttributedType implements Relationship {
+    private static final long serialVersionUID = 1L;
+
+    public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() {
+
+        @Override
+        public String getName() {
+            return "client";
+        }
+    };
+
+    protected Agent client;
+    protected Role scope;
+
+    @IdentityProperty
+    public Agent getClient() {
+        return client;
+    }
+
+    public void setClient(Agent client) {
+        this.client = client;
+    }
+
+    @IdentityProperty
+    public Role getScope() {
+        return scope;
+    }
+
+    public void setScope(Role scope) {
+        this.scope = scope;
+    }
 }
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 6476ef7..c8ca584 100755
--- a/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
@@ -1,42 +1,48 @@
 package org.keycloak.services.models;
 
+import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class RequiredCredentialModel
-{
-   protected String type;
-   protected boolean input;
-   protected boolean secret;
-
-   public String getType()
-   {
-      return type;
-   }
-
-   public void setType(String type)
-   {
-      this.type = type;
-   }
-
-   public boolean isInput()
-   {
-      return input;
-   }
-
-   public void setInput(boolean input)
-   {
-      this.input = input;
-   }
-
-   public boolean isSecret()
-   {
-      return secret;
-   }
-
-   public void setSecret(boolean secret)
-   {
-      this.secret = secret;
-   }
+public class RequiredCredentialModel {
+    protected String type;
+    protected boolean input;
+    protected boolean secret;
+
+    public RequiredCredentialModel() {
+    }
+
+    public RequiredCredentialModel(String type, boolean input, boolean secret) {
+        this.type = type;
+        this.input = input;
+        this.secret = secret;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public boolean isInput() {
+        return input;
+    }
+
+    public void setInput(boolean input) {
+        this.input = input;
+    }
+
+    public boolean isSecret() {
+        return secret;
+    }
+
+    public void setSecret(boolean secret) {
+        this.secret = secret;
+    }
+
+    public static final RequiredCredentialModel PASSWORD = new RequiredCredentialModel(RequiredCredentialRepresentation.PASSWORD, true, true);
 }
diff --git a/services/src/main/java/org/keycloak/services/models/ResourceModel.java b/services/src/main/java/org/keycloak/services/models/ResourceModel.java
index b41edd6..cb343b0 100755
--- a/services/src/main/java/org/keycloak/services/models/ResourceModel.java
+++ b/services/src/main/java/org/keycloak/services/models/ResourceModel.java
@@ -1,8 +1,9 @@
 package org.keycloak.services.models;
 
+import org.keycloak.services.models.relationships.ResourceRelationship;
 import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.internal.IdentityManagerFactory;
 import org.picketlink.idm.model.Agent;
 import org.picketlink.idm.model.Attribute;
 import org.picketlink.idm.model.Grant;
@@ -20,112 +21,94 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class ResourceModel
-{
-   public static final String RESOURCE_AGENT_ID = "_resource_";
-   public static final String RESOURCE_NAME = "name";
-   public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
-
-   protected Tier tier;
-   protected Agent agent;
-   protected RealmModel realm;
-   protected IdentityManagerFactory factory;
-
-   public ResourceModel(Tier tier, Agent agent, RealmModel realm, IdentityManagerFactory factory)
-   {
-      this.tier = tier;
-      this.agent = agent;
-      this.realm = realm;
-      this.factory = factory;
-   }
-
-   public IdentityManager getIdm()
-   {
-      return factory.createIdentityManager(tier);
-   }
-
-   public void updateResource()
-   {
-      getIdm().update(agent);
-   }
-
-   public String getId()
-   {
-      return tier.getId();
-   }
-
-   public String getName()
-   {
-      return (String)agent.getAttribute(RESOURCE_NAME).getValue();
-   }
-
-   public void setName(String name)
-   {
-      agent.setAttribute(new Attribute<String>(RESOURCE_NAME, name));
-      getIdm().update(agent);
-   }
-
-   public boolean isEnabled()
-   {
-      return agent.isEnabled();
-   }
-
-   public void setEnabled(boolean enabled)
-   {
-      agent.setEnabled(enabled);
-   }
-
-   public boolean isSurrogateAuthRequired()
-   {
-      return (Boolean)agent.getAttribute(RESOURCE_SURROGATE_AUTH).getValue();
-   }
-
-   public void setSurrogateAuthRequired(boolean surrogateAuthRequired)
-   {
-      agent.setAttribute(new Attribute<Boolean>(RESOURCE_SURROGATE_AUTH, surrogateAuthRequired));
-   }
-
-   public List<Role> getRoles()
-   {
-      IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
-      query.setParameter(Role.PARTITION, tier);
-      return query.getResultList();
-   }
-
-   public Set<String> getRoleMappings(User user)
-   {
-      RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
-      query.setParameter(Grant.ASSIGNEE, user);
-      List<Grant> grants = query.getResultList();
-      HashSet<String> set = new HashSet<String>();
-      for (Grant grant : grants)
-      {
-         if (grant.getRole().getPartition().getId().equals(tier.getId()))set.add(grant.getRole().getName());
-      }
-      return set;
-   }
-
-   public void addScope(Agent agent, String roleName)
-   {
-      IdentityManager idm = getIdm();
-      Role role = idm.getRole(roleName);
-      if (role == null) throw new RuntimeException("role not found");
-      ScopeRelationship scope = new ScopeRelationship();
-      scope.setClient(agent);
-      scope.setScope(role);
-
-   }
-
-   public Set<String> getScope(Agent agent)
-   {
-      RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
-      query.setParameter(ScopeRelationship.CLIENT, agent);
-      List<ScopeRelationship> scope = query.getResultList();
-      HashSet<String> set = new HashSet<String>();
-      for (ScopeRelationship rel : scope)
-      {
-         if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
-      }
-      return set;
-   }
+public class ResourceModel {
+    public static final String RESOURCE_AGENT_ID = "_resource_";
+    public static final String RESOURCE_NAME = "name";
+    public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
+
+    protected Tier tier;
+    protected ResourceRelationship agent;
+    protected RealmModel realm;
+    protected IdentitySession IdentitySession;
+
+    public ResourceModel(Tier tier, ResourceRelationship agent, RealmModel realm, IdentitySession factory) {
+        this.tier = tier;
+        this.agent = agent;
+        this.realm = realm;
+        this.IdentitySession = factory;
+    }
+
+    public IdentityManager getIdm() {
+        return IdentitySession.createIdentityManager(tier);
+    }
+
+    public void updateResource() {
+        getIdm().update(agent);
+    }
+
+    public String getId() {
+        return tier.getId();
+    }
+
+    public String getName() {
+        return agent.getResourceName();
+    }
+
+    public void setName(String name) {
+        agent.setResourceName(name);
+    }
+
+    public boolean isEnabled() {
+        return agent.getEnabled();
+    }
+
+    public void setEnabled(boolean enabled) {
+        agent.setEnabled(enabled);
+    }
+
+    public boolean isSurrogateAuthRequired() {
+        return agent.getSurrogateAuthRequired();
+    }
+
+    public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+        agent.setSurrogateAuthRequired(surrogateAuthRequired);
+    }
+
+    public List<Role> getRoles() {
+        IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
+        query.setParameter(Role.PARTITION, tier);
+        return query.getResultList();
+    }
+
+    public Set<String> getRoleMappings(User user) {
+        RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, user);
+        List<Grant> grants = query.getResultList();
+        HashSet<String> set = new HashSet<String>();
+        for (Grant grant : grants) {
+            if (grant.getRole().getPartition().getId().equals(tier.getId())) set.add(grant.getRole().getName());
+        }
+        return set;
+    }
+
+    public void addScope(Agent agent, String roleName) {
+        IdentityManager idm = getIdm();
+        Role role = idm.getRole(roleName);
+        if (role == null) throw new RuntimeException("role not found");
+        ScopeRelationship scope = new ScopeRelationship();
+        scope.setClient(agent);
+        scope.setScope(role);
+
+    }
+
+    public Set<String> getScope(Agent agent) {
+        RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
+        query.setParameter(ScopeRelationship.CLIENT, agent);
+        List<ScopeRelationship> scope = query.getResultList();
+        HashSet<String> set = new HashSet<String>();
+        for (ScopeRelationship rel : scope) {
+            if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
+        }
+        return set;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
index e2a3603..5807319 100755
--- a/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
+++ b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
@@ -4,29 +4,24 @@ package org.keycloak.services.models;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class UserCredentialModel
-{
+public class UserCredentialModel {
 
-   protected String type;
-   protected String value;
+    protected String type;
+    protected String value;
 
-   public String getType()
-   {
-      return type;
-   }
+    public String getType() {
+        return type;
+    }
 
-   public void setType(String type)
-   {
-      this.type = type;
-   }
+    public void setType(String type) {
+        this.type = type;
+    }
 
-   public String getValue()
-   {
-      return value;
-   }
+    public String getValue() {
+        return value;
+    }
 
-   public void setValue(String value)
-   {
-      this.value = value;
-   }
+    public void setValue(String value) {
+        this.value = value;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
new file mode 100755
index 0000000..3af3e9c
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -0,0 +1,90 @@
+package org.keycloak.services.resources;
+
+import org.keycloak.SkeletonKeyContextResolver;
+import org.keycloak.services.filters.IdentitySessionFilter;
+import org.keycloak.services.models.relationships.RealmAdminRelationship;
+import org.keycloak.services.models.relationships.ResourceRelationship;
+import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
+import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySessionFactory;
+import org.picketlink.idm.config.IdentityConfiguration;
+import org.picketlink.idm.config.IdentityConfigurationBuilder;
+import org.picketlink.idm.internal.DefaultIdentitySessionFactory;
+import org.picketlink.idm.jpa.internal.ResourceLocalJpaIdentitySessionHandler;
+import org.picketlink.idm.jpa.schema.CredentialObject;
+import org.picketlink.idm.jpa.schema.CredentialObjectAttribute;
+import org.picketlink.idm.jpa.schema.IdentityObject;
+import org.picketlink.idm.jpa.schema.IdentityObjectAttribute;
+import org.picketlink.idm.jpa.schema.PartitionObject;
+import org.picketlink.idm.jpa.schema.RelationshipIdentityObject;
+import org.picketlink.idm.jpa.schema.RelationshipObject;
+import org.picketlink.idm.jpa.schema.RelationshipObjectAttribute;
+
+import javax.annotation.PreDestroy;
+import javax.ws.rs.core.Application;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakApplication extends Application {
+    protected Set<Object> singletons = new HashSet<Object>();
+    protected Set<Class<?>> classes = new HashSet<Class<?>>();
+
+    protected IdentitySessionFactory factory;
+
+    public KeycloakApplication() {
+        this.factory = createFactory();
+        IdentitySessionFilter filter = new IdentitySessionFilter(factory);
+        singletons.add(new RealmsResource());
+        singletons.add(filter);
+        classes.add(SkeletonKeyContextResolver.class);
+        classes.add(RegistrationService.class);
+    }
+
+    public IdentitySessionFactory getFactory() {
+        return factory;
+    }
+
+    @PreDestroy
+    public void destroy() {
+        factory.close();
+    }
+
+    public static IdentitySessionFactory createFactory() {
+        ResourceLocalJpaIdentitySessionHandler handler = new ResourceLocalJpaIdentitySessionHandler("keycloak-identity-store");
+        IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
+
+        builder
+                .stores()
+                .jpa()
+                .identityClass(IdentityObject.class)
+                .attributeClass(IdentityObjectAttribute.class)
+                .relationshipClass(RelationshipObject.class)
+                .relationshipIdentityClass(RelationshipIdentityObject.class)
+                .relationshipAttributeClass(RelationshipObjectAttribute.class)
+                .credentialClass(CredentialObject.class)
+                .credentialAttributeClass(CredentialObjectAttribute.class)
+                .partitionClass(PartitionObject.class)
+                .supportAllFeatures()
+                .supportRelationshipType(RealmAdminRelationship.class, ResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class)
+                .setIdentitySessionHandler(handler);
+
+        IdentityConfiguration build = builder.build();
+        return new DefaultIdentitySessionFactory(build);
+    }
+
+
+    @Override
+    public Set<Class<?>> getClasses() {
+        return classes;
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        return singletons;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/RegistrationService.java b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
index c4c9b05..55c576c 100755
--- a/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
+++ b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
@@ -1,15 +1,17 @@
 package org.keycloak.services.resources;
 
+import org.jboss.resteasy.logging.Logger;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.models.RealmManager;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.UserCredentialModel;
-import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.model.Role;
 import org.picketlink.idm.model.SimpleUser;
 import org.picketlink.idm.model.User;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.core.Context;
@@ -23,47 +25,53 @@ import java.net.URI;
  * @version $Revision: 1 $
  */
 @Path("/registrations")
-public class RegistrationService
-{
-   public static final String REALM_CREATOR_ROLE = "realm-creator";
-   protected RealmManager adapter;
-   protected RealmModel defaultRealm;
+public class RegistrationService {
+    protected static final Logger logger = Logger.getLogger(RegistrationService.class);
+    public static final String REALM_CREATOR_ROLE = "realm-creator";
 
-   @Context
-   protected UriInfo uriInfo;
+    @Context
+    protected UriInfo uriInfo;
 
-   public RegistrationService(RealmManager adapter)
-   {
-      this.adapter = adapter;
-      defaultRealm = adapter.getRealm(Realm.DEFAULT_REALM);
-   }
+    @Context
+    protected IdentitySession identitySession;
 
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response register(UserRepresentation newUser) {
+        identitySession.getTransaction().begin();
+        try {
+            RealmManager realmManager = new RealmManager(identitySession);
+            RealmModel defaultRealm = realmManager.defaultRealm();
+            if (!defaultRealm.isEnabled()) {
+                throw new ForbiddenException();
+            }
+            if (!defaultRealm.isRegistrationAllowed()) {
+                throw new ForbiddenException();
+            }
+            User user = defaultRealm.getIdm().getUser(newUser.getUsername());
+            if (user != null) {
+                return Response.status(400).type("text/plain").entity("user exists").build();
+            }
 
-
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   public Response register(UserRepresentation newUser)
-   {
-      User user = defaultRealm.getIdm().getUser(newUser.getUsername());
-      if (user != null)
-      {
-         return Response.status(400).type("text/plain").entity("user exists").build();
-      }
-
-      user = new SimpleUser(newUser.getUsername());
-      defaultRealm.getIdm().add(user);
-      for (UserRepresentation.Credential cred : newUser.getCredentials())
-      {
-         UserCredentialModel credModel = new UserCredentialModel();
-         credModel.setType(cred.getType());
-         credModel.setValue(cred.getValue());
-         defaultRealm.updateCredential(user, credModel);
-      }
-      Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE);
-      defaultRealm.getIdm().grantRole(user, realmCreator);
-      URI uri = uriInfo.getBaseUriBuilder().path(RealmFactory.class).path(user.getLoginName()).build();
-      return Response.created(uri).build();
-   }
+            user = new SimpleUser(newUser.getUsername());
+            defaultRealm.getIdm().add(user);
+            for (UserRepresentation.Credential cred : newUser.getCredentials()) {
+                UserCredentialModel credModel = new UserCredentialModel();
+                credModel.setType(cred.getType());
+                credModel.setValue(cred.getValue());
+                defaultRealm.updateCredential(user, credModel);
+            }
+            Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE);
+            defaultRealm.getIdm().grantRole(user, realmCreator);
+            identitySession.getTransaction().commit();
+            URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
+            return Response.created(uri).build();
+        } catch (RuntimeException e) {
+            logger.error("Failed to register", e);
+            identitySession.getTransaction().rollback();
+            throw e;
+        }
+    }
 
 
 }
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 ebdf2a9..d77339d 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -9,21 +9,21 @@ import org.jboss.resteasy.logging.Logger;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.SkeletonKeyScope;
 import org.keycloak.representations.SkeletonKeyToken;
+import org.keycloak.services.managers.AccessCodeEntry;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.models.RealmManager;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.RequiredCredentialModel;
 import org.keycloak.services.models.ResourceModel;
+import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.model.User;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.NotAuthorizedException;
-import javax.ws.rs.NotFoundException;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
@@ -41,555 +41,400 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-@Path("/realms")
-public class TokenService
-{
-   public static class AccessCode
-   {
-      protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
-      protected long expiration;
-      protected SkeletonKeyToken token;
-      protected User client;
-
-      public boolean isExpired()
-      {
-         return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
-      }
-
-      public String getId()
-      {
-         return id;
-      }
-
-      public long getExpiration()
-      {
-         return expiration;
-      }
-
-      public void setExpiration(long expiration)
-      {
-         this.expiration = expiration;
-      }
-
-      public SkeletonKeyToken getToken()
-      {
-         return token;
-      }
-
-      public void setToken(SkeletonKeyToken token)
-      {
-         this.token = token;
-      }
-
-      public User getClient()
-      {
-         return client;
-      }
-
-      public void setClient(User client)
-      {
-         this.client = client;
-      }
-   }
-
-   protected RealmManager adapter;
-   protected TokenManager tokenManager;
-   protected AuthenticationManager authManager;
-   protected Logger logger = Logger.getLogger(TokenService.class);
-   protected Map<String, AccessCode> accessCodeMap = new HashMap<String, AccessCode>();
-   @Context
-   protected UriInfo uriInfo;
-   @Context
-   protected Providers providers;
-   @Context
-   protected SecurityContext securityContext;
-   @Context
-   protected HttpHeaders headers;
-
-   private static AtomicLong counter = new AtomicLong(1);
-   private static String generateId()
-   {
-      return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
-   }
-
-   public TokenService(RealmManager adapter)
-   {
-      this.adapter = adapter;
-      this.tokenManager = new TokenManager(adapter);
-      this.authManager = new AuthenticationManager(adapter);
-   }
-
-   @Path("{realm}/grants/identity-token")
-   @POST
-   @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-   @Produces(MediaType.APPLICATION_JSON)
-   public Response identityTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form)
-   {
-      String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
-      if (username == null)
-      {
-         throw new NotAuthorizedException("No user");
-      }
-      RealmModel realm = adapter.getRealm(realmId);
-      if (realm == null)
-      {
-         throw new NotFoundException("Realm not found");
-      }
-      if (!realm.isEnabled())
-      {
-         throw new NotAuthorizedException("Disabled realm");
-      }
-      User user = realm.getIdm().getUser(username);
-      if (user == null)
-      {
-         throw new NotAuthorizedException("No user");
-      }
-      if (!user.isEnabled())
-      {
-         throw new NotAuthorizedException("Disabled user.");
-      }
-      SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
-      String encoded = tokenManager.encodeToken(realm, token);
-      AccessTokenResponse res = accessTokenResponse(token, encoded);
-      return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
-   }
-
-   @Path("{realm}/grants/access")
-   @POST
-   @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-   @Produces(MediaType.APPLICATION_JSON)
-   public Response accessTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form)
-   {
-      String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
-      if (username == null)
-      {
-         throw new NotAuthorizedException("No user");
-      }
-      RealmModel realm = adapter.getRealm(realmId);
-      if (realm == null)
-      {
-         throw new NotFoundException("Realm not found");
-      }
-      if (!realm.isEnabled())
-      {
-         throw new NotAuthorizedException("Disabled realm");
-      }
-      User user = realm.getIdm().getUser(username);
-      if (user == null)
-      {
-         throw new NotAuthorizedException("No user");
-      }
-      if (!user.isEnabled())
-      {
-         throw new NotAuthorizedException("Disabled user.");
-      }
-      if (authManager.authenticateForm(realm, user, form))
-      {
-         throw new NotAuthorizedException("Auth failed");
-      }
-      SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
-      String encoded = tokenManager.encodeToken(realm, token);
-      AccessTokenResponse res = accessTokenResponse(token, encoded);
-      return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
-   }
-
-   @Path("{realm}/auth/request/login")
-   @POST
-   @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-   public Response login(@PathParam("realm") String realmId,
-                         MultivaluedMap<String, String> formData)
-   {
-      String clientId = formData.getFirst("client_id");
-      String scopeParam = formData.getFirst("scope");
-      String state = formData.getFirst("state");
-      String redirect = formData.getFirst("redirect_uri");
-
-      RealmModel realm = adapter.getRealm(realmId);
-      if (realm == null)
-      {
-         throw new NotFoundException("Realm not found");
-      }
-      if (!realm.isEnabled())
-      {
-         return Response.ok("Realm not enabled").type("text/html").build();
-      }
-      User client = realm.getIdm().getUser(clientId);
-      if (client == null)
-      {
-         throw new NotAuthorizedException("No client");
-      }
-      if (!client.isEnabled())
-      {
-         return Response.ok("Requester not enabled").type("text/html").build();
-      }
-      String username = formData.getFirst("username");
-      User user = realm.getIdm().getUser(username);
-      if (user == null)
-      {
-         logger.debug("user not found");
-         return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client);
-      }
-      if (!user.isEnabled())
-      {
-         return Response.ok("Your account is not enabled").type("text/html").build();
-
-      }
-      boolean authenticated = authManager.authenticateForm(realm, user, formData);
-      if (!authenticated) return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
-
-      SkeletonKeyToken token = null;
-      if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
-      else token = tokenManager.createLoginToken(realm, client, user);
-
-      AccessCode code = new AccessCode();
-      code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
-      code.setToken(token);
-      code.setClient(client);
-      synchronized (accessCodeMap)
-      {
-         accessCodeMap.put(code.getId(), code);
-      }
-      String accessCode = null;
-      try
-      {
-         accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
-      }
-      catch (UnsupportedEncodingException e)
-      {
-         throw new RuntimeException(e);
-      }
-      UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
-      if (state != null) redirectUri.queryParam("state", state);
-      return Response.status(302).location(redirectUri.build()).build();
-   }
-
-   @Path("{realm}/access/codes")
-   @POST
-   @Produces("application/json")
-   public Response accessRequest(@PathParam("realm") String realmId,
-                                 MultivaluedMap<String, String> formData)
-   {
-      RealmModel realm = adapter.getRealm(realmId);
-      if (realm == null)
-      {
-         throw new NotFoundException("Realm not found");
-      }
-      if (!realm.isEnabled())
-      {
-         throw new NotAuthorizedException("Realm not enabled");
-      }
-
-      String code = formData.getFirst("code");
-      if (code == null)
-      {
-         logger.debug("code not specified");
-         Map<String, String> error = new HashMap<String, String>();
-         error.put("error", "invalid_request");
-         error.put("error_description", "code not specified");
-         return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-
-      }
-      String client_id = formData.getFirst("client_id");
-      if (client_id == null)
-      {
-         logger.debug("client_id not specified");
-         Map<String, String> error = new HashMap<String, String>();
-         error.put("error", "invalid_request");
-         error.put("error_description", "client_id not specified");
-         return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-      }
-      User client = realm.getIdm().getUser(client_id);
-      if (client == null)
-      {
-         logger.debug("Could not find user");
-         Map<String, String> error = new HashMap<String, String>();
-         error.put("error", "invalid_client");
-         error.put("error_description", "Could not find user");
-         return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-      }
-
-      if (!client.isEnabled())
-      {
-         logger.debug("user is not enabled");
-         Map<String, String> error = new HashMap<String, String>();
-         error.put("error", "invalid_client");
-         error.put("error_description", "User is not enabled");
-         return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-      }
-
-      boolean authenticated = authManager.authenticateForm(realm, client, formData);
-      if (!authenticated)
-      {
-         Map<String, String> error = new HashMap<String, String>();
-         error.put("error", "unauthorized_client");
-         return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-      }
-
-
-
-      JWSInput input = new JWSInput(code, providers);
-      boolean verifiedCode = false;
-      try
-      {
-         verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
-      }
-      catch (Exception ignored)
-      {
-         logger.debug("Failed to verify signature", ignored);
-      }
-      if (!verifiedCode)
-      {
-         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();
-      }
-      String key = input.readContent(String.class);
-      AccessCode accessCode = null;
-      synchronized (accessCodeMap)
-      {
-         accessCode = accessCodeMap.remove(key);
-      }
-      if (accessCode == null)
-      {
-         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();
-      }
-      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();
-      }
-      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();
-      }
-      if (!client.getId().equals(accessCode.getClient().getId()))
-      {
-         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();
-      }
-      AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
-      return Response.ok(res).build();
-
-   }
-
-   protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token)
-   {
-      byte[] tokenBytes = null;
-      try
-      {
-         tokenBytes = JsonSerialization.toByteArray(token, false);
-      }
-      catch (Exception e)
-      {
-         throw new RuntimeException(e);
-      }
-      String encodedToken = new JWSBuilder()
-              .content(tokenBytes)
-              .rsa256(privateKey);
-
-      return accessTokenResponse(token, encodedToken);
-   }
-
-   protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken)
-   {
-      AccessTokenResponse res = new AccessTokenResponse();
-      res.setToken(encodedToken);
-      res.setTokenType("bearer");
-      if (token.getExpiration() != 0)
-      {
-         long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
-         res.setExpiresIn(time);
-      }
-      return res;
-   }
-
-   @Path("{realm}/auth/request")
-   @GET
-   public Response requestAccessCode(@PathParam("realm") String realmId,
-                                     @QueryParam("response_type") String responseType,
-                                     @QueryParam("redirect_uri") String redirect,
-                                     @QueryParam("client_id") String clientId,
-                                     @QueryParam("scope") String scopeParam,
-                                     @QueryParam("state") String state)
-   {
-      RealmModel realm = adapter.getRealm(realmId);
-      if (realm == null)
-      {
-         throw new NotFoundException("Realm not found");
-      }
-      if (!realm.isEnabled())
-      {
-         throw new NotAuthorizedException("Realm not enabled");
-      }
-      User client = realm.getIdm().getUser(clientId);
-      if (client == null)
-         return Response.ok("<h1>Security Alert</h1><p>Unknown client trying to get access to your account.</p>").type("text/html").build();
-
-      return loginForm(null, redirect, clientId, scopeParam, state, realm, client);
-   }
-
-   private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client)
-   {
-      StringBuffer html = new StringBuffer();
-      if (scopeParam != null)
-      {
-         html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
-         if (validationError != null)
-         {
-            try
-            {
-               Thread.sleep(1000); // put in a delay
-            }
-            catch (InterruptedException e)
-            {
-               throw new RuntimeException(e);
-            }
-            html.append("<p/><p><b>").append(validationError).append("</b></p>");
-         }
-         html.append("<p>A Third Party is requesting access to the following resources</p>");
-         html.append("<table>");
-         SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
-         Map<String, ResourceModel> resourceMap = realm.getResourceMap();
-
-         for (String res : scope.keySet())
-         {
-            ResourceModel resource = resourceMap.get(res);
-            html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
-            Set<String> scopeMapping = resource.getScope(client);
-            for (String role : scope.get(res))
-            {
-               html.append(" ").append(role);
-               if (!scopeMapping.contains("*") && !scopeMapping.contains(role))
-               {
-                  return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
-               }
-            }
-            html.append("</td></tr>");
-         }
-         html.append("</table><p>To Authorize, please login below</p>");
-      }
-      else
-      {
-         Set<String> scopeMapping = realm.getScope(client);
-         if (scopeMapping.contains("*"))
-         {
-            html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
-            if (validationError != null)
-            {
-               try
-               {
-                  Thread.sleep(1000); // put in a delay
-               }
-               catch (InterruptedException e)
-               {
-                  throw new RuntimeException(e);
-               }
-               html.append("<p/><p><b>").append(validationError).append("</b></p>");
-            }
-         }
-         else
-         {
+public class TokenService {
+
+
+    protected static final Logger logger = Logger.getLogger(TokenService.class);
+    protected Map<String, AccessCodeEntry> accessCodeMap;
+
+    @Context
+    protected UriInfo uriInfo;
+    @Context
+    protected Providers providers;
+    @Context
+    protected SecurityContext securityContext;
+    @Context
+    protected HttpHeaders headers;
+    @Context
+    protected
+    IdentitySession IdentitySession;
+
+    protected RealmModel realm;
+    protected TokenManager tokenManager = new TokenManager();
+    protected AuthenticationManager authManager = new AuthenticationManager();
+
+    public TokenService(RealmModel realm, Map<String, AccessCodeEntry> accessCodeMap) {
+        this.realm = realm;
+        this.accessCodeMap = accessCodeMap;
+    }
+
+    @Path("grants/identity-token")
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response identityTokenGrant(MultivaluedMap<String, String> form) {
+        String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
+        if (username == null) {
+            throw new NotAuthorizedException("No user");
+        }
+        if (!realm.isEnabled()) {
+            throw new NotAuthorizedException("Disabled realm");
+        }
+        User user = realm.getIdm().getUser(username);
+        if (user == null) {
+            throw new NotAuthorizedException("No user");
+        }
+        if (!user.isEnabled()) {
+            throw new NotAuthorizedException("Disabled user.");
+        }
+        if (!authManager.authenticateForm(realm, user, form)) {
+            throw new NotAuthorizedException("FORM");
+        }
+        tokenManager = new TokenManager();
+        SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
+        String encoded = tokenManager.encodeToken(realm, token);
+        AccessTokenResponse res = accessTokenResponse(token, encoded);
+        return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
+    }
+
+    @Path("grants/access")
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response accessTokenGrant(MultivaluedMap<String, String> form) {
+        String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
+        if (username == null) {
+            throw new NotAuthorizedException("No user");
+        }
+        if (!realm.isEnabled()) {
+            throw new NotAuthorizedException("Disabled realm");
+        }
+        User user = realm.getIdm().getUser(username);
+        if (user == null) {
+            throw new NotAuthorizedException("No user");
+        }
+        if (!user.isEnabled()) {
+            throw new NotAuthorizedException("Disabled user.");
+        }
+        if (authManager.authenticateForm(realm, user, form)) {
+            throw new NotAuthorizedException("Auth failed");
+        }
+        SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
+        String encoded = tokenManager.encodeToken(realm, token);
+        AccessTokenResponse res = accessTokenResponse(token, encoded);
+        return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
+    }
+
+    @Path("auth/request/login")
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response login(MultivaluedMap<String, String> formData) {
+        String clientId = formData.getFirst("client_id");
+        String scopeParam = formData.getFirst("scope");
+        String state = formData.getFirst("state");
+        String redirect = formData.getFirst("redirect_uri");
+
+        if (!realm.isEnabled()) {
+            return Response.ok("Realm not enabled").type("text/html").build();
+        }
+        User client = realm.getIdm().getUser(clientId);
+        if (client == null) {
+            throw new NotAuthorizedException("No client");
+        }
+        if (!client.isEnabled()) {
+            return Response.ok("Requester not enabled").type("text/html").build();
+        }
+        String username = formData.getFirst("username");
+        User user = realm.getIdm().getUser(username);
+        if (user == null) {
+            logger.debug("user not found");
+            return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client);
+        }
+        if (!user.isEnabled()) {
+            return Response.ok("Your account is not enabled").type("text/html").build();
+
+        }
+        boolean authenticated = authManager.authenticateForm(realm, user, formData);
+        if (!authenticated)
+            return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
+
+        SkeletonKeyToken token = null;
+        if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
+        else token = tokenManager.createLoginToken(realm, client, user);
+
+        AccessCodeEntry code = new AccessCodeEntry();
+        code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
+        code.setToken(token);
+        code.setClient(client);
+        synchronized (accessCodeMap) {
+            accessCodeMap.put(code.getId(), code);
+        }
+        String accessCode = null;
+        try {
+            accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
+        if (state != null) redirectUri.queryParam("state", state);
+        return Response.status(302).location(redirectUri.build()).build();
+    }
+
+    @Path("access/codes")
+    @POST
+    @Produces("application/json")
+    public Response accessRequest(MultivaluedMap<String, String> formData) {
+        if (!realm.isEnabled()) {
+            throw new NotAuthorizedException("Realm not enabled");
+        }
+
+        String code = formData.getFirst("code");
+        if (code == null) {
+            logger.debug("code not specified");
+            Map<String, String> error = new HashMap<String, String>();
+            error.put("error", "invalid_request");
+            error.put("error_description", "code not specified");
+            return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+
+        }
+        String client_id = formData.getFirst("client_id");
+        if (client_id == null) {
+            logger.debug("client_id not specified");
+            Map<String, String> error = new HashMap<String, String>();
+            error.put("error", "invalid_request");
+            error.put("error_description", "client_id not specified");
+            return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+        }
+        User client = realm.getIdm().getUser(client_id);
+        if (client == null) {
+            logger.debug("Could not find user");
+            Map<String, String> error = new HashMap<String, String>();
+            error.put("error", "invalid_client");
+            error.put("error_description", "Could not find user");
+            return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+        }
+
+        if (!client.isEnabled()) {
+            logger.debug("user is not enabled");
+            Map<String, String> error = new HashMap<String, String>();
+            error.put("error", "invalid_client");
+            error.put("error_description", "User is not enabled");
+            return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+        }
+
+        boolean authenticated = authManager.authenticateForm(realm, client, formData);
+        if (!authenticated) {
+            Map<String, String> error = new HashMap<String, String>();
+            error.put("error", "unauthorized_client");
+            return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+        }
+
+
+        JWSInput input = new JWSInput(code, providers);
+        boolean verifiedCode = false;
+        try {
+            verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
+        } catch (Exception ignored) {
+            logger.debug("Failed to verify signature", ignored);
+        }
+        if (!verifiedCode) {
+            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();
+        }
+        String key = input.readContent(String.class);
+        AccessCodeEntry accessCode = null;
+        synchronized (accessCodeMap) {
+            accessCode = accessCodeMap.remove(key);
+        }
+        if (accessCode == null) {
+            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();
+        }
+        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();
+        }
+        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();
+        }
+        if (!client.getId().equals(accessCode.getClient().getId())) {
+            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();
+        }
+        AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
+        return Response.ok(res).build();
+
+    }
+
+    protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
+        byte[] tokenBytes = null;
+        try {
+            tokenBytes = JsonSerialization.toByteArray(token, false);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        String encodedToken = new JWSBuilder()
+                .content(tokenBytes)
+                .rsa256(privateKey);
+
+        return accessTokenResponse(token, encodedToken);
+    }
+
+    protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken) {
+        AccessTokenResponse res = new AccessTokenResponse();
+        res.setToken(encodedToken);
+        res.setTokenType("bearer");
+        if (token.getExpiration() != 0) {
+            long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
+            res.setExpiresIn(time);
+        }
+        return res;
+    }
+
+    @Path("auth/request")
+    @GET
+    public Response requestAccessCode(@QueryParam("response_type") String responseType,
+                                      @QueryParam("redirect_uri") String redirect,
+                                      @QueryParam("client_id") String clientId,
+                                      @QueryParam("scope") String scopeParam,
+                                      @QueryParam("state") String state) {
+        if (!realm.isEnabled()) {
+            throw new NotAuthorizedException("Realm not enabled");
+        }
+        User client = realm.getIdm().getUser(clientId);
+        if (client == null)
+            return Response.ok("<h1>Security Alert</h1><p>Unknown client trying to get access to your account.</p>").type("text/html").build();
+
+        return loginForm(null, redirect, clientId, scopeParam, state, realm, client);
+    }
+
+    private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
+        StringBuffer html = new StringBuffer();
+        if (scopeParam != null) {
             html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
-            if (validationError != null)
-            {
-               try
-               {
-                  Thread.sleep(1000); // put in a delay
-               }
-               catch (InterruptedException e)
-               {
-                  throw new RuntimeException(e);
-               }
-               html.append("<p/><p><b>").append(validationError).append("</b></p>");
-            }
-            SkeletonKeyScope scope = new SkeletonKeyScope();
-            List<ResourceModel> resources = realm.getResources();
-            boolean found = false;
-            for (ResourceModel resource : resources)
-            {
-               Set<String> resourceScope = resource.getScope(client);
-               if (resourceScope == null) continue;
-               if (resourceScope.size() == 0) continue;
-               if (!found)
-               {
-                  found = true;
-                  html.append("<p>A Third Party is requesting access to the following resources</p>");
-                  html.append("<table>");
-               }
-               html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
-               // todo add description of role
-               for (String role : resourceScope)
-               {
-                  html.append(" ").append(role);
-                  scope.add(resource.getName(), role);
-               }
+            if (validationError != null) {
+                try {
+                    Thread.sleep(1000); // put in a delay
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                html.append("<p/><p><b>").append(validationError).append("</b></p>");
             }
-            if (!found)
-            {
-               return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
+            html.append("<p>A Third Party is requesting access to the following resources</p>");
+            html.append("<table>");
+            SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
+            Map<String, ResourceModel> resourceMap = realm.getResourceMap();
+
+            for (String res : scope.keySet()) {
+                ResourceModel resource = resourceMap.get(res);
+                html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
+                Set<String> scopeMapping = resource.getScope(client);
+                for (String role : scope.get(res)) {
+                    html.append(" ").append(role);
+                    if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
+                        return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
+                    }
+                }
+                html.append("</td></tr>");
             }
-            html.append("</table>");
-            try
-            {
-               String json = JsonSerialization.toString(scope, false);
-               scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
-            }
-            catch (Exception e)
-            {
-               throw new RuntimeException(e);
+            html.append("</table><p>To Authorize, please login below</p>");
+        } else {
+            Set<String> scopeMapping = realm.getScope(client);
+            if (scopeMapping.contains("*")) {
+                html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
+                if (validationError != null) {
+                    try {
+                        Thread.sleep(1000); // put in a delay
+                    } catch (InterruptedException e) {
+                        throw new RuntimeException(e);
+                    }
+                    html.append("<p/><p><b>").append(validationError).append("</b></p>");
+                }
+            } else {
+                html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
+                if (validationError != null) {
+                    try {
+                        Thread.sleep(1000); // put in a delay
+                    } catch (InterruptedException e) {
+                        throw new RuntimeException(e);
+                    }
+                    html.append("<p/><p><b>").append(validationError).append("</b></p>");
+                }
+                SkeletonKeyScope scope = new SkeletonKeyScope();
+                List<ResourceModel> resources = realm.getResources();
+                boolean found = false;
+                for (ResourceModel resource : resources) {
+                    Set<String> resourceScope = resource.getScope(client);
+                    if (resourceScope == null) continue;
+                    if (resourceScope.size() == 0) continue;
+                    if (!found) {
+                        found = true;
+                        html.append("<p>A Third Party is requesting access to the following resources</p>");
+                        html.append("<table>");
+                    }
+                    html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
+                    // todo add description of role
+                    for (String role : resourceScope) {
+                        html.append(" ").append(role);
+                        scope.add(resource.getName(), role);
+                    }
+                }
+                if (!found) {
+                    return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
+                }
+                html.append("</table>");
+                try {
+                    String json = JsonSerialization.toString(scope, false);
+                    scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+
             }
+        }
+
+        UriBuilder formActionUri = uriInfo.getBaseUriBuilder().path(TokenService.class).path(TokenService.class, "login");
+        String action = formActionUri.build(realm.getId()).toString();
+        html.append("<form action=\"").append(action).append("\" method=\"POST\">");
+        html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
 
-         }
-      }
-
-      UriBuilder formActionUri = uriInfo.getBaseUriBuilder().path(TokenService.class).path(TokenService.class, "login");
-      String action = formActionUri.build(realm.getId()).toString();
-      html.append("<form action=\"").append(action).append("\" method=\"POST\">");
-      html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
-
-      for (RequiredCredentialModel credential : realm.getRequiredCredentials())
-      {
-         if (!credential.isInput()) continue;
-         html.append(credential.getType()).append(": ");
-         if (credential.isSecret())
-         {
-            html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\"  size=\"20\"><br>");
-
-         } else
-         {
-            html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\"  size=\"20\"><br>");
-         }
-      }
-      html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
-      if (scopeParam != null)
-      {
-         html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
-      }
-      if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");
-      html.append("<input type=\"hidden\" name=\"redirect_uri\" value=\"").append(redirect).append("\">");
-      html.append("<input type=\"submit\" value=\"");
-      if (scopeParam == null) html.append("Login");
-      else html.append("Grant Access");
-      html.append("\">");
-      html.append("</form>");
-      return Response.ok(html.toString()).type("text/html").build();
-   }
+        for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
+            if (!credential.isInput()) continue;
+            html.append(credential.getType()).append(": ");
+            if (credential.isSecret()) {
+                html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\"  size=\"20\"><br>");
+
+            } else {
+                html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\"  size=\"20\"><br>");
+            }
+        }
+        html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
+        if (scopeParam != null) {
+            html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
+        }
+        if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");
+        html.append("<input type=\"hidden\" name=\"redirect_uri\" value=\"").append(redirect).append("\">");
+        html.append("<input type=\"submit\" value=\"");
+        if (scopeParam == null) html.append("Login");
+        else html.append("Grant Access");
+        html.append("\">");
+        html.append("</form>");
+        return Response.ok(html.toString()).type("text/html").build();
+    }
 }
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 6605780..98fa18b 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -7,27 +7,23 @@ import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
 import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+import org.keycloak.services.managers.InstallationManager;
 import org.keycloak.services.models.RealmManager;
 import org.keycloak.services.models.RealmModel;
-import org.keycloak.services.models.relationships.RealmResourceRelationship;
 import org.keycloak.services.models.RequiredCredentialModel;
-import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
-import org.keycloak.services.models.relationships.ScopeRelationship;
 import org.keycloak.services.models.UserCredentialModel;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.IdentitySessionFactory;
 import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.config.IdentityConfigurationBuilder;
 import org.picketlink.idm.credential.Credentials;
 import org.picketlink.idm.credential.Password;
 import org.picketlink.idm.credential.UsernamePasswordCredentials;
-import org.picketlink.idm.file.internal.FileUtils;
-import org.picketlink.idm.internal.IdentityManagerFactory;
-import org.picketlink.idm.model.Realm;
 import org.picketlink.idm.model.Role;
 import org.picketlink.idm.model.SimpleRole;
 import org.picketlink.idm.model.SimpleUser;
 import org.picketlink.idm.model.User;
 
-import java.io.File;
 import java.util.List;
 
 /**
@@ -35,125 +31,108 @@ import java.util.List;
  * @version $Revision: 1 $
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class AdapterTest
-{
-   private static IdentityManagerFactory factory;
-   public static final String WORKING_DIRECTORY = "/tmp/keycloak";
-   public RealmManager adapter;
-   public RealmModel realmModel;
-   @Before
-   public void before() throws Exception
-   {
-      after();
-      factory = createFactory();
-      adapter = new RealmManager(factory);
-   }
+public class AdapterTest {
+    private IdentitySessionFactory factory;
+    private IdentitySession IdentitySession;
+    private RealmManager adapter;
+    private RealmModel realmModel;
 
-   private static IdentityManagerFactory createFactory() {
-      IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
+    @Before
+    public void before() throws Exception {
+        factory = KeycloakApplication.createFactory();
+        IdentitySession = factory.createIdentitySession();
+        adapter = new RealmManager(IdentitySession);
+    }
 
-      builder
-              .stores()
-              .file()
-              .addRealm(Realm.DEFAULT_REALM)
-              .workingDirectory(WORKING_DIRECTORY)
-              .preserveState(true)
-              .supportAllFeatures()
-              .supportRelationshipType(RealmResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class);
+    @After
+    public void after() throws Exception {
+        IdentitySession.close();
+        factory.close();
+    }
 
-      return new IdentityManagerFactory(builder.build());
-   }
+    @Test
+    public void installTest() throws Exception {
+        new InstallationManager().install(adapter);
 
-   @After
-   public void after() throws Exception
-   {
-      File file = new File(WORKING_DIRECTORY);
-      FileUtils.delete(file);
-      Thread.sleep(10); // my windows machine seems to have delays on deleting files sometimes
-   }
+    }
 
-   @Test
-   public void test1CreateRealm() throws Exception
-   {
-      realmModel = adapter.create("JUGGLER");
-      realmModel.setAccessCodeLifespan(100);
-      realmModel.setCookieLoginAllowed(true);
-      realmModel.setEnabled(true);
-      realmModel.setName("JUGGLER");
-      realmModel.setPrivateKeyPem("0234234");
-      realmModel.setPublicKeyPem("0234234");
-      realmModel.setTokenLifespan(1000);
-      realmModel.updateRealm();
+    @Test
+    public void test1CreateRealm() throws Exception {
+        realmModel = adapter.createRealm("JUGGLER");
+        realmModel.setAccessCodeLifespan(100);
+        realmModel.setCookieLoginAllowed(true);
+        realmModel.setEnabled(true);
+        realmModel.setName("JUGGLER");
+        realmModel.setPrivateKeyPem("0234234");
+        realmModel.setPublicKeyPem("0234234");
+        realmModel.setTokenLifespan(1000);
+        realmModel.updateRealm();
 
-      System.out.println(realmModel.getId());
-      realmModel = adapter.getRealm(realmModel.getId());
-      Assert.assertNotNull(realmModel);
-      Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
-      Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
-      Assert.assertEquals(realmModel.isEnabled(), true);
-      Assert.assertEquals(realmModel.getName(), "JUGGLER");
-      Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
-      Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
-   }
+        System.out.println(realmModel.getId());
+        realmModel = adapter.getRealm(realmModel.getId());
+        Assert.assertNotNull(realmModel);
+        Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
+        Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
+        Assert.assertEquals(realmModel.isEnabled(), true);
+        Assert.assertEquals(realmModel.getName(), "JUGGLER");
+        Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
+        Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
+    }
 
-   @Test
-   public void test2RequiredCredential() throws Exception
-   {
-      test1CreateRealm();
-      RequiredCredentialModel creds = new RequiredCredentialModel();
-      creds.setSecret(true);
-      creds.setType(RequiredCredentialRepresentation.PASSWORD);
-      creds.setInput(true);
-      realmModel.addRequiredCredential(creds);
-      creds = new RequiredCredentialModel();
-      creds.setSecret(true);
-      creds.setType(RequiredCredentialRepresentation.TOTP);
-      creds.setInput(true);
-      realmModel.addRequiredCredential(creds);
-      List<RequiredCredentialModel> storedCreds = realmModel.getRequiredCredentials();
-      Assert.assertEquals(2, storedCreds.size());
-      boolean totp = false;
-      boolean password = false;
-      for (RequiredCredentialModel cred : storedCreds)
-      {
-         if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
-         else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
-      }
-      Assert.assertTrue(totp);
-      Assert.assertTrue(password);
-   }
+    @Test
+    public void test2RequiredCredential() throws Exception {
+        test1CreateRealm();
+        RequiredCredentialModel creds = new RequiredCredentialModel();
+        creds.setSecret(true);
+        creds.setType(RequiredCredentialRepresentation.PASSWORD);
+        creds.setInput(true);
+        realmModel.addRequiredCredential(creds);
+        creds = new RequiredCredentialModel();
+        creds.setSecret(true);
+        creds.setType(RequiredCredentialRepresentation.TOTP);
+        creds.setInput(true);
+        realmModel.addRequiredCredential(creds);
+        List<RequiredCredentialModel> storedCreds = realmModel.getRequiredCredentials();
+        Assert.assertEquals(2, storedCreds.size());
+        boolean totp = false;
+        boolean password = false;
+        for (RequiredCredentialModel cred : storedCreds) {
+            if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
+            else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
+        }
+        Assert.assertTrue(totp);
+        Assert.assertTrue(password);
+    }
 
-   @Test
-   public void testCredentialValidation() throws Exception
-   {
-      test1CreateRealm();
-      User user = new SimpleUser("bburke");
-      realmModel.getIdm().add(user);
-      UserCredentialModel cred = new UserCredentialModel();
-      cred.setType(RequiredCredentialRepresentation.PASSWORD);
-      cred.setValue("geheim");
-      realmModel.updateCredential(user, cred);
-      IdentityManager idm = realmModel.getIdm();
-      UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user.getLoginName(), new Password("geheim"));
-      idm.validateCredentials(creds);
-      Assert.assertEquals(creds.getStatus(), Credentials.Status.VALID);
-   }
+    @Test
+    public void testCredentialValidation() throws Exception {
+        test1CreateRealm();
+        User user = new SimpleUser("bburke");
+        realmModel.getIdm().add(user);
+        UserCredentialModel cred = new UserCredentialModel();
+        cred.setType(RequiredCredentialRepresentation.PASSWORD);
+        cred.setValue("geheim");
+        realmModel.updateCredential(user, cred);
+        IdentityManager idm = realmModel.getIdm();
+        UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user.getLoginName(), new Password("geheim"));
+        idm.validateCredentials(creds);
+        Assert.assertEquals(creds.getStatus(), Credentials.Status.VALID);
+    }
 
-   @Test
-   public void testRoles() throws Exception
-   {
-      test1CreateRealm();
-      IdentityManager idm = realmModel.getIdm();
-      idm.add(new SimpleRole("admin"));
-      idm.add(new SimpleRole("user"));
-      List<Role> roles = realmModel.getRoles();
-      Assert.assertEquals(2, roles.size());
-      SimpleUser user = new SimpleUser("bburke");
-      idm.add(user);
-      Role role = idm.getRole("user");
-      idm.grantRole(user, role);
-      Assert.assertTrue(idm.hasRole(user, role));
-   }
+    @Test
+    public void testRoles() throws Exception {
+        test1CreateRealm();
+        IdentityManager idm = realmModel.getIdm();
+        idm.add(new SimpleRole("admin"));
+        idm.add(new SimpleRole("user"));
+        List<Role> roles = realmModel.getRoles();
+        Assert.assertEquals(2, roles.size());
+        SimpleUser user = new SimpleUser("bburke");
+        idm.add(user);
+        Role role = idm.getRole("user");
+        idm.grantRole(user, role);
+        Assert.assertTrue(idm.hasRole(user, role));
+    }
 
 
 }
diff --git a/services/src/test/java/org/keycloak/test/KeycloakTestBase.java b/services/src/test/java/org/keycloak/test/KeycloakTestBase.java
new file mode 100755
index 0000000..5bd0b6d
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/KeycloakTestBase.java
@@ -0,0 +1,31 @@
+package org.keycloak.test;
+
+import org.jboss.resteasy.jwt.JsonSerialization;
+import org.jboss.resteasy.test.BaseResourceTest;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakTestBase extends BaseResourceTest
+{
+   public static RealmRepresentation loadJson(String path) throws IOException
+   {
+      InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
+      ByteArrayOutputStream os = new ByteArrayOutputStream();
+      int c;
+      while ( (c = is.read()) != -1)
+      {
+         os.write(c);
+      }
+      byte[] bytes = os.toByteArray();
+      System.out.println(new String(bytes));
+
+      return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
+   }
+}
diff --git a/services/src/test/java/org/keycloak/test/RealmCreationTest.java b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
new file mode 100755
index 0000000..57d378f
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
@@ -0,0 +1,94 @@
+package org.keycloak.test;
+
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.spi.ResteasyDeployment;
+import org.jboss.resteasy.test.EmbeddedContainer;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.SkeletonKeyContextResolver;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.InstallationManager;
+import org.keycloak.services.models.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.model.Realm;
+
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import static org.jboss.resteasy.test.TestPortProvider.generateURL;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmCreationTest {
+
+    private static ResteasyDeployment deployment;
+    private static Client client;
+
+    @BeforeClass
+    public static void before() throws Exception {
+        deployment = new ResteasyDeployment();
+        deployment.setApplicationClass(KeycloakApplication.class.getName());
+        EmbeddedContainer.start(deployment);
+        KeycloakApplication application = (KeycloakApplication) deployment.getApplication();
+        IdentitySession IdentitySession = application.getFactory().createIdentitySession();
+        RealmManager manager = new RealmManager(IdentitySession);
+        new InstallationManager().install(manager);
+        client = new ResteasyClientBuilder().build();
+        client.register(SkeletonKeyContextResolver.class);
+    }
+
+    public static void after() throws Exception {
+        client.close();
+        EmbeddedContainer.stop();
+    }
+
+    @Test
+    public void testRegisterLoginAndCreate() throws Exception {
+        UserRepresentation user = new UserRepresentation();
+        user.setUsername("bburke");
+        user.credential(RequiredCredentialRepresentation.PASSWORD, "geheim", false);
+
+        WebTarget target = client.target(generateURL("/"));
+        Response response = target.path("registrations").request().post(Entity.json(user));
+        Assert.assertEquals(201, response.getStatus());
+        response.close();
+
+
+        AccessTokenResponse tokenResponse = null;
+        try {
+            Form form = new Form();
+            form.param(AuthenticationManager.FORM_USERNAME, "bburke");
+            form.param(RequiredCredentialRepresentation.PASSWORD, "badpassword");
+            tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
+            Assert.fail();
+        } catch (NotAuthorizedException e) {
+        }
+        Form form = new Form();
+        form.param(AuthenticationManager.FORM_USERNAME, "bburke");
+        form.param(RequiredCredentialRepresentation.PASSWORD, "geheim");
+        tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
+        Assert.assertNotNull(tokenResponse);
+        System.out.println(tokenResponse.getToken());
+        //
+
+        RealmRepresentation realm = KeycloakTestBase.loadJson("testrealm.json");
+        response = target.path("realms").request().header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getToken()).post(Entity.json(realm));
+        Assert.assertEquals(201, response.getStatus());
+        response.close();
+    }
+}
diff --git a/services/src/test/resources/META-INF/persistence.xml b/services/src/test/resources/META-INF/persistence.xml
index 1e5524f..7b7e664 100755
--- a/services/src/test/resources/META-INF/persistence.xml
+++ b/services/src/test/resources/META-INF/persistence.xml
@@ -2,7 +2,7 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
     version="1.0">
-    <persistence-unit name="identitydb" transaction-type="RESOURCE_LOCAL">
+    <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
         <provider>org.hibernate.ejb.HibernatePersistence</provider>
         
         <class>org.picketlink.idm.jpa.schema.IdentityObject</class>