KEYCLOAK-14901 Replace deprecated ClientProvider related methods across Keycloak
This commit is contained in:
parent
76f7fbb984
commit
4e9bdd44f3
52 changed files with 419 additions and 489 deletions
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ****************/
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue