diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java index 49a54ebe28..6d7ed543ac 100644 --- a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java +++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java @@ -3,10 +3,12 @@ package org.keycloak.authorization.policy.provider.client; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.keycloak.Config; import org.keycloak.authorization.AuthorizationProvider; @@ -71,6 +73,21 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory(Arrays.asList(getClients(policy))), authorization); } + @Override + public void onExport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorizationProvider) { + ClientPolicyRepresentation userRep = toRepresentation(policy, new ClientPolicyRepresentation()); + Map config = new HashMap<>(); + + try { + RealmModel realm = authorizationProvider.getRealm(); + config.put("clients", JsonSerialization.writeValueAsString(userRep.getClients().stream().map(id -> realm.getClientById(id).getClientId()).collect(Collectors.toList()))); + } catch (IOException cause) { + throw new RuntimeException("Failed to export user policy [" + policy.getName() + "]", cause); + } + + representation.setConfig(config); + } + @Override public PolicyProvider create(KeycloakSession session) { return null; @@ -129,7 +146,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory clients, AuthorizationProvider authorization) { - RealmModel realm = authorization.getKeycloakSession().getContext().getRealm(); + RealmModel realm = authorization.getRealm(); if (clients == null || clients.isEmpty()) { throw new RuntimeException("No client provided."); diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index a0beb7f6b1..7431ed2cc0 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -799,6 +799,10 @@ public class ModelToRepresentation { } public static R toRepresentation(Policy policy, Class representationType, AuthorizationProvider authorization) { + return toRepresentation(policy, representationType, authorization, false); + } + + public static R toRepresentation(Policy policy, Class representationType, AuthorizationProvider authorization, boolean export) { R representation; try { @@ -817,7 +821,7 @@ public class ModelToRepresentation { representation.setLogic(policy.getLogic()); if (representation instanceof PolicyRepresentation) { - if (providerFactory != null) { + if (providerFactory != null && export) { providerFactory.onExport(policy, PolicyRepresentation.class.cast(representation), authorization); } else { PolicyRepresentation.class.cast(representation).setConfig(policy.getConfig()); diff --git a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java index 61822926e2..8f2e153956 100755 --- a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java +++ b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java @@ -358,11 +358,8 @@ public class ExportUtils { } private static PolicyRepresentation createPolicyRepresentation(AuthorizationProvider authorizationProvider, Policy policy) { - KeycloakSession session = authorizationProvider.getKeycloakSession(); - RealmModel realm = authorizationProvider.getRealm(); - try { - PolicyRepresentation rep = toRepresentation(policy, PolicyRepresentation.class, authorizationProvider); + PolicyRepresentation rep = toRepresentation(policy, PolicyRepresentation.class, authorizationProvider, true); rep.setId(null); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java index d63a15f94d..b29abc143f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java @@ -627,11 +627,12 @@ public class ExportImportUtil { assertPredicate(scopes, scopePredicates); List policies = authzResource.policies().policies(); - Assert.assertEquals(12, policies.size()); + Assert.assertEquals(13, policies.size()); List> policyPredicates = new ArrayList<>(); policyPredicates.add(policyRepresentation -> "Any Admin Policy".equals(policyRepresentation.getName())); policyPredicates.add(policyRepresentation -> "Any User Policy".equals(policyRepresentation.getName())); - policyPredicates.add(representation -> "Client and Realm Role Policy".equals(representation.getName()) && representation.getConfig().get("roles").contains("\"id\":\"realm-management/impersonation\"")); + policyPredicates.add(representation -> "Client and Realm Role Policy".equals(representation.getName())); + policyPredicates.add(representation -> "Client Test Policy".equals(representation.getName())); policyPredicates.add(policyRepresentation -> "Only Premium User Policy".equals(policyRepresentation.getName())); policyPredicates.add(policyRepresentation -> "wburke policy".equals(policyRepresentation.getName())); policyPredicates.add(policyRepresentation -> "All Users Policy".equals(policyRepresentation.getName())); diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json index e285dee989..5f84e38b51 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json @@ -289,6 +289,15 @@ "roles": "[{\"id\":\"realm-management/impersonation\",\"required\":false},{\"id\":\"realm-management/manage-authorization\",\"required\":true},{\"id\":\"user\",\"required\":false}]" } }, + { + "name": "Client Test Policy", + "type": "client", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "clients": "[\"broker\",\"admin-cli\"]" + } + }, { "name": "Only Premium User Policy", "description": "Defines that only premium users can do something", diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/resource/ResourcesTable.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/resource/ResourcesTable.java index f5dc5a7efc..94ed572432 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/resource/ResourcesTable.java +++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/authorization/resource/ResourcesTable.java @@ -66,14 +66,18 @@ public class ResourcesTable extends DataTable { public ResourceRepresentation toRepresentation(WebElement row) { ResourceRepresentation representation = null; List tds = row.findElements(tagName("td")); - if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) { - representation = new ResourceRepresentation(); - representation.setName(tds.get(0).getText()); - representation.setType(tds.get(1).getText()); - representation.setUri(tds.get(2).getText()); - ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation(); - owner.setName(tds.get(3).getText()); - representation.setOwner(owner); + try { + if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) { + representation = new ResourceRepresentation(); + representation.setName(tds.get(0).getText()); + representation.setType(tds.get(1).getText()); + representation.setUri(tds.get(2).getText()); + ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation(); + owner.setName(tds.get(3).getText()); + representation.setOwner(owner); + } + } catch (IndexOutOfBoundsException cause) { + // is empty } return representation; }