diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index f18f4eb21b9..cc9e54b7ea5 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -17,6 +17,8 @@
package org.keycloak.representations.idm;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+
import java.util.List;
import java.util.Map;
@@ -62,6 +64,7 @@ public class ClientRepresentation {
private Boolean useTemplateConfig;
private Boolean useTemplateScope;
private Boolean useTemplateMappers;
+ private ResourceServerRepresentation authorizationSettings;
public String getId() {
@@ -241,6 +244,9 @@ public class ClientRepresentation {
}
public Boolean getAuthorizationServicesEnabled() {
+ if (authorizationSettings != null) {
+ return true;
+ }
return authorizationServicesEnabled;
}
@@ -353,4 +359,11 @@ public class ClientRepresentation {
this.useTemplateMappers = useTemplateMappers;
}
+ public ResourceServerRepresentation getAuthorizationSettings() {
+ return authorizationSettings;
+ }
+
+ public void setAuthorizationSettings(ResourceServerRepresentation authorizationSettings) {
+ this.authorizationSettings = authorizationSettings;
+ }
}
diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index 17d949691d8..4ef3f0e3ea8 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -89,7 +89,7 @@
-
+
diff --git a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
index ff646bbfe54..fb7c91b796b 100644
--- a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
+++ b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -24,6 +24,7 @@ import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
@@ -64,17 +65,19 @@ public final class AuthorizationProvider implements Provider {
private final StoreFactory storeFactory;
private final List policyProviderFactories;
private final KeycloakSession keycloakSession;
+ private final RealmModel realm;
- public AuthorizationProvider(KeycloakSession session, StoreFactory storeFactory, Executor scheduller) {
+ public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Executor scheduller) {
this.keycloakSession = session;
+ this.realm = realm;
this.storeFactory = storeFactory;
this.scheduller = scheduller;
this.policyProviderFactories = configurePolicyProviderFactories(session);
this.policyEvaluator = new DefaultPolicyEvaluator(this, this.policyProviderFactories);
}
- public AuthorizationProvider(KeycloakSession session, StoreFactory storeFactory) {
- this(session, storeFactory, Runnable::run);
+ public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory) {
+ this(session, realm, storeFactory, Runnable::run);
}
/**
@@ -120,6 +123,10 @@ public final class AuthorizationProvider implements Provider {
return this.keycloakSession;
}
+ public RealmModel getRealm() {
+ return realm;
+ }
+
private List configurePolicyProviderFactories(KeycloakSession session) {
List providerFactories = session.getKeycloakSessionFactory().getProviderFactories(PolicyProvider.class);
diff --git a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java
index ae4dcc2fe91..7ca684c2514 100644
--- a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java
+++ b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java
@@ -18,10 +18,14 @@
package org.keycloak.authorization;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderFactory;
/**
* @author Pedro Igor
*/
public interface AuthorizationProviderFactory extends ProviderFactory {
+
+ AuthorizationProvider create(KeycloakSession session, RealmModel realm);
}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 73c907bb85e..e2d4799206d 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -17,6 +17,14 @@
package org.keycloak.models.utils;
+import org.keycloak.authorization.AuthorizationProvider;
+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.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.events.Event;
import org.keycloak.events.admin.AdminEvent;
@@ -31,6 +39,7 @@ import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.ProtocolMapperModel;
@@ -72,8 +81,25 @@ import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.common.util.Time;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
-import java.util.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* @author Bill Burke
@@ -767,4 +793,181 @@ public class ModelToRepresentation {
rep.setConfig(component.getConfig());
return rep;
}
+
+ public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) {
+ ScopeRepresentation scope = new ScopeRepresentation();
+
+ scope.setId(model.getId());
+ scope.setName(model.getName());
+ scope.setIconUri(model.getIconUri());
+
+ StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+
+ scope.setResources(new ArrayList<>());
+
+ storeFactory.getResourceStore().findByScope(model.getId()).forEach(resource -> scope.getResources().add(toRepresentation(resource, resource.getResourceServer(), authorizationProvider)));
+
+ PolicyStore policyStore = storeFactory.getPolicyStore();
+
+ scope.setPolicies(new ArrayList<>());
+
+ policyStore.findByScopeIds(Arrays.asList(model.getId()), model.getResourceServer().getId()).forEach(policyModel -> {
+ PolicyRepresentation policy = new PolicyRepresentation();
+
+ policy.setId(policyModel.getId());
+ policy.setName(policyModel.getName());
+ policy.setType(policyModel.getType());
+
+ if (!scope.getPolicies().contains(policy)) {
+ scope.getPolicies().add(policy);
+ }
+ });
+
+ return scope;
+ }
+
+ public static ResourceServerRepresentation toRepresentation(ResourceServer model, ClientModel client) {
+ ResourceServerRepresentation server = new ResourceServerRepresentation();
+
+ server.setId(model.getId());
+ server.setClientId(model.getClientId());
+ server.setName(client.getClientId());
+ server.setAllowRemoteResourceManagement(model.isAllowRemoteResourceManagement());
+ server.setPolicyEnforcementMode(model.getPolicyEnforcementMode());
+
+ return server;
+ }
+
+ public static PolicyRepresentation toRepresentation(Policy model, AuthorizationProvider authorization) {
+ PolicyRepresentation representation = new PolicyRepresentation();
+
+ representation.setId(model.getId());
+ representation.setName(model.getName());
+ representation.setDescription(model.getDescription());
+ representation.setType(model.getType());
+ representation.setDecisionStrategy(model.getDecisionStrategy());
+ representation.setLogic(model.getLogic());
+ representation.setConfig(new HashMap<>(model.getConfig()));
+
+ List policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(model.getId());
+
+ representation.setDependentPolicies(policies.stream().map(policy -> {
+ PolicyRepresentation representation1 = new PolicyRepresentation();
+
+ representation1.setId(policy.getId());
+ representation1.setName(policy.getName());
+
+ return representation1;
+ }).collect(Collectors.toList()));
+
+ List associatedPolicies = new ArrayList<>();
+
+ List obj = model.getAssociatedPolicies().stream().map(policy -> {
+ PolicyRepresentation representation1 = new PolicyRepresentation();
+
+ representation1.setId(policy.getId());
+ representation1.setName(policy.getName());
+ representation1.setType(policy.getType());
+
+ associatedPolicies.add(representation1);
+
+ return policy.getId();
+ }).collect(Collectors.toList());
+
+ representation.setAssociatedPolicies(associatedPolicies);
+
+ try {
+ representation.getConfig().put("applyPolicies", JsonSerialization.writeValueAsString(obj));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return representation;
+ }
+
+ public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization) {
+ ResourceRepresentation resource = new ResourceRepresentation();
+
+ resource.setId(model.getId());
+ resource.setType(model.getType());
+ resource.setName(model.getName());
+ resource.setUri(model.getUri());
+ resource.setIconUri(model.getIconUri());
+
+ ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
+
+ owner.setId(model.getOwner());
+
+ KeycloakSession keycloakSession = authorization.getKeycloakSession();
+ RealmModel realm = authorization.getRealm();
+
+ if (owner.getId().equals(resourceServer.getClientId())) {
+ ClientModel clientModel = realm.getClientById(resourceServer.getClientId());
+ owner.setName(clientModel.getClientId());
+ } else {
+ UserModel userModel = keycloakSession.users().getUserById(owner.getId(), realm);
+
+ if (userModel == null) {
+ throw new RuntimeException("Could not find the user [" + owner.getId() + "] who owns the Resource [" + resource.getId() + "].");
+ }
+
+ owner.setName(userModel.getUsername());
+ }
+
+ resource.setOwner(owner);
+
+ resource.setScopes(model.getScopes().stream().map(model1 -> {
+ ScopeRepresentation scope = new ScopeRepresentation();
+ scope.setId(model1.getId());
+ scope.setName(model1.getName());
+ String iconUri = model1.getIconUri();
+ if (iconUri != null) {
+ scope.setIconUri(iconUri);
+ }
+ return scope;
+ }).collect(Collectors.toSet()));
+
+ resource.setTypedScopes(new ArrayList<>());
+
+ if (resource.getType() != null) {
+ ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+ for (Resource typed : resourceStore.findByType(resource.getType())) {
+ if (typed.getOwner().equals(resourceServer.getClientId()) && !typed.getId().equals(resource.getId())) {
+ resource.setTypedScopes(typed.getScopes().stream().map(model1 -> {
+ ScopeRepresentation scope = new ScopeRepresentation();
+ scope.setId(model1.getId());
+ scope.setName(model1.getName());
+ String iconUri = model1.getIconUri();
+ if (iconUri != null) {
+ scope.setIconUri(iconUri);
+ }
+ return scope;
+ }).filter(scopeRepresentation -> !resource.getScopes().contains(scopeRepresentation)).collect(Collectors.toList()));
+ }
+ }
+ }
+
+ resource.setPolicies(new ArrayList<>());
+
+ Set policies = new HashSet<>();
+ PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
+
+ policies.addAll(policyStore.findByResource(resource.getId()));
+ policies.addAll(policyStore.findByResourceType(resource.getType(), resourceServer.getId()));
+ policies.addAll(policyStore.findByScopeIds(resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), resourceServer.getId()));
+
+ for (Policy policyModel : policies) {
+ PolicyRepresentation policy = new PolicyRepresentation();
+
+ policy.setId(policyModel.getId());
+ policy.setName(policyModel.getName());
+ policy.setType(policyModel.getType());
+
+ if (!resource.getPolicies().contains(policy)) {
+ resource.getPolicies().add(policy);
+ }
+ }
+
+ return resource;
+ }
}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 7e813d64595..f36f0104106 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -18,8 +18,16 @@
package org.keycloak.models.utils;
import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+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.store.PolicyStore;
import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.hash.Pbkdf2PasswordHashProvider;
@@ -84,6 +92,12 @@ import org.keycloak.representations.idm.UserFederationMapperRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.util.ArrayList;
@@ -95,8 +109,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
-
-import static java.lang.Boolean.TRUE;
+import java.util.function.Function;
+import java.util.stream.Collectors;
public class RepresentationToModel {
@@ -277,6 +291,13 @@ public class RepresentationToModel {
}
}
+ if (rep.getClients() != null) {
+ rep.getClients().forEach(clientRepresentation -> {
+ ClientModel client = newRealm.getClientByClientId(clientRepresentation.getClientId());
+ importAuthorizationSettings(clientRepresentation, client, session);
+ });
+ }
+
if (rep.getSmtpServer() != null) {
newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
}
@@ -1022,22 +1043,6 @@ public class RepresentationToModel {
if (resourceRep.isUseTemplateMappers() != null) client.setUseTemplateMappers(resourceRep.isUseTemplateMappers());
else client.setUseTemplateMappers(resourceRep.getClientTemplate() != null);
- boolean createResourceServer = TRUE.equals(resourceRep.getAuthorizationServicesEnabled());
-
- if (createResourceServer) {
- AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
- ResourceServerStore resourceServerStore = provider.getStoreFactory().getResourceServerStore();
-
- client.setServiceAccountsEnabled(true);
- client.setBearerOnly(false);
- client.setPublicClient(false);
-
- ResourceServer resourceServer = resourceServerStore.create(client.getId());
-
- resourceServer.setAllowRemoteResourceManagement(true);
- resourceServer.setPolicyEnforcementMode(PolicyEnforcementMode.ENFORCING);
- }
-
return client;
}
@@ -1656,4 +1661,432 @@ public class RepresentationToModel {
model.setName(rep.getName());
return model;
}
+
+ public static void importAuthorizationSettings(ClientRepresentation clientRepresentation, ClientModel client, KeycloakSession session) {
+ if (Boolean.TRUE.equals(clientRepresentation.getAuthorizationServicesEnabled())) {
+ AuthorizationProviderFactory authorizationFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+ AuthorizationProvider authorization = authorizationFactory.create(session, client.getRealm());
+
+ client.setServiceAccountsEnabled(true);
+ client.setBearerOnly(false);
+ client.setPublicClient(false);
+
+ ResourceServerRepresentation rep = clientRepresentation.getAuthorizationSettings();
+
+ if (rep == null) {
+ rep = new ResourceServerRepresentation();
+ }
+
+ rep.setClientId(client.getId());
+
+ toModel(rep, authorization);
+ }
+ }
+
+ public static void toModel(ResourceServerRepresentation rep, AuthorizationProvider authorization) {
+ ResourceServerStore resourceServerStore = authorization.getStoreFactory().getResourceServerStore();
+ ResourceServer resourceServer;
+ ResourceServer existing = resourceServerStore.findByClient(rep.getClientId());
+
+ if (existing == null) {
+ resourceServer = resourceServerStore.create(rep.getClientId());
+ resourceServer.setAllowRemoteResourceManagement(true);
+ resourceServer.setPolicyEnforcementMode(PolicyEnforcementMode.ENFORCING);
+ } else {
+ resourceServer = existing;
+ }
+
+ resourceServer.setPolicyEnforcementMode(rep.getPolicyEnforcementMode());
+ resourceServer.setAllowRemoteResourceManagement(rep.isAllowRemoteResourceManagement());
+
+ StoreFactory storeFactory = authorization.getStoreFactory();
+ ScopeStore scopeStore = storeFactory.getScopeStore();
+
+ rep.getScopes().forEach(scope -> {
+ toModel(scope, resourceServer, authorization);
+ });
+
+ KeycloakSession session = authorization.getKeycloakSession();
+ RealmModel realm = authorization.getRealm();
+
+ rep.getResources().forEach(resourceRepresentation -> {
+ ResourceOwnerRepresentation owner = resourceRepresentation.getOwner();
+
+ if (owner == null) {
+ owner = new ResourceOwnerRepresentation();
+ resourceRepresentation.setOwner(owner);
+ }
+
+ owner.setId(resourceServer.getClientId());
+
+ if (owner.getName() != null) {
+ UserModel user = session.users().getUserByUsername(owner.getName(), realm);
+
+ if (user != null) {
+ owner.setId(user.getId());
+ }
+ }
+
+ toModel(resourceRepresentation, resourceServer, authorization);
+ });
+
+ rep.getPolicies().forEach(policyRepresentation -> {
+ Map config = policyRepresentation.getConfig();
+
+ String roles = config.get("roles");
+
+ if (roles != null && !roles.isEmpty()) {
+ try {
+ List