Do not export ids when exporting authorization settings

Closes #25975

Co-authored-by: 박시준 <sjpark@logblack.com>
Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2024-04-03 17:23:29 -03:00 committed by Alexander Schwartz
parent ebeb001fe9
commit 8fb6d43e07
4 changed files with 100 additions and 99 deletions

View file

@ -34,3 +34,8 @@ For users of the `keycloak-authz-client` library, calling `AuthorizationResource
Previously, it would return a `List<Map>` at runtime, even though the method declaration advertised `List<Permission>`.
This fix will break code that relied on casting the List or its contents to `List<Map>`. If you have used this method in any capacity, you are likely to have done this and be affected.
= IDs are no longer set when exporting authorization settings for a client
When exporting the authorization settings for a client, the IDs for resources, scopes, and policies are no longer set. As a
result, you can now import the settings from a client to another client.

View file

@ -1119,6 +1119,8 @@ public class ModelToRepresentation {
.stream().map(resource -> {
ResourceRepresentation rep = toRepresentation(resource, settingsModel, authorization);
rep.setId(null);
if (rep.getOwner().getId().equals(settingsModel.getClientId())) {
rep.setOwner((ResourceOwnerRepresentation) null);
} else {
@ -1139,16 +1141,25 @@ public class ModelToRepresentation {
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> !policy.getType().equals("resource") && !policy.getType().equals("scope") && policy.getOwner() == null)
.map(policy -> toRepresentation(authorization, policy)).collect(Collectors.toList()));
.map(policy -> {
PolicyRepresentation rep = toRepresentation(authorization, policy);
rep.setId(null);
return rep;
}).collect(Collectors.toList()));
policies.addAll(policyStore.findByResourceServer(settingsModel)
.stream().filter(policy -> (policy.getType().equals("resource") || policy.getType().equals("scope") && policy.getOwner() == null))
.map(policy -> toRepresentation(authorization, policy)).collect(Collectors.toList()));
.map(policy -> {
PolicyRepresentation rep = toRepresentation(authorization, policy);
rep.setId(null);
return rep;
}).collect(Collectors.toList()));
representation.setPolicies(policies);
List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel).stream().map(scope -> {
ScopeRepresentation rep = toRepresentation(scope);
rep.setId(null);
rep.setPolicies(null);
rep.setResources(null);

View file

@ -20,12 +20,19 @@ package org.keycloak.testsuite.authz.admin;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.util.JsonSerialization;
import java.util.List;
import java.util.Objects;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -96,4 +103,57 @@ public class ResourceServerManagementTest extends AbstractAuthorizationTest {
// expected
}
}
@Test
public void testImportSettingsToDifferentClient() throws Exception {
ClientsResource clientsResource = testRealmResource().clients();
ClientRepresentation clientRep = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/client-with-authz-settings.json"), ClientRepresentation.class);
clientRep.setClientId(KeycloakModelUtils.generateId());
clientsResource.create(clientRep).close();
List<ClientRepresentation> clients = clientsResource.findByClientId(clientRep.getClientId());
assertFalse(clients.isEmpty());
String clientId = clients.get(0).getId();
AuthorizationResource authorization = clientsResource.get(clientId).authorization();
ResourceServerRepresentation settings = authorization.exportSettings();
assertEquals(PolicyEnforcementMode.PERMISSIVE, settings.getPolicyEnforcementMode());
assertEquals(DecisionStrategy.UNANIMOUS, settings.getDecisionStrategy());
assertFalse(authorization.resources().findByName("Resource 1").isEmpty());
assertFalse(authorization.resources().findByName("Resource 15").isEmpty());
assertFalse(authorization.resources().findByName("Resource 20").isEmpty());
assertNotNull(authorization.permissions().resource().findByName("Resource 15 Permission"));
assertNotNull(authorization.policies().role().findByName("Resource 1 Policy"));
settings.getPolicies().removeIf(p -> "js".equals(p.getType()));
ClientRepresentation anotherClientRep = ClientBuilder.create().clientId(KeycloakModelUtils.generateId()).secret("secret").authorizationServicesEnabled(true).serviceAccount().enabled(true).build();
clientsResource.create(anotherClientRep).close();
clients = clientsResource.findByClientId(anotherClientRep.getClientId());
assertFalse(clients.isEmpty());
ClientRepresentation anotherClient = clients.get(0);
authorization = clientsResource.get(anotherClient.getId()).authorization();
authorization.importSettings(settings);
ResourceServerRepresentation anotherSettings = authorization.exportSettings();
assertEquals(PolicyEnforcementMode.PERMISSIVE, anotherSettings.getPolicyEnforcementMode());
assertEquals(DecisionStrategy.UNANIMOUS, anotherSettings.getDecisionStrategy());
assertFalse(authorization.resources().findByName("Resource 1").isEmpty());
assertFalse(authorization.resources().findByName("Resource 15").isEmpty());
assertFalse(authorization.resources().findByName("Resource 20").isEmpty());
assertNotNull(authorization.permissions().resource().findByName("Resource 15 Permission"));
assertNotNull(authorization.policies().role().findByName("Resource 1 Policy"));
}
@Test
public void testExportSettings() throws Exception {
ClientsResource clientsResource = testRealmResource().clients();
ClientRepresentation clientRep = JsonSerialization.readValue(getClass().getResourceAsStream("/authorization-test/client-with-authz-settings.json"), ClientRepresentation.class);
clientRep.setClientId(KeycloakModelUtils.generateId());
clientsResource.create(clientRep).close();
List<ClientRepresentation> clients = clientsResource.findByClientId(clientRep.getClientId());
assertFalse(clients.isEmpty());
String clientId = clients.get(0).getId();
AuthorizationResource authorization = clientsResource.get(clientId).authorization();
ResourceServerRepresentation settings = authorization.exportSettings();
assertFalse(settings.getResources().stream().map(ResourceRepresentation::getId).anyMatch(Objects::nonNull));
assertFalse(settings.getScopes().stream().map(ScopeRepresentation::getId).anyMatch(Objects::nonNull));
assertFalse(settings.getPolicies().stream().map(PolicyRepresentation::getId).anyMatch(Objects::nonNull));
}
}

View file

@ -447,202 +447,127 @@
"name": "Resource 1 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 2 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 3 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 4 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 5 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 6 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 7 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 8 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 9 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 10 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 11 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 12 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 13 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 14 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 15 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 16 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 17 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 18 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 19 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 20 Policy",
"type": "role",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"roles": "[{\"id\":\"authz-client/uma_protection\",\"required\":false}]"
}
},
{
"name": "Default Permission",
"description": "A permission that applies to the default resource type",
"type": "resource",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"defaultResourceType": "urn:authz-client:resources:default",
"applyPolicies": "[\"Default Policy\"]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 1 Permission",
"type": "resource",
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"resources": "[\"Resource 1\"]",
"applyPolicies": "[\"Resource 1 Policy\"]"
}
"decisionStrategy": "UNANIMOUS"
},
{
"name": "Resource 2 Permission",