keycloak-memoizeit

Changes

Details

diff --git a/core/src/main/java/org/keycloak/RealmConfiguration.java b/core/src/main/java/org/keycloak/RealmConfiguration.java
index 8563cdf..5e4a7a4 100755
--- a/core/src/main/java/org/keycloak/RealmConfiguration.java
+++ b/core/src/main/java/org/keycloak/RealmConfiguration.java
@@ -15,8 +15,7 @@ public class RealmConfiguration {
     protected ResteasyClient client;
     protected UriBuilder authUrl;
     protected ResteasyWebTarget codeUrl;
-    protected String clientId;
-    protected Form credentials = new Form();
+    protected Form resourceCredentials = new Form();
     protected boolean sslRequired = true;
     protected String stateCookieName = "OAuth_Token_Request_State";
 
@@ -44,16 +43,8 @@ public class RealmConfiguration {
         this.authUrl = authUrl;
     }
 
-    public String getClientId() {
-        return clientId;
-    }
-
-    public void setClientId(String clientId) {
-        this.clientId = clientId;
-    }
-
-    public Form getCredentials() {
-        return credentials;
+    public Form getResourceCredentials() {
+        return resourceCredentials;
     }
 
     public ResteasyWebTarget getCodeUrl() {
diff --git a/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java b/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java
new file mode 100755
index 0000000..0a7f553
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/admin/AdminAction.java
@@ -0,0 +1,66 @@
+package org.keycloak.representations.idm.admin;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Posted to managed client from admin server.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AdminAction {
+    protected String id;
+    protected long expiration;
+    protected String resource;
+    protected String action;
+
+    public AdminAction() {
+    }
+
+    public AdminAction(String id, long expiration, String resource, String action) {
+        this.id = id;
+        this.expiration = expiration;
+        this.resource = resource;
+        this.action = action;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    @JsonIgnore
+    public boolean isExpired()
+    {
+        long time = System.currentTimeMillis() / 1000;
+        return time > expiration;
+    }
+
+    public long getExpiration() {
+        return expiration;
+    }
+
+    public void setExpiration(long expiration) {
+        this.expiration = expiration;
+    }
+
+    public String getResource() {
+        return resource;
+    }
+
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/admin/LogoutAction.java b/core/src/main/java/org/keycloak/representations/idm/admin/LogoutAction.java
new file mode 100755
index 0000000..946b7f8
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/admin/LogoutAction.java
@@ -0,0 +1,26 @@
+package org.keycloak.representations.idm.admin;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class LogoutAction extends AdminAction {
+    public static final String LOGOUT_ACTION = "logout";
+    protected String user;
+
+    public LogoutAction() {
+    }
+
+    public LogoutAction(String id, long expiration, String resource, String user) {
+        super(id, expiration, resource, LOGOUT_ACTION);
+        this.user = user;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
new file mode 100755
index 0000000..2259317
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
@@ -0,0 +1,35 @@
+package org.keycloak.representations.idm;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public class CredentialRepresentation {
+    protected String type;
+    protected String value;
+    protected boolean hashed;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public boolean isHashed() {
+        return hashed;
+    }
+
+    public void setHashed(boolean hashed) {
+        this.hashed = hashed;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java
index 529ed35..15c49f9 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java
@@ -12,7 +12,10 @@ import java.util.Set;
 public class ResourceRepresentation {
     protected String self; // link
     protected String name;
+    protected String adminUrl;
     protected boolean surrogateAuthRequired;
+    protected boolean useRealmMappings;
+    protected List<CredentialRepresentation> credentials;
     protected Set<String> roles;
     protected List<RoleMappingRepresentation> roleMappings;
     protected List<ScopeMappingRepresentation> scopeMappings;
@@ -79,5 +82,37 @@ public class ResourceRepresentation {
         return mapping;
     }
 
+    public String getAdminUrl() {
+        return adminUrl;
+    }
+
+    public void setAdminUrl(String adminUrl) {
+        this.adminUrl = adminUrl;
+    }
+
+    public List<CredentialRepresentation> getCredentials() {
+        return credentials;
+    }
+
+    public void setCredentials(List<CredentialRepresentation> credentials) {
+        this.credentials = credentials;
+    }
 
+    public ResourceRepresentation credential(String type, String value, boolean hashed) {
+        if (this.credentials == null) credentials = new ArrayList<CredentialRepresentation>();
+        CredentialRepresentation cred = new CredentialRepresentation();
+        cred.setType(type);
+        cred.setValue(value);
+        cred.setHashed(hashed);
+        credentials.add(cred);
+        return this;
+    }
+
+    public boolean isUseRealmMappings() {
+        return useRealmMappings;
+    }
+
+    public void setUseRealmMappings(boolean useRealmMappings) {
+        this.useRealmMappings = useRealmMappings;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 96d2b72..cbbff89 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -10,41 +10,12 @@ import java.util.Map;
  * @version $Revision: 1 $
  */
 public class UserRepresentation {
-    public static class Credential {
-        protected String type;
-        protected String value;
-        protected boolean hashed;
-
-        public String getType() {
-            return type;
-        }
-
-        public void setType(String type) {
-            this.type = type;
-        }
-
-        public String getValue() {
-            return value;
-        }
-
-        public void setValue(String value) {
-            this.value = value;
-        }
-
-        public boolean isHashed() {
-            return hashed;
-        }
-
-        public void setHashed(boolean hashed) {
-            this.hashed = hashed;
-        }
-    }
 
     protected String self; // link
     protected String username;
     protected boolean enabled;
     protected Map<String, String> attributes;
-    protected List<Credential> credentials;
+    protected List<CredentialRepresentation> credentials;
 
     public String getSelf() {
         return self;
@@ -70,23 +41,23 @@ public class UserRepresentation {
         this.attributes = attributes;
     }
 
-    public List<Credential> getCredentials() {
-        return credentials;
-    }
-
-    public void setCredentials(List<Credential> credentials) {
-        this.credentials = credentials;
-    }
-
     public UserRepresentation attribute(String name, String value) {
         if (this.attributes == null) attributes = new HashMap<String, String>();
         attributes.put(name, value);
         return this;
     }
 
+    public List<CredentialRepresentation> getCredentials() {
+        return credentials;
+    }
+
+    public void setCredentials(List<CredentialRepresentation> credentials) {
+        this.credentials = credentials;
+    }
+
     public UserRepresentation credential(String type, String value, boolean hashed) {
-        if (this.credentials == null) credentials = new ArrayList<Credential>();
-        Credential cred = new Credential();
+        if (this.credentials == null) credentials = new ArrayList<CredentialRepresentation>();
+        CredentialRepresentation cred = new CredentialRepresentation();
         cred.setType(type);
         cred.setValue(value);
         cred.setHashed(hashed);
diff --git a/core/src/main/java/org/keycloak/ResourceMetadata.java b/core/src/main/java/org/keycloak/ResourceMetadata.java
index 24a2772..0a3f811 100755
--- a/core/src/main/java/org/keycloak/ResourceMetadata.java
+++ b/core/src/main/java/org/keycloak/ResourceMetadata.java
@@ -8,8 +8,8 @@ import java.security.PublicKey;
  * @version $Revision: 1 $
  */
 public class ResourceMetadata {
-    protected String resourceName;
     protected String realm;
+    protected String resourceName;
     protected KeyStore clientKeystore;
     protected String clientKeyPassword;
     protected KeyStore truststore;
diff --git a/core/src/main/java/org/keycloak/TokenIdGenerator.java b/core/src/main/java/org/keycloak/TokenIdGenerator.java
new file mode 100755
index 0000000..f1b5e55
--- /dev/null
+++ b/core/src/main/java/org/keycloak/TokenIdGenerator.java
@@ -0,0 +1,15 @@
+package org.keycloak;
+
+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 TokenIdGenerator {
+    private static final AtomicLong counter = new AtomicLong();
+    public static String generateId() {
+        return UUID.randomUUID().toString() + "-" + System.currentTimeMillis();
+    }
+}
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
old mode 100644
new mode 100755
index f6bd0c5..91657c9
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/customers/view.jsp
@@ -1,11 +1,15 @@
-<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
 <html>
 <head>
     <title>Customer View Page</title>
 </head>
 <body bgcolor="#E3F6CE">
-<p>Goto: <a href="https://localhost:8443/product-portal">products</a> | <a href="https://localhost:8443/auth-server/j_oauth_logout">logout</a></p>
+<%
+   String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
+                                     .queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
+%>
+<p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a></p>
 User <b><%=request.getUserPrincipal().getName()%></b> made this request.
 <h2>Customer Listing</h2>
 <%
diff --git a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/resteasy-oauth.json b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/resteasy-oauth.json
index e0df12d..a36b5cf 100755
--- a/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/resteasy-oauth.json
+++ b/examples/as7-eap-demo/customer-app/src/main/webapp/WEB-INF/resteasy-oauth.json
@@ -1,11 +1,11 @@
 {
   "realm" : "demo",
+  "resource" : "customer-portal",
   "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
   "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
   "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
    "ssl-not-required" : true,
-   "client-id" : "customer-portal",
-   "client-credentials" : {
+   "credentials" : {
       "password" : "password"
    }
 }
diff --git a/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/resteasy-oauth.json b/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/resteasy-oauth.json
index 156706f..cacacd0 100755
--- a/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/resteasy-oauth.json
+++ b/examples/as7-eap-demo/database-service/src/main/webapp/WEB-INF/resteasy-oauth.json
@@ -1,4 +1,5 @@
 {
   "realm" : "demo",
+  "resource" : "database-service",
   "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"
 }
diff --git a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
old mode 100644
new mode 100755
index 5a9a641..fe8d990
--- a/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
+++ b/examples/as7-eap-demo/product-app/src/main/webapp/products/view.jsp
@@ -1,11 +1,16 @@
-<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
 <html>
 <head>
     <title>Product View Page</title>
 </head>
 <body bgcolor="#F5F6CE">
-<p>Goto: <a href="https://localhost:8443/customer-portal">customers</a> | <a href="https://localhost:8443/auth-server/j_oauth_logout">logout</a></p>
+<%
+   String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
+                                     .queryParam("redirect_uri", "http://localhost:8080/product-portal").build().toString();
+%>
+
+<p>Goto: <a href="http://localhost:8080/customer-portal">customers</a> | <a href="<%=logoutUri%>">logout</a></p>
 User <b><%=request.getUserPrincipal().getName()%></b> made this request.
 <h2>Product Listing</h2>
 <%
diff --git a/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/resteasy-oauth.json b/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/resteasy-oauth.json
index 53ad29f..26bc1fe 100755
--- a/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/resteasy-oauth.json
+++ b/examples/as7-eap-demo/product-app/src/main/webapp/WEB-INF/resteasy-oauth.json
@@ -1,11 +1,11 @@
 {
   "realm" : "demo",
+  "resource" : "product-portal",
   "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
   "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
   "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
    "ssl-not-required" : true,
-   "client-id" : "product-portal",
-   "client-credentials" : {
+   "credentials" : {
       "password" : "password"
    }
 }
diff --git a/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json b/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
index 150c218..db10768 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
+++ b/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
@@ -25,22 +25,6 @@
                 { "type" : "Password",
                  "value" : "password" }
             ]
-      },
-      {
-            "username" : "customer-portal",
-            "enabled" : true,
-            "credentials" : [
-                { "type" : "Password",
-                 "value" : "password" }
-            ]
-      },
-      {
-            "username" : "product-portal",
-            "enabled" : true,
-            "credentials" : [
-                { "type" : "Password",
-                 "value" : "password" }
-            ]
       }
    ],
    "roleMappings" : [
@@ -49,14 +33,24 @@
           "roles" : ["user"]
        }
    ],
-   "scopeMappings" : [
+   "resources" : [
        {
-          "username" : "customer-portal",
-          "roles" : ["*"]
+          "name" : "customer-portal",
+          "adminUrl" : "http://localhost:8080/customer-portal/j_admin_request",
+          "useRealmMappings" : true,
+          "credentials" : [
+                { "type" : "Password",
+                 "value" : "password" }
+          ]
        },
        {
-          "username" : "product-portal",
-          "roles" : ["*"]
+          "name" : "product-portal",
+          "adminUrl" : "http://localhost:8080/product-portal/j_admin_request",
+          "useRealmMappings" : true,
+          "credentials" : [
+                { "type" : "Password",
+                 "value" : "password" }
+          ]
        }
    ]
 }
\ No newline at end of file
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
index b87ed0b..6ed560c 100755
--- 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
@@ -63,7 +63,7 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements 
     @Override
     protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
         try {
-            CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true);
+            CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
             if (bearer.login(request, response)) {
                 return true;
             }
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
index 835296b..b02cb45 100755
--- 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
@@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -29,11 +30,13 @@ public class CatalinaBearerTokenAuthenticator {
     protected SkeletonKeyToken token;
     private Principal principal;
     protected boolean propagateToken;
+    protected boolean useResourceRoleMappings;
 
-    public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge) {
+    public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge, boolean useResourceRoleMappings) {
         this.resourceMetadata = resourceMetadata;
         this.challenge = challenge;
         this.propagateToken = propagateToken;
+        this.useResourceRoleMappings = useResourceRoleMappings;
     }
 
     public ResourceMetadata getResourceMetadata() {
@@ -77,8 +80,8 @@ public class CatalinaBearerTokenAuthenticator {
             challengeResponse(response, "invalid_token", e.getMessage());
         }
         boolean verifyCaller = false;
-        Set<String> roles = null;
-        if (resourceMetadata.getResourceName() != null) {
+        Set<String> roles = new HashSet<String>();
+        if (useResourceRoleMappings) {
             SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
             if (access != null) roles = access.getRoles();
             verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
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
index 756950c..00da369 100755
--- 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
@@ -26,6 +26,8 @@ public class ManagedResourceConfig {
     protected String authUrl;
     @JsonProperty("code-url")
     protected String codeUrl;
+    @JsonProperty("use-resource-role-mappings")
+    protected boolean useResourceRoleMappings;
 
     @JsonProperty("ssl-not-required")
     protected boolean sslNotRequired;
@@ -37,21 +39,27 @@ public class ManagedResourceConfig {
     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("credentials")
+    protected Map<String, String> credentials = new HashMap<String, String>();
     @JsonProperty("connection-pool-size")
     protected int connectionPoolSize;
     @JsonProperty("cancel-propagation")
     protected boolean cancelPropagation;
 
+    public boolean isUseResourceRoleMappings() {
+        return useResourceRoleMappings;
+    }
+
+    public void setUseResourceRoleMappings(boolean useResourceRoleMappings) {
+        this.useResourceRoleMappings = useResourceRoleMappings;
+    }
+
     public boolean isSslNotRequired() {
         return sslNotRequired;
     }
@@ -140,16 +148,8 @@ public class ManagedResourceConfig {
         this.truststorePassword = truststorePassword;
     }
 
-    public String getClientId() {
-        return clientId;
-    }
-
-    public void setClientId(String clientId) {
-        this.clientId = clientId;
-    }
-
-    public Map<String, String> getClientCredentials() {
-        return clientCredentials;
+    public Map<String, String> getCredentials() {
+        return credentials;
     }
 
     public String getClientKeystore() {
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
index e55c3c7..cc6a2d6 100755
--- 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
@@ -103,8 +103,9 @@ public class ManagedResourceConfigLoader {
         }
 
         String realm = remoteSkeletonKeyConfig.getRealm();
-        String resource = remoteSkeletonKeyConfig.getResource();
         if (realm == null) throw new RuntimeException("Must set 'realm' in config");
+        String resource = remoteSkeletonKeyConfig.getResource();
+        if (resource == null) throw new RuntimeException("Must set 'resource' in config");
 
         String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
         if (realmKeyPem == null) {
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
index 1b04c9a..66621df 100755
--- 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
@@ -527,8 +527,8 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
         html.append("<br>");
 
         writer = new StringWriter();
-        rep.getClientCredentials().put("password", "REQUIRED");
-        rep.setClientId("REQUIRED");
+        rep.getCredentials().put("password", "REQUIRED");
+        //rep.setClientId("REQUIRED");
         rep.setTruststore("REQUIRED");
         rep.setTruststorePassword("REQUIRED");
         mapper.writeValue(writer, rep);
@@ -561,7 +561,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
 
     public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException {
         if (request.getHeader("Authorization") != null) {
-            CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false);
+            CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false, false);
             try {
                 if (bearer.login(request, response)) {
                     return true;
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
index 6c1385c..3614d58 100755
--- 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
@@ -14,8 +14,9 @@ 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.jboss.resteasy.jose.jws.JWSInput;
+import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
+import org.jboss.resteasy.jwt.JsonSerialization;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.RealmConfiguration;
 import org.keycloak.ResourceMetadata;
@@ -24,12 +25,14 @@ 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.keycloak.representations.idm.admin.LogoutAction;
 
 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.HashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -67,10 +70,6 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
         managedResourceConfigLoader.init(true);
         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) {
@@ -81,17 +80,16 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
             throw new RuntimeException("You mut specify code-url");
         }
         realmConfiguration.setMetadata(resourceMetadata);
-        realmConfiguration.setClientId(client_id);
         realmConfiguration.setSslRequired(!remoteSkeletonKeyConfig.isSslNotRequired());
 
-        for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet()) {
-            realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue());
+        for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getCredentials().entrySet()) {
+            realmConfiguration.getResourceCredentials().param(entry.getKey(), entry.getValue());
         }
 
         ResteasyClient client = managedResourceConfigLoader.getClient();
 
         realmConfiguration.setClient(client);
-        realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
+        realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
         realmConfiguration.setCodeUrl(client.target(tokenUrl));
     }
 
@@ -99,8 +97,8 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
     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);
+            if (requestURI.endsWith("j_admin_request")) {
+                adminRequest(request, response);
                 return;
             }
             super.invoke(request, response);
@@ -135,33 +133,71 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
         return false;
     }
 
-    protected void remoteLogout(Request request, HttpServletResponse response) throws IOException {
+    protected void adminRequest(Request request, HttpServletResponse response) throws IOException {
+        String token = request.getParameter("token");
+        if (token == null) {
+            log.warn("admin request failed, no token");
+            response.sendError(403, "no token");
+            return;
+        }
+
+        JWSInput input = new JWSInput(token);
+        boolean verified = false;
+        try {
+            verified = RSAProvider.verify(input, resourceMetadata.getRealmKey());
+        } catch (Exception ignore) {
+        }
+        if (!verified) {
+            log.warn("admin request failed, unable to verify token");
+            response.sendError(403, "verification failed");
+            return;
+        }
+        String action = request.getParameter("action");
+        if (LogoutAction.LOGOUT_ACTION.equals(action)) {
+            remoteLogout(input, response);
+        } else {
+            log.warn("admin request failed, unknown action");
+            response.sendError(403, "Unknown action");
+        }
+    }
+
+    protected void remoteLogout(JWSInput token, HttpServletResponse response) throws IOException {
         try {
             log.debug("->> remoteLogout: ");
-            if (!bearer(true, request, response)) {
-                log.debug("remoteLogout: bearer auth failed");
+            LogoutAction action = JsonSerialization.fromBytes(LogoutAction.class, token.getContent());
+            if (action.isExpired()) {
+                log.warn("admin request failed, expired token");
+                response.sendError(400, "Expired token");
                 return;
             }
-            GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
-            if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole())) {
-                log.debug("remoteLogout: role failure");
-                response.sendError(403);
+            if (!LogoutAction.LOGOUT_ACTION.equals(action.getAction())) {
+                log.warn("Action doesn't match");
+                response.sendError(400, "Action does not match");
                 return;
             }
-            String user = request.getParameter("user");
+            if (!resourceMetadata.getResourceName().equals(action.getResource())) {
+                log.warn("Resource name does not match");
+                response.sendError(400, "Resource name does not match");
+                return;
+
+            }
+           String user = action.getUser();
             if (user != null) {
+                log.info("logout of session for: " + user);
                 userSessionManagement.logout(user);
             } else {
+                log.info("logout of all sessions");
                 userSessionManagement.logoutAll();
             }
         } catch (Exception e) {
-            log.error("failed to logout", e);
+            log.warn("failed to logout", e);
+            response.sendError(500, "Failed to logout");
         }
         response.setStatus(204);
     }
 
     protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException {
-        CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge);
+        CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
         if (bearer.login(request, response)) {
             return true;
         }
@@ -207,13 +243,13 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
             if (!oauth.resolveCode(code)) return;
 
             SkeletonKeyToken token = oauth.getToken();
-            Set<String> roles = null;
-            if (resourceMetadata.getResourceName() != null) {
+            Set<String> roles = new HashSet<String>();
+            if (remoteSkeletonKeyConfig.isUseResourceRoleMappings()) {
                 SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
-                if (access != null) roles = access.getRoles();
+                if (access != null) roles.addAll(access.getRoles());
             } else {
                 SkeletonKeyToken.Access access = token.getRealmAccess();
-                if (access != null) roles = access.getRoles();
+                if (access != null) roles.addAll(access.getRoles());
             }
             SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
             GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);
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
index 8e177a8..b3cdebb 100755
--- 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
@@ -1,7 +1,6 @@
 package org.keycloak.adapters.as7;
 
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.util.BasicAuthHelper;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.RealmConfiguration;
 import org.keycloak.VerificationException;
@@ -14,7 +13,6 @@ 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;
@@ -144,7 +142,7 @@ public class ServletOAuthLogin {
             url = secureUrl.build().toString();
         }
         return realmInfo.getAuthUrl().clone()
-                .queryParam("client_id", realmInfo.getClientId())
+                .queryParam("client_id", realmInfo.getMetadata().getResourceName())
                 .queryParam("redirect_uri", url)
                 .queryParam("state", state)
                 .queryParam("login", "true")
@@ -223,8 +221,8 @@ public class ServletOAuthLogin {
 
         if (!checkStateCookie()) return false;
 
-        String client_id = realmInfo.getClientId();
-        String password = realmInfo.getCredentials().asMap().getFirst("password");
+        String client_id = realmInfo.getMetadata().getResourceName();
+        String password = realmInfo.getResourceCredentials().asMap().getFirst("password");
         //String authHeader = BasicAuthHelper.createHeader(client_id, password);
         String redirectUri = stripOauthParametersFromRedirect();
         Form form = new Form();
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 fc62795..00c8bd2 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -9,6 +9,7 @@ import org.keycloak.representations.SkeletonKeyToken;
 import org.keycloak.representations.idm.RequiredCredentialRepresentation;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.RequiredCredentialModel;
+import org.keycloak.services.resources.RealmsResource;
 import org.picketlink.idm.credential.Credentials;
 import org.picketlink.idm.credential.Password;
 import org.picketlink.idm.credential.TOTPCredentials;
@@ -20,6 +21,8 @@ import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -45,14 +48,19 @@ public class AuthenticationManager {
         return realm.isRealmAdmin(user);
     }
 
-    protected void expireIdentityCookie(Cookie cookie) {
+    public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
+        URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
         HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
-        if (response == null) return;
-        NewCookie expireIt = new NewCookie(cookie.getName(), "", cookie.getPath(), null, "Expiring cookie", 0, false);
+        if (response == null) {
+            logger.info("can't expire identity cookie, no HttpResponse");
+            return;
+        }
+        logger.info("Expiring identity cookie");
+        NewCookie expireIt = new NewCookie(TokenManager.KEYCLOAK_IDENTITY_COOKIE, "", uri.getPath(), null, "Expiring cookie", 0, false);
         response.addNewCookie(expireIt);
     }
 
-    public User authenticateIdentityCookie(RealmModel realm, HttpHeaders headers) {
+    public User authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
         Cookie cookie = headers.getCookies().get(TokenManager.KEYCLOAK_IDENTITY_COOKIE);
         if (cookie == null) return null;
 
@@ -61,19 +69,19 @@ public class AuthenticationManager {
             SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
             if (!token.isActive()) {
                 logger.info("identity cookie expired");
-                expireIdentityCookie(cookie);
+                expireIdentityCookie(realm, uriInfo);
                 return null;
             }
             User user = realm.getIdm().getUser(token.getPrincipal());
             if (user == null || !user.isEnabled()) {
                 logger.info("Unknown user in identity cookie");
-                expireIdentityCookie(cookie);
+                expireIdentityCookie(realm, uriInfo);
                 return null;
             }
             return user;
         } catch (VerificationException e) {
             logger.info("Failed to verify identity cookie", e);
-            expireIdentityCookie(cookie);
+            expireIdentityCookie(realm, uriInfo);
         }
         return null;
     }
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 18a10e3..080e688 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -1,17 +1,16 @@
 package org.keycloak.services.managers;
 
+import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RequiredCredentialRepresentation;
 import org.keycloak.representations.idm.ResourceRepresentation;
 import org.keycloak.representations.idm.RoleMappingRepresentation;
 import org.keycloak.representations.idm.ScopeMappingRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
-import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.RequiredCredentialModel;
 import org.keycloak.services.models.ResourceModel;
 import org.keycloak.services.models.UserCredentialModel;
-import org.keycloak.services.resources.RegistrationService;
 import org.picketlink.idm.IdentityManager;
 import org.picketlink.idm.IdentitySession;
 import org.picketlink.idm.model.Attribute;
@@ -22,7 +21,6 @@ import org.picketlink.idm.model.SimpleRole;
 import org.picketlink.idm.model.SimpleUser;
 import org.picketlink.idm.model.User;
 
-import javax.ws.rs.NotAuthorizedException;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
 import java.security.KeyPair;
@@ -73,6 +71,7 @@ public class RealmManager {
         SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
         idm.add(agent);
         RealmModel realm = new RealmModel(newRealm, identitySession);
+        idm.add(new SimpleRole("*"));
         return realm;
     }
 
@@ -135,7 +134,7 @@ public class RealmManager {
             }
             newRealm.getIdm().add(user);
             if (userRep.getCredentials() != null) {
-                for (UserRepresentation.Credential cred : userRep.getCredentials()) {
+                for (CredentialRepresentation cred : userRep.getCredentials()) {
                     UserCredentialModel credential = new UserCredentialModel();
                     credential.setType(cred.getType());
                     credential.setValue(cred.getValue());
@@ -145,25 +144,25 @@ public class RealmManager {
             userMap.put(user.getLoginName(), user);
         }
 
-        Map<String, Role> roles = new HashMap<String, Role>();
-
         if (rep.getRoles() != null) {
             for (String roleString : rep.getRoles()) {
                 SimpleRole role = new SimpleRole(roleString.trim());
                 newRealm.getIdm().add(role);
-                roles.put(role.getName(), role);
             }
         }
 
+        if (rep.getResources() != null) {
+            createResources(rep, newRealm, userMap);
+        }
+
         if (rep.getRoleMappings() != null) {
             for (RoleMappingRepresentation mapping : rep.getRoleMappings()) {
                 User user = userMap.get(mapping.getUsername());
                 for (String roleString : mapping.getRoles()) {
-                    Role role = roles.get(roleString.trim());
+                    Role role = newRealm.getIdm().getRole(roleString.trim());
                     if (role == null) {
                         role = new SimpleRole(roleString.trim());
                         newRealm.getIdm().add(role);
-                        roles.put(role.getName(), role);
                     }
                     newRealm.getIdm().grantRole(user, role);
                 }
@@ -173,11 +172,10 @@ public class RealmManager {
         if (rep.getScopeMappings() != null) {
             for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
                 for (String roleString : scope.getRoles()) {
-                    Role role = roles.get(roleString.trim());
+                    Role role = newRealm.getIdm().getRole(roleString.trim());
                     if (role == null) {
                         role = new SimpleRole(roleString.trim());
                         newRealm.getIdm().add(role);
-                        roles.put(role.getName(), role);
                     }
                     User user = userMap.get(scope.getUsername());
                     newRealm.addScope(user, role.getName());
@@ -185,43 +183,43 @@ public class RealmManager {
 
             }
         }
-
-        if (!roles.containsKey("*")) {
-            SimpleRole wildcard = new SimpleRole("*");
-            newRealm.getIdm().add(wildcard);
-            roles.put("*", wildcard);
-        }
-
-        if (rep.getResources() != null) {
-            createResources(rep, newRealm, userMap);
-        }
     }
 
     protected void createResources(RealmRepresentation rep, RealmModel realm, Map<String, User> userMap) {
         for (ResourceRepresentation resourceRep : rep.getResources()) {
             ResourceModel resource = realm.addResource(resourceRep.getName());
+            resource.setManagementUrl(resourceRep.getAdminUrl());
             resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
             resource.updateResource();
-            Map<String, Role> roles = new HashMap<String, Role>();
+
+            User resourceUser = resource.getResourceUser();
+            if (resourceRep.getCredentials() != null) {
+                for (CredentialRepresentation cred : resourceRep.getCredentials()) {
+                    UserCredentialModel credential = new UserCredentialModel();
+                    credential.setType(cred.getType());
+                    credential.setValue(cred.getValue());
+                    realm.updateCredential(resourceUser, credential);
+                }
+            }
+            userMap.put(resourceUser.getLoginName(), resourceUser);
+
+
             if (resourceRep.getRoles() != null) {
                 for (String roleString : resourceRep.getRoles()) {
                     SimpleRole role = new SimpleRole(roleString.trim());
                     resource.getIdm().add(role);
-                    roles.put(role.getName(), role);
                 }
             }
             if (resourceRep.getRoleMappings() != null) {
                 for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
                     User user = userMap.get(mapping.getUsername());
                     for (String roleString : mapping.getRoles()) {
-                        Role role = roles.get(roleString.trim());
+                        Role role = resource.getIdm().getRole(roleString.trim());
                         if (role == null) {
                             role = new SimpleRole(roleString.trim());
                             resource.getIdm().add(role);
-                            roles.put(role.getName(), role);
                         }
-                        Role role1 = resource.getIdm().getRole(role.getName());
-                        realm.getIdm().grantRole(user, role1);
+                        realm.getIdm().grantRole(user, role);
                     }
                 }
             }
@@ -229,22 +227,16 @@ public class RealmManager {
                 for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) {
                     User user = userMap.get(mapping.getUsername());
                     for (String roleString : mapping.getRoles()) {
-                        Role role = roles.get(roleString.trim());
+                        Role role = resource.getIdm().getRole(roleString.trim());
                         if (role == null) {
                             role = new SimpleRole(roleString.trim());
                             resource.getIdm().add(role);
-                            roles.put(role.getName(), role);
                         }
                         resource.addScope(user, role.getName());
                     }
                 }
             }
-            if (!roles.containsKey("*")) {
-                SimpleRole wildcard = new SimpleRole("*");
-                resource.getIdm().add(wildcard);
-                roles.put("*", wildcard);
-            }
-
+            if (resourceRep.isUseRealmMappings()) realm.addScope(resource.getResourceUser(), "*");
         }
     }
 
@@ -266,7 +258,7 @@ public class RealmManager {
                 boolean hasBrowserCredentials = true;
                 for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) {
                     boolean hasCredential = false;
-                    for (UserRepresentation.Credential cred : userRep.getCredentials()) {
+                    for (CredentialRepresentation cred : userRep.getCredentials()) {
                         if (cred.getType().equals(credential.getType())) {
                             hasCredential = true;
                             break;
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
new file mode 100755
index 0000000..fd2fe2a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -0,0 +1,47 @@
+package org.keycloak.services.managers;
+
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.keycloak.TokenIdGenerator;
+import org.keycloak.representations.idm.admin.LogoutAction;
+import org.keycloak.services.models.RealmModel;
+import org.keycloak.services.models.ResourceModel;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ResourceAdminManager {
+
+    public void logoutAll(RealmModel realm) {
+        singleLogOut(realm, null);
+    }
+
+    public void singleLogOut(RealmModel realm, String user) {
+        ResteasyClient client = new ResteasyClientBuilder()
+                .disableTrustManager() // todo fix this, should have a trust manager or a good default
+                .build();
+
+        List<ResourceModel> resources = realm.getResources();
+        for (ResourceModel resource : resources) {
+            logoutResource(realm, resource, user, client);
+        }
+    }
+
+    protected boolean logoutResource(RealmModel realm, ResourceModel resource, String user, ResteasyClient client) {
+        LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), System.currentTimeMillis() / 1000 + 30, resource.getName(), user);
+        String token = new TokenManager().encodeToken(realm, adminAction);
+        Form form = new Form();
+        form.param("token", token);
+        Response response = client.target(resource.getManagementUrl()).queryParam("action", "logout").request().post(Entity.form(form));
+        boolean success = response.getStatus() == 204;
+        response.close();
+        return success;
+    }
+
+}
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 6e7f287..68ef550 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -3,15 +3,17 @@ package org.keycloak.services.managers;
 import org.jboss.resteasy.jose.Base64Url;
 import org.jboss.resteasy.jose.jws.JWSBuilder;
 import org.jboss.resteasy.jwt.JsonSerialization;
+import org.jboss.resteasy.spi.HttpResponse;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.representations.SkeletonKeyScope;
 import org.keycloak.representations.SkeletonKeyToken;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.ResourceModel;
 import org.keycloak.services.resources.RealmsResource;
-import org.keycloak.services.resources.TokenService;
 import org.picketlink.idm.model.User;
 
 import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.NewCookie;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
@@ -38,6 +40,7 @@ public class TokenManager {
         accessCodeMap.clear();
     }
 
+
     public AccessCodeEntry pullAccessCode(String key) {
         return accessCodeMap.remove(key);
     }
@@ -55,7 +58,7 @@ public class TokenManager {
     {
         SkeletonKeyToken token = null;
         if (scopeParam != null) token = createScopedToken(scopeParam, realm, client, user);
-        else token = createLoginToken(realm, client, user);
+        else token = createUnscopedToken(realm, client, user);
 
         AccessCodeEntry code = new AccessCodeEntry();
         code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
@@ -72,15 +75,7 @@ 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());
-        }
+        SkeletonKeyToken token = initToken(realm, client, user);
         Map<String, ResourceModel> resourceMap = realm.getResourceMap();
 
         for (String res : scope.keySet()) {
@@ -102,23 +97,53 @@ public class TokenManager {
         return token;
     }
 
+    protected SkeletonKeyToken initToken(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());
+        }
+        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.getScopes(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());
+    public SkeletonKeyToken createUnscopedToken(RealmModel realm, User client, User user) {
+
+        SkeletonKeyToken token = initToken(realm, client, user);
+
+        Set<String> realmMapping = realm.getRoleMappings(user);
+
+        if (realmMapping != null && realmMapping.size() > 0) {
+            Set<String> scope = realm.getScope(client);
+            SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
+            for (String role : realmMapping) {
+                if (scope.contains("*") || scope.contains(role)) access.addRole(role);
+            }
+            token.setRealmAccess(access);
+        }
+        List<ResourceModel> resources = realm.getResources();
+        for (ResourceModel resource : resources) {
+            Set<String> scope = resource.getScope(client);
+            Set<String> mapping = resource.getRoleMappings(user);
+            if (mapping.size() == 0 || scope.size() == 0) continue;
+            SkeletonKeyToken.Access access = token.addAccess(resource.getName())
+                    .verifyCaller(resource.isSurrogateAuthRequired());
+            for (String role : mapping) {
+                if (scope.contains("*") || scope.contains(role)) access.addRole(role);
+            }
         }
-        SkeletonKeyToken token = createAccessToken(realm, user);
-        token.issuedFor(client.getLoginName());
         return token;
 
     }
 
-
     public String encodeScope(SkeletonKeyScope scope) {
         String token = null;
         try {
@@ -187,7 +212,7 @@ public class TokenManager {
         return token;
     }
 
-    public String encodeToken(RealmModel realm, SkeletonKeyToken token) {
+    public String encodeToken(RealmModel realm, Object token) {
         byte[] tokenBytes = null;
         try {
             tokenBytes = JsonSerialization.toByteArray(token, false);
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 76f5d4d..6ab850a 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java
@@ -18,6 +18,8 @@ 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.SimpleRole;
+import org.picketlink.idm.model.SimpleUser;
 import org.picketlink.idm.model.Tier;
 import org.picketlink.idm.model.User;
 import org.picketlink.idm.query.IdentityQuery;
@@ -293,8 +295,15 @@ public class RealmModel {
         relationship.setResourceName(name);
         relationship.setRealmAgent(realmAgent);
         relationship.setResourceId(newTier.getId());
+        relationship.setManagementUrl(""); // Picketlink doesn't like null attribute values
+        User resourceUser = new SimpleUser(name);
+        idm.add(resourceUser);
+        relationship.setResourceUser(resourceUser);
         idm.add(relationship);
-        return new ResourceModel(newTier, relationship, this, identitySession);
+        ResourceModel resource = new ResourceModel(newTier, relationship, this, identitySession);
+        resource.getIdm().add(new SimpleRole("*"));
+        resource.addScope(resourceUser, "*");
+        return resource;
     }
 
     public Set<String> getRoleMappings(User user) {
@@ -320,7 +329,7 @@ public class RealmModel {
     }
 
 
-    public Set<String> getScopes(Agent agent) {
+    public Set<String> getScope(Agent agent) {
         RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
         query.setParameter(ScopeRelationship.CLIENT, agent);
         List<ScopeRelationship> scope = query.getResultList();
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/ResourceRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/ResourceRelationship.java
index 10d1030..f63e76a 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/ResourceRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/ResourceRelationship.java
@@ -3,6 +3,7 @@ package org.keycloak.services.models.relationships;
 import org.picketlink.idm.model.AbstractAttributedType;
 import org.picketlink.idm.model.Agent;
 import org.picketlink.idm.model.Relationship;
+import org.picketlink.idm.model.User;
 import org.picketlink.idm.model.annotation.AttributeProperty;
 import org.picketlink.idm.model.annotation.IdentityProperty;
 import org.picketlink.idm.query.RelationshipQueryParameter;
@@ -23,8 +24,10 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
     };
 
     protected Agent realmAgent;
+    protected User resourceUser;
     protected String resourceId;
     protected String resourceName;
+    protected String managementUrl = ""; // Picketlink doesn't like null attribute values
     protected boolean surrogateAuthRequired;
     protected boolean enabled;
 
@@ -37,6 +40,15 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
         this.realmAgent = realmAgent;
     }
 
+    @IdentityProperty
+    public User getResourceUser() {
+        return resourceUser;
+    }
+
+    public void setResourceUser(User resourceUser) {
+        this.resourceUser = resourceUser;
+    }
+
     @AttributeProperty
     public String getResourceId() {
         return resourceId;
@@ -72,4 +84,15 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
     public void setEnabled(boolean enabled) {
         this.enabled = enabled;
     }
+
+    @AttributeProperty
+    public String getManagementUrl()
+    {
+        return managementUrl;
+    }
+
+    public void setManagementUrl(String managementUrl) {
+        if (managementUrl == null) managementUrl = ""; // Picketlink doesn't like NULL attribute values.
+        this.managementUrl = managementUrl;
+    }
 }
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 bad532c..c47785b 100755
--- a/services/src/main/java/org/keycloak/services/models/ResourceModel.java
+++ b/services/src/main/java/org/keycloak/services/models/ResourceModel.java
@@ -41,6 +41,10 @@ public class ResourceModel {
         getIdm().update(agent);
     }
 
+    public User getResourceUser() {
+        return agent.getResourceUser();
+    }
+
     public String getId() {
         return tier.getId();
     }
@@ -69,6 +73,14 @@ public class ResourceModel {
         agent.setSurrogateAuthRequired(surrogateAuthRequired);
     }
 
+    public String getManagementUrl() {
+        return agent.getManagementUrl();
+    }
+
+    public void setManagementUrl(String url) {
+        agent.setManagementUrl(url);
+    }
+
     public List<Role> getRoles() {
         IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
         query.setParameter(Role.PARTITION, tier);
@@ -90,10 +102,14 @@ public class ResourceModel {
         IdentityManager idm = getIdm();
         Role role = idm.getRole(roleName);
         if (role == null) throw new RuntimeException("role not found");
+        addScope(agent, role);
+
+    }
+
+    public void addScope(Agent agent, Role role) {
         ScopeRelationship scope = new ScopeRelationship();
         scope.setClient(agent);
         scope.setScope(role);
-
     }
 
     public Set<String> getScope(Agent agent) {
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmSubResource.java b/services/src/main/java/org/keycloak/services/resources/RealmSubResource.java
index 7d2ab1f..4221f12 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmSubResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmSubResource.java
@@ -52,9 +52,9 @@ public class RealmSubResource {
         StringBuffer html = new StringBuffer();
 
         String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString();
-        String codeUri = TokenService.accessCodeRequest(uriInfo).build(realm.getId()).toString();
-        String grantUrl = TokenService.grantRequest(uriInfo).build(realm.getId()).toString();
-        String idGrantUrl = TokenService.identityGrantRequest(uriInfo).build(realm.getId()).toString();
+        String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString();
+        String grantUrl = TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString();
+        String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString();
 
         html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
         html.append("<p>auth: ").append(authUri).append("</p>");
@@ -76,9 +76,9 @@ public class RealmSubResource {
         rep.setAdminRole(ADMIN_ROLE);
 
         rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString());
-        rep.setCodeUrl(TokenService.accessCodeRequest(uriInfo).build(realm.getId()).toString());
-        rep.setGrantUrl(TokenService.grantRequest(uriInfo).build(realm.getId()).toString());
-        String idGrantUrl = TokenService.identityGrantRequest(uriInfo).build(realm.getId()).toString();
+        rep.setCodeUrl(TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString());
+        rep.setGrantUrl(TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString());
+        String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString();
         rep.setIdentityGrantUrl(idGrantUrl);
         return rep;
     }
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 2dfda68..7bd38fe 100755
--- a/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
+++ b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
@@ -1,6 +1,7 @@
 package org.keycloak.services.resources;
 
 import org.jboss.resteasy.logging.Logger;
+import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.models.RealmModel;
@@ -12,10 +13,8 @@ import org.picketlink.idm.model.User;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.ForbiddenException;
-import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -57,7 +56,7 @@ public class RegistrationService {
 
             user = new SimpleUser(newUser.getUsername());
             defaultRealm.getIdm().add(user);
-            for (UserRepresentation.Credential cred : newUser.getCredentials()) {
+            for (CredentialRepresentation cred : newUser.getCredentials()) {
                 UserCredentialModel credModel = new UserCredentialModel();
                 credModel.setType(cred.getType());
                 credModel.setValue(cred.getValue());
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 0f10ec8..eaaaf74 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -13,6 +13,7 @@ import org.keycloak.representations.SkeletonKeyToken;
 import org.keycloak.services.JspRequestParameters;
 import org.keycloak.services.managers.AccessCodeEntry;
 import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.ResourceAdminManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.models.RealmModel;
 import org.keycloak.services.models.RequiredCredentialModel;
@@ -31,7 +32,6 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.NewCookie;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
@@ -51,7 +51,6 @@ public class TokenService {
 
 
     protected static final Logger logger = Logger.getLogger(TokenService.class);
-    //protected Map<String, AccessCodeEntry> accessCodeMap;
 
     @Context
     protected UriInfo uriInfo;
@@ -73,39 +72,40 @@ public class TokenService {
     protected RealmModel realm;
     protected TokenManager tokenManager;
     protected AuthenticationManager authManager = new AuthenticationManager();
+    private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
 
     public TokenService(RealmModel realm, TokenManager tokenManager) {
         this.realm = realm;
         this.tokenManager = tokenManager;
     }
 
-    public static UriBuilder tokenServiceBase(UriInfo uriInfo) {
+    public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
         UriBuilder base = uriInfo.getBaseUriBuilder()
                 .path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
         return base;
     }
 
-    public static UriBuilder accessCodeRequest(UriInfo uriInfo) {
-        return tokenServiceBase(uriInfo).path(TokenService.class, "accessRequest");
+    public static UriBuilder accessCodeToTokenUrl(UriInfo uriInfo) {
+        return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "accessCodeToToken");
 
     }
 
-    public static UriBuilder grantRequest(UriInfo uriInfo) {
-        return tokenServiceBase(uriInfo).path(TokenService.class, "accessTokenGrant");
+    public static UriBuilder grantAccessTokenUrl(UriInfo uriInfo) {
+        return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "grantAccessToken");
 
     }
 
-    public static UriBuilder identityGrantRequest(UriInfo uriInfo) {
-        return tokenServiceBase(uriInfo).path(TokenService.class, "accessTokenGrant");
+    public static UriBuilder grantIdentityTokenUrl(UriInfo uriInfo) {
+        return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "grantIdentityToken");
 
     }
 
     public static UriBuilder loginPageUrl(UriInfo uriInfo) {
-        return tokenServiceBase(uriInfo).path(TokenService.class, "loginRequest");
+        return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "loginPage");
     }
 
-    public static UriBuilder logainActionUrl(UriInfo uriInfo) {
-        return tokenServiceBase(uriInfo).path(TokenService.class, "login");
+    public static UriBuilder processLoginUrl(UriInfo uriInfo) {
+        return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processLogin");
     }
 
 
@@ -113,7 +113,7 @@ public class TokenService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response identityTokenGrant(MultivaluedMap<String, String> form) {
+    public Response grantIdentityToken(MultivaluedMap<String, String> form) {
         String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
         if (username == null) {
             throw new NotAuthorizedException("No user");
@@ -142,7 +142,7 @@ public class TokenService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response accessTokenGrant(MultivaluedMap<String, String> form) {
+    public Response grantAccessToken(MultivaluedMap<String, String> form) {
         String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
         if (username == null) {
             throw new NotAuthorizedException("No user");
@@ -169,7 +169,7 @@ public class TokenService {
     @Path("auth/request/login")
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public Response login(MultivaluedMap<String, String> formData) {
+    public Response processLogin(MultivaluedMap<String, String> formData) {
         String clientId = formData.getFirst("client_id");
         String scopeParam = formData.getFirst("scope");
         String state = formData.getFirst("state");
@@ -226,7 +226,7 @@ public class TokenService {
     @Path("access/codes")
     @POST
     @Produces("application/json")
-    public Response accessRequest(MultivaluedMap<String, String> formData) {
+    public Response accessCodeToToken(MultivaluedMap<String, String> formData) {
         logger.info("accessRequest <---");
         if (!realm.isEnabled()) {
             throw new NotAuthorizedException("Realm not enabled");
@@ -356,7 +356,7 @@ public class TokenService {
                                       String scopeParam,
                                       String state) {
         request.setAttribute(RealmModel.class.getName(), realm);
-        request.setAttribute("KEYCLOAK_LOGIN_ACTION", logainActionUrl(uriInfo).build(realm.getId()));
+        request.setAttribute("KEYCLOAK_LOGIN_ACTION", processLoginUrl(uriInfo).build(realm.getId()));
 
         // RESTEASY eats the form data, so we send via an attribute
         request.setAttribute("redirect_uri", redirect);
@@ -369,11 +369,11 @@ public class TokenService {
 
     @Path("login")
     @GET
-    public Response loginRequest(@QueryParam("response_type") String responseType,
-                                 @QueryParam("redirect_uri") String redirect,
-                                 @QueryParam("client_id") String clientId,
-                                 @QueryParam("scope") String scopeParam,
-                                 @QueryParam("state") String state) {
+    public Response loginPage(@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()) {
             securityFailureForward("Realm not enabled");
             return null;
@@ -390,7 +390,7 @@ public class TokenService {
             return null;
         }
 
-        User user = authManager.authenticateIdentityCookie(realm, headers);
+        User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
         if (user != null) {
             return redirectAccessCode(scopeParam, state, redirect, client, user);
         }
@@ -400,6 +400,21 @@ public class TokenService {
         return null;
     }
 
+    @Path("logout")
+    @GET
+    public Response logout(@QueryParam("redirect_uri") String redirectUri) {
+        // todo do we care if anybody can trigger this?
+
+        User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
+        if (user != null) {
+            logger.info("Logging out: " + user.getLoginName());
+            authManager.expireIdentityCookie(realm, uriInfo);
+            resourceAdminManager.singleLogOut(realm, user.getLoginName());
+        }
+        // todo manage legal redirects
+        return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
+    }
+
     private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
         StringBuffer html = new StringBuffer();
         if (scopeParam != null) {
@@ -431,7 +446,7 @@ public class TokenService {
             }
             html.append("</table><p>To Authorize, please login below</p>");
         } else {
-            Set<String> scopeMapping = realm.getScopes(client);
+            Set<String> scopeMapping = realm.getScope(client);
             if (scopeMapping.contains("*")) {
                 html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
                 if (validationError != null) {
@@ -485,7 +500,7 @@ public class TokenService {
             }
         }
 
-        UriBuilder formActionUri = logainActionUrl(uriInfo);
+        UriBuilder formActionUri = processLoginUrl(uriInfo);
         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>");
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 78622cc..f798539 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -166,7 +166,7 @@ public class AdapterTest {
         idm.add(new SimpleRole("admin"));
         idm.add(new SimpleRole("user"));
         List<Role> roles = realmModel.getRoles();
-        Assert.assertEquals(2, roles.size());
+        Assert.assertEquals(3, roles.size());
         SimpleUser user = new SimpleUser("bburke");
         idm.add(user);
         Role role = idm.getRole("user");
diff --git a/services/src/test/java/org/keycloak/test/ImportTest.java b/services/src/test/java/org/keycloak/test/ImportTest.java
index 335169a..c785e21 100755
--- a/services/src/test/java/org/keycloak/test/ImportTest.java
+++ b/services/src/test/java/org/keycloak/test/ImportTest.java
@@ -104,7 +104,7 @@ public class ImportTest {
 
         User user = realm.getIdm().getUser("loginclient");
         Assert.assertNotNull(user);
-        Set<String> scopes = realm.getScopes(user);
+        Set<String> scopes = realm.getScope(user);
         System.out.println("Scopes size: " + scopes.size());
         Assert.assertTrue(scopes.contains("*"));