[KEYCLOAK-9478] - Support multiple CIP providers in the policy enforcer configuration

This commit is contained in:
Pedro Igor 2019-02-01 16:25:44 -02:00 committed by Bruno Oliveira da Silva
parent bacc1b538f
commit 75d9847672
5 changed files with 119 additions and 7 deletions

View file

@ -349,24 +349,23 @@ public abstract class AbstractPolicyEnforcer {
} }
protected Map<String, List<String>> resolveClaims(PathConfig pathConfig, OIDCHttpFacade httpFacade) { protected Map<String, List<String>> resolveClaims(PathConfig pathConfig, OIDCHttpFacade httpFacade) {
Map<String, List<String>> claims = getClaims(getEnforcerConfig().getClaimInformationPointConfig(), httpFacade); Map<String, List<String>> claims = new HashMap<>();
claims.putAll(getClaims(pathConfig.getClaimInformationPointConfig(), httpFacade)); resolveClaims(claims, getEnforcerConfig().getClaimInformationPointConfig(), httpFacade);
resolveClaims(claims, pathConfig.getClaimInformationPointConfig(), httpFacade);
return claims; return claims;
} }
private Map<String, List<String>> getClaims(Map<String, Map<String, Object>>claimInformationPointConfig, HttpFacade httpFacade) { private void resolveClaims(Map<String, List<String>> claims, Map<String, Map<String, Object>> claimInformationPointConfig, HttpFacade httpFacade) {
if (claimInformationPointConfig != null) { if (claimInformationPointConfig != null) {
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) { for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey()); ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
if (factory != null) { if (factory != null) {
return factory.create(claimDef.getValue()).resolve(httpFacade); claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
} }
} }
} }
return new HashMap<>();
} }
} }

View file

@ -0,0 +1,63 @@
/*
* Copyright 2018 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.client.authorization;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.keycloak.adapters.authorization.ClaimInformationPointProvider;
import org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.adapters.spi.HttpFacade;
public class MyCustomCIPFactory implements ClaimInformationPointProviderFactory<MyCustomCIP> {
@Override
public String getName() {
return "my-custom-cip";
}
@Override
public void init(PolicyEnforcer policyEnforcer) {
}
@Override
public MyCustomCIP create(Map<String, Object> config) {
return new MyCustomCIP(config);
}
}
class MyCustomCIP implements ClaimInformationPointProvider {
private final Map<String, Object> config;
MyCustomCIP(Map<String, Object> config) {
this.config = config;
}
@Override
public Map<String, List<String>> resolve(HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
claims.put("resolved-claim", Arrays.asList(config.get("claim-value").toString()));
return claims;
}
}

View file

@ -34,6 +34,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -68,6 +69,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.AuthorizationRequest; import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse; import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation; import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation; import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation; import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
@ -175,13 +177,40 @@ public class PolicyEnforcerTest extends AbstractKeycloakTest {
@Override @Override
public String apply(String s) { public String apply(String s) {
Assert.assertTrue(resolved.compareAndSet(false, true)); Assert.assertTrue(resolved.compareAndSet(false, true));
return "claim-value"; return "value-" + s;
} }
}); });
AuthorizationContext context = policyEnforcer.enforce(httpFacade); AuthorizationContext context = policyEnforcer.enforce(httpFacade);
Permission permission = context.getPermissions().get(0);
Map<String, Set<String>> claims = permission.getClaims();
assertTrue(context.isGranted()); assertTrue(context.isGranted());
assertEquals("value-claim-a", claims.get("claim-a").iterator().next());
assertEquals("claim-b", claims.get("claim-b").iterator().next());
}
@Test
public void testCustomClaimProvider() {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getAdapterConfiguration("enforcer-bearer-only-with-cip.json"));
PolicyEnforcer policyEnforcer = deployment.getPolicyEnforcer();
oauth.realm(REALM_NAME);
oauth.clientId("public-client-test");
oauth.doLogin("marta", "password");
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, null);
String token = response.getAccessToken();
OIDCHttpFacade httpFacade = createHttpFacade("/api/resourcea", token);
AuthorizationContext context = policyEnforcer.enforce(httpFacade);
Permission permission = context.getPermissions().get(0);
Map<String, Set<String>> claims = permission.getClaims();
assertTrue(context.isGranted());
assertEquals("test", claims.get("resolved-claim").iterator().next());
} }
@Test @Test

View file

@ -0,0 +1,18 @@
#
# * Copyright 2018 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.
#
org.keycloak.testsuite.admin.client.authorization.MyCustomCIPFactory

View file

@ -19,6 +19,9 @@
"claim-information-point": { "claim-information-point": {
"claims": { "claims": {
"claim-a": "{request.parameter['claim-a']}" "claim-a": "{request.parameter['claim-a']}"
},
"my-custom-cip": {
"claim-value": "test"
} }
} }
} }