From bd5b4348947a1c4fb9ae7ed5481e815bacae83d7 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Fri, 29 Jul 2016 22:08:38 -0300 Subject: [PATCH] [KEYCLOAK-3376] - Show authorization data when evaluating authorization requests --- .../admin/PolicyEvaluationService.java | 24 ++++++------------- .../PolicyEvaluationResponse.java | 19 ++++++++++++++- .../messages/admin-messages_en.properties | 6 ++++- .../resources/js/authz/authz-controller.js | 14 +++++++++++ .../resource-server-policy-evaluate.html | 22 +++++++++++------ 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java index 6712a9dac3..67ae7d4c9e 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java @@ -87,16 +87,17 @@ public class PolicyEvaluationService { @Consumes("application/json") @Produces("application/json") public void evaluate(PolicyEvaluationRequest evaluationRequest, @Suspended AsyncResponse asyncResponse) { - EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest); - authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(createDecisionCollector(evaluationRequest, authorization, asyncResponse)); + KeycloakIdentity identity = createIdentity(evaluationRequest); + EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity); + authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(createDecisionCollector(evaluationRequest, authorization, identity, asyncResponse)); } - private DecisionResultCollector createDecisionCollector(PolicyEvaluationRequest evaluationRequest, AuthorizationProvider authorization, AsyncResponse asyncResponse) { + private DecisionResultCollector createDecisionCollector(PolicyEvaluationRequest evaluationRequest, AuthorizationProvider authorization, KeycloakIdentity identity, AsyncResponse asyncResponse) { return new DecisionResultCollector() { @Override protected void onComplete(List results) { try { - asyncResponse.resume(Response.ok(PolicyEvaluationResponse.build(evaluationRequest, results, resourceServer, authorization)).build()); + asyncResponse.resume(Response.ok(PolicyEvaluationResponse.build(evaluationRequest, results, resourceServer, authorization, identity)).build()); } catch (Throwable cause) { asyncResponse.resume(cause); } @@ -109,8 +110,8 @@ public class PolicyEvaluationService { }; } - private EvaluationContext createEvaluationContext(PolicyEvaluationRequest representation) { - return new KeycloakEvaluationContext(createIdentity(representation), this.authorization.getKeycloakSession()) { + private EvaluationContext createEvaluationContext(PolicyEvaluationRequest representation, KeycloakIdentity identity) { + return new KeycloakEvaluationContext(identity, this.authorization.getKeycloakSession()) { @Override public Attributes getAttributes() { Map> attributes = new HashMap<>(super.getAttributes().toMap()); @@ -137,17 +138,6 @@ public class PolicyEvaluationService { private List createPermissions(PolicyEvaluationRequest representation, EvaluationContext evaluationContext, AuthorizationProvider authorization) { List resources = representation.getResources(); - - for (PolicyEvaluationRequest.Resource resource : new ArrayList<>(resources)) { - if (resource.getId() == null && (resource.getScopes() == null || resource.getScopes().isEmpty())) { - resources.remove(resource); - } - } - - if (representation.isEntitlements() || resources.isEmpty()) { - return Permissions.all(this.resourceServer, evaluationContext.getIdentity(), authorization); - } - return resources.stream().flatMap((Function>) resource -> { Set givenScopes = resource.getScopes(); diff --git a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java index 9a3c9b361a..cccb38ff39 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java +++ b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java @@ -21,10 +21,15 @@ package org.keycloak.authorization.admin.representation; import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.Decision.Effect; import org.keycloak.authorization.admin.util.Models; +import org.keycloak.authorization.common.KeycloakIdentity; import org.keycloak.authorization.model.ResourceServer; import org.keycloak.authorization.model.Scope; import org.keycloak.authorization.policy.evaluation.Result; import org.keycloak.authorization.policy.evaluation.Result.PolicyResult; +import org.keycloak.authorization.util.Permissions; +import org.keycloak.protocol.oidc.TokenManager; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.idm.authorization.Permission; import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ScopeRepresentation; @@ -42,14 +47,22 @@ public class PolicyEvaluationResponse { private List results; private boolean entitlements; private Effect status; + private AccessToken rpt; private PolicyEvaluationResponse() { } - public static PolicyEvaluationResponse build(PolicyEvaluationRequest evaluationRequest, List results, ResourceServer resourceServer, AuthorizationProvider authorization) { + public static PolicyEvaluationResponse build(PolicyEvaluationRequest evaluationRequest, List results, ResourceServer resourceServer, AuthorizationProvider authorization, KeycloakIdentity identity) { PolicyEvaluationResponse response = new PolicyEvaluationResponse(); List resultsRep = new ArrayList<>(); + AccessToken accessToken = identity.getAccessToken(); + AccessToken.Authorization authorizationData = new AccessToken.Authorization(); + + authorizationData.setPermissions(Permissions.allPermits(results)); + accessToken.setAuthorization(authorizationData); + + response.rpt = accessToken; if (results.stream().anyMatch(evaluationResult -> evaluationResult.getEffect().equals(Effect.DENY))) { response.status = Effect.DENY; @@ -124,6 +137,10 @@ public class PolicyEvaluationResponse { return entitlements; } + public AccessToken getRpt() { + return rpt; + } + public static class EvaluationResultRepresentation { private ResourceRepresentation resource; diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties index 50d591960b..1f39b06b66 100644 --- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties +++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties @@ -1076,10 +1076,11 @@ authz-permission-scope-scope.tooltip=Specifies that this permission must be appl # Authz Evaluation authz-evaluation-identity-information=Identity Information authz-evaluation-identity-information.tooltip=The available options to configure the identity information that will be used when evaluating policies. -authz-evaluation-client.tooltip=Select the client making this authorization request. +authz-evaluation-client.tooltip=Select the client making this authorization request. If not provided, authorization requests would be done based on the client you are in. authz-evaluation-user.tooltip=Select an user whose identity is going to be used to query permissions from the server. authz-evaluation-role.tooltip=Select the roles you want to associate with the selected user. authz-evaluation-new=New Evaluation +authz-evaluation-re-evaluate=Re-Evaluate authz-evaluation-previous=Previous Evaluation authz-evaluation-contextual-info=Contextual Information authz-evaluation-contextual-info.tooltip=The available options to configure any contextual information that will be used when evaluating policies. @@ -1093,3 +1094,6 @@ authz-evaluation-no-policies-resource=No policies were found for this resource. authz-evaluation-result.tooltip=The overall result for this permission request. authz-evaluation-scopes.tooltip=The requested scopes. authz-evaluation-policies.tooltip=Details about which policies were evaluated and their decisions. +authz-evaluation-authorization-data=Response +authz-evaluation-authorization-data.tooltip=Represents a token carrying authorization data as a result of the processing of an authorization request. This representation is basically what Keycloak issues to clients asking for permissions. Check the 'authorization' claim for the permissions that were granted based on the current authorization request. +authz-show-authorization-data=Show Authorization Data 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 bbe0fd0a45..d772f92f0e 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 @@ -1329,6 +1329,18 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio } } + $scope.reevaluate = function() { + if ($scope.authzRequest.entitlements) { + $scope.entitlements(); + } else { + $scope.save(); + } + } + + $scope.showAuthzData = function() { + $scope.showRpt = true; + } + $scope.save = function() { $scope.authzRequest.entitlements = false; if ($scope.applyResourceType) { @@ -1356,10 +1368,12 @@ module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $locatio $scope.showResultTab = function() { $scope.showResult = true; + $scope.showRpt = false; } $scope.showRequestTab = function() { $scope.showResult = false; + $scope.showRpt = false; } User.query({realm: $route.current.params.realm}, function(data) { diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html index ce62c33529..d875e86159 100644 --- a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html @@ -12,6 +12,10 @@ +
+
+ +
+ +
+ {{:: 'authz-evaluation-authorization-data.tooltip' | translate}} +
+
+
@@ -56,12 +70,6 @@ {{:: 'authz-evaluation-user.tooltip' | translate}}
-
-
- -
-
-
@@ -268,7 +276,7 @@
-
+
\ No newline at end of file