KEYCLOAK-14901 Replace deprecated ClientProvider related methods across Keycloak

This commit is contained in:
Martin Kanis 2020-07-29 15:07:52 +02:00 committed by Hynek Mlnařík
parent 76f7fbb984
commit 4e9bdd44f3
52 changed files with 419 additions and 489 deletions

View file

@ -140,6 +140,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
} }
private void updateRoles(Policy policy, AuthorizationProvider authorization, Set<RolePolicyRepresentation.RoleDefinition> roles) { private void updateRoles(Policy policy, AuthorizationProvider authorization, Set<RolePolicyRepresentation.RoleDefinition> roles) {
KeycloakSession session = authorization.getKeycloakSession();
RealmModel realm = authorization.getRealm(); RealmModel realm = authorization.getRealm();
Set<RolePolicyRepresentation.RoleDefinition> updatedRoles = new HashSet<>(); Set<RolePolicyRepresentation.RoleDefinition> updatedRoles = new HashSet<>();
@ -175,7 +176,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
// fallback to find any client role with the given name // fallback to find any client role with the given name
if (role == null) { if (role == null) {
String finalRoleName = roleName; String finalRoleName = roleName;
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null) role = realm.getClientsStream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
.findFirst().orElse(null); .findFirst().orElse(null);
} }
@ -215,7 +216,8 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
if (container instanceof RealmModel) { if (container instanceof RealmModel) {
RealmModel realm = (RealmModel) container; RealmModel realm = (RealmModel) container;
realm.getClients().forEach(clientModel -> updateResourceServer(clientModel, removedRole, resourceServerStore, policyStore)); realm.getClientsStream()
.forEach(clientModel -> updateResourceServer(clientModel, removedRole, resourceServerStore, policyStore));
} else { } else {
ClientModel clientModel = (ClientModel) container; ClientModel clientModel = (ClientModel) container;
updateResourceServer(clientModel, removedRole, resourceServerStore, policyStore); updateResourceServer(clientModel, removedRole, resourceServerStore, policyStore);

View file

@ -182,7 +182,7 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
UserModel removedUser = ((UserRemovedEvent) event).getUser(); UserModel removedUser = ((UserRemovedEvent) event).getUser();
RealmModel realm = ((UserRemovedEvent) event).getRealm(); RealmModel realm = ((UserRemovedEvent) event).getRealm();
ResourceServerStore resourceServerStore = storeFactory.getResourceServerStore(); ResourceServerStore resourceServerStore = storeFactory.getResourceServerStore();
realm.getClients().forEach(clientModel -> { realm.getClientsStream().forEach(clientModel -> {
ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId()); ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId());
if (resourceServer != null) { if (resourceServer != null) {

View file

@ -38,6 +38,7 @@ import org.keycloak.storage.ldap.mappers.AbstractLDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.membership.CommonLDAPGroupMapper; import org.keycloak.storage.ldap.mappers.membership.CommonLDAPGroupMapper;
import org.keycloak.storage.ldap.mappers.membership.CommonLDAPGroupMapperConfig; import org.keycloak.storage.ldap.mappers.membership.CommonLDAPGroupMapperConfig;
import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode; import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode;
import org.keycloak.storage.ldap.mappers.membership.MembershipType;
import org.keycloak.storage.ldap.mappers.membership.UserRolesRetrieveStrategy; import org.keycloak.storage.ldap.mappers.membership.UserRolesRetrieveStrategy;
import org.keycloak.storage.user.SynchronizationResult; import org.keycloak.storage.user.SynchronizationResult;
@ -46,7 +47,8 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.keycloak.storage.ldap.mappers.membership.MembershipType; import java.util.function.Consumer;
import java.util.stream.Stream;
/** /**
* Map realm roles or roles of particular client to LDAP groups * Map realm roles or roles of particular client to LDAP groups
@ -178,10 +180,9 @@ public class RoleLDAPStorageMapper extends AbstractLDAPStorageMapper implements
RoleContainerModel roleContainer = getTargetRoleContainer(realm); RoleContainerModel roleContainer = getTargetRoleContainer(realm);
Set<RoleModel> keycloakRoles = roleContainer.getRoles(); Stream<RoleModel> keycloakRoles = roleContainer.getRolesStream();
for (RoleModel keycloakRole : keycloakRoles) { Consumer<String> syncRoleFromKCToLDAP = roleName -> {
String roleName = keycloakRole.getName();
if (ldapRoleNames.contains(roleName)) { if (ldapRoleNames.contains(roleName)) {
syncResult.increaseUpdated(); syncResult.increaseUpdated();
} else { } else {
@ -189,7 +190,8 @@ public class RoleLDAPStorageMapper extends AbstractLDAPStorageMapper implements
createLDAPRole(roleName); createLDAPRole(roleName);
syncResult.increaseAdded(); syncResult.increaseAdded();
} }
} };
keycloakRoles.map(RoleModel::getName).forEach(syncRoleFromKCToLDAP);
return syncResult; return syncResult;
} }

View file

@ -31,6 +31,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -661,19 +662,9 @@ public class ClientAdapter implements ClientModel, CachedObject {
if (isUpdated()) return updated.hasScope(role); if (isUpdated()) return updated.hasScope(role);
if (cached.isFullScopeAllowed() || cached.getScope().contains(role.getId())) return true; if (cached.isFullScopeAllowed() || cached.getScope().contains(role.getId())) return true;
Set<RoleModel> roles = getScopeMappings(); if (getScopeMappingsStream().anyMatch(r -> r.hasRole(role))) return true;
for (RoleModel mapping : roles) { return getRolesStream().anyMatch(r -> (Objects.equals(r, role) || r.hasRole(role)));
if (mapping.hasRole(role)) return true;
}
roles = getRoles();
if (roles.contains(role)) return true;
for (RoleModel mapping : roles) {
if (mapping.hasRole(role)) return true;
}
return false;
} }
@Override @Override

View file

@ -583,9 +583,9 @@ public class RealmCacheSession implements CacheRealmProvider {
invalidationEvents.add(ClientRemovedEvent.create(client)); invalidationEvents.add(ClientRemovedEvent.create(client));
cache.clientRemoval(realm.getId(), id, client.getClientId(), invalidations); cache.clientRemoval(realm.getId(), id, client.getClientId(), invalidations);
for (RoleModel role : client.getRoles()) { client.getRolesStream().forEach(role -> {
roleRemovalInvalidations(role.getId(), role.getName(), client.getId()); roleRemovalInvalidations(role.getId(), role.getName(), client.getId());
} });
if (client.isServiceAccountsEnabled()) { if (client.isServiceAccountsEnabled()) {
UserModel serviceAccount = session.users().getServiceAccount(client); UserModel serviceAccount = session.users().getServiceAccount(client);

View file

@ -17,7 +17,6 @@
package org.keycloak.models.cache.infinispan.events; package org.keycloak.models.cache.infinispan.events;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -29,6 +28,8 @@ import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.infinispan.commons.marshall.Externalizer; import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.MarshallUtil; import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.commons.marshall.SerializeWith; import org.infinispan.commons.marshall.SerializeWith;
@ -51,10 +52,7 @@ public class ClientRemovedEvent extends InvalidationEvent implements RealmCacheI
event.realmId = client.getRealm().getId(); event.realmId = client.getRealm().getId();
event.clientUuid = client.getId(); event.clientUuid = client.getId();
event.clientId = client.getClientId(); event.clientId = client.getClientId();
event.clientRoles = new HashMap<>(); event.clientRoles = client.getRolesStream().collect(Collectors.toMap(RoleModel::getId, RoleModel::getName));
for (RoleModel clientRole : client.getRoles()) {
event.clientRoles.put(clientRole.getId(), clientRole.getName());
}
return event; return event;
} }

View file

@ -46,6 +46,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
@ -688,19 +689,14 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
@Override @Override
public boolean hasScope(RoleModel role) { public boolean hasScope(RoleModel role) {
if (isFullScopeAllowed()) return true; if (isFullScopeAllowed()) return true;
Set<RoleModel> roles = getScopeMappings();
if (roles.contains(role)) return true;
for (RoleModel mapping : roles) { Predicate<RoleModel> hasRoleOrEquals = r -> (Objects.equals(r, role) || r.hasRole(role));
if (mapping.hasRole(role)) return true;
}
roles = getRoles();
if (roles.contains(role)) return true;
for (RoleModel mapping : roles) { if (getScopeMappingsStream().anyMatch(hasRoleOrEquals)) {
if (mapping.hasRole(role)) return true; return true;
} }
return false;
return getRolesStream().anyMatch(hasRoleOrEquals);
} }
@Override @Override

View file

@ -26,9 +26,6 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import com.google.common.base.Functions; import com.google.common.base.Functions;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -454,10 +451,7 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
return true; return true;
} }
Set<RoleModel> roles = getRoles(); return getRolesStream().anyMatch(r -> (Objects.equals(r, role) || r.hasRole(role)));
if (roles.contains(role)) return true;
return roles.stream().anyMatch(r -> r.hasRole(role));
} }
/*************** Default roles ****************/ /*************** Default roles ****************/

View file

@ -25,8 +25,6 @@ import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmModel.ClientUpdatedEvent; import org.keycloak.models.RealmModel.ClientUpdatedEvent;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.map.storage.MapKeycloakTransaction; import org.keycloak.models.map.storage.MapKeycloakTransaction;
import org.keycloak.models.map.common.Serialization; import org.keycloak.models.map.common.Serialization;
import java.util.Comparator; import java.util.Comparator;
@ -41,7 +39,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.MapStorage;
import static org.keycloak.common.util.StackUtil.getShortStackTrace; import static org.keycloak.common.util.StackUtil.getShortStackTrace;
import org.keycloak.models.RoleProvider;
public class MapClientProvider implements ClientProvider { public class MapClientProvider implements ClientProvider {

View file

@ -35,7 +35,7 @@ public class RealmSynchronizer implements Synchronizer<RealmRemovedEvent> {
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession()); AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
StoreFactory storeFactory = authorizationProvider.getStoreFactory(); StoreFactory storeFactory = authorizationProvider.getStoreFactory();
event.getRealm().getClients().forEach(clientModel -> { event.getRealm().getClientsStream().forEach(clientModel -> {
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId()); ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
if (resourceServer != null) { if (resourceServer != null) {

View file

@ -89,7 +89,7 @@ public class UserSynchronizer implements Synchronizer<UserRemovedEvent> {
RealmModel realm = event.getRealm(); RealmModel realm = event.getRealm();
UserModel userModel = event.getUser(); UserModel userModel = event.getUser();
realm.getClients().forEach(clientModel -> { realm.getClientsStream().forEach(clientModel -> {
ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId()); ResourceServer resourceServer = resourceServerStore.findById(clientModel.getId());
if (resourceServer != null) { if (resourceServer != null) {

View file

@ -19,12 +19,10 @@ package org.keycloak.migration.migrators;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy; import org.keycloak.models.OTPPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List; import java.util.List;
@ -43,17 +41,17 @@ public class MigrateTo1_5_0 implements Migration {
public void migrate(KeycloakSession session) { public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms(); List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) { for (RealmModel realm : realms) {
migrateRealm(realm); migrateRealm(session, realm);
} }
} }
@Override @Override
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
migrateRealm(realm); migrateRealm(session, realm);
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(KeycloakSession session, RealmModel realm) {
DefaultAuthenticationFlows.migrateFlows(realm); // add reset credentials flo DefaultAuthenticationFlows.migrateFlows(realm); // add reset credentials flo
realm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY); realm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY);
realm.setBrowserFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW)); realm.setBrowserFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW));
@ -74,8 +72,6 @@ public class MigrateTo1_5_0 implements Migration {
realm.setClientAuthenticationFlow(clientAuthFlow); realm.setClientAuthenticationFlow(clientAuthFlow);
} }
for (ClientModel client : realm.getClients()) { realm.getClientsStream().forEach(MigrationUtils::setDefaultClientAuthenticatorType);
client.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType());
}
} }
} }

View file

@ -74,7 +74,7 @@ public class MigrateTo2_1_0 implements Migration {
AuthorizationProvider authorizationProvider = session.getProvider(AuthorizationProvider.class); AuthorizationProvider authorizationProvider = session.getProvider(AuthorizationProvider.class);
StoreFactory storeFactory = authorizationProvider.getStoreFactory(); StoreFactory storeFactory = authorizationProvider.getStoreFactory();
PolicyStore policyStore = storeFactory.getPolicyStore(); PolicyStore policyStore = storeFactory.getPolicyStore();
realm.getClients().forEach(clientModel -> { realm.getClientsStream().forEach(clientModel -> {
ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId()); ResourceServer resourceServer = storeFactory.getResourceServerStore().findById(clientModel.getId());
if (resourceServer != null) { if (resourceServer != null) {

View file

@ -19,7 +19,6 @@ package org.keycloak.migration.migrators;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -40,9 +39,7 @@ public class MigrateTo2_3_0 implements Migration {
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(RealmModel realm) {
for (ClientModel client : realm.getClients()) { realm.getClientsStream().forEach(MigrationUtils::updateProtocolMappers);
MigrationUtils.updateProtocolMappers(client);
}
for (ClientScopeModel clientScope : realm.getClientScopes()) { for (ClientScopeModel clientScope : realm.getClientScopes()) {
MigrationUtils.updateProtocolMappers(clientScope); MigrationUtils.updateProtocolMappers(clientScope);

View file

@ -55,7 +55,7 @@ public class MigrateTo3_0_0 implements Migration {
} }
protected void migrateRealm(RealmModel realm) { protected void migrateRealm(RealmModel realm) {
realm.getClients().stream() realm.getClientsStream()
.filter(clientModel -> defaultClients.contains(clientModel.getId())) .filter(clientModel -> defaultClients.contains(clientModel.getId()))
.filter(clientModel -> Objects.isNull(clientModel.getProtocol())) .filter(clientModel -> Objects.isNull(clientModel.getProtocol()))
.forEach(clientModel -> clientModel.setProtocol("openid-connect")); .forEach(clientModel -> clientModel.setProtocol("openid-connect"));

View file

@ -94,7 +94,7 @@ public class MigrateTo4_0_0 implements Migration {
// If client has scope for offline_access role (either directly or through fullScopeAllowed), then add offline_access client // If client has scope for offline_access role (either directly or through fullScopeAllowed), then add offline_access client
// scope as optional scope to the client. If it's indirectly (no fullScopeAllowed), then remove role from the scoped roles // scope as optional scope to the client. If it's indirectly (no fullScopeAllowed), then remove role from the scoped roles
RoleModel offlineAccessRole = realm.getRole(OAuth2Constants.OFFLINE_ACCESS); RoleModel offlineAccessRole = realm.getRole(OAuth2Constants.OFFLINE_ACCESS);
ClientScopeModel offlineAccessScope = null; ClientScopeModel offlineAccessScope;
if (offlineAccessRole == null) { if (offlineAccessRole == null) {
LOG.infof("Role 'offline_access' not available in realm '%s'. Skip migration of offline_access client scope.", realm.getName()); LOG.infof("Role 'offline_access' not available in realm '%s'. Skip migration of offline_access client scope.", realm.getName());
} else { } else {
@ -102,32 +102,32 @@ public class MigrateTo4_0_0 implements Migration {
if (offlineAccessScope == null) { if (offlineAccessScope == null) {
LOG.infof("Client scope 'offline_access' not available in realm '%s'. Skip migration of offline_access client scope.", realm.getName()); LOG.infof("Client scope 'offline_access' not available in realm '%s'. Skip migration of offline_access client scope.", realm.getName());
} else { } else {
for (ClientModel client : realm.getClients()) { realm.getClientsStream()
if ("openid-connect".equals(client.getProtocol()) .filter(MigrationUtils::isOIDCNonBearerOnlyClient)
&& !client.isBearerOnly() .filter(c -> c.hasScope(offlineAccessRole))
&& client.hasScope(offlineAccessRole) .filter(c -> !c.getClientScopes(false, true).containsKey(OAuth2Constants.OFFLINE_ACCESS))
&& !client.getClientScopes(false, true).containsKey(OAuth2Constants.OFFLINE_ACCESS)) { .peek(c -> {
LOG.debugf("Adding client scope 'offline_access' as optional scope to client '%s' in realm '%s'.", client.getClientId(), realm.getName()); LOG.debugf("Adding client scope 'offline_access' as optional scope to client '%s' in realm '%s'.", c.getClientId(), realm.getName());
client.addClientScope(offlineAccessScope, false); c.addClientScope(offlineAccessScope, false);
})
if (!client.isFullScopeAllowed()) { .filter(c -> !c.isFullScopeAllowed())
LOG.debugf("Removing role scope mapping for role 'offline_access' from client '%s' in realm '%s'.", client.getClientId(), realm.getName()); .forEach(c -> {
client.deleteScopeMapping(offlineAccessRole); LOG.debugf("Removing role scope mapping for role 'offline_access' from client '%s' in realm '%s'.", c.getClientId(), realm.getName());
} c.deleteScopeMapping(offlineAccessRole);
} });
}
} }
} }
// Clients with consentRequired, which don't have any client scopes will be added itself to require consent, so that consent screen is shown when users authenticate // Clients with consentRequired, which don't have any client scopes will be added itself to require consent, so that consent screen is shown when users authenticate
for (ClientModel client : realm.getClients()) { realm.getClientsStream()
if (client.isConsentRequired() && client.getClientScopes(true, true).isEmpty()) { .filter(ClientModel::isConsentRequired)
LOG.debugf("Adding client '%s' of realm '%s' to display itself on consent screen", client.getClientId(), realm.getName()); .filter(c -> c.getClientScopes(true, true).isEmpty())
client.setDisplayOnConsentScreen(true); .forEach(c -> {
String consentText = client.getName()==null ? client.getClientId() : client.getName(); LOG.debugf("Adding client '%s' of realm '%s' to display itself on consent screen", c.getClientId(), realm.getName());
client.setConsentScreenText(consentText); c.setDisplayOnConsentScreen(true);
} String consentText = c.getName() == null ? c.getClientId() : c.getName();
} c.setConsentScreenText(consentText);
});
} }
} }

View file

@ -20,7 +20,6 @@ package org.keycloak.migration.migrators;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.migration.MigrationProvider; import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -63,12 +62,12 @@ public class MigrateTo4_6_0 implements Migration {
LOG.debugf("Added '%s' and '%s' default client scopes", rolesScope.getName(), webOriginsScope.getName()); LOG.debugf("Added '%s' and '%s' default client scopes", rolesScope.getName(), webOriginsScope.getName());
// Assign "roles" and "web-origins" clientScopes to all the OIDC clients // Assign "roles" and "web-origins" clientScopes to all the OIDC clients
for (ClientModel client : realm.getClients()) { realm.getClientsStream()
if ((client.getProtocol()==null || "openid-connect".equals(client.getProtocol())) && (!client.isBearerOnly())) { .filter(MigrationUtils::isOIDCNonBearerOnlyClient)
client.addClientScope(rolesScope, true); .forEach(c -> {
client.addClientScope(webOriginsScope, true); c.addClientScope(rolesScope, true);
} c.addClientScope(webOriginsScope, true);
} });
LOG.debugf("Client scope '%s' assigned to all the clients", rolesScope.getName()); LOG.debugf("Client scope '%s' assigned to all the clients", rolesScope.getName());
} }

View file

@ -20,7 +20,6 @@ package org.keycloak.migration.migrators;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.migration.MigrationProvider; import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -63,11 +62,9 @@ public class MigrateTo6_0_0 implements Migration {
LOG.debugf("Added '%s' optional client scope", mpJWTScope.getName()); LOG.debugf("Added '%s' optional client scope", mpJWTScope.getName());
// assign 'microprofile-jwt' optional client scope to all the OIDC clients. // assign 'microprofile-jwt' optional client scope to all the OIDC clients.
for (ClientModel client : realm.getClients()) { realm.getClientsStream()
if ((client.getProtocol() == null || "openid-connect".equals(client.getProtocol())) && (!client.isBearerOnly())) { .filter(MigrationUtils::isOIDCNonBearerOnlyClient)
client.addClientScope(mpJWTScope, false); .forEach(c -> c.addClientScope(mpJWTScope, false));
}
}
LOG.debugf("Client scope '%s' assigned to all the clients", mpJWTScope.getName()); LOG.debugf("Client scope '%s' assigned to all the clients", mpJWTScope.getName());
} }

View file

@ -107,4 +107,11 @@ public class MigrationUtils {
} }
} }
public static void setDefaultClientAuthenticatorType(ClientModel s) {
s.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType());
}
public static boolean isOIDCNonBearerOnlyClient(ClientModel c) {
return (c.getProtocol() == null || "openid-connect".equals(c.getProtocol())) && !c.isBearerOnly();
}
} }

View file

@ -586,13 +586,10 @@ public final class KeycloakModelUtils {
} }
public static boolean isClientScopeUsed(RealmModel realm, ClientScopeModel clientScope) { public static boolean isClientScopeUsed(RealmModel realm, ClientScopeModel clientScope) {
for (ClientModel client : realm.getClients()) { return realm.getClientsStream()
if ((client.getClientScopes(true, false).containsKey(clientScope.getName())) || .filter(c -> (c.getClientScopes(true, false).containsKey(clientScope.getName())) ||
(client.getClientScopes(false, false).containsKey(clientScope.getName()))) { (c.getClientScopes(false, false).containsKey(clientScope.getName())))
return true; .findFirst().isPresent();
}
}
return false;
} }
public static ClientScopeModel getClientScopeByName(RealmModel realm, String clientScopeName) { public static ClientScopeModel getClientScopeByName(RealmModel realm, String clientScopeName) {
@ -602,14 +599,7 @@ public final class KeycloakModelUtils {
} }
} }
// check if we are referencing a client instead of a scope // check if we are referencing a client instead of a scope
if (realm.getClients() != null) { return realm.getClientsStream().filter(c -> clientScopeName.equals(c.getClientId())).findFirst().orElse(null);
for (ClientModel client : realm.getClients()) {
if (clientScopeName.equals(client.getClientId())) {
return client;
}
}
}
return null;
} }
/** /**

View file

@ -25,11 +25,10 @@ import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener; import org.keycloak.provider.ProviderEventListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -62,7 +61,7 @@ public abstract class AbstractLoginProtocolFactory implements LoginProtocolFacto
// Create default client scopes for realm built-in clients too // Create default client scopes for realm built-in clients too
if (addScopesToExistingClients) { if (addScopesToExistingClients) {
addDefaultClientScopes(newRealm, newRealm.getClients()); addDefaultClientScopes(newRealm, newRealm.getClientsStream());
} }
} }
@ -73,27 +72,27 @@ public abstract class AbstractLoginProtocolFactory implements LoginProtocolFacto
protected void addDefaultClientScopes(RealmModel realm, ClientModel newClient) { protected void addDefaultClientScopes(RealmModel realm, ClientModel newClient) {
addDefaultClientScopes(realm, Arrays.asList(newClient)); addDefaultClientScopes(realm, Stream.of(newClient));
} }
protected void addDefaultClientScopes(RealmModel realm, List<ClientModel> newClients) { protected void addDefaultClientScopes(RealmModel realm, Stream<ClientModel> newClients) {
Set<ClientScopeModel> defaultClientScopes = realm.getDefaultClientScopes(true).stream() Set<ClientScopeModel> defaultClientScopes = realm.getDefaultClientScopes(true).stream()
.filter(clientScope -> getId().equals(clientScope.getProtocol())) .filter(clientScope -> getId().equals(clientScope.getProtocol()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (!defaultClientScopes.isEmpty()) {
for (ClientModel newClient : newClients) {
newClient.addClientScopes(defaultClientScopes, true);
}
}
Set<ClientScopeModel> nonDefaultClientScopes = realm.getDefaultClientScopes(false).stream() Set<ClientScopeModel> nonDefaultClientScopes = realm.getDefaultClientScopes(false).stream()
.filter(clientScope -> getId().equals(clientScope.getProtocol())) .filter(clientScope -> getId().equals(clientScope.getProtocol()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (!nonDefaultClientScopes.isEmpty()) {
for (ClientModel newClient : newClients) { Consumer<ClientModel> addDefault = c -> c.addClientScopes(defaultClientScopes, true);
newClient.addClientScopes(nonDefaultClientScopes, false); Consumer<ClientModel> addNonDefault = c -> c.addClientScopes(nonDefaultClientScopes, false);
}
} if (!defaultClientScopes.isEmpty() && !nonDefaultClientScopes.isEmpty())
newClients.forEach(addDefault.andThen(addNonDefault));
else if (!defaultClientScopes.isEmpty())
newClients.forEach(addDefault);
else if (!nonDefaultClientScopes.isEmpty())
newClients.forEach(addNonDefault);
} }
protected abstract void addDefaults(ClientModel realm); protected abstract void addDefaults(ClientModel realm);

View file

@ -49,7 +49,6 @@ public interface RoleContainerModel {
boolean removeRole(RoleModel role); boolean removeRole(RoleModel role);
// TODO switch all usages to the stream variant
@Deprecated @Deprecated
default Set<RoleModel> getRoles() { default Set<RoleModel> getRoles() {
return getRolesStream().collect(Collectors.toSet()); return getRolesStream().collect(Collectors.toSet());
@ -57,7 +56,6 @@ public interface RoleContainerModel {
Stream<RoleModel> getRolesStream(); Stream<RoleModel> getRolesStream();
// TODO switch all usages to the stream variant
@Deprecated @Deprecated
default Set<RoleModel> getRoles(Integer firstResult, Integer maxResults) { default Set<RoleModel> getRoles(Integer firstResult, Integer maxResults) {
return getRolesStream(firstResult, maxResults).collect(Collectors.toSet()); return getRolesStream(firstResult, maxResults).collect(Collectors.toSet());
@ -65,7 +63,6 @@ public interface RoleContainerModel {
Stream<RoleModel> getRolesStream(Integer firstResult, Integer maxResults); Stream<RoleModel> getRolesStream(Integer firstResult, Integer maxResults);
// TODO switch all usages to the stream variant
@Deprecated @Deprecated
default Set<RoleModel> searchForRoles(String search, Integer first, Integer max) { default Set<RoleModel> searchForRoles(String search, Integer first, Integer max) {
return searchForRolesStream(search, first, max).collect(Collectors.toSet()); return searchForRolesStream(search, first, max).collect(Collectors.toSet());

View file

@ -22,7 +22,11 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -35,13 +39,10 @@ public class DefaultRoles {
set.add(realm.getRole(r)); set.add(realm.getRole(r));
} }
for (ClientModel application : realm.getClients()) { Function<ClientModel, Set<RoleModel>> defaultRoles = i -> i.getDefaultRoles().stream().map(i::getRole).collect(Collectors.toSet());
for (String r : application.getDefaultRoles()) { realm.getClientsStream().map(defaultRoles).forEach(set::addAll);
set.add(application.getRole(r));
}
}
return set;
return set;
} }
public static void addDefaultRoles(RealmModel realm, UserModel userModel) { public static void addDefaultRoles(RealmModel realm, UserModel userModel) {
for (RoleModel role : getDefaultRoles(realm)) { for (RoleModel role : getDefaultRoles(realm)) {

View file

@ -189,6 +189,16 @@ public class RoleUtils {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
/**
* @param roles
* @return stream with composite roles expanded
*/
public static Stream<RoleModel> expandCompositeRolesStream(Stream<RoleModel> roles) {
Set<RoleModel> visited = new HashSet<>();
return roles.flatMap(roleModel -> RoleUtils.expandCompositeRolesStream(roleModel, visited));
}
/** /**
* @param user * @param user

View file

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.keycloak.authorization.AuthorizationProvider; import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.AuthorizationProviderFactory; import org.keycloak.authorization.AuthorizationProviderFactory;
@ -120,7 +121,7 @@ public class ExportUtils {
List<ClientModel> clients = Collections.emptyList(); List<ClientModel> clients = Collections.emptyList();
if (options.isClientsIncluded()) { if (options.isClientsIncluded()) {
clients = realm.getClients(); clients = realm.getClientsStream().collect(Collectors.toList());
List<ClientRepresentation> clientReps = new ArrayList<>(); List<ClientRepresentation> clientReps = new ArrayList<>();
for (ClientModel app : clients) { for (ClientModel app : clients) {
ClientRepresentation clientRep = exportClient(session, app); ClientRepresentation clientRep = exportClient(session, app);
@ -133,22 +134,18 @@ public class ExportUtils {
if (options.isGroupsAndRolesIncluded()) { if (options.isGroupsAndRolesIncluded()) {
ModelToRepresentation.exportGroups(realm, rep); ModelToRepresentation.exportGroups(realm, rep);
List<RoleRepresentation> realmRoleReps = null;
Map<String, List<RoleRepresentation>> clientRolesReps = new HashMap<>(); Map<String, List<RoleRepresentation>> clientRolesReps = new HashMap<>();
Set<RoleModel> realmRoles = realm.getRoles(); List<RoleRepresentation> realmRoleReps = exportRoles(realm.getRolesStream());
if (realmRoles != null && realmRoles.size() > 0) {
realmRoleReps = exportRoles(realmRoles);
}
RolesRepresentation rolesRep = new RolesRepresentation(); RolesRepresentation rolesRep = new RolesRepresentation();
if (realmRoleReps != null) { if (!realmRoleReps.isEmpty()) {
rolesRep.setRealm(realmRoleReps); rolesRep.setRealm(realmRoleReps);
} }
if (options.isClientsIncluded()) { if (options.isClientsIncluded()) {
for (ClientModel client : clients) { for (ClientModel client : clients) {
Set<RoleModel> currentAppRoles = client.getRoles(); Stream<RoleModel> currentAppRoles = client.getRolesStream();
List<RoleRepresentation> currentAppRoleReps = exportRoles(currentAppRoles); List<RoleRepresentation> currentAppRoleReps = exportRoles(currentAppRoles);
clientRolesReps.put(client.getClientId(), currentAppRoleReps); clientRolesReps.put(client.getClientId(), currentAppRoleReps);
} }
@ -411,14 +408,8 @@ public class ExportUtils {
} }
} }
public static List<RoleRepresentation> exportRoles(Collection<RoleModel> roles) { public static List<RoleRepresentation> exportRoles(Stream<RoleModel> roles) {
List<RoleRepresentation> roleReps = new ArrayList<RoleRepresentation>(); return roles.map(ExportUtils::exportRole).collect(Collectors.toList());
for (RoleModel role : roles) {
RoleRepresentation roleRep = exportRole(role);
roleReps.add(roleRep);
}
return roleReps;
} }
public static List<String> getRoleNames(Collection<RoleModel> roles) { public static List<String> getRoleNames(Collection<RoleModel> roles) {

View file

@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -102,14 +103,8 @@ public class ApplicationsBean {
private Set<ClientModel> getApplications(KeycloakSession session, RealmModel realm, UserModel user) { private Set<ClientModel> getApplications(KeycloakSession session, RealmModel realm, UserModel user) {
Set<ClientModel> clients = new HashSet<>(); Set<ClientModel> clients = new HashSet<>();
for (ClientModel client : realm.getClients()) { Predicate<ClientModel> bearerOnly = ClientModel::isBearerOnly;
// Don't show bearerOnly clients clients.addAll(realm.getClientsStream().filter(bearerOnly.negate()).collect(Collectors.toSet()));
if (client.isBearerOnly()) {
continue;
}
clients.add(client);
}
List<UserConsentModel> consents = session.users().getConsents(realm, user.getId()); List<UserConsentModel> consents = session.users().getConsents(realm, user.getId());

View file

@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
/** /**
@ -68,11 +69,7 @@ public class ClientRolesPartialImport {
ClientModel client = realm.getClientByClientId(clientId); ClientModel client = realm.getClientByClientId(clientId);
if (client == null) return false; if (client == null) return false;
for (RoleModel role : client.getRoles()) { return client.getRolesStream().anyMatch(role -> Objects.equals(getName(roleRep), role.getName()));
if (getName(roleRep).equals(role.getName())) return true;
}
return false;
} }
// check if client currently exists or will exists as a result of this partial import // check if client currently exists or will exists as a result of this partial import

View file

@ -24,6 +24,7 @@ import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.RoleResource; import org.keycloak.services.resources.admin.RoleResource;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
/** /**
@ -56,20 +57,15 @@ public class RealmRolesPartialImport extends AbstractPartialImport<RoleRepresent
@Override @Override
public String getModelId(RealmModel realm, KeycloakSession session, RoleRepresentation roleRep) { public String getModelId(RealmModel realm, KeycloakSession session, RoleRepresentation roleRep) {
for (RoleModel role : realm.getRoles()) { return realm.getRolesStream()
if (getName(roleRep).equals(role.getName())) return role.getId(); .filter(r -> Objects.equals(getName(roleRep), r.getName()))
} .map(RoleModel::getId)
.findFirst().orElse(null);
return null;
} }
@Override @Override
public boolean exists(RealmModel realm, KeycloakSession session, RoleRepresentation roleRep) { public boolean exists(RealmModel realm, KeycloakSession session, RoleRepresentation roleRep) {
for (RoleModel role : realm.getRoles()) { return realm.getRolesStream().anyMatch(role -> Objects.equals(getName(roleRep), role.getName()));
if (getName(roleRep).equals(role.getName())) return true;
}
return false;
} }
@Override @Override

View file

@ -21,7 +21,6 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
import org.keycloak.Token;
import org.keycloak.TokenCategory; import org.keycloak.TokenCategory;
import org.keycloak.TokenVerifier; import org.keycloak.TokenVerifier;
import org.keycloak.broker.oidc.OIDCIdentityProvider; import org.keycloak.broker.oidc.OIDCIdentityProvider;
@ -61,7 +60,6 @@ import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper; import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper; import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper; import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper;
import org.keycloak.protocol.oidc.utils.OAuth2Code;
import org.keycloak.protocol.oidc.utils.OIDCResponseType; import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
@ -83,16 +81,15 @@ import org.keycloak.util.TokenUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@ -495,21 +492,21 @@ public class TokenManager {
} else { } else {
// 1 - Client roles of this client itself // 1 - Client roles of this client itself
Set<RoleModel> scopeMappings = new HashSet<>(client.getRoles()); Stream<RoleModel> scopeMappings = client.getRolesStream();
// 2 - Role mappings of client itself + default client scopes + optional client scopes requested by scope parameter (if applyScopeParam is true) // 2 - Role mappings of client itself + default client scopes + optional client scopes requested by scope parameter (if applyScopeParam is true)
for (ClientScopeModel clientScope : clientScopes) { for (ClientScopeModel clientScope : clientScopes) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.tracef("Adding client scope role mappings of client scope '%s' to client '%s'", clientScope.getName(), client.getClientId()); logger.tracef("Adding client scope role mappings of client scope '%s' to client '%s'", clientScope.getName(), client.getClientId());
} }
scopeMappings.addAll(clientScope.getScopeMappings()); scopeMappings = Stream.concat(scopeMappings, clientScope.getScopeMappingsStream());
} }
// 3 - Expand scope mappings // 3 - Expand scope mappings
scopeMappings = RoleUtils.expandCompositeRoles(scopeMappings); scopeMappings = RoleUtils.expandCompositeRolesStream(scopeMappings);
// Intersection of expanded user roles and expanded scopeMappings // Intersection of expanded user roles and expanded scopeMappings
roleMappings.retainAll(scopeMappings); roleMappings.retainAll(scopeMappings.collect(Collectors.toSet()));
return roleMappings; return roleMappings;
} }

View file

@ -40,8 +40,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -58,7 +58,7 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
if (client.isPublicClient() && !client.isBearerOnly()) rep.setPublicClient(true); if (client.isPublicClient() && !client.isBearerOnly()) rep.setPublicClient(true);
if (client.isBearerOnly()) rep.setBearerOnly(true); if (client.isBearerOnly()) rep.setBearerOnly(true);
if (client.getRoles().size() > 0) rep.setUseResourceRoleMappings(true); if (client.getRolesStream().count() > 0) rep.setUseResourceRoleMappings(true);
rep.setResource(client.getClientId()); rep.setResource(client.getClientId());
@ -104,7 +104,7 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
static boolean showVerifyTokenAudience(ClientModel client) { static boolean showVerifyTokenAudience(ClientModel client) {
// We want to verify-token-audience if service client has any client roles // We want to verify-token-audience if service client has any client roles
if (client.getRoles().size() > 0) { if (client.getRolesStream().count() > 0) {
return true; return true;
} }
@ -187,13 +187,21 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
rep.setEnforcerConfig(enforcerConfig); rep.setEnforcerConfig(enforcerConfig);
Set<RoleModel> clientRoles = client.getRoles(); Iterator<RoleModel> it = client.getRolesStream().iterator();
if (clientRoles.size() == 1) { RoleModel role = hasOnlyOne(it);
if (clientRoles.iterator().next().getName().equals(Constants.AUTHZ_UMA_PROTECTION)) { if (role != null && role.getName().equals(Constants.AUTHZ_UMA_PROTECTION)) {
rep.setUseResourceRoleMappings(null); rep.setUseResourceRoleMappings(null);
}
} }
} }
} }
private RoleModel hasOnlyOne(Iterator<RoleModel> it) {
if (!it.hasNext()) return null;
else {
RoleModel role = it.next();
if (it.hasNext()) return null;
else return role;
}
}
} }

View file

@ -53,7 +53,7 @@ public class KeycloakOIDCJbossSubsystemClientCliInstallation implements ClientIn
if (KeycloakOIDCClientInstallation.showVerifyTokenAudience(client)) { if (KeycloakOIDCClientInstallation.showVerifyTokenAudience(client)) {
builder.append(" verify-token-audience=true, \\\n"); builder.append(" verify-token-audience=true, \\\n");
} }
if (client.getRoles().size() > 0) { if (client.getRolesStream().count() > 0) {
builder.append(" use-resource-role-mappings=true, \\\n"); builder.append(" use-resource-role-mappings=true, \\\n");
} }
builder.append(" ssl-required=").append(realm.getSslRequired().name()).append(")\n\n"); builder.append(" ssl-required=").append(realm.getSslRequired().name()).append(")\n\n");

View file

@ -73,7 +73,7 @@ public class KeycloakOIDCJbossSubsystemClientInstallation implements ClientInsta
} }
} }
} }
if (client.getRoles().size() > 0) { if (client.getRolesStream().count() > 0) {
buffer.append(" <use-resource-role-mappings>true</use-resource-role-mappings>\n"); buffer.append(" <use-resource-role-mappings>true</use-resource-role-mappings>\n");
} }
buffer.append("</secure-deployment>\n"); buffer.append("</secure-deployment>\n");

View file

@ -31,6 +31,7 @@ import java.net.URI;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -70,13 +71,11 @@ public class RedirectUtils {
} }
private static Set<String> getValidateRedirectUris(KeycloakSession session) { private static Set<String> getValidateRedirectUris(KeycloakSession session) {
Set<String> redirects = new HashSet<>(); return session.getContext().getRealm().getClientsStream()
for (ClientModel client : session.getContext().getRealm().getClients()) { .filter(ClientModel::isEnabled)
if (client.isEnabled()) { .map(c -> resolveValidRedirects(session, c.getRootUrl(), c.getRedirectUris()))
redirects.addAll(resolveValidRedirects(session, client.getRootUrl(), client.getRedirectUris())); .flatMap(Collection::stream)
} .collect(Collectors.toSet());
}
return redirects;
} }
private static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set<String> validRedirects, boolean requireRedirectUri) { private static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set<String> validRedirects, boolean requireRedirectUri) {

View file

@ -22,7 +22,6 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.common.util.PemUtils; import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.crypto.KeyStatus; import org.keycloak.crypto.KeyStatus;
import org.keycloak.dom.saml.v2.SAML2Object; import org.keycloak.dom.saml.v2.SAML2Object;
import org.keycloak.dom.saml.v2.assertion.BaseIDAbstractType; import org.keycloak.dom.saml.v2.assertion.BaseIDAbstractType;
@ -75,7 +74,6 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.security.PublicKey; import java.security.PublicKey;
@ -83,21 +81,16 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import org.keycloak.common.util.StringPropertyReplacer;
import org.keycloak.crypto.Algorithm; import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyUse; import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper; import org.keycloak.crypto.KeyWrapper;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.rotation.HardcodedKeyLocator; import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator; import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.SPMetadataDescriptor;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator; import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
import org.keycloak.saml.validators.DestinationValidator; import org.keycloak.saml.validators.DestinationValidator;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
import java.nio.charset.StandardCharsets;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignature;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -698,16 +691,11 @@ public class SamlService extends AuthorizationEndpointBase {
public Response idpInitiatedSSO(@PathParam("client") String clientUrlName, @QueryParam("RelayState") String relayState) { public Response idpInitiatedSSO(@PathParam("client") String clientUrlName, @QueryParam("RelayState") String relayState) {
event.event(EventType.LOGIN); event.event(EventType.LOGIN);
CacheControlUtil.noBackButtonCacheControlHeader(); CacheControlUtil.noBackButtonCacheControlHeader();
ClientModel client = null; ClientModel client = realm.getClientsStream()
for (ClientModel c : realm.getClients()) { .filter(c -> Objects.nonNull(c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME)))
String urlName = c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME); .filter(c -> Objects.equals(c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME), clientUrlName))
if (urlName == null) .findFirst().orElse(null);
continue;
if (urlName.equals(clientUrlName)) {
client = c;
break;
}
}
if (client == null) { if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND); event.error(Errors.CLIENT_NOT_FOUND);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_NOT_FOUND); return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.CLIENT_NOT_FOUND);

View file

@ -42,7 +42,7 @@ public class MaxClientsClientRegistrationPolicy implements ClientRegistrationPol
@Override @Override
public void beforeRegister(ClientRegistrationContext context) throws ClientRegistrationPolicyException { public void beforeRegister(ClientRegistrationContext context) throws ClientRegistrationPolicyException {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
int currentCount = realm.getClients().size(); long currentCount = realm.getClientsCount();
int maxCount = componentModel.get(MaxClientsClientRegistrationPolicyFactory.MAX_CLIENTS, MaxClientsClientRegistrationPolicyFactory.DEFAULT_MAX_CLIENTS); int maxCount = componentModel.get(MaxClientsClientRegistrationPolicyFactory.MAX_CLIENTS, MaxClientsClientRegistrationPolicyFactory.DEFAULT_MAX_CLIENTS);
if (currentCount >= maxCount) { if (currentCount >= maxCount) {

View file

@ -292,7 +292,7 @@ public class ClientManager {
if (clientModel.isPublicClient() && !clientModel.isBearerOnly()) rep.setPublicClient(true); if (clientModel.isPublicClient() && !clientModel.isBearerOnly()) rep.setPublicClient(true);
if (clientModel.isBearerOnly()) rep.setBearerOnly(true); if (clientModel.isBearerOnly()) rep.setBearerOnly(true);
if (clientModel.getRoles().size() > 0) rep.setUseResourceRoleMappings(true); if (clientModel.getRolesStream().count() > 0) rep.setUseResourceRoleMappings(true);
rep.setResource(clientModel.getClientId()); rep.setResource(clientModel.getClientId());
@ -336,7 +336,7 @@ public class ClientManager {
} }
} }
} }
if (clientModel.getRoles().size() > 0) { if (clientModel.getRolesStream().count() > 0) {
buffer.append(" <use-resource-role-mappings>true</use-resource-role-mappings>\n"); buffer.append(" <use-resource-role-mappings>true</use-resource-role-mappings>\n");
} }
buffer.append("</secure-deployment>\n"); buffer.append("</secure-deployment>\n");

View file

@ -59,6 +59,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -267,14 +269,17 @@ public class ResourceAdminManager {
public GlobalRequestResult logoutAll(RealmModel realm) { public GlobalRequestResult logoutAll(RealmModel realm) {
realm.setNotBefore(Time.currentTime()); realm.setNotBefore(Time.currentTime());
List<ClientModel> resources = realm.getClients(); Stream<ClientModel> resources = realm.getClientsStream();
logger.debugv("logging out {0} resources ", resources.size());
GlobalRequestResult finalResult = new GlobalRequestResult(); GlobalRequestResult finalResult = new GlobalRequestResult();
for (ClientModel resource : resources) { AtomicInteger counter = new AtomicInteger(0);
GlobalRequestResult currentResult = logoutClient(realm, resource, realm.getNotBefore()); resources.forEach(r -> {
counter.getAndIncrement();
GlobalRequestResult currentResult = logoutClient(realm, r, realm.getNotBefore());
finalResult.addAll(currentResult); finalResult.addAll(currentResult);
} });
logger.debugv("logging out {0} resources ", counter);
return finalResult; return finalResult;
} }
@ -328,10 +333,10 @@ public class ResourceAdminManager {
public GlobalRequestResult pushRealmRevocationPolicy(RealmModel realm) { public GlobalRequestResult pushRealmRevocationPolicy(RealmModel realm) {
GlobalRequestResult finalResult = new GlobalRequestResult(); GlobalRequestResult finalResult = new GlobalRequestResult();
for (ClientModel client : realm.getClients()) { realm.getClientsStream().forEach(c -> {
GlobalRequestResult currentResult = pushRevocationPolicy(realm, client, realm.getNotBefore()); GlobalRequestResult currentResult = pushRevocationPolicy(realm, c, realm.getNotBefore());
finalResult.addAll(currentResult); finalResult.addAll(currentResult);
} });
return finalResult; return finalResult;
} }

View file

@ -22,7 +22,6 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.OAuthErrorException; import org.keycloak.OAuthErrorException;
import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.AuthenticationFlowException;
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator; import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants; import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants;
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext; import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
@ -1120,7 +1119,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private ParsedCodeContext samlIdpInitiatedSSO(final String clientUrlName) { private ParsedCodeContext samlIdpInitiatedSSO(final String clientUrlName) {
event.event(EventType.LOGIN); event.event(EventType.LOGIN);
CacheControlUtil.noBackButtonCacheControlHeader(); CacheControlUtil.noBackButtonCacheControlHeader();
Optional<ClientModel> oClient = this.realmModel.getClients().stream() Optional<ClientModel> oClient = this.realmModel.getClientsStream()
.filter(c -> Objects.equals(c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME), clientUrlName)) .filter(c -> Objects.equals(c.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_URL_NAME), clientUrlName))
.findFirst(); .findFirst();

View file

@ -515,10 +515,7 @@ public class AccountRestService {
consentModels.put(client.getClientId(), consent); consentModels.put(client.getClientId(), consent);
} }
List<ClientModel> alwaysDisplayClients = realm.getAlwaysDisplayInConsoleClients(); realm.getAlwaysDisplayInConsoleClientsStream().forEach(clients::add);
for(ClientModel client : alwaysDisplayClients) {
clients.add(client);
}
List<ClientRepresentation> apps = new LinkedList<ClientRepresentation>(); List<ClientRepresentation> apps = new LinkedList<ClientRepresentation>();
for (ClientModel client : clients) { for (ClientModel client : clients) {

View file

@ -53,18 +53,17 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.Providers; import javax.ws.rs.ext.Providers;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -219,7 +218,7 @@ public class AdminConsole {
if (realm.equals(masterRealm)) { if (realm.equals(masterRealm)) {
logger.debug("setting up realm access for a master realm user"); logger.debug("setting up realm access for a master realm user");
createRealm = user.hasRole(masterRealm.getRole(AdminRoles.CREATE_REALM)); createRealm = user.hasRole(masterRealm.getRole(AdminRoles.CREATE_REALM));
addMasterRealmAccess(realm, user, realmAccess); addMasterRealmAccess(user, realmAccess);
} else { } else {
logger.debug("setting up realm access for a realm user"); logger.debug("setting up realm access for a realm user");
addRealmAccess(realm, user, realmAccess); addRealmAccess(realm, user, realmAccess);
@ -233,28 +232,26 @@ public class AdminConsole {
private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) { private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
ClientModel realmAdminApp = realm.getClientByClientId(realmManager.getRealmAdminClientId(realm)); ClientModel realmAdminApp = realm.getClientByClientId(realmManager.getRealmAdminClientId(realm));
Set<RoleModel> roles = realmAdminApp.getRoles(); getRealmAdminAccess(realmAdminApp, user, realmAdminAccess);
for (RoleModel role : roles) {
if (!user.hasRole(role)) continue;
if (!realmAdminAccess.containsKey(realm.getName())) {
realmAdminAccess.put(realm.getName(), new HashSet<String>());
}
realmAdminAccess.get(realm.getName()).add(role.getName());
}
} }
private void addMasterRealmAccess(RealmModel masterRealm, UserModel user, Map<String, Set<String>> realmAdminAccess) { private void addMasterRealmAccess(UserModel user, Map<String, Set<String>> realmAdminAccess) {
List<RealmModel> realms = session.realms().getRealms(); List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) { for (RealmModel realm : realms) {
ClientModel realmAdminApp = realm.getMasterAdminClient(); ClientModel realmAdminApp = realm.getMasterAdminClient();
Set<RoleModel> roles = realmAdminApp.getRoles(); getRealmAdminAccess(realmAdminApp, user, realmAdminAccess);
for (RoleModel role : roles) { }
if (!user.hasRole(role)) continue; }
if (!realmAdminAccess.containsKey(realm.getName())) {
realmAdminAccess.put(realm.getName(), new HashSet<String>()); private void getRealmAdminAccess(ClientModel client, UserModel user, Map<String, Set<String>> realmAdminAccess) {
} Set<String> roles = client.getRolesStream().filter(user::hasRole)
realmAdminAccess.get(realm.getName()).add(role.getName()); .map(RoleModel::getName).collect(Collectors.toSet());
if (!roles.isEmpty()) {
if (!realmAdminAccess.containsKey(realm.getName())) {
realmAdminAccess.put(realm.getName(), roles);
} else {
realmAdminAccess.get(realm.getName()).addAll(roles);
} }
} }
} }

View file

@ -19,7 +19,6 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
@ -46,14 +45,13 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/** /**
* @resource Client Role Mappings * @resource Client Role Mappings
@ -120,17 +118,13 @@ public class ClientRoleMappingsResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeClientRoleMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { public Stream<RoleRepresentation> getCompositeClientRoleMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
viewPermission.require(); viewPermission.require();
Set<RoleModel> roles = client.getRoles(); Stream<RoleModel> roles = client.getRolesStream();
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>(); Function<RoleModel, RoleRepresentation> toBriefRepresentation = briefRepresentation
for (RoleModel roleModel : roles) { ? ModelToRepresentation::toBriefRepresentation : ModelToRepresentation::toRepresentation;
if (user.hasRole(roleModel)) { return roles.filter(user::hasRole).map(toBriefRepresentation);
mapRep.add(briefRepresentation ? ModelToRepresentation.toBriefRepresentation(roleModel) : ModelToRepresentation.toRepresentation(roleModel));
}
}
return mapRep;
} }
/** /**
@ -142,28 +136,13 @@ public class ClientRoleMappingsResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableClientRoleMappings() { public Stream<RoleRepresentation> getAvailableClientRoleMappings() {
viewPermission.require(); viewPermission.require();
Set<RoleModel> available = client.getRoles(); return client.getRolesStream()
available = available.stream().filter(r -> .filter(auth.roles()::canMapRole)
auth.roles().canMapRole(r) .filter(((Predicate<RoleModel>) user::hasRole).negate())
).collect(Collectors.toSet()); .map(ModelToRepresentation::toBriefRepresentation);
return getAvailableRoles(user, available);
}
public static List<RoleRepresentation> getAvailableRoles(RoleMapperModel mapper, Set<RoleModel> available) {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (RoleModel roleModel : available) {
if (mapper.hasRole(roleModel)) continue;
roles.add(roleModel);
}
List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
mappings.add(ModelToRepresentation.toBriefRepresentation(roleModel));
}
return mappings;
} }
/** /**

View file

@ -17,10 +17,11 @@
package org.keycloak.services.resources.admin; package org.keycloak.services.resources.admin;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -33,7 +34,6 @@ import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
@ -92,44 +92,32 @@ public class ClientScopeEvaluateScopeMappingsResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getNotGrantedScopeMappings() { public Stream<RoleRepresentation> getNotGrantedScopeMappings() {
List<RoleModel> grantedRoles = getGrantedRoles(); Set<RoleModel> grantedRoles = getGrantedRoles();
return roleContainer.getRoles().stream().filter((RoleModel role) -> { return roleContainer.getRolesStream()
.filter(r -> !grantedRoles.contains(r))
return !grantedRoles.contains(role); .map(ModelToRepresentation::toBriefRepresentation);
}).map((RoleModel role) -> {
return ModelToRepresentation.toBriefRepresentation(role);
}).collect(Collectors.toList());
} }
private List<RoleModel> getGrantedRoles() { private Set<RoleModel> getGrantedRoles() {
if (client.isFullScopeAllowed()) { if (client.isFullScopeAllowed()) {
return new LinkedList<>(roleContainer.getRoles()); // intentionally using deprecated method as a set is more appropriate here
return roleContainer.getRoles();
} }
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client); Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client);
List<RoleModel> result = new LinkedList<>(); BiPredicate<Set<ClientScopeModel>, RoleModel> hasClientScope = (scopes, role) ->
scopes.stream().anyMatch(scopeContainer -> scopeContainer.hasScope(role));
for (RoleModel role : roleContainer.getRoles()) { return roleContainer.getRolesStream()
if (!auth.roles().canView(role)) continue; .filter(auth.roles()::canView)
.filter(r -> hasClientScope.test(clientScopes, r))
for (ScopeContainerModel scopeContainer : clientScopes) { .collect(Collectors.toSet());
if (scopeContainer.hasScope(role)) {
result.add(role);
break;
}
}
}
return result;
} }
} }

View file

@ -36,7 +36,6 @@ import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.clientpolicy.AdminClientRegisterContext; import org.keycloak.services.clientpolicy.AdminClientRegisterContext;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.DefaultClientPolicyManager;
import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.ClientManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
@ -57,10 +56,9 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.ArrayList; import java.util.Objects;
import java.util.Collections;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.stream.Stream;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
@ -101,65 +99,57 @@ public class ClientsResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<ClientRepresentation> getClients(@QueryParam("clientId") String clientId, public Stream<ClientRepresentation> getClients(@QueryParam("clientId") String clientId,
@QueryParam("viewableOnly") @DefaultValue("false") boolean viewableOnly, @QueryParam("viewableOnly") @DefaultValue("false") boolean viewableOnly,
@QueryParam("search") @DefaultValue("false") boolean search, @QueryParam("search") @DefaultValue("false") boolean search,
@QueryParam("first") Integer firstResult, @QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") Integer maxResults) {
if (firstResult == null) {
firstResult = -1;
}
if (maxResults == null) {
maxResults = -1;
}
List<ClientRepresentation> rep = new ArrayList<>();
boolean canView = auth.clients().canView(); boolean canView = auth.clients().canView();
List<ClientModel> clientModels; Stream<ClientModel> clientModels = Stream.empty();
if (clientId == null || clientId.trim().equals("")) { if (clientId == null || clientId.trim().equals("")) {
clientModels = canView ? realm.getClients(firstResult, maxResults) : realm.getClients(); clientModels = canView
? realm.getClientsStream(firstResult, maxResults)
: realm.getClientsStream();
auth.clients().requireList(); auth.clients().requireList();
} else if (search) {
clientModels = canView
? realm.searchClientByClientIdStream(clientId, firstResult, maxResults)
: realm.searchClientByClientIdStream(clientId, -1, -1);
} else { } else {
clientModels = Collections.emptyList(); ClientModel client = realm.getClientByClientId(clientId);
if(search) { if (client != null) {
clientModels = canView ? realm.searchClientByClientId(clientId, firstResult, maxResults) : realm.searchClientByClientId(clientId, -1, -1); clientModels = Stream.of(client);
} else {
ClientModel client = realm.getClientByClientId(clientId);
if(client != null) {
clientModels = Collections.singletonList(client);
}
} }
} }
int idx = 0; Stream<ClientRepresentation> s = clientModels
.map(c -> {
ClientRepresentation representation = null;
if (canView || auth.clients().canView(c)) {
representation = ModelToRepresentation.toRepresentation(c, session);
representation.setAccess(auth.clients().getAccess(c));
} else if (!viewableOnly && auth.clients().canView(c)) {
representation = new ClientRepresentation();
representation.setId(c.getId());
representation.setClientId(c.getClientId());
representation.setDescription(c.getDescription());
}
for(ClientModel clientModel : clientModels) { return representation;
if (!canView) { })
if (rep.size() == maxResults) { .filter(Objects::nonNull);
return rep;
} if (!canView) {
if (firstResult != null && firstResult > 0) {
s = s.skip(firstResult);
} }
if (maxResults != null && maxResults > 0) {
ClientRepresentation representation = null; s = s.limit(maxResults);
if (canView || auth.clients().canView(clientModel)) {
representation = ModelToRepresentation.toRepresentation(clientModel, session);
representation.setAccess(auth.clients().getAccess(clientModel));
} else if (!viewableOnly && auth.clients().canView(clientModel)) {
representation = new ClientRepresentation();
representation.setId(clientModel.getId());
representation.setClientId(clientModel.getClientId());
representation.setDescription(clientModel.getDescription());
}
if (representation != null) {
if (canView || idx++ >= firstResult) {
rep.add(representation);
}
} }
} }
return rep;
return s;
} }
private AuthorizationService getAuthorizationService(ClientModel clientModel) { private AuthorizationService getAuthorizationService(ClientModel clientModel) {

View file

@ -100,20 +100,20 @@ public class RoleContainerResource extends RoleResource {
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { @QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
auth.roles().requireList(roleContainer); auth.roles().requireList(roleContainer);
Set<RoleModel> roleModels; Stream<RoleModel> roleModels;
if(search != null && search.trim().length() > 0) { if(search != null && search.trim().length() > 0) {
roleModels = roleContainer.searchForRoles(search, firstResult, maxResults); roleModels = roleContainer.searchForRolesStream(search, firstResult, maxResults);
} else if (!Objects.isNull(firstResult) && !Objects.isNull(maxResults)) { } else if (!Objects.isNull(firstResult) && !Objects.isNull(maxResults)) {
roleModels = roleContainer.getRoles(firstResult, maxResults); roleModels = roleContainer.getRolesStream(firstResult, maxResults);
} else { } else {
roleModels = roleContainer.getRoles(); roleModels = roleContainer.getRolesStream();
} }
Function<RoleModel, RoleRepresentation> toRoleRepresentation = briefRepresentation ? Function<RoleModel, RoleRepresentation> toRoleRepresentation = briefRepresentation ?
ModelToRepresentation::toBriefRepresentation : ModelToRepresentation::toBriefRepresentation :
ModelToRepresentation::toRepresentation; ModelToRepresentation::toRepresentation;
return roleModels.stream().map(toRoleRepresentation); return roleModels.map(toRoleRepresentation);
} }
/** /**

View file

@ -19,7 +19,6 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
@ -35,7 +34,6 @@ import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientMappingsRepresentation; import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation; import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.storage.ReadOnlyException; import org.keycloak.storage.ReadOnlyException;
@ -53,15 +51,15 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/** /**
* Base resource for managing users * Base resource for managing users
@ -183,17 +181,12 @@ public class RoleMapperResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeRealmRoleMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { public Stream<RoleRepresentation> getCompositeRealmRoleMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
viewPermission.require(); viewPermission.require();
Set<RoleModel> roles = realm.getRoles(); Function<RoleModel, RoleRepresentation> toBriefRepresentation = briefRepresentation ?
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>(); ModelToRepresentation::toBriefRepresentation : ModelToRepresentation::toRepresentation;
for (RoleModel roleModel : roles) { return realm.getRolesStream().filter(roleMapper::hasRole).map(toBriefRepresentation);
if (roleMapper.hasRole(roleModel)) {
realmMappingsRep.add(briefRepresentation ? ModelToRepresentation.toBriefRepresentation(roleModel) : ModelToRepresentation.toRepresentation(roleModel));
}
}
return realmMappingsRep;
} }
/** /**
@ -205,14 +198,13 @@ public class RoleMapperResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableRealmRoleMappings() { public Stream<RoleRepresentation> getAvailableRealmRoleMappings() {
viewPermission.require(); viewPermission.require();
Set<RoleModel> available = realm.getRoles(); return realm.getRolesStream()
Set<RoleModel> set = available.stream().filter(r -> .filter(this::canMapRole)
canMapRole(r) .filter(((Predicate<RoleModel>) roleMapper::hasRole).negate())
).collect(Collectors.toSet()); .map(ModelToRepresentation::toBriefRepresentation);
return ClientRoleMappingsResource.getAvailableRoles(roleMapper, set);
} }
/** /**

View file

@ -44,6 +44,9 @@ import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/** /**
* @resource Scope Mappings * @resource Scope Mappings
@ -105,11 +108,13 @@ public class ScopeMappedClientResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableClientScopeMappings() { public Stream<RoleRepresentation> getAvailableClientScopeMappings() {
viewPermission.require(); viewPermission.require();
Set<RoleModel> roles = scopedClient.getRoles(); return scopedClient.getRolesStream()
return ScopeMappedResource.getAvailable(auth, scopeContainer, roles); .filter(((Predicate<RoleModel>) scopeContainer::hasScope).negate())
.filter(auth.roles()::canMapClientScope)
.map(ModelToRepresentation::toBriefRepresentation);
} }
/** /**
@ -125,11 +130,14 @@ public class ScopeMappedClientResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeClientScopeMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { public Stream<RoleRepresentation> getCompositeClientScopeMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
viewPermission.require(); viewPermission.require();
Set<RoleModel> roles = scopedClient.getRoles(); Function<RoleModel, RoleRepresentation> toBriefRepresentation = briefRepresentation ?
return ScopeMappedResource.getComposite(scopeContainer, roles, briefRepresentation); ModelToRepresentation::toBriefRepresentation : ModelToRepresentation::toRepresentation;
return scopedClient.getRolesStream()
.filter(scopeContainer::hasScope)
.map(toBriefRepresentation);
} }
/** /**

View file

@ -26,12 +26,12 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.ScopeContainerModel; import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientMappingsRepresentation; import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation; import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.services.util.ScopeMappedUtil;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -44,11 +44,15 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* Base class for managing the scope mappings of a specific client. * Base class for managing the scope mappings of a specific client.
@ -97,32 +101,22 @@ public class ScopeMappedResource {
MappingsRepresentation all = new MappingsRepresentation(); MappingsRepresentation all = new MappingsRepresentation();
Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings(); Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings();
if (realmMappings.size() > 0) { if (!realmMappings.isEmpty()) {
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>(); List<RoleRepresentation> realmRep = new LinkedList<>();
for (RoleModel roleModel : realmMappings) { for (RoleModel roleModel : realmMappings) {
realmRep.add(ModelToRepresentation.toBriefRepresentation(roleModel)); realmRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
} }
all.setRealmMappings(realmRep); all.setRealmMappings(realmRep);
} }
List<ClientModel> clients = realm.getClients(); Stream<ClientModel> clients = realm.getClientsStream();
if (clients.size() > 0) { Map<String, ClientMappingsRepresentation> clientMappings = clients
Map<String, ClientMappingsRepresentation> clientMappings = new HashMap<String, ClientMappingsRepresentation>(); .map(c -> ScopeMappedUtil.toClientMappingsRepresentation(c, scopeContainer))
for (ClientModel client : clients) { .filter(Objects::nonNull)
Set<RoleModel> roleMappings = KeycloakModelUtils.getClientScopeMappings(client, this.scopeContainer); //client.getClientScopeMappings(this.client); .collect(Collectors.toMap(ClientMappingsRepresentation::getClient, Function.identity()));
if (roleMappings.size() > 0) {
ClientMappingsRepresentation mappings = new ClientMappingsRepresentation(); if (!clientMappings.isEmpty()) {
mappings.setId(client.getId()); all.setClientMappings(clientMappings);
mappings.setClient(client.getClientId());
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
mappings.setMappings(roles);
for (RoleModel role : roleMappings) {
roles.add(ModelToRepresentation.toBriefRepresentation(role));
}
clientMappings.put(client.getClientId(), mappings);
all.setClientMappings(clientMappings);
}
}
} }
return all; return all;
} }
@ -160,25 +154,17 @@ public class ScopeMappedResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getAvailableRealmScopeMappings() { public Stream<RoleRepresentation> getAvailableRealmScopeMappings() {
viewPermission.require(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
} }
Set<RoleModel> roles = realm.getRoles(); return realm.getRolesStream()
return getAvailable(auth, scopeContainer, roles); .filter(((Predicate<RoleModel>) scopeContainer::hasScope).negate())
} .filter(auth.roles()::canMapClientScope)
.map(ModelToRepresentation::toBriefRepresentation);
public static List<RoleRepresentation> getAvailable(AdminPermissionEvaluator auth, ScopeContainerModel client, Set<RoleModel> roles) {
List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (client.hasScope(roleModel)) continue;
if (!auth.roles().canMapClientScope(roleModel)) continue;
available.add(ModelToRepresentation.toBriefRepresentation(roleModel));
}
return available;
} }
/** /**
@ -196,23 +182,18 @@ public class ScopeMappedResource {
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public List<RoleRepresentation> getCompositeRealmScopeMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { public Stream<RoleRepresentation> getCompositeRealmScopeMappings(@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
viewPermission.require(); viewPermission.require();
if (scopeContainer == null) { if (scopeContainer == null) {
throw new NotFoundException("Could not find client"); throw new NotFoundException("Could not find client");
} }
Set<RoleModel> roles = realm.getRoles(); Function<RoleModel, RoleRepresentation> toBriefRepresentation = briefRepresentation ?
return getComposite(scopeContainer, roles, briefRepresentation); ModelToRepresentation::toBriefRepresentation : ModelToRepresentation::toRepresentation;
} return realm.getRolesStream()
.filter(scopeContainer::hasScope)
public static List<RoleRepresentation> getComposite(ScopeContainerModel client, Set<RoleModel> roles, boolean briefRepresentation) { .map(toBriefRepresentation);
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (client.hasScope(roleModel)) composite.add(briefRepresentation ? ModelToRepresentation.toBriefRepresentation(roleModel) : ModelToRepresentation.toRepresentation(roleModel));
}
return composite;
} }
/** /**

View file

@ -466,40 +466,40 @@ public class UserResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public List<Map<String, Object>> getConsents() { public List<Map<String, Object>> getConsents() {
auth.users().requireView(user); auth.users().requireView(user);
List<Map<String, Object>> result = new LinkedList<>();
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
for (ClientModel client : realm.getClients()) { return realm.getClientsStream()
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId()); .map(client -> toConsent(client, offlineClients))
boolean hasOfflineToken = offlineClients.contains(client); .filter(Objects::nonNull)
.collect(Collectors.toList());
}
if (consent == null && !hasOfflineToken) { private Map<String, Object> toConsent(ClientModel client, Set<ClientModel> offlineClients) {
continue; UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
} boolean hasOfflineToken = offlineClients.contains(client);
UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent); if (consent == null && !hasOfflineToken) {
return null;
Map<String, Object> currentRep = new HashMap<>();
currentRep.put("clientId", client.getClientId());
currentRep.put("grantedClientScopes", (rep==null ? Collections.emptyList() : rep.getGrantedClientScopes()));
currentRep.put("createdDate", (rep==null ? null : rep.getCreatedDate()));
currentRep.put("lastUpdatedDate", (rep==null ? null : rep.getLastUpdatedDate()));
List<Map<String, String>> additionalGrants = new LinkedList<>();
if (hasOfflineToken) {
Map<String, String> offlineTokens = new HashMap<>();
offlineTokens.put("client", client.getId());
// TODO: translate
offlineTokens.put("key", "Offline Token");
additionalGrants.add(offlineTokens);
}
currentRep.put("additionalGrants", additionalGrants);
result.add(currentRep);
} }
return result; UserConsentRepresentation rep = (consent == null) ? null : ModelToRepresentation.toRepresentation(consent);
Map<String, Object> currentRep = new HashMap<>();
currentRep.put("clientId", client.getClientId());
currentRep.put("grantedClientScopes", (rep == null ? Collections.emptyList() : rep.getGrantedClientScopes()));
currentRep.put("createdDate", (rep == null ? null : rep.getCreatedDate()));
currentRep.put("lastUpdatedDate", (rep == null ? null : rep.getLastUpdatedDate()));
List<Map<String, String>> additionalGrants = new LinkedList<>();
if (hasOfflineToken) {
Map<String, String> offlineTokens = new HashMap<>();
offlineTokens.put("client", client.getId());
offlineTokens.put("key", "Offline Token");
additionalGrants.add(offlineTokens);
}
currentRep.put("additionalGrants", additionalGrants);
return currentRep;
} }

View file

@ -0,0 +1,52 @@
/*
* Copyright 2020 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.services.util;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.ScopeContainerModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.ClientMappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class ScopeMappedUtil {
public static ClientMappingsRepresentation toClientMappingsRepresentation(ClientModel client, ScopeContainerModel scopeContainer) {
Set<RoleModel> roleMappings = KeycloakModelUtils.getClientScopeMappings(client, scopeContainer);
if (!roleMappings.isEmpty()) {
ClientMappingsRepresentation mappings = new ClientMappingsRepresentation();
mappings.setId(client.getId());
mappings.setClient(client.getClientId());
List<RoleRepresentation> roles = new LinkedList<>();
mappings.setMappings(roles);
for (RoleModel role : roleMappings) {
roles.add(ModelToRepresentation.toBriefRepresentation(role));
}
return mappings;
} else {
return null;
}
}
}

View file

@ -64,10 +64,11 @@ public class TestClientRolesCondition implements ClientPolicyConditionProvider {
List<String> rolesForMatching = getRolesForMatching(); List<String> rolesForMatching = getRolesForMatching();
if (rolesForMatching == null) return false; if (rolesForMatching == null) return false;
client.getRoles().stream().forEach(i -> ClientPolicyLogger.log(logger, "client role = " + i.getName())); client.getRolesStream().forEach(i -> ClientPolicyLogger.log(logger, "client role = " + i.getName()));
rolesForMatching.stream().forEach(i -> ClientPolicyLogger.log(logger, "roles expected = " + i)); rolesForMatching.stream().forEach(i -> ClientPolicyLogger.log(logger, "roles expected = " + i));
boolean isMatched = rolesForMatching.stream().anyMatch(i->client.getRoles().stream().anyMatch(j->j.getName().equals(i))); boolean isMatched = rolesForMatching.stream()
.anyMatch(i -> client.getRolesStream().anyMatch(j -> j.getName().equals(i)));
if (isMatched) { if (isMatched) {
ClientPolicyLogger.log(logger, "role matched."); ClientPolicyLogger.log(logger, "role matched.");
} else { } else {

View file

@ -34,6 +34,7 @@ import org.keycloak.testsuite.arquillian.annotation.ModelTest;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
@ -52,17 +53,14 @@ public class CompositeRolesModelTest extends AbstractTestRealmKeycloakTest {
Set<RoleModel> requestedRoles = new HashSet<>(); Set<RoleModel> requestedRoles = new HashSet<>();
Set<RoleModel> roleMappings = user.getRoleMappings(); Set<RoleModel> roleMappings = user.getRoleMappings();
Set<RoleModel> scopeMappings = application.getScopeMappings(); Stream<RoleModel> scopeMappings = Stream.concat(application.getScopeMappingsStream(), application.getRolesStream());
Set<RoleModel> appRoles = application.getRoles();
if (appRoles != null) scopeMappings.addAll(appRoles);
for (RoleModel role : roleMappings) { scopeMappings.forEach(scope -> roleMappings.forEach(role -> {
if (role.getContainer().equals(application)) requestedRoles.add(role); if (role.getContainer().equals(application)) requestedRoles.add(role);
for (RoleModel desiredRole : scopeMappings) {
Set<RoleModel> visited = new HashSet<>(); Set<RoleModel> visited = new HashSet<>();
applyScope(role, desiredRole, visited, requestedRoles); applyScope(role, scope, visited, requestedRoles);
} }));
}
return requestedRoles; return requestedRoles;
} }

View file

@ -24,7 +24,6 @@ import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
/** /**
@ -35,12 +34,12 @@ public class TestCacheUtils {
public static void cacheRealmWithEverything(KeycloakSession session, String realmName) { public static void cacheRealmWithEverything(KeycloakSession session, String realmName) {
RealmModel realm = session.realms().getRealmByName(realmName); RealmModel realm = session.realms().getRealmByName(realmName);
for (ClientModel client : realm.getClients()) { realm.getClientsStream().forEach(c -> {
realm.getClientById(client.getId()); realm.getClientById(c.getId());
realm.getClientByClientId(client.getClientId()); realm.getClientByClientId(c.getClientId());
cacheRoles(session, realm, client); cacheRoles(session, realm, c);
} });
cacheRoles(session, realm, realm); cacheRoles(session, realm, realm);
@ -66,7 +65,7 @@ public class TestCacheUtils {
} }
private static void cacheRoles(KeycloakSession session, RealmModel realm, RoleContainerModel roleContainer) { private static void cacheRoles(KeycloakSession session, RealmModel realm, RoleContainerModel roleContainer) {
for (RoleModel role : roleContainer.getRoles()) { roleContainer.getRolesStream().forEach(role -> {
realm.getRoleById(role.getId()); realm.getRoleById(role.getId());
roleContainer.getRole(role.getName()); roleContainer.getRole(role.getName());
if (roleContainer instanceof RealmModel) { if (roleContainer instanceof RealmModel) {
@ -74,7 +73,7 @@ public class TestCacheUtils {
} else { } else {
session.roles().getClientRole((ClientModel) roleContainer, role.getName()); session.roles().getClientRole((ClientModel) roleContainer, role.getName());
} }
} });
} }
private static void cacheGroupRecursive(RealmModel realm, GroupModel group) { private static void cacheGroupRecursive(RealmModel realm, GroupModel group) {