From f1154dae783a374b9316b911f995b2b6c0ef6f2f Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 15 Aug 2024 08:41:57 +0200 Subject: [PATCH 1/2] Move PolicyEnforcerClaimsTest closes keycloak/keycloak#31981 Signed-off-by: mposolda --- .../PolicyEnforcerClaimsTest.java | 381 ++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/PolicyEnforcerClaimsTest.java diff --git a/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/PolicyEnforcerClaimsTest.java b/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/PolicyEnforcerClaimsTest.java new file mode 100644 index 0000000..9b78c56 --- /dev/null +++ b/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/PolicyEnforcerClaimsTest.java @@ -0,0 +1,381 @@ +/* + * 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.client.testsuite.policyenforcer; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Test; +import org.keycloak.AuthorizationContext; +import org.keycloak.adapters.authorization.PolicyEnforcer; +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.ClientsResource; +import org.keycloak.authorization.client.AuthzClient; +import org.keycloak.client.testsuite.authz.AbstractAuthzTest; +import org.keycloak.client.testsuite.common.OAuthClient; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.authorization.AuthorizationRequest; +import org.keycloak.representations.idm.authorization.AuthorizationResponse; +import org.keycloak.representations.idm.authorization.JSPolicyRepresentation; +import org.keycloak.representations.idm.authorization.Permission; +import org.keycloak.representations.idm.authorization.ResourceRepresentation; +import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation; +import org.keycloak.representations.idm.authorization.ScopeRepresentation; +import org.keycloak.testsuite.util.AuthzTestUtils; +import org.keycloak.testsuite.util.ClientBuilder; +import org.keycloak.testsuite.util.RealmBuilder; +import org.keycloak.testsuite.util.RoleBuilder; +import org.keycloak.testsuite.util.RolesBuilder; +import org.keycloak.testsuite.util.UserBuilder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Pedro Igor + */ +public class PolicyEnforcerClaimsTest extends AbstractAuthzTest { + + protected static final String REALM_NAME = "authz-test"; + + @Override + public List getRealmsForImport() { + RealmRepresentation realm = RealmBuilder.create().name(REALM_NAME) + .roles(RolesBuilder.create() + .realmRole(RoleBuilder.create().name("uma_authorization").build()) + .realmRole(RoleBuilder.create().name("uma_protection").build()) + ) + .user(UserBuilder.create().username("marta").password("password") + .addRoles("uma_authorization", "uma_protection") + .role("resource-server-test", "uma_protection")) + .user(UserBuilder.create().username("kolo").password("password")) + .client(ClientBuilder.create().clientId("resource-server-uma-test") + .secret("secret") + .authorizationServicesEnabled(true) + .redirectUris("http://localhost/resource-server-uma-test") + .defaultRoles("uma_protection") + .directAccessGrants()) + .client(ClientBuilder.create().clientId("resource-server-test") + .secret("secret") + .authorizationServicesEnabled(true) + .redirectUris("http://localhost/resource-server-test") + .defaultRoles("uma_protection") + .directAccessGrants()) + .client(ClientBuilder.create().clientId("public-client-test") + .publicClient() + .redirectUris("http://localhost:8180/auth/realms/master/app/auth/*", "https://localhost:8543/auth/realms/master/app/auth/*") + .directAccessGrants()) + .build(); + return Collections.singletonList(realm); + } + + @Test + public void testEnforceUMAAccessWithClaimsUsingBearerToken() { + initAuthorizationSettings(getClientResource("resource-server-uma-test")); + + PolicyEnforcer policyEnforcer = AuthzTestUtils.createPolicyEnforcer("enforcer-uma-claims-test.json", true); + HashMap> headers = new HashMap<>(); + HashMap> parameters = new HashMap<>(); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + AuthzClient authzClient = policyEnforcer.getAuthzClient(); + String token = authzClient.obtainAccessToken("marta", "password").getToken(); + + headers.put("Authorization", Arrays.asList("Bearer " + token)); + + AuthzTestUtils.TestResponse testResponse = new AuthzTestUtils.TestResponse(); + AuthorizationContext context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse); + assertFalse(context.isGranted()); + + AuthorizationRequest request = new AuthorizationRequest(); + + request.setTicket(extractTicket(testResponse.getHeaders())); + + AuthorizationResponse response = authzClient.authorization("marta", "password").authorize(request); + token = response.getToken(); + + assertNotNull(token); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("200")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse.clear()); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("10")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse.clear()); + + request = new AuthorizationRequest(); + + request.setTicket(extractTicket(testResponse.getHeaders())); + + response = authzClient.authorization("marta", "password").authorize(request); + token = response.getToken(); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "POST", token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", "GET", token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + assertEquals(1, context.getPermissions().size()); + Permission permission = context.getPermissions().get(0); + + assertEquals(parameters.get("withdrawal.amount").get(0), permission.getClaims().get("withdrawal.amount").iterator().next()); + } + + @Test + public void testEnforceEntitlementAccessWithClaimsWithoutBearerToken() { + initAuthorizationSettings(getClientResource("resource-server-test")); + + PolicyEnforcer policyEnforcer = AuthzTestUtils.createPolicyEnforcer("enforcer-entitlement-claims-test.json", false); + HashMap> headers = new HashMap<>(); + HashMap> parameters = new HashMap<>(); + + AuthzClient authzClient = policyEnforcer.getAuthzClient(); + String token = authzClient.obtainAccessToken("marta", "password").getToken(); + + AuthzTestUtils.TestResponse testResponse = new AuthzTestUtils.TestResponse(); + AuthorizationContext context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + assertEquals(1, context.getPermissions().size()); + Permission permission = context.getPermissions().get(0); + assertEquals(parameters.get("withdrawal.amount").get(0), permission.getClaims().get("withdrawal.amount").iterator().next()); + + parameters.put("withdrawal.amount", Arrays.asList("200")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("10")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + + assertTrue(context.isGranted()); + + assertEquals(1, context.getPermissions().size()); + permission = context.getPermissions().get(0); + assertEquals(parameters.get("withdrawal.amount").get(0), permission.getClaims().get("withdrawal.amount").iterator().next()); + } + + @Test + public void testEnforceEntitlementAccessWithClaimsWithBearerToken() { + initAuthorizationSettings(getClientResource("resource-server-test")); + + PolicyEnforcer policyEnforcer = AuthzTestUtils.createPolicyEnforcer("enforcer-entitlement-claims-test.json", false); + HashMap> headers = new HashMap<>(); + HashMap> parameters = new HashMap<>(); + + AuthzClient authzClient = policyEnforcer.getAuthzClient(); + String token = authzClient.obtainAccessToken("marta", "password").getToken(); + + headers.put("Authorization", Arrays.asList("Bearer " + token)); + + AuthzTestUtils.TestResponse testResponse = new AuthzTestUtils.TestResponse(); + AuthorizationContext context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("200")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("10")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + + assertTrue(context.isGranted()); + } + + @Test + public void testEnforceEntitlementAccessWithClaimsWithBearerTokenFromPublicClient() { + initAuthorizationSettings(getClientResource("resource-server-test")); + + PolicyEnforcer policyEnforcer = AuthzTestUtils.createPolicyEnforcer("enforcer-entitlement-claims-test.json", false); + HashMap> headers = new HashMap<>(); + HashMap> parameters = new HashMap<>(); + + String token = doLoginAndGetAccessToken(); + + headers.put("Authorization", Arrays.asList("Bearer " + token)); + + AuthzTestUtils.TestResponse testResponse = new AuthzTestUtils.TestResponse(); + AuthorizationContext context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("200")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertFalse(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("50")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + assertTrue(context.isGranted()); + + parameters.put("withdrawal.amount", Arrays.asList("10")); + + context = policyEnforcer.enforce( + AuthzTestUtils.createHttpRequest("/api/bank/account/1/withdrawal", null, token, headers, parameters, null), + testResponse.clear()); + + assertTrue(context.isGranted()); + } + + private String extractTicket(Map> headers) { + List wwwAuthenticateHeader = headers.get("WWW-Authenticate"); + + assertNotNull(wwwAuthenticateHeader); + assertFalse(wwwAuthenticateHeader.isEmpty()); + + String wwwAuthenticate = wwwAuthenticateHeader.get(0); + return wwwAuthenticate.substring(wwwAuthenticate.indexOf("ticket=") + "ticket=\"".length(), wwwAuthenticate.lastIndexOf('"')); + } + + private void initAuthorizationSettings(ClientResource clientResource) { + if (clientResource.authorization().resources().findByName("Bank Account").isEmpty()) { + JSPolicyRepresentation policy = new JSPolicyRepresentation(); + + policy.setName("Withdrawal Limit Policy"); + policy.setType("script-scripts/enforce-withdraw-limit-policy.js"); + + clientResource.authorization().policies().js().create(policy).close(); + + createResource(clientResource, "Bank Account", "/api/bank/account/{id}/withdrawal", "withdrawal"); + + ScopePermissionRepresentation permission = new ScopePermissionRepresentation(); + + permission.setName("Withdrawal Permission"); + permission.addScope("withdrawal"); + permission.addPolicy(policy.getName()); + + clientResource.authorization().permissions().scope().create(permission).close(); + } + } + + private ResourceRepresentation createResource(ClientResource clientResource, String name, String uri, String... scopes) { + ResourceRepresentation representation = new ResourceRepresentation(); + + representation.setName(name); + representation.setUri(uri); + representation.setScopes(Arrays.asList(scopes).stream().map(ScopeRepresentation::new).collect(Collectors.toSet())); + + try (jakarta.ws.rs.core.Response response = clientResource.authorization().resources().create(representation)) { + + representation.setId(response.readEntity(ResourceRepresentation.class).getId()); + + return representation; + } + } + + private ClientResource getClientResource(String name) { + ClientsResource clients = realmsResource().realm(REALM_NAME).clients(); + ClientRepresentation representation = clients.findByClientId(name).get(0); + return clients.get(representation.getId()); + } + + private String doLoginAndGetAccessToken() { + oauth.realm(REALM_NAME); + oauth.clientId("public-client-test"); + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest(null, "marta", "password"); + return response.getAccessToken(); + } +} + From 2cce7d27f8e8b4058aa3b073d97f460ac8fd3350 Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 15 Aug 2024 09:37:37 +0200 Subject: [PATCH 2/2] Move ClaimInformationPointProviderTest closes keycloak/keycloak#31982 Signed-off-by: mposolda --- testsuite/authz-tests/pom.xml | 6 + .../ClaimInformationPointProviderTest.java | 312 ++++++++++++++++++ testsuite/pom.xml | 1 + 3 files changed, 319 insertions(+) create mode 100644 testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/ClaimInformationPointProviderTest.java diff --git a/testsuite/authz-tests/pom.xml b/testsuite/authz-tests/pom.xml index f55106b..81770b1 100644 --- a/testsuite/authz-tests/pom.xml +++ b/testsuite/authz-tests/pom.xml @@ -19,6 +19,12 @@ ${project.version} test + + io.undertow + undertow-core + ${undertow.version} + test + \ No newline at end of file diff --git a/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/ClaimInformationPointProviderTest.java b/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/ClaimInformationPointProviderTest.java new file mode 100644 index 0000000..9dd5f51 --- /dev/null +++ b/testsuite/authz-tests/src/test/java/org/keycloak/client/testsuite/policyenforcer/ClaimInformationPointProviderTest.java @@ -0,0 +1,312 @@ +/* + * 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.client.testsuite.policyenforcer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.undertow.Undertow; +import io.undertow.server.handlers.form.FormData; +import io.undertow.server.handlers.form.FormDataParser; +import io.undertow.server.handlers.form.FormParserFactory; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.keycloak.adapters.authorization.cip.spi.ClaimInformationPointProvider; +import org.keycloak.adapters.authorization.cip.spi.ClaimInformationPointProviderFactory; +import org.keycloak.adapters.authorization.PolicyEnforcer; +import org.keycloak.adapters.authorization.spi.HttpRequest; +import org.keycloak.client.testsuite.authz.AbstractAuthzTest; +import org.keycloak.jose.jws.JWSBuilder; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.util.AuthzTestUtils; +import org.keycloak.util.JsonSerialization; + +/** + * @author Pedro Igor + */ +public class ClaimInformationPointProviderTest extends AbstractAuthzTest { + + private static Undertow httpService; + + + @BeforeAll + public static void onBeforeClass() { + httpService = Undertow.builder().addHttpListener(8989, "localhost").setHandler(exchange -> { + if (exchange.isInIoThread()) { + try { + if (exchange.getRelativePath().equals("/post-claim-information-provider")) { + FormParserFactory parserFactory = FormParserFactory.builder().build(); + FormDataParser parser = parserFactory.createParser(exchange); + FormData formData = parser.parseBlocking(); + + if (!("Bearer " + accessTokenString()).equals(exchange.getRequestHeaders().getFirst("Authorization")) + || !"post".equalsIgnoreCase(exchange.getRequestMethod().toString()) + || !"application/x-www-form-urlencoded".equals(exchange.getRequestHeaders().getFirst("Content-Type")) + || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1") + || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2") + || !formData.get("param-a").getFirst().getValue().equals("param-a-value1") + || !formData.get("param-a").getLast().getValue().equals("param-a-value2") + || !formData.get("param-subject").getFirst().getValue().equals("sub") + || !formData.get("param-user-name").getFirst().getValue().equals("username") + || !formData.get("param-other-claims").getFirst().getValue().equals("param-other-claims-value1") + || !formData.get("param-other-claims").getLast().getValue().equals("param-other-claims-value2")) { + exchange.setStatusCode(400); + return; + } + + exchange.setStatusCode(200); + } else if (exchange.getRelativePath().equals("/get-claim-information-provider")) { + if (!("Bearer " + accessTokenString()).equals(exchange.getRequestHeaders().getFirst("Authorization")) + || !"get".equalsIgnoreCase(exchange.getRequestMethod().toString()) + || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1") + || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2") + || !exchange.getQueryParameters().get("param-a").contains("param-a-value1") + || !exchange.getQueryParameters().get("param-a").contains("param-a-value2") + || !exchange.getQueryParameters().get("param-subject").contains("sub") + || !exchange.getQueryParameters().get("param-user-name").contains("username")) { + exchange.setStatusCode(400); + return; + } + + exchange.setStatusCode(200); + } else { + exchange.setStatusCode(404); + } + } finally { + if (exchange.getStatusCode() == 200) { + try { + ObjectMapper mapper = JsonSerialization.mapper; + JsonParser jsonParser = mapper.getFactory().createParser("{\"a\": \"a-value1\", \"b\": \"b-value1\", \"d\": [\"d-value1\", \"d-value2\"]}"); + TreeNode treeNode = mapper.readTree(jsonParser); + exchange.getResponseSender().send(treeNode.toString()); + } catch (Exception ignore) { + ignore.printStackTrace(); + } + } + exchange.endExchange(); + } + } + }).build(); + + httpService.start(); + } + + @AfterAll + public static void onAfterClass() { + if (httpService != null) { + httpService.stop(); + } + } + + @Override + public List getRealmsForImport() { + RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json")); + return Collections.singletonList(realm); + } + + private ClaimInformationPointProvider getClaimInformationProviderForPath(String path, String providerName) { + PolicyEnforcer policyEnforcer = AuthzTestUtils.createPolicyEnforcer("enforcer-config-claims-provider.json", true); + Map providers = policyEnforcer.getClaimInformationPointProviderFactories(); + + PathConfig pathConfig = policyEnforcer.getPaths().get(path); + + assertNotNull(pathConfig); + + Map> cipConfig = pathConfig.getClaimInformationPointConfig(); + + assertNotNull(cipConfig); + + ClaimInformationPointProviderFactory factory = providers.get(providerName); + + assertNotNull(factory); + + Map claimsConfig = cipConfig.get(providerName); + + return factory.create(claimsConfig); + } + + @Test + public void testBasicClaimsInformationPoint() { + Map> claims = getClaimInformationProviderForPath("/claims-provider", "claims") + .resolve(createHttpRequest()); + + assertEquals("parameter-a", claims.get("claim-from-request-parameter").get(0)); + assertEquals("header-b", claims.get("claim-from-header").get(0)); + assertEquals("cookie-c", claims.get("claim-from-cookie").get(0)); + assertEquals("user-remote-addr", claims.get("claim-from-remoteAddr").get(0)); + assertEquals("GET", claims.get("claim-from-method").get(0)); + assertEquals("/app/request-uri", claims.get("claim-from-uri").get(0)); + assertEquals("/request-relative-path", claims.get("claim-from-relativePath").get(0)); + assertEquals("true", claims.get("claim-from-secure").get(0)); + assertEquals("static value", claims.get("claim-from-static-value").get(0)); + assertEquals("static", claims.get("claim-from-multiple-static-value").get(0)); + assertEquals("value", claims.get("claim-from-multiple-static-value").get(1)); + assertEquals("Test param-other-claims-value1 and parameter-a", claims.get("param-replace-multiple-placeholder").get(0)); + } + + @Test + public void testBodyJsonClaimsInformationPoint() throws Exception { + Map> headers = new HashMap<>(); + + headers.put("Content-Type", Arrays.asList("application/json")); + + ObjectMapper mapper = JsonSerialization.mapper; + JsonParser parser = mapper.getFactory().createParser("{\"a\": {\"b\": {\"c\": \"c-value\"}}, \"d\": [\"d-value1\", \"d-value2\"], \"e\": {\"number\": 123}}"); + TreeNode treeNode = mapper.readTree(parser); + + Map> claims = getClaimInformationProviderForPath("/claims-provider", "claims").resolve( + createHttpRequest(headers, new ByteArrayInputStream(treeNode.toString().getBytes()))); + + assertEquals("c-value", claims.get("claim-from-json-body-object").get(0)); + assertEquals("d-value2", claims.get("claim-from-json-body-array").get(0)); + assertEquals("123", claims.get("claim-from-json-body-number").get(0)); + } + + @Test + public void testBodyJsonObjectClaim() throws Exception { + Map> headers = new HashMap<>(); + + headers.put("Content-Type", Arrays.asList("application/json")); + + ObjectMapper mapper = JsonSerialization.mapper; + JsonParser parser = mapper.getFactory().createParser("{\"Individual\" : {\n" + + "\n" + + " \"Name\": \"John\",\n" + + "\n" + + " \"Lastname\": \"Doe\",\n" + + "\n" + + " \"individualRoles\" : [ {\n" + + "\n" + + " \"roleSpec\": 2342,\n" + + "\n" + + " \"roleId\": 4234},\n" + + "\n" + + "{\n" + + "\n" + + " \"roleSpec\": 4223,\n" + + "\n" + + " \"roleId\": 523\n" + + "\n" + + " }\n" + + "\n" + + " ]\n" + + "\n" + + "}}"); + TreeNode treeNode = mapper.readTree(parser); + + Map> claims = getClaimInformationProviderForPath("/claims-from-body-json-object", "claims") + .resolve(createHttpRequest(headers, new ByteArrayInputStream(treeNode.toString().getBytes()))); + + assertEquals(1, claims.size()); + assertEquals(2, claims.get("individualRoles").size()); + assertEquals("{\"roleSpec\":2342,\"roleId\":4234}", claims.get("individualRoles").get(0)); + assertEquals("{\"roleSpec\":4223,\"roleId\":523}", claims.get("individualRoles").get(1)); + + headers.put("Content-Type", Arrays.asList("application/json; charset=utf-8")); + + claims = getClaimInformationProviderForPath("/claims-from-body-json-object", "claims") + .resolve(createHttpRequest(headers, new ByteArrayInputStream(treeNode.toString().getBytes()))); + + assertEquals(1, claims.size()); + assertEquals(2, claims.get("individualRoles").size()); + assertEquals("{\"roleSpec\":2342,\"roleId\":4234}", claims.get("individualRoles").get(0)); + assertEquals("{\"roleSpec\":4223,\"roleId\":523}", claims.get("individualRoles").get(1)); + } + + @Test + public void testBodyClaimsInformationPoint() { + Map> claims = getClaimInformationProviderForPath("/claims-provider", "claims") + .resolve(createHttpRequest(new HashMap<>(), new ByteArrayInputStream("raw-body-text".getBytes()))); + + assertEquals("raw-body-text", claims.get("claim-from-body").get(0)); + } + + @Test + public void testHttpClaimInformationPointProviderWithoutClaims() { + Map> claims = getClaimInformationProviderForPath("/http-get-claim-provider", "http") + .resolve(createHttpRequest(new HashMap<>(), null)); + + assertEquals("a-value1", claims.get("a").get(0)); + assertEquals("b-value1", claims.get("b").get(0)); + assertEquals("d-value1", claims.get("d").get(0)); + assertEquals("d-value2", claims.get("d").get(1)); + + assertNull(claims.get("claim-a")); + assertNull(claims.get("claim-d")); + assertNull(claims.get("claim-d0")); + assertNull(claims.get("claim-d-all")); + } + + @Test + public void testHttpClaimInformationPointProviderWithClaims() { + Map> claims = getClaimInformationProviderForPath("/http-post-claim-provider", "http") + .resolve(createHttpRequest(new HashMap<>(), null)); + + assertEquals("a-value1", claims.get("claim-a").get(0)); + assertEquals("d-value1", claims.get("claim-d").get(0)); + assertEquals("d-value2", claims.get("claim-d").get(1)); + assertEquals("d-value1", claims.get("claim-d0").get(0)); + assertEquals("d-value1", claims.get("claim-d-all").get(0)); + assertEquals("d-value2", claims.get("claim-d-all").get(1)); + + assertNull(claims.get("a")); + assertNull(claims.get("b")); + assertNull(claims.get("d")); + } + + private static HttpRequest createHttpRequest() { + return createHttpRequest(new HashMap<>(), null); + } + + private static HttpRequest createHttpRequest(Map> headers, InputStream requestBody) { + Map> queryParameter = new HashMap<>(); + queryParameter.put("a", Arrays.asList("parameter-a")); + headers.put("b", Arrays.asList("header-b")); + Map cookies = new HashMap<>(); + cookies.put("c", "cookie-c"); + return AuthzTestUtils.createHttpRequest("/app/request-uri", "/request-relative-path", "GET", + accessTokenString(), headers, queryParameter, cookies, requestBody); + } + + private static AccessToken accessToken() { + AccessToken token = new AccessToken(); + token.subject("sub"); + token.setPreferredUsername("username"); + token.getOtherClaims().put("custom_claim", Arrays.asList("param-other-claims-value1", "param-other-claims-value2")); + return token; + } + + private static String accessTokenString() { + return new JWSBuilder().jsonContent(accessToken()).none(); + } +} + diff --git a/testsuite/pom.xml b/testsuite/pom.xml index 7168bf2..bea5775 100644 --- a/testsuite/pom.xml +++ b/testsuite/pom.xml @@ -24,6 +24,7 @@ 3.4.0 3.8.5 3.5.4 + 2.3.2.Final