diff --git a/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java
new file mode 100644
index 0000000000..2189c32fbf
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResult.java
@@ -0,0 +1,51 @@
+/*
+ * 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.policy.evaluation;
+
+import java.util.List;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+public class DecisionResult extends DecisionResultCollector {
+ protected List results;
+ protected Throwable error;
+
+ @Override
+ protected void onComplete(List results) {
+ this.results = results;
+
+ }
+
+ @Override
+ public void onError(Throwable cause) {
+ this.error = cause;
+ }
+
+ public boolean completed() {
+ return results != null && error == null;
+ }
+
+ public List getResults() {
+ return results;
+ }
+
+ public Throwable getError() {
+ return error;
+ }
+}
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 2e82794927..1267b186c3 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -38,6 +38,7 @@ import javax.ws.rs.core.Response;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.policy.evaluation.DecisionResult;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
import org.keycloak.authorization.admin.representation.PolicyEvaluationResponseBuilder;
@@ -86,21 +87,6 @@ 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();
@@ -116,12 +102,12 @@ public class PolicyEvaluationService {
CloseableKeycloakIdentity identity = createIdentity(evaluationRequest);
try {
EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity);
- Decision decisionCollector = new Decision();
+ DecisionResult decisionCollector = new DecisionResult();
authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(decisionCollector);
- if (decisionCollector.error != null) {
- throw decisionCollector.error;
+ if (!decisionCollector.completed()) {
+ throw decisionCollector.getError();
}
- return Response.ok(PolicyEvaluationResponseBuilder.build(decisionCollector.results, resourceServer, authorization, identity)).build();
+ return Response.ok(PolicyEvaluationResponseBuilder.build(decisionCollector.getResults(), resourceServer, authorization, identity)).build();
} finally {
identity.close();
}
diff --git a/services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java b/services/src/main/java/org/keycloak/authorization/common/DefaultEvaluationContext.java
similarity index 82%
rename from services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java
rename to services/src/main/java/org/keycloak/authorization/common/DefaultEvaluationContext.java
index 75882101c8..2551639fad 100644
--- a/services/src/main/java/org/keycloak/authorization/common/AbstractEvaluationContext.java
+++ b/services/src/main/java/org/keycloak/authorization/common/DefaultEvaluationContext.java
@@ -35,12 +35,19 @@ import java.util.Map;
/**
* @author Pedro Igor
*/
-public abstract class AbstractEvaluationContext implements EvaluationContext {
+public class DefaultEvaluationContext implements EvaluationContext {
- private final KeycloakSession keycloakSession;
+ protected final KeycloakSession keycloakSession;
+ protected final Identity identity;
- public AbstractEvaluationContext(KeycloakSession keycloakSession) {
+ public DefaultEvaluationContext(Identity identity, KeycloakSession keycloakSession) {
this.keycloakSession = keycloakSession;
+ this.identity = identity;
+ }
+
+ @Override
+ public Identity getIdentity() {
+ return identity;
}
public Map> getBaseAttributes() {
@@ -60,4 +67,9 @@ public abstract class AbstractEvaluationContext implements EvaluationContext {
return attributes;
}
+
+ @Override
+ public Attributes getAttributes() {
+ return Attributes.from(getBaseAttributes());
+ }
}
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 fc929ec5d9..da3cb0fa9c 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
@@ -18,34 +18,28 @@
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 class KeycloakEvaluationContext implements EvaluationContext {
+public class KeycloakEvaluationContext extends DefaultEvaluationContext {
private final KeycloakIdentity identity;
- private final KeycloakSession keycloakSession;
public KeycloakEvaluationContext(KeycloakSession keycloakSession) {
this(new KeycloakIdentity(keycloakSession), keycloakSession);
}
public KeycloakEvaluationContext(KeycloakIdentity identity, KeycloakSession keycloakSession) {
+ super(identity, keycloakSession);
this.identity = identity;
- this.keycloakSession = keycloakSession;
}
@Override
@@ -54,27 +48,13 @@ public class KeycloakEvaluationContext implements EvaluationContext {
}
@Override
- public Attributes getAttributes() {
- 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()));
-
+ public Map> getBaseAttributes() {
+ Map> attributes = super.getBaseAttributes();
AccessToken accessToken = this.identity.getAccessToken();
if (accessToken != null) {
attributes.put("kc.client.id", Arrays.asList(accessToken.getIssuedFor()));
}
-
- 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.from(attributes);
+ 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
index 67e6bb494b..c54e4c0532 100644
--- a/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/UserModelIdentity.java
@@ -34,7 +34,8 @@ public class UserModelIdentity implements Identity {
protected RealmModel realm;
protected UserModel user;
- public UserModelIdentity(UserModel user) {
+ public UserModelIdentity(RealmModel realm, UserModel user) {
+ this.realm = realm;
this.user = user;
}
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 2e2c4a8b6a..80fcb81cbb 100644
--- a/services/src/main/java/org/keycloak/authorization/util/Permissions.java
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -19,6 +19,8 @@
package org.keycloak.authorization.util;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -45,6 +47,10 @@ import org.keycloak.representations.idm.authorization.Permission;
*/
public final class Permissions {
+ public static List permission(ResourceServer server, Resource resource, Scope scope) {
+ return Arrays.asList(new ResourcePermission(resource, Arrays.asList(scope), server));
+ }
+
/**
* Returns a list of permissions for all resources and scopes that belong to the given resourceServer
and
* identity
.
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
index a533c41037..00aaf919bf 100644
--- 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
@@ -21,10 +21,18 @@ import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.DefaultEvaluationContext;
+import org.keycloak.authorization.common.UserModelIdentity;
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.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
+import org.keycloak.authorization.policy.evaluation.DecisionResult;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.util.Permissions;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
@@ -43,6 +51,7 @@ import org.keycloak.testsuite.AbstractKeycloakTest;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -53,7 +62,7 @@ import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
* @author Bill Burke
* @version $Revision: 1 $
*/
-@Ignore
+//@Ignore
public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
@Override
@@ -170,15 +179,16 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
}
- @Test
+ //@Test
public void testUI() throws Exception {
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
- //Thread.sleep(1000000000);
+ Thread.sleep(1000000000);
}
public static void evaluateAdminHasManageRealmPermissions(KeycloakSession session) {
RealmModel realm = session.realms().getRealmByName(TEST);
+ session.getContext().setRealm(realm);
UserModel admin = session.users().getUserByUsername("admin", realm);
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
@@ -187,9 +197,29 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
RoleModel manageRealmRole = client.getRole(AdminRoles.MANAGE_REALM);
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(manageRealmRole), resourceServer.getId());
+ Scope mapRoleScope = authz.getStoreFactory().getScopeStore().findByName("map-role", resourceServer.getId());
+
+ UserModelIdentity identity = new UserModelIdentity(realm, admin);
+ EvaluationContext context = new DefaultEvaluationContext(identity, session);
+ DecisionResult decisionCollector = new DecisionResult();
+
+ List permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
+ PermissionEvaluator from = authz.evaluators().from(permissions, context);
+ from.evaluate(decisionCollector);
+ if (!decisionCollector.completed()) {
+ decisionCollector.getError().printStackTrace();
+ }
+ Assert.assertTrue(decisionCollector.completed());
+ Assert.assertEquals(decisionCollector.getResults().get(0).getEffect(), Decision.Effect.PERMIT);
+ }
+ @Test
+ public void testEvaluation2() throws Exception {
+ testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
+ testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
+ testingClient.server().run(FineGrainAdminLocalTest::evaluateAdminHasManageRealmPermissions);
}
@Test