prototype
This commit is contained in:
parent
9452d37926
commit
58868ca99f
7 changed files with 118 additions and 52 deletions
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class DecisionResult extends DecisionResultCollector {
|
||||
protected List<Result> results;
|
||||
protected Throwable error;
|
||||
|
||||
@Override
|
||||
protected void onComplete(List<Result> results) {
|
||||
this.results = results;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable cause) {
|
||||
this.error = cause;
|
||||
}
|
||||
|
||||
public boolean completed() {
|
||||
return results != null && error == null;
|
||||
}
|
||||
|
||||
public List<Result> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
|
@ -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<Result> results;
|
||||
|
||||
@Override
|
||||
protected void onComplete(List<Result> results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable cause) {
|
||||
this.error = cause;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> List<T> asList(T... a) {
|
||||
List<T> list = new LinkedList<T>();
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -35,12 +35,19 @@ import java.util.Map;
|
|||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
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<String, Collection<String>> getBaseAttributes() {
|
||||
|
@ -60,4 +67,9 @@ public abstract class AbstractEvaluationContext implements EvaluationContext {
|
|||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getAttributes() {
|
||||
return Attributes.from(getBaseAttributes());
|
||||
}
|
||||
}
|
|
@ -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 <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
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<String, Collection<String>> 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<String, Collection<String>> getBaseAttributes() {
|
||||
Map<String, Collection<String>> attributes = super.getBaseAttributes();
|
||||
AccessToken accessToken = this.identity.getAccessToken();
|
||||
|
||||
if (accessToken != null) {
|
||||
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.client.user_agent", userAgents);
|
||||
}
|
||||
|
||||
attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
|
||||
|
||||
return Attributes.from(attributes);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ResourcePermission> 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 <code>resourceServer</code> and
|
||||
* <code>identity</code>.
|
||||
|
|
|
@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @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<ResourcePermission> 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
|
||||
|
|
Loading…
Reference in a new issue