diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionEffect.java b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionEffect.java
new file mode 100644
index 0000000000..cc13a08ca1
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionEffect.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public enum DecisionEffect {
+ PERMIT,
+ DENY
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationRequest.java
similarity index 74%
rename from services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java
rename to core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationRequest.java
index da7b4204c2..268cf37519 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationRequest.java
@@ -16,8 +16,10 @@
* limitations under the License.
*/
-package org.keycloak.authorization.admin.representation;
+package org.keycloak.representations.idm.authorization;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -29,11 +31,11 @@ import org.keycloak.representations.idm.authorization.ResourceRepresentation;
*/
public class PolicyEvaluationRequest {
- private Map> context;
- private List resources;
+ private Map> context = new HashMap<>();
+ private List resources = new LinkedList<>();
private String clientId;
private String userId;
- private List roleIds;
+ private List roleIds = new LinkedList<>();
private boolean entitlements;
public Map> getContext() {
@@ -44,11 +46,11 @@ public class PolicyEvaluationRequest {
this.context = context;
}
- public List getResources() {
+ public List getResources() {
return this.resources;
}
- public void setResources(List resources) {
+ public void setResources(List resources) {
this.resources = resources;
}
@@ -84,7 +86,13 @@ public class PolicyEvaluationRequest {
this.entitlements = entitlements;
}
- public static class Resource extends ResourceRepresentation {
-
+ public PolicyEvaluationRequest addResource(String name, String... scopes) {
+ if (resources == null) {
+ resources = new LinkedList<>();
+ }
+ resources.add(new ResourceRepresentation(name, scopes));
+ return this;
}
+
+
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationResponse.java b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationResponse.java
new file mode 100644
index 0000000000..45657713a4
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEvaluationResponse.java
@@ -0,0 +1,173 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.
+ */
+
+package org.keycloak.representations.idm.authorization;
+
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.DecisionEffect;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Pedro Igor
+ */
+public class PolicyEvaluationResponse {
+
+ private List results;
+ private boolean entitlements;
+ private DecisionEffect status;
+ private AccessToken rpt;
+
+ public List getResults() {
+ return results;
+ }
+
+ public DecisionEffect getStatus() {
+ return status;
+ }
+
+ public boolean isEntitlements() {
+ return entitlements;
+ }
+
+ public AccessToken getRpt() {
+ return rpt;
+ }
+
+ public void setResults(List results) {
+ this.results = results;
+ }
+
+ public void setEntitlements(boolean entitlements) {
+ this.entitlements = entitlements;
+ }
+
+ public void setStatus(DecisionEffect status) {
+ this.status = status;
+ }
+
+ public void setRpt(AccessToken rpt) {
+ this.rpt = rpt;
+ }
+
+ public static class EvaluationResultRepresentation {
+
+ private ResourceRepresentation resource;
+ private List scopes;
+ private List policies;
+ private DecisionEffect status;
+ private List allowedScopes = new ArrayList<>();
+
+ public void setResource(final ResourceRepresentation resource) {
+ this.resource = resource;
+ }
+
+ public ResourceRepresentation getResource() {
+ return resource;
+ }
+
+ public void setScopes(List scopes) {
+ this.scopes = scopes;
+ }
+
+ public List getScopes() {
+ return scopes;
+ }
+
+ public void setPolicies(final List policies) {
+ this.policies = policies;
+ }
+
+ public List getPolicies() {
+ return policies;
+ }
+
+ public void setStatus(final DecisionEffect status) {
+ this.status = status;
+ }
+
+ public DecisionEffect getStatus() {
+ return status;
+ }
+
+ public void setAllowedScopes(List allowedScopes) {
+ this.allowedScopes = allowedScopes;
+ }
+
+ public List getAllowedScopes() {
+ return allowedScopes;
+ }
+ }
+
+ public static class PolicyResultRepresentation {
+
+ private PolicyRepresentation policy;
+ private DecisionEffect status;
+ private List associatedPolicies;
+ private List scopes = new ArrayList<>();
+
+ public PolicyRepresentation getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(final PolicyRepresentation policy) {
+ this.policy = policy;
+ }
+
+ public DecisionEffect getStatus() {
+ return status;
+ }
+
+ public void setStatus(final DecisionEffect status) {
+ this.status = status;
+ }
+
+ public List getAssociatedPolicies() {
+ return associatedPolicies;
+ }
+
+ public void setAssociatedPolicies(final List associatedPolicies) {
+ this.associatedPolicies = associatedPolicies;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.policy.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final PolicyResultRepresentation policy = (PolicyResultRepresentation) o;
+ return this.policy.equals(policy.getPolicy());
+ }
+
+ public void setScopes(List scopes) {
+ this.scopes = scopes;
+ }
+
+ public List getScopes() {
+ return scopes;
+ }
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
index 86f6f98bed..d3c2e4620c 100644
--- a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
@@ -18,6 +18,8 @@ package org.keycloak.representations.idm.authorization;
import java.net.URI;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -91,6 +93,15 @@ public class ResourceRepresentation {
this(name, scopes, null, null, null);
}
+ public ResourceRepresentation(String name, String... scopes) {
+ this.name = name;
+ this.scopes = new HashSet<>();
+ for (String s : scopes) {
+ ScopeRepresentation rep = new ScopeRepresentation(s);
+ this.scopes.add(rep);
+ }
+ }
+
/**
* Creates a new instance.
*
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java
index fd5d43a9ca..e5120c621c 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java
@@ -17,6 +17,8 @@
package org.keycloak.admin.client.resource;
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
@@ -53,4 +55,11 @@ public interface PoliciesResource {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
List policyProviders();
+
+ @POST
+ @Consumes("application/json")
+ @Produces("application/json")
+ @Path("evaluate")
+ PolicyEvaluationResponse evaluate(PolicyEvaluationRequest evaluationRequest);
+
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
index 3d57c07a02..b5fa96d568 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
@@ -36,11 +36,15 @@ public interface UsersResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
List search(@QueryParam("username") String username,
- @QueryParam("firstName") String firstName,
- @QueryParam("lastName") String lastName,
- @QueryParam("email") String email,
- @QueryParam("first") Integer firstResult,
- @QueryParam("max") Integer maxResults);
+ @QueryParam("firstName") String firstName,
+ @QueryParam("lastName") String lastName,
+ @QueryParam("email") String email,
+ @QueryParam("first") Integer firstResult,
+ @QueryParam("max") Integer maxResults);
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ List search(@QueryParam("username") String username);
@GET
@Produces(MediaType.APPLICATION_JSON)
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 b096d24d4d..6a2f522318 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -17,12 +17,12 @@
*/
package org.keycloak.authorization.admin;
-import static java.util.Arrays.asList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -33,15 +33,13 @@ import java.util.stream.Stream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
-import javax.ws.rs.container.AsyncResponse;
-import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.authorization.AuthorizationProvider;
-import org.keycloak.authorization.admin.representation.PolicyEvaluationRequest;
-import org.keycloak.authorization.admin.representation.PolicyEvaluationResponse;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
+import org.keycloak.authorization.admin.representation.PolicyEvaluationResponseBuilder;
import org.keycloak.authorization.attribute.Attributes;
import org.keycloak.authorization.common.KeycloakEvaluationContext;
import org.keycloak.authorization.common.KeycloakIdentity;
@@ -58,15 +56,13 @@ import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
-import org.keycloak.protocol.ProtocolMapper;
-import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
+import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.Urls;
import org.keycloak.services.resources.admin.RealmAuth;
@@ -89,32 +85,41 @@ public class PolicyEvaluationService {
this.auth = auth;
}
+ static class Decision extends DecisionResultCollector {
+ Throwable error;
+ List results;
+
+ @Override
+ protected void onComplete(List results) {
+ this.results = results;
+ }
+
+ @Override
+ public void onError(Throwable cause) {
+ this.error = cause;
+
+ }
+ }
+
+ public static List asList(T... a) {
+ List list = new LinkedList();
+ for (T t : a) list.add(t);
+ return list;
+ }
+
@POST
@Consumes("application/json")
@Produces("application/json")
- public void evaluate(PolicyEvaluationRequest evaluationRequest, @Suspended AsyncResponse asyncResponse) {
+ public Response evaluate(PolicyEvaluationRequest evaluationRequest) throws Throwable {
this.auth.requireView();
KeycloakIdentity identity = createIdentity(evaluationRequest);
EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity);
- authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(createDecisionCollector(authorization, identity, asyncResponse));
- }
-
- private DecisionResultCollector createDecisionCollector(AuthorizationProvider authorization, KeycloakIdentity identity, AsyncResponse asyncResponse) {
- return new DecisionResultCollector() {
- @Override
- protected void onComplete(List results) {
- try {
- asyncResponse.resume(Response.ok(PolicyEvaluationResponse.build(results, resourceServer, authorization, identity)).build());
- } catch (Throwable cause) {
- asyncResponse.resume(cause);
- }
- }
-
- @Override
- public void onError(Throwable cause) {
- asyncResponse.resume(cause);
- }
- };
+ Decision decisionCollector = new Decision();
+ authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(decisionCollector);
+ if (decisionCollector.error != null) {
+ throw decisionCollector.error;
+ }
+ return Response.ok(PolicyEvaluationResponseBuilder.build(decisionCollector.results, resourceServer, authorization, identity)).build();
}
private EvaluationContext createEvaluationContext(PolicyEvaluationRequest representation, KeycloakIdentity identity) {
@@ -144,11 +149,11 @@ public class PolicyEvaluationService {
}
private List createPermissions(PolicyEvaluationRequest representation, EvaluationContext evaluationContext, AuthorizationProvider authorization) {
- List resources = representation.getResources();
- return resources.stream().flatMap((Function>) resource -> {
+ List resources = representation.getResources();
+ return resources.stream().flatMap((Function>) resource -> {
StoreFactory storeFactory = authorization.getStoreFactory();
if (resource == null) {
- resource = new PolicyEvaluationRequest.Resource();
+ resource = new ResourceRepresentation();
}
Set givenScopes = resource.getScopes();
@@ -183,32 +188,15 @@ public class PolicyEvaluationService {
private KeycloakIdentity createIdentity(PolicyEvaluationRequest representation) {
KeycloakSession keycloakSession = this.authorization.getKeycloakSession();
RealmModel realm = keycloakSession.getContext().getRealm();
- AccessToken accessToken = new AccessToken();
+ AccessToken accessToken = null;
- accessToken.subject(representation.getUserId());
- accessToken.issuedFor(representation.getClientId());
- accessToken.audience(representation.getClientId());
- accessToken.issuer(Urls.realmIssuer(keycloakSession.getContext().getUri().getBaseUri(), realm.getName()));
- accessToken.setRealmAccess(new AccessToken.Access());
- AccessToken.Access realmAccess = accessToken.getRealmAccess();
- Map claims = accessToken.getOtherClaims();
- Map givenAttributes = representation.getContext().get("attributes");
-
- if (givenAttributes != null) {
- givenAttributes.forEach((key, value) -> claims.put(key, asList(value)));
- }
-
- String subject = accessToken.getSubject();
+ String subject = representation.getUserId();
if (subject != null) {
UserModel userModel = keycloakSession.users().getUserById(subject, realm);
if (userModel != null) {
- userModel.getAttributes().forEach(claims::put);
-
- userModel.getRoleMappings().stream().map(RoleModel::getName).forEach(roleName -> realmAccess.addRole(roleName));
-
String clientId = representation.getClientId();
if (clientId == null) {
@@ -223,17 +211,18 @@ public class PolicyEvaluationService {
clientSession = keycloakSession.sessions().createClientSession(realm, clientModel);
userSession = keycloakSession.sessions().createUserSession(realm, userModel, userModel.getUsername(), "127.0.0.1", "passwd", false, null, null);
- UserSessionModel finalUserSession = userSession;
- ClientSessionModel finalClientSession = clientSession;
+ new TokenManager().attachClientSession(userSession, clientSession);
- for (ProtocolMapperModel mapping : clientModel.getProtocolMappers()) {
- KeycloakSessionFactory sessionFactory = keycloakSession.getKeycloakSessionFactory();
- ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
-
- if (mapper != null && (mapper instanceof OIDCAccessTokenMapper)) {
- accessToken = ((OIDCAccessTokenMapper)mapper).transformAccessToken(accessToken, mapping, keycloakSession, finalUserSession, finalClientSession);
+ Set requestedRoles = new HashSet<>();
+ for (String roleId : clientSession.getRoles()) {
+ RoleModel role = realm.getRoleById(roleId);
+ if (role != null) {
+ requestedRoles.add(role);
}
}
+
+
+ accessToken = new TokenManager().createClientAccessToken(keycloakSession, requestedRoles, realm, clientModel, userModel, userSession, clientSession);
} finally {
if (clientSession != null) {
keycloakSession.sessions().removeClientSession(realm, clientSession);
@@ -243,21 +232,30 @@ public class PolicyEvaluationService {
keycloakSession.sessions().removeUserSession(realm, userSession);
}
}
-
- AccessToken.Access clientAccess = accessToken.addAccess(clientModel.getClientId());
- clientAccess.roles(new HashSet<>());
-
- userModel.getClientRoleMappings(clientModel).stream().map(RoleModel::getName).forEach(roleName -> clientAccess.addRole(roleName));
-
- ClientModel resourceServerClient = realm.getClientById(resourceServer.getClientId());
- AccessToken.Access resourceServerAccess = accessToken.addAccess(resourceServerClient.getClientId());
- resourceServerAccess.roles(new HashSet<>());
-
- userModel.getClientRoleMappings(resourceServerClient).stream().map(RoleModel::getName).forEach(roleName -> resourceServerAccess.addRole(roleName));
}
}
}
+ if (accessToken == null) {
+ accessToken = new AccessToken();
+
+ accessToken.subject(representation.getUserId());
+ accessToken.issuedFor(representation.getClientId());
+ accessToken.audience(representation.getClientId());
+ accessToken.issuer(Urls.realmIssuer(keycloakSession.getContext().getUri().getBaseUri(), realm.getName()));
+ accessToken.setRealmAccess(new AccessToken.Access());
+
+ }
+
+ AccessToken.Access realmAccess = accessToken.getRealmAccess();
+ Map claims = accessToken.getOtherClaims();
+ Map givenAttributes = representation.getContext().get("attributes");
+
+ if (givenAttributes != null) {
+ givenAttributes.forEach((key, value) -> claims.put(key, asList(value)));
+ }
+
+
if (representation.getRoleIds() != null) {
representation.getRoleIds().forEach(roleName -> realmAccess.addRole(roleName));
}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponseBuilder.java
similarity index 57%
rename from services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java
rename to services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponseBuilder.java
index 427978a2c4..c42472549c 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponseBuilder.java
@@ -1,13 +1,12 @@
/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2016 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
+ * 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
+ * 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,
@@ -15,9 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.keycloak.authorization.admin.representation;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.util.Permissions;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.DecisionEffect;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -29,56 +43,37 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.keycloak.authorization.AuthorizationProvider;
-import org.keycloak.authorization.Decision.Effect;
-import org.keycloak.authorization.common.KeycloakIdentity;
-import org.keycloak.authorization.model.Policy;
-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.models.utils.ModelToRepresentation;
-import org.keycloak.representations.AccessToken;
-import org.keycloak.representations.idm.authorization.PolicyRepresentation;
-import org.keycloak.representations.idm.authorization.ResourceRepresentation;
-import org.keycloak.representations.idm.authorization.ScopeRepresentation;
-
/**
- * @author Pedro Igor
+ * @author Bill Burke
+ * @version $Revision: 1 $
*/
-public class PolicyEvaluationResponse {
-
- private List results;
- private boolean entitlements;
- private Effect status;
- private AccessToken rpt;
-
- private PolicyEvaluationResponse() {
-
- }
-
+public class PolicyEvaluationResponseBuilder {
public static PolicyEvaluationResponse build(List results, ResourceServer resourceServer, AuthorizationProvider authorization, KeycloakIdentity identity) {
PolicyEvaluationResponse response = new PolicyEvaluationResponse();
- List resultsRep = new ArrayList<>();
+ List resultsRep = new ArrayList<>();
AccessToken accessToken = identity.getAccessToken();
AccessToken.Authorization authorizationData = new AccessToken.Authorization();
authorizationData.setPermissions(Permissions.permits(results, authorization, resourceServer.getId()));
accessToken.setAuthorization(authorizationData);
- response.rpt = accessToken;
+ response.setRpt(accessToken);
- if (results.stream().anyMatch(evaluationResult -> evaluationResult.getEffect().equals(Effect.DENY))) {
- response.status = Effect.DENY;
+ if (results.stream().anyMatch(evaluationResult -> evaluationResult.getEffect().equals(Decision.Effect.DENY))) {
+ response.setStatus(DecisionEffect.DENY);
} else {
- response.status = Effect.PERMIT;
+ response.setStatus(DecisionEffect.PERMIT);
}
for (Result result : results) {
- EvaluationResultRepresentation rep = new EvaluationResultRepresentation();
+ PolicyEvaluationResponse.EvaluationResultRepresentation rep = new PolicyEvaluationResponse.EvaluationResultRepresentation();
- rep.setStatus(result.getEffect());
+ if (result.getEffect() == Decision.Effect.DENY) {
+ rep.setStatus(DecisionEffect.DENY);
+ } else {
+ rep.setStatus(DecisionEffect.PERMIT);
+
+ }
resultsRep.add(rep);
if (result.getPermission().getResource() != null) {
@@ -105,9 +100,9 @@ public class PolicyEvaluationResponse {
return representation;
}).collect(Collectors.toList()));
- List policies = new ArrayList<>();
+ List policies = new ArrayList<>();
- for (PolicyResult policy : result.getResults()) {
+ for (Result.PolicyResult policy : result.getResults()) {
policies.add(toRepresentation(policy, authorization));
}
@@ -116,10 +111,10 @@ public class PolicyEvaluationResponse {
resultsRep.sort(Comparator.comparing(o -> o.getResource().getName()));
- Map groupedResults = new HashMap<>();
+ Map groupedResults = new HashMap<>();
resultsRep.forEach(evaluationResultRepresentation -> {
- EvaluationResultRepresentation result = groupedResults.get(evaluationResultRepresentation.getResource().getId());
+ PolicyEvaluationResponse.EvaluationResultRepresentation result = groupedResults.get(evaluationResultRepresentation.getResource().getId());
ResourceRepresentation resource = evaluationResultRepresentation.getResource();
if (result == null) {
@@ -127,8 +122,8 @@ public class PolicyEvaluationResponse {
result = evaluationResultRepresentation;
}
- if (result.getStatus().equals(Effect.PERMIT) || (evaluationResultRepresentation.getStatus().equals(Effect.PERMIT) && result.getStatus().equals(Effect.DENY))) {
- result.setStatus(Effect.PERMIT);
+ if (result.getStatus().equals(DecisionEffect.PERMIT) || (evaluationResultRepresentation.getStatus().equals(DecisionEffect.PERMIT) && result.getStatus().equals(DecisionEffect.DENY))) {
+ result.setStatus(DecisionEffect.PERMIT);
}
List scopes = result.getScopes();
@@ -146,15 +141,15 @@ public class PolicyEvaluationResponse {
if (!scopes.contains(scope)) {
scopes.add(scope);
}
- if (evaluationResultRepresentation.getStatus().equals(Effect.PERMIT)) {
+ if (evaluationResultRepresentation.getStatus().equals(Decision.Effect.PERMIT)) {
if (!allowedScopes.contains(scope)) {
allowedScopes.add(scope);
}
} else {
- evaluationResultRepresentation.getPolicies().forEach(new Consumer() {
+ evaluationResultRepresentation.getPolicies().forEach(new Consumer() {
@Override
- public void accept(PolicyResultRepresentation policyResultRepresentation) {
- if (policyResultRepresentation.getStatus().equals(Effect.PERMIT)) {
+ public void accept(PolicyEvaluationResponse.PolicyResultRepresentation policyResultRepresentation) {
+ if (policyResultRepresentation.getStatus().equals(Decision.Effect.PERMIT)) {
if (!allowedScopes.contains(scope)) {
allowedScopes.add(scope);
}
@@ -176,16 +171,16 @@ public class PolicyEvaluationResponse {
result.getResource().setName("Any Resource with Scopes " + scopes.stream().flatMap((Function>) scopeRepresentation -> Arrays.asList(scopeRepresentation.getName()).stream()).collect(Collectors.toList()));
}
- List policies = result.getPolicies();
+ List policies = result.getPolicies();
- for (PolicyResultRepresentation policy : new ArrayList<>(evaluationResultRepresentation.getPolicies())) {
+ for (PolicyEvaluationResponse.PolicyResultRepresentation policy : new ArrayList<>(evaluationResultRepresentation.getPolicies())) {
if (!policies.contains(policy)) {
policies.add(policy);
} else {
policy = policies.get(policies.indexOf(policy));
}
- if (policy.getStatus().equals(Effect.DENY)) {
+ if (policy.getStatus().equals(Decision.Effect.DENY)) {
Policy policyModel = authorization.getStoreFactory().getPolicyStore().findById(policy.getPolicy().getId(), resourceServer.getId());
for (ScopeRepresentation scope : policyModel.getScopes().stream().map(scopeModel -> ModelToRepresentation.toRepresentation(scopeModel, authorization)).collect(Collectors.toList())) {
if (!policy.getScopes().contains(scope) && policyModel.getScopes().stream().filter(policyScope -> policyScope.getId().equals(scope.getId())).findFirst().isPresent()) {
@@ -197,13 +192,13 @@ public class PolicyEvaluationResponse {
}
});
- response.results = groupedResults.values().stream().collect(Collectors.toList());
+ response.setResults(groupedResults.values().stream().collect(Collectors.toList()));
return response;
}
- private static PolicyResultRepresentation toRepresentation(PolicyResult policy, AuthorizationProvider authorization) {
- PolicyResultRepresentation policyResultRep = new PolicyResultRepresentation();
+ private static PolicyEvaluationResponse.PolicyResultRepresentation toRepresentation(Result.PolicyResult policy, AuthorizationProvider authorization) {
+ PolicyEvaluationResponse.PolicyResultRepresentation policyResultRep = new PolicyEvaluationResponse.PolicyResultRepresentation();
PolicyRepresentation representation = new PolicyRepresentation();
@@ -213,127 +208,15 @@ public class PolicyEvaluationResponse {
representation.setDecisionStrategy(policy.getPolicy().getDecisionStrategy());
policyResultRep.setPolicy(representation);
- policyResultRep.setStatus(policy.getStatus());
+ if (policy.getStatus() == Decision.Effect.DENY) {
+ policyResultRep.setStatus(DecisionEffect.DENY);
+ } else {
+ policyResultRep.setStatus(DecisionEffect.PERMIT);
+
+ }
+
policyResultRep.setAssociatedPolicies(policy.getAssociatedPolicies().stream().map(result -> toRepresentation(result, authorization)).collect(Collectors.toList()));
return policyResultRep;
}
-
- public List getResults() {
- return results;
- }
-
- public Effect getStatus() {
- return status;
- }
-
- public boolean isEntitlements() {
- return entitlements;
- }
-
- public AccessToken getRpt() {
- return rpt;
- }
-
- public static class EvaluationResultRepresentation {
-
- private ResourceRepresentation resource;
- private List scopes;
- private List policies;
- private Effect status;
- private List allowedScopes = new ArrayList<>();
-
- public void setResource(final ResourceRepresentation resource) {
- this.resource = resource;
- }
-
- public ResourceRepresentation getResource() {
- return resource;
- }
-
- public void setScopes(List scopes) {
- this.scopes = scopes;
- }
-
- public List getScopes() {
- return scopes;
- }
-
- public void setPolicies(final List policies) {
- this.policies = policies;
- }
-
- public List getPolicies() {
- return policies;
- }
-
- public void setStatus(final Effect status) {
- this.status = status;
- }
-
- public Effect getStatus() {
- return status;
- }
-
- public void setAllowedScopes(List allowedScopes) {
- this.allowedScopes = allowedScopes;
- }
-
- public List getAllowedScopes() {
- return allowedScopes;
- }
- }
-
- public static class PolicyResultRepresentation {
-
- private PolicyRepresentation policy;
- private Effect status;
- private List associatedPolicies;
- private List scopes = new ArrayList<>();
-
- public PolicyRepresentation getPolicy() {
- return policy;
- }
-
- public void setPolicy(final PolicyRepresentation policy) {
- this.policy = policy;
- }
-
- public Effect getStatus() {
- return status;
- }
-
- public void setStatus(final Effect status) {
- this.status = status;
- }
-
- public List getAssociatedPolicies() {
- return associatedPolicies;
- }
-
- public void setAssociatedPolicies(final List associatedPolicies) {
- this.associatedPolicies = associatedPolicies;
- }
-
- @Override
- public int hashCode() {
- return this.policy.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final PolicyResultRepresentation policy = (PolicyResultRepresentation) o;
- return this.policy.equals(policy.getPolicy());
- }
-
- public void setScopes(List scopes) {
- this.scopes = scopes;
- }
-
- public List getScopes() {
- return scopes;
- }
- }
}
diff --git a/services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java b/services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java
new file mode 100644
index 0000000000..75882101c8
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.
+ */
+
+package org.keycloak.authorization.common;
+
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.representations.AccessToken;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Pedro Igor
+ */
+public abstract class AbstractEvaluationContext implements EvaluationContext {
+
+ private final KeycloakSession keycloakSession;
+
+ public AbstractEvaluationContext(KeycloakSession keycloakSession) {
+ this.keycloakSession = keycloakSession;
+ }
+
+ public Map> getBaseAttributes() {
+ HashMap> attributes = new HashMap<>();
+
+ 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()));
+
+ List userAgents = this.keycloakSession.getContext().getRequestHeaders().getRequestHeader("User-Agent");
+
+ if (userAgents != null) {
+ attributes.put("kc.client.user_agent", userAgents);
+ }
+
+ attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
+
+ return attributes;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java b/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
new file mode 100644
index 0000000000..67e6bb494b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package org.keycloak.authorization.common;
+
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class UserModelIdentity implements Identity {
+ protected RealmModel realm;
+ protected UserModel user;
+
+ public UserModelIdentity(UserModel user) {
+ this.user = user;
+ }
+
+ @Override
+ public String getId() {
+ return user.getId();
+ }
+
+ @Override
+ public Attributes getAttributes() {
+ Map attr = user.getAttributes();
+ return Attributes.from(attr);
+ }
+
+ @Override
+ public boolean hasRealmRole(String roleName) {
+ RoleModel role = realm.getRole(roleName);
+ if (role == null) return false;
+ return user.hasRole(role);
+ }
+
+ @Override
+ public boolean hasClientRole(String clientId, String roleName) {
+ ClientModel client = realm.getClientByClientId(clientId);
+ RoleModel role = client.getRole(roleName);
+ if (role == null) return false;
+ return user.hasRole(role);
+ }
+
+ @Override
+ public boolean hasRole(String roleName) {
+ throw new RuntimeException("Should not execute");
+ }
+
+ @Override
+ public boolean hasClientRole(String roleName) {
+ throw new RuntimeException("Should not execute");
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java
new file mode 100644
index 0000000000..f4a11be693
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/FineGrainAdminLocalTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+package org.keycloak.testsuite.admin;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.DecisionEffect;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+//@Ignore
+public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
+
+ @Override
+ public void addTestRealms(List testRealms) {
+ RealmRepresentation testRealmRep = new RealmRepresentation();
+ testRealmRep.setId(TEST);
+ testRealmRep.setRealm(TEST);
+ testRealmRep.setEnabled(true);
+ testRealms.add(testRealmRep);
+ }
+
+ public static void setupDefaults(KeycloakSession session) {
+ RealmModel realm = session.realms().getRealmByName(TEST);
+
+ ClientModel client = realm.getClientByClientId("realm-management");
+
+ AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
+ ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
+ Scope mapRoleScope = authz.getStoreFactory().getScopeStore().create("map-role", resourceServer);
+ Scope manageScope = authz.getStoreFactory().getScopeStore().create("manage", resourceServer);
+
+ Policy manageUsersPolicy = null;
+ Policy manageClientsPolicy = null;
+ for (RoleModel role : client.getRoles()) {
+ Policy policy = createRolePolicy(authz, resourceServer, role);
+ if (role.getName().equals(AdminRoles.MANAGE_USERS)) {
+ manageUsersPolicy = policy;
+ } else if (role.getName().equals(AdminRoles.MANAGE_CLIENTS)) {
+ manageClientsPolicy = policy;
+ }
+ Resource resource = createRoleResource(authz, resourceServer, role);
+ Set scopeset = new HashSet<>();
+ scopeset.add(mapRoleScope);
+ resource.updateScopes(scopeset);
+
+
+ String name = "map.role.permission." + client.getClientId() + "." + role.getName();
+ Policy permission = addScopePermission(authz, resourceServer, name, resource, mapRoleScope, policy);
+
+ }
+ Resource usersResource = authz.getStoreFactory().getResourceStore().create("Users", resourceServer, resourceServer.getClientId());
+ Set scopeset = new HashSet<>();
+ scopeset.add(manageScope);
+ usersResource.updateScopes(scopeset);
+ addScopePermission(authz, resourceServer, "Users.manage.permission", usersResource, manageScope, manageUsersPolicy);
+ }
+
+ private static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
+ Policy permission = authz.getStoreFactory().getPolicyStore().create(name, "scope", resourceServer);
+ String resources = "[\"" + resource.getId() + "\"]";
+ String scopes = "[\"" + scope.getId() + "\"]";
+ String applyPolicies = "[\"" + policy.getId() + "\"]";
+ Map config = new HashMap<>();
+ config.put("resources", resources);
+ config.put("scopes", scopes);
+ config.put("applyPolicies", applyPolicies);
+ permission.setConfig(config);
+ permission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+ permission.setLogic(Logic.POSITIVE);
+ permission.addResource(resource);
+ permission.addScope(scope);
+ permission.addAssociatedPolicy(policy);
+ return permission;
+ }
+
+ private static Resource createRoleResource(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
+ String roleName = getRoleResourceName(role);
+ Resource resource = authz.getStoreFactory().getResourceStore().create(roleName, resourceServer, resourceServer.getClientId());
+ resource.setType("Role");
+ return resource;
+ }
+
+ private static String getRoleResourceName(RoleModel role) {
+ String roleName = "realm";
+ if (role.getContainer() instanceof ClientModel) {
+ ClientModel client = (ClientModel)role.getContainer();
+ roleName = client.getClientId();
+ }
+ roleName = "role.resource." + roleName + "." + role.getName();
+ return roleName;
+ }
+
+
+ private static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
+ String roleName = "realm";
+ if (role.getContainer() instanceof ClientModel) {
+ ClientModel client = (ClientModel) role.getContainer();
+ roleName = client.getClientId() ;
+ }
+ roleName = "role.policy." + roleName + "." + role.getName();
+ Policy policy = authz.getStoreFactory().getPolicyStore().create(roleName, "role", resourceServer);
+
+ String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
+ policy.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+ policy.setLogic(Logic.POSITIVE);
+ Map config = new HashMap<>();
+ config.put("roles", roleValues);
+ policy.setConfig(config);
+ return policy;
+ }
+
+ public static void setupUsers(KeycloakSession session) {
+ RealmModel realm = session.realms().getRealmByName(TEST);
+ ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+ UserModel admin = session.users().addUser(realm, "admin");
+ admin.grantRole(client.getRole(AdminRoles.REALM_ADMIN));
+ UserModel manageUserOnlyUser = session.users().addUser(realm, "manage-user");
+ RoleModel manageUsersRole = client.getRole(AdminRoles.MANAGE_USERS);
+ manageUserOnlyUser.grantRole(manageUsersRole);
+ UserModel manageRealmUser = session.users().addUser(realm, "manage-realm");
+ manageRealmUser.grantRole(manageUsersRole);
+ RoleModel manageRealmRole = client.getRole(AdminRoles.MANAGE_REALM);
+ manageRealmUser.grantRole(manageRealmRole);
+
+ }
+
+ @Test
+ public void testUI() throws Exception {
+ testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
+ testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
+ //Thread.sleep(1000000000);
+ }
+
+ public static void evaluateAdminHasManageRealmPermissions(KeycloakSession session) {
+ RealmModel realm = session.realms().getRealmByName(TEST);
+ UserModel admin = session.users().getUserByUsername("admin", realm);
+
+ AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
+ ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+ ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+
+ RoleModel manageRealmRole = client.getRole(AdminRoles.MANAGE_REALM);
+ Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(manageRealmRole), resourceServer.getId());
+
+
+
+ }
+
+ @Test
+ public void testEvaluation() throws Exception {
+ testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
+ testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
+
+ RealmResource realm = adminClient.realm(TEST);
+ String resourceServerId = realm.clients().findByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).get(0).getId();
+ UserRepresentation admin = realm.users().search("admin").get(0);
+ UserRepresentation manageUser = realm.users().search("manage-user").get(0);
+ UserRepresentation manageRealm = realm.users().search("manage-realm").get(0);
+
+ PolicyEvaluationRequest request = new PolicyEvaluationRequest();
+ request.setUserId(admin.getId());
+ request.setClientId(resourceServerId);
+ request.addResource("role.resource." + Constants.REALM_MANAGEMENT_CLIENT_ID + "." + AdminRoles.MANAGE_REALM,
+ "map-role");
+ PolicyEvaluationResponse result = realm.clients().get(resourceServerId).authorization().policies().evaluate(request);
+ Assert.assertEquals(result.getStatus(), DecisionEffect.PERMIT);
+ }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java
new file mode 100644
index 0000000000..98d33663a7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/PolicyEvaluationCompositeRoleTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+package org.keycloak.testsuite.authz;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.DecisionEffect;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
+import org.keycloak.representations.idm.authorization.PolicyEvaluationResponse;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class PolicyEvaluationCompositeRoleTest extends AbstractKeycloakTest {
+ @Override
+ public void addTestRealms(List testRealms) {
+ RealmRepresentation testRealmRep = new RealmRepresentation();
+ testRealmRep.setId(TEST);
+ testRealmRep.setRealm(TEST);
+ testRealmRep.setEnabled(true);
+ testRealms.add(testRealmRep);
+ }
+
+ public static void setup(KeycloakSession session) {
+ RealmModel realm = session.realms().getRealmByName(TEST);
+ ClientModel client = session.realms().addClient(realm, "myclient");
+ RoleModel role1 = client.addRole("client-role1");
+
+
+ AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
+ ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
+ Policy policy = createRolePolicy(authz, resourceServer, role1);
+
+ Scope scope = authz.getStoreFactory().getScopeStore().create("myscope", resourceServer);
+ Resource resource = authz.getStoreFactory().getResourceStore().create("myresource", resourceServer, resourceServer.getClientId());
+ addScopePermission(authz, resourceServer, "mypermission", resource, scope, policy);
+
+ RoleModel composite = realm.addRole("composite");
+ composite.addCompositeRole(role1);
+
+ UserModel user = session.users().addUser(realm, "user");
+ user.grantRole(composite);
+ }
+
+ private static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
+ Policy permission = authz.getStoreFactory().getPolicyStore().create(name, "scope", resourceServer);
+ String resources = "[\"" + resource.getId() + "\"]";
+ String scopes = "[\"" + scope.getId() + "\"]";
+ String applyPolicies = "[\"" + policy.getId() + "\"]";
+ Map config = new HashMap<>();
+ config.put("resources", resources);
+ config.put("scopes", scopes);
+ config.put("applyPolicies", applyPolicies);
+ permission.setConfig(config);
+ permission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+ permission.setLogic(Logic.POSITIVE);
+ permission.addResource(resource);
+ permission.addScope(scope);
+ permission.addAssociatedPolicy(policy);
+ return permission;
+ }
+
+
+ private static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
+ Policy policy = authz.getStoreFactory().getPolicyStore().create(role.getName(), "role", resourceServer);
+
+ String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
+ policy.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+ policy.setLogic(Logic.POSITIVE);
+ Map config = new HashMap<>();
+ config.put("roles", roleValues);
+ policy.setConfig(config);
+ return policy;
+ }
+
+
+ @Test
+ public void testCreate() throws Exception {
+ testingClient.server().run(PolicyEvaluationCompositeRoleTest::setup);
+
+ RealmResource realm = adminClient.realm(TEST);
+ String resourceServerId = realm.clients().findByClientId("myclient").get(0).getId();
+ UserRepresentation user = realm.users().search("user").get(0);
+
+ PolicyEvaluationRequest request = new PolicyEvaluationRequest();
+ request.setUserId(user.getId());
+ request.setClientId(resourceServerId);
+ request.addResource("myresource", "myscope");
+ PolicyEvaluationResponse result = realm.clients().get(resourceServerId).authorization().policies().evaluate(request);
+ Assert.assertEquals(result.getStatus(), DecisionEffect.PERMIT);
+ }
+
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index 4a2ce9693d..4eb2bb4b80 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -99,7 +99,7 @@ public class AdapterTest {
@Rule
public AdapterTestStrategy testStrategy = new AdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8081", keycloakRule);
- //@Test
+ @Test
public void testUi() throws Exception {
Thread.sleep(1000000000);
}