keycloak-aplcache

Merge pull request #2957 from pedroigor/authz-changes Changes

6/23/2016 2:49:47 AM

Changes

examples/authz/photoz-uma/photoz-uma-restful-api/src/main/webapp/index.html 1(+0 -1)

Details

diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
index add1c83..3ae286f 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
@@ -129,7 +129,7 @@ public abstract class AbstractPolicyEnforcer {
             Set<String> allowedScopes = permission.getScopes();
 
             if (permission.getResourceSetId() != null) {
-                if (permission.getResourceSetId().equals(actualPathConfig.getId())) {
+                if (isResourcePermission(actualPathConfig, permission)) {
                     if (((allowedScopes == null || allowedScopes.isEmpty()) && requiredScopes.isEmpty()) || allowedScopes.containsAll(requiredScopes)) {
                         LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
                         if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
@@ -211,6 +211,7 @@ public abstract class AbstractPolicyEnforcer {
                 config.setScopes(originalConfig.getScopes());
                 config.setMethods(originalConfig.getMethods());
                 config.setInstance(true);
+                config.setParentConfig(originalConfig);
 
                 this.paths.add(config);
 
@@ -240,4 +241,16 @@ public abstract class AbstractPolicyEnforcer {
     private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
         return new AuthorizationContext(accessToken, this.paths);
     }
+
+    private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
+        // first we try a match using resource id
+        boolean resourceMatch = permission.getResourceSetId().equals(actualPathConfig.getId());
+
+        // as a fallback, check if the current path is an instance and if so, check if parent's id matches the permission
+        if (!resourceMatch && actualPathConfig.isInstance()) {
+            resourceMatch = permission.getResourceSetId().equals(actualPathConfig.getParentConfig().getId());
+        }
+
+        return resourceMatch;
+    }
 }
diff --git a/adapters/oidc/js/pom.xml b/adapters/oidc/js/pom.xml
index 315f4b7..b03ccea 100755
--- a/adapters/oidc/js/pom.xml
+++ b/adapters/oidc/js/pom.xml
@@ -58,6 +58,25 @@
                             <goal>minify</goal>
                         </goals>
                     </execution>
+                    <execution>
+                        <id>min-authz-js</id>
+                        <phase>compile</phase>
+                        <configuration>
+                            <charset>utf-8</charset>
+                            <webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
+                            <jsSourceDir>.</jsSourceDir>
+                            <jsSourceFiles>
+                                <jsSourceFile>keycloak-authz.js</jsSourceFile>
+                            </jsSourceFiles>
+
+                            <webappTargetDir>${project.build.directory}/classes</webappTargetDir>
+                            <jsTargetDir>.</jsTargetDir>
+                            <jsFinalFile>keycloak-authz.js</jsFinalFile>
+                        </configuration>
+                        <goals>
+                            <goal>minify</goal>
+                        </goals>
+                    </execution>
                 </executions>
             </plugin>
 		</plugins>
diff --git a/adapters/oidc/js/src/main/resources/keycloak-authz.js b/adapters/oidc/js/src/main/resources/keycloak-authz.js
new file mode 100644
index 0000000..7658352
--- /dev/null
+++ b/adapters/oidc/js/src/main/resources/keycloak-authz.js
@@ -0,0 +1,170 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+(function( window, undefined ) {
+    
+    var KeycloakAuthorization = function (keycloak) {
+        var _instance = this;
+        this.rpt = null;
+
+        this.init = function () {
+            var request = new XMLHttpRequest();
+
+            request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma-configuration');
+            request.onreadystatechange = function () {
+                if (request.readyState == 4) {
+                    if (request.status == 200) {
+                        _instance.config = JSON.parse(request.responseText);
+                    } else {
+                        console.error('Could not obtain configuration from server.');
+                    }
+                }
+            }
+
+            request.send(null);
+        };
+
+        /**
+         * This method enables client applications to better integrate with resource servers protected by a Keycloak
+         * policy enforcer.
+         *
+         * In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
+         * necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
+         * depending on how the policy enforcer at the resource server was configured.
+         */
+        this.authorize = function (wwwAuthenticateHeader) {
+            this.then = function (onGrant, onDeny, onError) {
+                if (wwwAuthenticateHeader.startsWith('UMA')) {
+                    var params = wwwAuthenticateHeader.split(',');
+
+                    for (i = 0; i < params.length; i++) {
+                        var param = params[i].split('=');
+
+                        if (param[0] == 'ticket') {
+                            var request = new XMLHttpRequest();
+
+                            request.open('POST', _instance.config.rpt_endpoint, true);
+                            request.setRequestHeader('Content-Type', 'application/json')
+                            request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
+
+                            request.onreadystatechange = function () {
+                                if (request.readyState == 4) {
+                                    var status = request.status;
+
+                                    if (status >= 200 && status < 300) {
+                                        var rpt = JSON.parse(request.responseText).rpt;
+                                        _instance.rpt = rpt;
+                                        onGrant(rpt);
+                                    } else if (status == 403) {
+                                        if (onDeny) {
+                                            onDeny();
+                                        } else {
+                                            console.error('Authorization request was denied by the server.');
+                                        }
+                                    } else {
+                                        if (onError) {
+                                            onError();
+                                        } else {
+                                            console.error('Could not obtain authorization data from server.');
+                                        }
+                                    }
+                                }
+                            };
+
+                            var ticket = param[1].substring(1, param[1].length - 1).trim();
+
+                            request.send(JSON.stringify(
+                                {
+                                    ticket: ticket,
+                                    rpt: _instance.rpt
+                                }
+                            ));
+                        }
+                    }
+                } else if (wwwAuthenticateHeader.startsWith('KC_ETT')) {
+                    var params = wwwAuthenticateHeader.substring('KC_ETT'.length).trim().split(',');
+                    var clientId = null;
+
+                    for (i = 0; i < params.length; i++) {
+                        var param = params[i].split('=');
+
+                        if (param[0] == 'realm') {
+                            clientId = param[1].substring(1, param[1].length - 1).trim();
+                        }
+                    }
+
+                    _instance.entitlement(clientId).then(onGrant, onDeny, onError);
+                }
+            };
+
+            /**
+             * Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
+             */
+            this.entitlement = function (resourceSeververId) {
+                this.then = function (onGrant, onDeny, onError) {
+                    var request = new XMLHttpRequest();
+
+                    request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
+                    request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
+
+                    request.onreadystatechange = function () {
+                        if (request.readyState == 4) {
+                            var status = request.status;
+
+                            if (status >= 200 && status < 300) {
+                                var rpt = JSON.parse(request.responseText).rpt;
+                                _instance.rpt = rpt;
+                                onGrant(rpt);
+                            } else if (status == 403) {
+                                if (onDeny) {
+                                    onDeny();
+                                } else {
+                                    console.error('Authorization request was denied by the server.');
+                                }
+                            } else {
+                                if (onError) {
+                                    onError();
+                                } else {
+                                    console.error('Could not obtain authorization data from server.');
+                                }
+                            }
+                        }
+                    };
+
+                    request.send(null);
+                };
+
+                return this;
+            };
+
+            return this;
+        };
+
+        this.init(this);
+    };
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = KeycloakAuthorization;
+    } else {
+        window.KeycloakAuthorization = KeycloakAuthorization;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "keycloak-authorization", [], function () { return KeycloakAuthorization; } );
+        }
+    }
+})( window );
\ No newline at end of file
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java
index a693263..be83987 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java
@@ -89,7 +89,7 @@ public class HttpMethod<R> {
             int statusCode = statusLine.getStatusCode();
 
             if (statusCode < 200 || statusCode >= 300) {
-                throw new HttpResponseException(statusCode, statusLine.getReasonPhrase(), bytes);
+                throw new HttpResponseException("Unexpected response from server: " + statusCode + " / " + statusLine.getReasonPhrase(), statusCode, statusLine.getReasonPhrase(), bytes);
             }
 
             if (bytes == null) {
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
index 9b783e7..3531f40 100644
--- a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
@@ -26,7 +26,8 @@ public class HttpResponseException extends RuntimeException {
     private final String reasonPhrase;
     private final byte[] bytes;
 
-    public HttpResponseException(int statusCode, String reasonPhrase, byte[] bytes) {
+    public HttpResponseException(String message, int statusCode, String reasonPhrase, byte[] bytes) {
+        super(message);
         this.statusCode = statusCode;
         this.reasonPhrase = reasonPhrase;
         this.bytes = bytes;
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
index 98a4045..5145ec7 100644
--- a/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
@@ -17,6 +17,7 @@
  */
 package org.keycloak.representations.adapters.config;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 import java.util.ArrayList;
@@ -99,6 +100,9 @@ public class PolicyEnforcerConfig {
         private String id;
         private boolean instance;
 
+        @JsonIgnore
+        private PathConfig parentConfig;
+
         public String getPath() {
             return this.path;
         }
@@ -169,6 +173,14 @@ public class PolicyEnforcerConfig {
         public void setInstance(boolean instance) {
             this.instance = instance;
         }
+
+        public void setParentConfig(PathConfig parentConfig) {
+            this.parentConfig = parentConfig;
+        }
+
+        public PathConfig getParentConfig() {
+            return parentConfig;
+        }
     }
 
     public static class MethodConfig {
diff --git a/examples/authz/hello-world/hello-world-authz-realm.json b/examples/authz/hello-world/hello-world-authz-realm.json
index a263c69..3ab917c 100644
--- a/examples/authz/hello-world/hello-world-authz-realm.json
+++ b/examples/authz/hello-world/hello-world-authz-realm.json
@@ -12,16 +12,18 @@
       "enabled" : true,
       "credentials" : [ {
         "type" : "password",
-        "value" : "password"
-      } ]
+        "value" : "alice"
+      } ],
+      "realmRoles" : ["uma_authorization"]
     },
     {
       "username" : "jdoe",
       "enabled" : true,
       "credentials" : [ {
         "type" : "password",
-        "value" : "password"
-      } ]
+        "value" : "jdoe"
+      } ],
+      "realmRoles" : ["uma_authorization"]
     },
     {
       "username" : "service-account-hello-world-authz-service",
@@ -38,7 +40,9 @@
       "secret" : "secret",
       "authorizationServicesEnabled" : true,
       "enabled" : true,
-      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service" ],
+      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
+      "baseUrl": "http://localhost:8080/hello-world-authz-service",
+      "adminUrl": "http://localhost:8080/hello-world-authz-service",
       "directAccessGrantsEnabled" : true
     }
   ]
diff --git a/examples/authz/hello-world/hello-world-authz-service.json b/examples/authz/hello-world/hello-world-authz-service.json
index 24bd27f..ea56e62 100644
--- a/examples/authz/hello-world/hello-world-authz-service.json
+++ b/examples/authz/hello-world/hello-world-authz-service.json
@@ -1,24 +1,29 @@
 {
   "resources": [
     {
-      "name": "Hello World Resource"
+      "name": "Default Resource",
+      "uri": "/*",
+      "type": "urn:hello-world-authz-service:resources:default"
     }
   ],
   "policies": [
     {
-      "name": "Only Special Users Policy",
-      "type": "user",
-      "logic": "POSITIVE",
+      "name": "Only From Realm Policy",
+      "description": "A policy that grants access only for users within this realm",
+      "type": "js",
       "config": {
-        "users": "[\"alice\"]"
+        "applyPolicies": "[]",
+        "code": "var context = $evaluation.getContext();\n\n// using attributes from the evaluation context to obtain the realm\nvar contextAttributes = context.getAttributes();\nvar realmName = contextAttributes.getValue('kc.realm.name').asString(0);\n\n// using attributes from the identity to obtain the issuer\nvar identity = context.getIdentity();\nvar identityAttributes = identity.getAttributes();\nvar issuer = identityAttributes.getValue('iss').asString(0);\n\n// only users from the realm have access granted \nif (issuer.endsWith(realmName)) {\n    $evaluation.grant();\n}"
       }
     },
     {
-      "name": "Hello World Resource Permission",
+      "name": "Default Permission",
+      "description": "A permission that applies to the default resource type",
       "type": "resource",
       "config": {
-        "resources": "[\"Hello World Resource\"]",
-        "applyPolicies": "[\"Only Special Users Policy\"]"
+        "defaultResourceType": "urn:hello-world-authz-service:resources:default",
+        "default": "true",
+        "applyPolicies": "[\"Only From Realm Policy\"]"
       }
     }
   ]
diff --git a/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java b/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java
index 75ee0d3..2ab8788 100644
--- a/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java
+++ b/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java
@@ -49,7 +49,7 @@ public class AuthorizationClientExample {
         // query the server for a resource with a given name
         Set<String> resourceId = authzClient.protection()
                 .resource()
-                .findByFilter("name=Hello World Resource");
+                .findByFilter("name=Default Resource");
 
         // obtian a Entitlement API Token in order to get access to the Entitlement API.
         // this token is just an access token issued to a client on behalf of an user with a scope kc_entitlement
@@ -119,7 +119,7 @@ public class AuthorizationClientExample {
         EntitlementRequest request = new EntitlementRequest();
         PermissionRequest permission = new PermissionRequest();
 
-        permission.setResourceSetName("Hello World Resource");
+        permission.setResourceSetName("Default Resource");
 
         request.addPermission(permission);
 
@@ -157,6 +157,6 @@ public class AuthorizationClientExample {
      * @return a string representing a EAT
      */
     private static String getEntitlementAPIToken(AuthzClient authzClient) {
-        return authzClient.obtainAccessToken("alice", "password").getToken();
+        return authzClient.obtainAccessToken("alice", "alice").getToken();
     }
 }
diff --git a/examples/authz/hello-world-authz-service/hello-world-authz-realm.json b/examples/authz/hello-world-authz-service/hello-world-authz-realm.json
new file mode 100644
index 0000000..3ab917c
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/hello-world-authz-realm.json
@@ -0,0 +1,49 @@
+{
+  "realm" : "hello-world-authz",
+  "enabled" : true,
+  "privateKey" : "MIIEpQIBAAKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABAoIBAAwa4wVnKBOIS6srmYPfBTDNsTBBCEjxiYEErmn7JhoWxQ1DCPUxyxU6F177/q9Idqoj1FFOCtEO9P6/9+ym470HQmEQkR2Xxd1d3HOZy9oKuCro3ZbTDkVxY0JnlyxZz4MihGFxDH2e4MArfHy0sAgYbdIU+x2pWKGWSMzDd/TMSOExhc/sIQAg6ljbPCLLXCPQFAncoHRyGPrkRZs6UTZi5SJuCglVa2/3G+0drDdPuA83/mwsZfIBqQgbGbFgtq5T5C6CKMkPOQ42Rcclm7kEr6riTkJRo23EO1iOJVpxzI0tbxZsJAsW7zeqv0wWRyUgVfQAje6OdsNexp5aCtECgYEA6nMHCQ9xXvufCyzpIbYGxdAGqH6m1AR5gXerHqRiGNx+8UUt/E9cy/HTOhmZDK/eC4BT9tImeF01l1oSU/+wGKfux0SeAQchBhhq8GD6jmrtgczKAfZHp0Zrht7o9qu9KE7ZNWRmY1foJN9yNYmzY6qqHEy+zNo9amcqT7UZKO8CgYEA35sp9fMpMqkJE+NEJ9Ph/t2081BEkC0DYIuETZRSi+Ek5AliWTyEkg+oisTbWzi6fMQHS7W+M1SQP6djksLQNPP+353DKgup5gtKS+K/y2xNd7fSsNmkjW1bdJJpID7WzwwmwdahHxpcnFFuEXi5FkG3Vqmtd3cD0TYL33JlRy0CgYEA0+a3eybsDy9Zpp4m8IM3R98nxW8DlimdMLlafs2QpGvWiHdAgwWwF90wTxkHzgG+raKFQVbb0npcj7mnSyiUnxRZqt2H+eHZpUq4jR76F3LpzCGui2tvg+8QDMy4vwqmYyIxDCL8r9mqRnl3HpChBPoh2oY7BahTTjKEeZpzbR0CgYEAoNnVjX+mGzNNvGi4Fo5s/BIwoPcU20IGM+Uo/0W7O7Rx/Thi7x6BnzB0ZZ7GzRA51paNSQEsGXCzc5bOIjzR2cXLisDKK+zIAxwMDhrHLWZzM7OgdGeb38DTEUBhLzkE/VwYZUgoD1+/TxOkwhy9yCzt3gGhL1cF//GJCOwZvuECgYEAgsO4rdYScgCpsyePnHsFk+YtqtdORnmttF3JFcL3w2QneXuRwg2uW2Kfz8CVphrR9eOU0tiw38w6QTHIVeyRY8qqlHtiXj6dEYz7frh/k4hI29HwFx43rRpnAnN8kBEJYBYdbjaQ35Wsqkfu1tvHJ+6fxSwvQu/TVdGp0OfilAY=",
+  "publicKey" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQAB",
+  "certificate" : "MIICsTCCAZkCBgFVETX4AzANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFIZWxsbyBXb3JsZCBBdXRoWjAeFw0xNjA2MDIxMzAxMzdaFw0yNjA2MDIxMzAzMTdaMBwxGjAYBgNVBAMMEUhlbGxvIFdvcmxkIEF1dGhaMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQANm5gIT/c50lwjawM686gNXpppLA928WsCOn9NIIWjSKekP8Bf9S73kf7vWcsEppm5B8rRyRxolXmzwghv74L7uVDg8Injjgj+XbPVQP+cJqWpSaMZHF7UfWe0/4M945Xcbmsl5q+m9PmrPG0AaaZhqXHcp4ehB1H+awyRqiERpJUuwZNycw2+2kjDADpsFf8hZVUd1F6ReYyOkqUyUjbL+jYTC7ZBNa7Ok+w6HCXWgkgVATAgQXJRM3w14IOc5MH/vfMCrCl/eNQLbjGl9y7u8PKwh3MXHDO2OLqtg6hOTSrOGUPJZGmGtUAl+2/R7FzoWkML/BNe2hjsL6UJwg91",
+  "requiredCredentials" : [ "password" ],
+  "users" :
+  [
+    {
+      "username" : "alice",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "alice"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "jdoe",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "jdoe"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "service-account-hello-world-authz-service",
+      "enabled" : true,
+      "serviceAccountClientId" : "hello-world-authz-service",
+      "clientRoles": {
+        "hello-world-authz-service" : ["uma_protection"]
+      }
+    }
+  ],
+  "clients" : [
+    {
+      "clientId" : "hello-world-authz-service",
+      "secret" : "secret",
+      "authorizationServicesEnabled" : true,
+      "enabled" : true,
+      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
+      "baseUrl": "http://localhost:8080/hello-world-authz-service",
+      "adminUrl": "http://localhost:8080/hello-world-authz-service",
+      "directAccessGrantsEnabled" : true
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/hello-world-authz-service.json b/examples/authz/hello-world-authz-service/hello-world-authz-service.json
new file mode 100644
index 0000000..ea56e62
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/hello-world-authz-service.json
@@ -0,0 +1,30 @@
+{
+  "resources": [
+    {
+      "name": "Default Resource",
+      "uri": "/*",
+      "type": "urn:hello-world-authz-service:resources:default"
+    }
+  ],
+  "policies": [
+    {
+      "name": "Only From Realm Policy",
+      "description": "A policy that grants access only for users within this realm",
+      "type": "js",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "var context = $evaluation.getContext();\n\n// using attributes from the evaluation context to obtain the realm\nvar contextAttributes = context.getAttributes();\nvar realmName = contextAttributes.getValue('kc.realm.name').asString(0);\n\n// using attributes from the identity to obtain the issuer\nvar identity = context.getIdentity();\nvar identityAttributes = identity.getAttributes();\nvar issuer = identityAttributes.getValue('iss').asString(0);\n\n// only users from the realm have access granted \nif (issuer.endsWith(realmName)) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Default Permission",
+      "description": "A permission that applies to the default resource type",
+      "type": "resource",
+      "config": {
+        "defaultResourceType": "urn:hello-world-authz-service:resources:default",
+        "default": "true",
+        "applyPolicies": "[\"Only From Realm Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/README.md b/examples/authz/hello-world-authz-service/README.md
new file mode 100644
index 0000000..a0cc40f
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/README.md
@@ -0,0 +1,47 @@
+# About the Example Application
+
+This is a simple application to get you started with Keycloak Authorization Services.
+
+It provides a single page application which is protected by a policy enforcer that decides whether an user can access
+that page or not based on the permissions obtained from a Keycloak Server.
+
+## Create the Example Realm and a Resource Server
+
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
+
+Now, create a new realm based on the following configuration file:
+
+    examples/authz/hello-world-authz-service/hello-world-authz-realm.json
+    
+That will import a pre-configured realm with everything you need to run this example. For more details about how to import a realm 
+into Keycloak, check the Keycloak's reference documentation.
+
+After importing that file, you'll have a new realm called ``hello-world-authz``. 
+
+Now, let's import another configuration using the Administration Console in order to configure the client application ``hello-world-authz-service`` as a resource server with all resources, scopes, permissions and policies.
+
+Click on ``Clients`` on the left side menu. Click on the ``hello-world-authz-service`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
+
+Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
+
+    examples/authz/hello-world-authz-service/hello-world-authz-service.json
+    
+Now click ``Upload`` and the resource server will be updated accordingly.
+
+## Deploy and Run the Example Application
+
+To deploy the example application, follow these steps:
+
+    cd examples/authz/hello-world-authz-service
+    mvn clean package wildfly:deploy
+    
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/hello-world-authz-service
+
+If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
+
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+
diff --git a/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
index 04c0486..f303fe1 100644
--- a/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
@@ -1,11 +1,11 @@
 {
   "realm": "hello-world-authz",
-  "realm-public-key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwmm2Nso+rUOYUYc4hO67LSf4s0pAKcqUbWWycS3fcz6Q4jg/SsBbIBJJXOMVR9GqwyTCVTH5s8Rb0+0pA+UrbZfMG2XIDnJoaGfJj9DvJwQkD+vzTvaS5q0ilP0tPlbusI5pyMi9xx+cjJBOvKR2GxjhcKrgb21lpmGcA1F1CPO3y/DT8GzTKg+9/nPKt1dKEUD7P5Uy5N7d8zz1fuOSLb5G267T1fKJvi6am8kCgM+agFVQ23j7w/aJ7T1EHUCZdaJ+aSODSYl8dM4RFNTjda0KMHHXqMMvd2+g8lZ0lAfstHywqZtCcHc9ULClVvQmQyXovn2qTktHAcD6BHTAgQIDAQAB",
+  "realm-public-key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQAB",
   "auth-server-url": "http://localhost:8080/auth",
   "ssl-required": "external",
   "resource": "hello-world-authz-service",
   "credentials": {
-    "secret": "a7672d93-ea27-44a3-baa6-ba3536609067"
+    "secret": "secret"
   },
   "policy-enforcer": {
     "on-deny-redirect-to" : "/hello-world-authz-service/error.jsp"
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js
new file mode 100644
index 0000000..9a018e4
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/**
+ * Creates an Identity object holding the information obtained from the access token issued by Keycloak, after a successful authentication,
+ * and a few utility methods to manage it.
+ */
+(function (window, undefined) {
+    var Identity = function (keycloak) {
+        this.loggedIn = true;
+
+        this.claims = {};
+        this.claims.name = keycloak.idTokenParsed.name;
+
+        this.authc = {};
+        this.authc.token = keycloak.token;
+
+        this.logout = function () {
+            keycloak.logout();
+        };
+
+        this.hasRole = function (name) {
+            if (keycloak && keycloak.hasRealmRole(name)) {
+                return true;
+            }
+            return false;
+        };
+
+        this.isAdmin = function () {
+            return this.hasRole("admin");
+        };
+
+        this.authorization = new KeycloakAuthorization(keycloak);
+    }
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = Identity;
+    } else {
+        window.Identity = Identity;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "identity", [], function () { return Identity; } );
+        }
+    }
+})( window );
\ No newline at end of file
diff --git a/examples/authz/pom.xml b/examples/authz/pom.xml
index 318d01e..e9eb4eb 100755
--- a/examples/authz/pom.xml
+++ b/examples/authz/pom.xml
@@ -22,7 +22,7 @@
     </properties>
 
     <modules>
-        <module>photoz-uma</module>
+        <module>photoz</module>
         <module>servlet-authz</module>
         <module>hello-world</module>
         <module>hello-world-authz-service</module>
diff --git a/examples/authz/servlet-authz/README.md b/examples/authz/servlet-authz/README.md
index df52870..f93acb5 100644
--- a/examples/authz/servlet-authz/README.md
+++ b/examples/authz/servlet-authz/README.md
@@ -14,7 +14,7 @@ This application will also show you how to create a dynamic menu with the permis
 
 ## Create the Example Realm and a Resource Server
 
-Considering that your AuthZ Server is up and running, log in to the Keycloak Administration Console.
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
 
 Now, create a new realm based on the following configuration file:
 
@@ -25,26 +25,30 @@ into Keycloak, check the Keycloak's reference documentation.
 
 After importing that file, you'll have a new realm called ``servlet-authz``. 
 
-Now, let's import another configuration using the Administration Console in order to configure the ``servlet-authz-app`` client application as a resource server with all resources, scopes, permissions and policies.
+Now, let's import another configuration using the Administration Console in order to configure the client application ``servlet-authz-app`` as a resource server with all resources, scopes, permissions and policies.
 
-Click on ``Authorization`` on the left side menu. Click on the ``Create`` button on the top of the resource server table. This will
-open the page that allows you to create a new resource server.
+Click on ``Clients`` on the left side menu. Click on the ``servlet-authz-app`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
 
 Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
 
     examples/authz/servlet-authz/servlet-authz-app-config.json
     
-Now click ``Upload`` and a new resource server will be created based on the ``servlet-authz-app`` client application.
+Now click ``Upload`` and the resource server will be updated accordingly.
 
 ## Deploy and Run the Example Applications
 
-To deploy the example applications, follow these steps:
+To deploy the example application, follow these steps:
 
     cd examples/authz/servlet-authz
-    mvn wildfly:deploy
+    mvn clean package wildfly:deploy
     
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/servlet-authz-app
+
 If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
 
-* username: jdoe / password: jdoe (premium user)
-* username: alice / password: alice (regular user)
-* username: admin / password: admin (administrator)
\ No newline at end of file
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+* username: admin / password: admin
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp b/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp
index be85c22..6f25023 100644
--- a/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp
+++ b/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp
@@ -1,8 +1,6 @@
-<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
-<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
 <html>
     <body>
-        <h2 style="color: red">You can not access this resource. Click <a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
-            .queryParam("redirect_uri", "/servlet-authz-app").build("servlet-authz").toString()%>">here</a> to log in as a different user.</h2>
+        <h2 style="color: red">You can not access this resource.</h2>
+        <%@include file="logout-include.jsp"%>
     </body>
 </html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/index.jsp b/examples/authz/servlet-authz/src/main/webapp/index.jsp
index 118f142..78c5444 100755
--- a/examples/authz/servlet-authz/src/main/webapp/index.jsp
+++ b/examples/authz/servlet-authz/src/main/webapp/index.jsp
@@ -1,6 +1,4 @@
 <%@page import="org.keycloak.AuthorizationContext" %>
-<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
-<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
 <%@ page import="org.keycloak.KeycloakSecurityContext" %>
 <%@ page import="org.keycloak.representations.authorization.Permission" %>
 
@@ -11,8 +9,7 @@
 
 <html>
 <body>
-    <h2>Click <a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
-            .queryParam("redirect_uri", "/servlet-authz-app").build("servlet-authz").toString()%>">here</a> to logout.</h2>
+    <%@include file="logout-include.jsp"%>
     <h2>This is a public resource. Try to access one of these <i>protected</i> resources:</h2>
 
     <p><a href="protected/dynamicMenu.jsp">Dynamic Menu</a></p>
diff --git a/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp b/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp
new file mode 100644
index 0000000..95365ea
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp
@@ -0,0 +1,11 @@
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%
+    String scheme = request.getScheme();
+    String host = request.getServerName();
+    int port = request.getServerPort();
+    String contextPath = request.getContextPath();
+    String redirectUri = scheme + "://" + host + ":" + port + contextPath;
+%>
+<h2>Click <a href="<%= KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", redirectUri).build("servlet-authz").toString()%>">here</a> to logout.</h2>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
index 554b250..5946cd6 100644
--- a/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
@@ -1,8 +1,6 @@
-<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
-<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
 <html>
 <body>
-    <h2>Only Administrators can access this page. Click <a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
-            .queryParam("redirect_uri", "/servlet-authz-app").build("servlet-authz").toString()%>">here</a> to logout.</h2></h2>
+    <h2>Only Administrators can access this page.</h2>
+    <%@include file="../../logout-include.jsp"%>
 </body>
 </html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
index 7240a98..1473d22 100644
--- a/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
@@ -1,6 +1,4 @@
 <%@page import="org.keycloak.AuthorizationContext" %>
-<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
-<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
 <%@ page import="org.keycloak.KeycloakSecurityContext" %>
 
 <%
@@ -10,8 +8,8 @@
 
 <html>
 <body>
-<h2>Any authenticated user can access this page. Click <a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
-            .queryParam("redirect_uri", "/servlet-authz-app").build("servlet-authz").toString()%>">here</a> to logout.</h2>
+<h2>Any authenticated user can access this page.</h2>
+<%@include file="../logout-include.jsp"%>
 
 <p>Here is a dynamic menu built from the permissions returned by the server:</p>
 
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
index f172573..9244f9c 100644
--- a/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
@@ -1,9 +1,6 @@
-<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
-<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
 <html>
 <body>
-<h2>Only for premium users. Click <a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
-            .queryParam("redirect_uri", "/servlet-authz-app").build("servlet-authz").toString()%>">here</a> to logout.</h2>
-
+<h2>Only for premium users.</h2>
+<%@include file="../../logout-include.jsp"%>
 </body>
 </html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
index 7f37597..eaffea8 100644
--- a/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
@@ -8,5 +8,7 @@
   "credentials": {
     "secret": "secret"
   },
-  "policy-enforcer": {}
+  "policy-enforcer": {
+    "on-deny-redirect-to" : "/servlet-authz-app/accessDenied.jsp"
+  }
 }
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
index 1c31fcc..84e5295 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
@@ -463,7 +463,7 @@ public class ResourceServerService {
                 "\n" +
                 "// using attributes from the evaluation context to obtain the realm\n" +
                 "var contextAttributes = context.getAttributes();\n" +
-                "var realmName = contextAttributes.getValue('kc.authz.context.authc.realm').asString(0);\n" +
+                "var realmName = contextAttributes.getValue('kc.realm.name').asString(0);\n" +
                 "\n" +
                 "// using attributes from the identity to obtain the issuer\n" +
                 "var identity = context.getIdentity();\n" +
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index eaa8c78..ad154a6 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -106,7 +106,10 @@ public class AuthorizationTokenService {
                 List<Permission> entitlements = Permissions.allPermits(results);
 
                 if (entitlements.isEmpty()) {
-                    asyncResponse.resume(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN));
+                    asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.FORBIDDEN)
+                            .entity(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN)))
+                            .allowedOrigins(identity.getAccessToken())
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
                 } else {
                     AuthorizationResponse response = new AuthorizationResponse(createRequestingPartyToken(entitlements, identity.getAccessToken()));
                     asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.CREATED).entity(response)).allowedOrigins(identity.getAccessToken())
@@ -217,12 +220,14 @@ public class AuthorizationTokenService {
     }
 
     private PermissionTicket verifyPermissionTicket(AuthorizationRequest request) {
-        if (!Tokens.verifySignature(request.getTicket(), getRealm().getPublicKey())) {
+        String ticketString = request.getTicket();
+
+        if (ticketString == null || !Tokens.verifySignature(ticketString, getRealm().getPublicKey())) {
             throw new ErrorResponseException("invalid_ticket", "Ticket verification failed", Status.FORBIDDEN);
         }
 
         try {
-            PermissionTicket ticket = new JWSInput(request.getTicket()).readJsonContent(PermissionTicket.class);
+            PermissionTicket ticket = new JWSInput(ticketString).readJsonContent(PermissionTicket.class);
 
             if (!ticket.isActive()) {
                 throw new ErrorResponseException("invalid_ticket", "Invalid permission ticket.", Status.FORBIDDEN);
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
index bc967b9..fc929ec 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
@@ -57,23 +57,23 @@ public class KeycloakEvaluationContext implements EvaluationContext {
     public Attributes getAttributes() {
         HashMap<String, Collection<String>> attributes = new HashMap<>();
 
-        attributes.put("kc.authz.context.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
-        attributes.put("kc.authz.context.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
-        attributes.put("kc.authz.context.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
+        attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
+        attributes.put("kc.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
+        attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
 
         AccessToken accessToken = this.identity.getAccessToken();
 
         if (accessToken != null) {
-            attributes.put("kc.authz.context.client_id", Arrays.asList(accessToken.getIssuedFor()));
+            attributes.put("kc.client.id", Arrays.asList(accessToken.getIssuedFor()));
         }
 
         List<String> userAgents = this.keycloakSession.getContext().getRequestHeaders().getRequestHeader("User-Agent");
 
         if (userAgents != null) {
-            attributes.put("kc.authz.context.client.user_agent", userAgents);
+            attributes.put("kc.client.user_agent", userAgents);
         }
 
-        attributes.put("kc.authz.context.authc.realm", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
+        attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
 
         return Attributes.from(attributes);
     }
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
index 983646b..df6f54d 100644
--- a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
@@ -80,8 +80,9 @@ public class EntitlementService {
         this.authorization = authorization;
     }
 
+    @Path("{resource_server_id}")
     @OPTIONS
-    public Response authorizePreFlight() {
+    public Response authorizePreFlight(@PathParam("resource_server_id") String resourceServerId) {
         return Cors.add(this.request, Response.ok()).auth().preflight().build();
     }
 
@@ -118,7 +119,10 @@ public class EntitlementService {
                 List<Permission> entitlements = Permissions.allPermits(results);
 
                 if (entitlements.isEmpty()) {
-                    asyncResponse.resume(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN));
+                    asyncResponse.resume(Cors.add(request, Response.status(Status.FORBIDDEN)
+                            .entity(new ErrorResponseException("not_authorized", "Authorization denied.", Status.FORBIDDEN)))
+                            .allowedOrigins(identity.getAccessToken())
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
                 } else {
                     asyncResponse.resume(Cors.add(request, Response.ok().entity(new EntitlementResponse(createRequestingPartyToken(entitlements)))).allowedOrigins(identity.getAccessToken()).allowedMethods("GET").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
                 }
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
index 240fafa..43204b8 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -26,6 +26,7 @@ import org.keycloak.authorization.model.ResourceServer;
 import org.keycloak.authorization.model.Scope;
 import org.keycloak.authorization.permission.ResourcePermission;
 import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.store.ResourceStore;
 import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.representations.authorization.Permission;
 
@@ -58,9 +59,10 @@ public final class Permissions {
     public static List<ResourcePermission> all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization) {
         List<ResourcePermission> permissions = new ArrayList<>();
         StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceStore resourceStore = storeFactory.getResourceStore();
 
-        storeFactory.getResourceStore().findByOwner(resourceServer.getClientId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
-        storeFactory.getResourceStore().findByOwner(identity.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
+        resourceStore.findByOwner(resourceServer.getClientId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
+        resourceStore.findByOwner(identity.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource)));
 
         return permissions;
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/JsResource.java b/services/src/main/java/org/keycloak/services/resources/JsResource.java
index 32161a4..c74abf0 100755
--- a/services/src/main/java/org/keycloak/services/resources/JsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/JsResource.java
@@ -44,55 +44,90 @@ public class JsResource {
     @GET
     @Path("/keycloak.js")
     @Produces("text/javascript")
-    public Response getJs() {
-        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js");
-        if (inputStream != null) {
-            CacheControl cacheControl = new CacheControl();
-            cacheControl.setNoTransform(false);
-            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+    public Response getKeycloakJs() {
+        return getJs("keycloak.js");
+    }
 
-            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
-        } else {
+    @GET
+    @Path("/{version}/keycloak.js")
+    @Produces("text/javascript")
+    public Response getKeycloakJsWithVersion(@PathParam("version") String version) {
+        if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
+
+        return getKeycloakJs();
     }
 
     @GET
-    @Path("/{version}/keycloak.js")
+    @Path("/keycloak.min.js")
+    @Produces("text/javascript")
+    public Response getKeycloakMinJs() {
+        return getJs("keycloak.min.js");
+    }
+
+    @GET
+    @Path("/{version}/keycloak.min.js")
     @Produces("text/javascript")
-    public Response getJsWithVersion(@PathParam("version") String version) {
+    public Response getKeycloakMinJsWithVersion(@PathParam("version") String version) {
         if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
 
-        return getJs();
+        return getKeycloakMinJs();
     }
 
+    /**
+     * Get keycloak-authz.js file for javascript clients
+     *
+     * @return
+     */
     @GET
-    @Path("/keycloak.min.js")
+    @Path("/keycloak-authz.js")
     @Produces("text/javascript")
-    public Response getMinJs() {
-        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.min.js");
-        if (inputStream != null) {
-            CacheControl cacheControl = new CacheControl();
-            cacheControl.setNoTransform(false);
-            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+    public Response getKeycloakAuthzJs() {
+        return getJs("keycloak-authz.js");
+    }
 
-            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
-        } else {
+    @GET
+    @Path("/{version}/keycloak-authz.js")
+    @Produces("text/javascript")
+    public Response getKeycloakAuthzJsWithVersion(@PathParam("version") String version) {
+        if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
+
+        return getKeycloakAuthzJs();
     }
 
     @GET
-    @Path("/{version}/keycloak.min.js")
+    @Path("/keycloak-authz.min.js")
     @Produces("text/javascript")
-    public Response getMinJsWithVersion(@PathParam("version") String version) {
+    public Response getKeycloakAuthzMinJs() {
+        return getJs("keycloak-authz.min.js");
+    }
+
+    @GET
+    @Path("/{version}/keycloak-authz.min.js")
+    @Produces("text/javascript")
+    public Response getKeycloakAuthzMinJsWithVersion(@PathParam("version") String version) {
         if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
 
-        return getMinJs();
+        return getKeycloakAuthzMinJs();
     }
 
+    private Response getJs(String name) {
+        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(name);
+        if (inputStream != null) {
+            CacheControl cacheControl = new CacheControl();
+            cacheControl.setNoTransform(false);
+            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+
+            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
+        } else {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java
index 8876f30..0786eab 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java
@@ -261,7 +261,7 @@ public abstract class AbstractPhotozAdminTest extends AbstractAuthorizationTest 
 
             config.put("code",
                     "var contextAttributes = $evaluation.getContext().getAttributes();" +
-                    "var networkAddress = contextAttributes.getValue('kc.authz.context.client.network.ip_address');" +
+                    "var networkAddress = contextAttributes.getValue('kc.client.network.ip_address');" +
                     "if ('127.0.0.1'.equals(networkAddress.asInetAddress(0).getHostAddress())) {" +
                         "$evaluation.grant();" +
                     "}");
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
index e07ed1a..ecbe9d5 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
@@ -1044,7 +1044,7 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
             custom: true
         },
         {
-            key : "kc.authz.context.authc.method",
+            key : "kc.identity.authc.method",
             name : "Authentication Method",
             values: [
                 {
@@ -1062,23 +1062,23 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio
             ]
         },
         {
-            key : "kc.authz.context.authc.realm",
+            key : "kc.realm.name",
             name : "Realm"
         },
         {
-            key : "kc.authz.context.time.date_time",
+            key : "kc.time.date_time",
             name : "Date/Time (MM/dd/yyyy hh:mm:ss)"
         },
         {
-            key : "kc.authz.context.client.network.ip_address",
+            key : "kc.client.network.ip_address",
             name : "Client IPv4 Address"
         },
         {
-            key : "kc.authz.context.client.network.host",
+            key : "kc.client.network.host",
             name : "Client Host"
         },
         {
-            key : "kc.authz.context.client.user_agent",
+            key : "kc.client.user_agent",
             name : "Client/User Agent"
         }
     ];
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html
index 4919fe6..d03eefb 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html
@@ -5,7 +5,7 @@
     <ul class="nav nav-tabs nav-tabs-pf"  data-ng-hide="create && !path[4]" style="margin-left: 15px">
         <li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/">Settings</a></li>
         <li ng-class="{active: path[6] == 'resource'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">Resources</a></li>
-        <li ng-class="{active: path[6] == 'scope'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope">Scopes</a></li>
+        <li ng-class="{active: path[6] == 'scope'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope">Authorization Scopes</a></li>
         <li ng-class="{active: path[6] == 'policy'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">Policies</a></li>
         <li ng-class="{active: path[6] == 'permission'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission">Permissions</a></li>
         <li ng-class="{active: path[6] == 'evaluate'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/evaluate">Evaluate</a></li>