KEYCLOAK-15889 Streamification of ProtocolMappers
This commit is contained in:
parent
e6bd12b174
commit
d9029b06b9
32 changed files with 363 additions and 431 deletions
|
@ -357,9 +357,9 @@ public class ClientAdapter implements ClientModel, CachedObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
if (isUpdated()) return updated.getProtocolMappers();
|
if (isUpdated()) return updated.getProtocolMappersStream();
|
||||||
return cached.getProtocolMappers();
|
return cached.getProtocolMappers().stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.keycloak.models.utils.RoleUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,9 +78,9 @@ public class ClientScopeAdapter implements ClientScopeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
if (isUpdated()) return updated.getProtocolMappers();
|
if (isUpdated()) return updated.getProtocolMappersStream();
|
||||||
return cached.getProtocolMappers();
|
return cached.getProtocolMappers().stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -94,9 +94,7 @@ public class CachedClient extends AbstractRevisioned implements InRealm {
|
||||||
redirectUris.addAll(model.getRedirectUris());
|
redirectUris.addAll(model.getRedirectUris());
|
||||||
webOrigins.addAll(model.getWebOrigins());
|
webOrigins.addAll(model.getWebOrigins());
|
||||||
scope.addAll(model.getScopeMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()));
|
scope.addAll(model.getScopeMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()));
|
||||||
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
protocolMappers.addAll(model.getProtocolMappersStream().collect(Collectors.toSet()));
|
||||||
this.protocolMappers.add(mapper);
|
|
||||||
}
|
|
||||||
surrogateAuthRequired = model.isSurrogateAuthRequired();
|
surrogateAuthRequired = model.isSurrogateAuthRequired();
|
||||||
managementUrl = model.getManagementUrl();
|
managementUrl = model.getManagementUrl();
|
||||||
rootUrl = model.getRootUrl();
|
rootUrl = model.getRootUrl();
|
||||||
|
|
|
@ -48,9 +48,7 @@ public class CachedClientScope extends AbstractRevisioned implements InRealm {
|
||||||
description = model.getDescription();
|
description = model.getDescription();
|
||||||
this.realm = realm.getId();
|
this.realm = realm.getId();
|
||||||
protocol = model.getProtocol();
|
protocol = model.getProtocol();
|
||||||
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
protocolMappers.addAll(model.getProtocolMappersStream().collect(Collectors.toSet()));
|
||||||
this.protocolMappers.add(mapper);
|
|
||||||
}
|
|
||||||
scope.addAll(model.getScopeMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()));
|
scope.addAll(model.getScopeMappingsStream().map(RoleModel::getId).collect(Collectors.toSet()));
|
||||||
attributes.putAll(model.getAttributes());
|
attributes.putAll(model.getAttributes());
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,22 +400,22 @@ public class ClientAdapter implements ClientModel, JpaModel<ClientEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
Set<ProtocolMapperModel> mappings = new HashSet<ProtocolMapperModel>();
|
return this.entity.getProtocolMappers().stream()
|
||||||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
.map(entity -> {
|
||||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||||
mapping.setId(entity.getId());
|
mapping.setId(entity.getId());
|
||||||
mapping.setName(entity.getName());
|
mapping.setName(entity.getName());
|
||||||
mapping.setProtocol(entity.getProtocol());
|
mapping.setProtocol(entity.getProtocol());
|
||||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||||
Map<String, String> config = new HashMap<String, String>();
|
Map<String, String> config = new HashMap<>();
|
||||||
if (entity.getConfig() != null) {
|
if (entity.getConfig() != null) {
|
||||||
config.putAll(entity.getConfig());
|
config.putAll(entity.getConfig());
|
||||||
}
|
}
|
||||||
mapping.setConfig(config);
|
mapping.setConfig(config);
|
||||||
mappings.add(mapping);
|
return mapping;
|
||||||
}
|
})
|
||||||
return mappings;
|
.distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,11 +32,9 @@ import org.keycloak.models.utils.RoleUtils;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,22 +98,22 @@ public class ClientScopeAdapter implements ClientScopeModel, JpaModel<ClientScop
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
Set<ProtocolMapperModel> mappings = new HashSet<ProtocolMapperModel>();
|
return this.entity.getProtocolMappers().stream()
|
||||||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
.map(entity -> {
|
||||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||||
mapping.setId(entity.getId());
|
mapping.setId(entity.getId());
|
||||||
mapping.setName(entity.getName());
|
mapping.setName(entity.getName());
|
||||||
mapping.setProtocol(entity.getProtocol());
|
mapping.setProtocol(entity.getProtocol());
|
||||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||||
Map<String, String> config = new HashMap<String, String>();
|
Map<String, String> config = new HashMap<>();
|
||||||
if (entity.getConfig() != null) {
|
if (entity.getConfig() != null) {
|
||||||
config.putAll(entity.getConfig());
|
config.putAll(entity.getConfig());
|
||||||
}
|
}
|
||||||
mapping.setConfig(config);
|
mapping.setConfig(config);
|
||||||
mappings.add(mapping);
|
return mapping;
|
||||||
}
|
})
|
||||||
return mappings;
|
.distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,10 +26,7 @@ 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.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
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;
|
||||||
|
@ -478,8 +475,8 @@ public abstract class MapClientAdapter extends AbstractClientModel<MapClientEnti
|
||||||
/*************** Protocol mappers ****************/
|
/*************** Protocol mappers ****************/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
return Collections.unmodifiableSet(new HashSet<>(entity.getProtocolMappers()));
|
return entity.getProtocolMappers().stream().distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
|
|
||||||
package org.keycloak.migration.migrators;
|
package org.keycloak.migration.migrators;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.OAuthErrorException;
|
import org.keycloak.OAuthErrorException;
|
||||||
|
@ -29,7 +26,6 @@ import org.keycloak.models.ClientScopeModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperContainerModel;
|
import org.keycloak.models.ProtocolMapperContainerModel;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredActionProviderModel;
|
import org.keycloak.models.RequiredActionProviderModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
@ -71,17 +67,10 @@ public class MigrationUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateProtocolMappers(ProtocolMapperContainerModel client) {
|
public static void updateProtocolMappers(ProtocolMapperContainerModel client) {
|
||||||
List<ProtocolMapperModel> toUpdate = new LinkedList<>();
|
client.getProtocolMappersStream()
|
||||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
.filter(mapper -> !mapper.getConfig().containsKey("userinfo.token.claim") && mapper.getConfig().containsKey("id.token.claim"))
|
||||||
if (!mapper.getConfig().containsKey("userinfo.token.claim") && mapper.getConfig().containsKey("id.token.claim")) {
|
.peek(mapper -> mapper.getConfig().put("userinfo.token.claim", mapper.getConfig().get("id.token.claim")))
|
||||||
mapper.getConfig().put("userinfo.token.claim", mapper.getConfig().get("id.token.claim"));
|
.forEach(client::updateProtocolMapper);
|
||||||
toUpdate.add(mapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ProtocolMapperModel mapper : toUpdate) {
|
|
||||||
client.updateProtocolMapper(mapper);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -555,13 +555,10 @@ public class ModelToRepresentation {
|
||||||
rep.setName(clientScopeModel.getName());
|
rep.setName(clientScopeModel.getName());
|
||||||
rep.setDescription(clientScopeModel.getDescription());
|
rep.setDescription(clientScopeModel.getDescription());
|
||||||
rep.setProtocol(clientScopeModel.getProtocol());
|
rep.setProtocol(clientScopeModel.getProtocol());
|
||||||
if (!clientScopeModel.getProtocolMappers().isEmpty()) {
|
List<ProtocolMapperRepresentation> mappings = clientScopeModel.getProtocolMappersStream()
|
||||||
List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
|
.map(ModelToRepresentation::toRepresentation).collect(Collectors.toList());
|
||||||
for (ProtocolMapperModel model : clientScopeModel.getProtocolMappers()) {
|
if (!mappings.isEmpty())
|
||||||
mappings.add(toRepresentation(model));
|
|
||||||
}
|
|
||||||
rep.setProtocolMappers(mappings);
|
rep.setProtocolMappers(mappings);
|
||||||
}
|
|
||||||
|
|
||||||
rep.setAttributes(new HashMap<>(clientScopeModel.getAttributes()));
|
rep.setAttributes(new HashMap<>(clientScopeModel.getAttributes()));
|
||||||
|
|
||||||
|
@ -621,13 +618,10 @@ public class ModelToRepresentation {
|
||||||
rep.setRegisteredNodes(new HashMap<>(clientModel.getRegisteredNodes()));
|
rep.setRegisteredNodes(new HashMap<>(clientModel.getRegisteredNodes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clientModel.getProtocolMappers().isEmpty()) {
|
List<ProtocolMapperRepresentation> mappings = clientModel.getProtocolMappersStream()
|
||||||
List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
|
.map(ModelToRepresentation::toRepresentation).collect(Collectors.toList());
|
||||||
for (ProtocolMapperModel model : clientModel.getProtocolMappers()) {
|
if (!mappings.isEmpty())
|
||||||
mappings.add(toRepresentation(model));
|
|
||||||
}
|
|
||||||
rep.setProtocolMappers(mappings);
|
rep.setProtocolMappers(mappings);
|
||||||
}
|
|
||||||
|
|
||||||
AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
|
AuthorizationProvider authorization = session.getProvider(AuthorizationProvider.class);
|
||||||
ResourceServer resourceServer = authorization.getStoreFactory().getResourceServerStore().findById(clientModel.getId());
|
ResourceServer resourceServer = authorization.getStoreFactory().getResourceServerStore().findById(clientModel.getId());
|
||||||
|
|
|
@ -1414,8 +1414,7 @@ public class RepresentationToModel {
|
||||||
|
|
||||||
if (resourceRep.getProtocolMappers() != null) {
|
if (resourceRep.getProtocolMappers() != null) {
|
||||||
// first, remove all default/built in mappers
|
// first, remove all default/built in mappers
|
||||||
Set<ProtocolMapperModel> mappers = client.getProtocolMappers();
|
client.getProtocolMappersStream().collect(Collectors.toList()).forEach(client::removeProtocolMapper);
|
||||||
for (ProtocolMapperModel mapper : mappers) client.removeProtocolMapper(mapper);
|
|
||||||
|
|
||||||
for (ProtocolMapperRepresentation mapper : resourceRep.getProtocolMappers()) {
|
for (ProtocolMapperRepresentation mapper : resourceRep.getProtocolMappers()) {
|
||||||
client.addProtocolMapper(toModel(mapper));
|
client.addProtocolMapper(toModel(mapper));
|
||||||
|
@ -1556,10 +1555,10 @@ public class RepresentationToModel {
|
||||||
public static void updateClientProtocolMappers(ClientRepresentation rep, ClientModel resource) {
|
public static void updateClientProtocolMappers(ClientRepresentation rep, ClientModel resource) {
|
||||||
|
|
||||||
if (rep.getProtocolMappers() != null) {
|
if (rep.getProtocolMappers() != null) {
|
||||||
Map<String,ProtocolMapperModel> existingProtocolMappers = new HashMap<>();
|
Map<String,ProtocolMapperModel> existingProtocolMappers =
|
||||||
for (ProtocolMapperModel existingProtocolMapper : resource.getProtocolMappers()) {
|
resource.getProtocolMappersStream().collect(Collectors.toMap(mapper ->
|
||||||
existingProtocolMappers.put(generateProtocolNameKey(existingProtocolMapper.getProtocol(), existingProtocolMapper.getName()), existingProtocolMapper);
|
generateProtocolNameKey(mapper.getProtocol(), mapper.getName()), Function.identity()));
|
||||||
}
|
|
||||||
|
|
||||||
for (ProtocolMapperRepresentation protocolMapperRepresentation : rep.getProtocolMappers()) {
|
for (ProtocolMapperRepresentation protocolMapperRepresentation : rep.getProtocolMappers()) {
|
||||||
String protocolNameKey = generateProtocolNameKey(protocolMapperRepresentation.getProtocol(), protocolMapperRepresentation.getName());
|
String protocolNameKey = generateProtocolNameKey(protocolMapperRepresentation.getProtocol(), protocolMapperRepresentation.getName());
|
||||||
|
@ -1606,8 +1605,7 @@ public class RepresentationToModel {
|
||||||
if (resourceRep.getProtocol() != null) clientScope.setProtocol(resourceRep.getProtocol());
|
if (resourceRep.getProtocol() != null) clientScope.setProtocol(resourceRep.getProtocol());
|
||||||
if (resourceRep.getProtocolMappers() != null) {
|
if (resourceRep.getProtocolMappers() != null) {
|
||||||
// first, remove all default/built in mappers
|
// first, remove all default/built in mappers
|
||||||
Set<ProtocolMapperModel> mappers = clientScope.getProtocolMappers();
|
clientScope.getProtocolMappersStream().collect(Collectors.toList()).forEach(clientScope::removeProtocolMapper);
|
||||||
for (ProtocolMapperModel mapper : mappers) clientScope.removeProtocolMapper(mapper);
|
|
||||||
|
|
||||||
for (ProtocolMapperRepresentation mapper : resourceRep.getProtocolMappers()) {
|
for (ProtocolMapperRepresentation mapper : resourceRep.getProtocolMappers()) {
|
||||||
clientScope.addProtocolMapper(toModel(mapper));
|
clientScope.addProtocolMapper(toModel(mapper));
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.storage.ReadOnlyException;
|
import org.keycloak.storage.ReadOnlyException;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,7 +32,20 @@ public interface ClientSessionContext {
|
||||||
|
|
||||||
Set<String> getClientScopeIds();
|
Set<String> getClientScopeIds();
|
||||||
|
|
||||||
Set<ClientScopeModel> getClientScopes();
|
/**
|
||||||
|
* @deprecated Use {@link #getClientScopesStream() getClientScopesStream} instead.
|
||||||
|
* @return Set of protocol mappers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Set<ClientScopeModel> getClientScopes() {
|
||||||
|
return getClientScopesStream().collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns client scopes as a stream.
|
||||||
|
* @return Stream of client scopes.
|
||||||
|
*/
|
||||||
|
Stream<ClientScopeModel> getClientScopesStream();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return expanded roles (composite roles already applied)
|
* @return expanded roles (composite roles already applied)
|
||||||
|
@ -44,7 +57,20 @@ public interface ClientSessionContext {
|
||||||
|
|
||||||
Stream<RoleModel> getRolesStream();
|
Stream<RoleModel> getRolesStream();
|
||||||
|
|
||||||
Set<ProtocolMapperModel> getProtocolMappers();
|
/**
|
||||||
|
* @deprecated Use {@link #getProtocolMappersStream() getProtocolMappersStream} instead.
|
||||||
|
* @return Set of protocol mappers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Set<ProtocolMapperModel> getProtocolMappers() {
|
||||||
|
return getProtocolMappersStream().collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns protocol mappers as a stream.
|
||||||
|
* @return Stream of protocol mappers.
|
||||||
|
*/
|
||||||
|
Stream<ProtocolMapperModel> getProtocolMappersStream();
|
||||||
|
|
||||||
String getScopeString();
|
String getScopeString();
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,28 @@
|
||||||
package org.keycloak.models;
|
package org.keycloak.models;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
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>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface ProtocolMapperContainerModel {
|
public interface ProtocolMapperContainerModel {
|
||||||
Set<ProtocolMapperModel> getProtocolMappers();
|
/**
|
||||||
|
* @deprecated Use {@link #getProtocolMappersStream() getProtocolMappersStream} instead.
|
||||||
|
* @return Set of protocol mappers
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Set<ProtocolMapperModel> getProtocolMappers() {
|
||||||
|
return getProtocolMappersStream().collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns protocol mappers as a stream.
|
||||||
|
* @return Stream of protocol mapper.
|
||||||
|
*/
|
||||||
|
Stream<ProtocolMapperModel> getProtocolMappersStream();
|
||||||
|
|
||||||
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -57,9 +58,10 @@ public class ApplicationsBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct scope parameter with all optional scopes to see all potentially available roles
|
// Construct scope parameter with all optional scopes to see all potentially available roles
|
||||||
Set<ClientScopeModel> allClientScopes = new HashSet<>(client.getClientScopes(true, true).values());
|
Stream<ClientScopeModel> allClientScopes = Stream.concat(
|
||||||
allClientScopes.addAll(client.getClientScopes(false, true).values());
|
client.getClientScopes(true, true).values().stream(),
|
||||||
allClientScopes.add(client);
|
client.getClientScopes(false, true).values().stream());
|
||||||
|
allClientScopes = Stream.concat(allClientScopes, Stream.of(client)).distinct();
|
||||||
|
|
||||||
Set<RoleModel> availableRoles = TokenManager.getAccess(user, client, allClientScopes);
|
Set<RoleModel> availableRoles = TokenManager.getAccess(user, client, allClientScopes);
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,10 @@ import org.keycloak.provider.ProviderFactory;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Map.Entry;
|
||||||
import java.util.stream.Collectors;
|
import java.util.Objects;
|
||||||
|
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>
|
||||||
|
@ -123,27 +123,22 @@ public class ProtocolMapperUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static List<Map.Entry<ProtocolMapperModel, ProtocolMapper>> getSortedProtocolMappers(KeycloakSession session, ClientSessionContext ctx) {
|
public static Stream<Entry<ProtocolMapperModel, ProtocolMapper>> getSortedProtocolMappers(KeycloakSession session, ClientSessionContext ctx) {
|
||||||
Set<ProtocolMapperModel> mapperModels = ctx.getProtocolMappers();
|
|
||||||
Map<ProtocolMapperModel, ProtocolMapper> result = new HashMap<>();
|
|
||||||
|
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
for (ProtocolMapperModel mapperModel : mapperModels) {
|
return ctx.getProtocolMappersStream()
|
||||||
ProtocolMapper mapper = (ProtocolMapper) sessionFactory.getProviderFactory(ProtocolMapper.class, mapperModel.getProtocolMapper());
|
.flatMap(mapperModel -> {
|
||||||
if (mapper == null) {
|
ProtocolMapper mapper = (ProtocolMapper) sessionFactory.getProviderFactory(ProtocolMapper.class, mapperModel.getProtocolMapper());
|
||||||
continue;
|
if (mapper == null)
|
||||||
}
|
return null;
|
||||||
|
Map<ProtocolMapperModel, ProtocolMapper> protocolMapperMap = new HashMap<>();
|
||||||
result.put(mapperModel, mapper);
|
protocolMapperMap.put(mapperModel, mapper);
|
||||||
}
|
return protocolMapperMap.entrySet().stream();
|
||||||
|
})
|
||||||
return result.entrySet()
|
.filter(Objects::nonNull)
|
||||||
.stream()
|
.sorted(Comparator.comparing(ProtocolMapperUtils::compare));
|
||||||
.sorted(Comparator.comparing(ProtocolMapperUtils::compare))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(Map.Entry<ProtocolMapperModel, ProtocolMapper> entry) {
|
public static int compare(Entry<ProtocolMapperModel, ProtocolMapper> entry) {
|
||||||
int priority = entry.getValue().getPriority();
|
int priority = entry.getValue().getPriority();
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,10 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientSessionContext;
|
import org.keycloak.models.ClientSessionContext;
|
||||||
import org.keycloak.models.KeyManager;
|
import org.keycloak.models.KeyManager;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.LoginProtocol;
|
import org.keycloak.protocol.LoginProtocol;
|
||||||
import org.keycloak.protocol.ProtocolMapper;
|
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.protocol.docker.mapper.DockerAuthV2AttributeMapper;
|
import org.keycloak.protocol.docker.mapper.DockerAuthV2AttributeMapper;
|
||||||
import org.keycloak.representations.docker.DockerResponse;
|
import org.keycloak.representations.docker.DockerResponse;
|
||||||
|
@ -30,7 +28,7 @@ import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public class DockerAuthV2Protocol implements LoginProtocol {
|
public class DockerAuthV2Protocol implements LoginProtocol {
|
||||||
protected static final Logger logger = Logger.getLogger(DockerEndpoint.class);
|
protected static final Logger logger = Logger.getLogger(DockerEndpoint.class);
|
||||||
|
@ -111,17 +109,13 @@ public class DockerAuthV2Protocol implements LoginProtocol {
|
||||||
|
|
||||||
// Next, allow mappers to decorate the token to add/remove scopes as appropriate
|
// Next, allow mappers to decorate the token to add/remove scopes as appropriate
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
AtomicReference<DockerResponseToken> finalResponseToken = new AtomicReference<>(responseToken);
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapper mapper = entry.getValue();
|
.filter(mapper -> mapper.getValue() instanceof DockerAuthV2AttributeMapper)
|
||||||
|
.filter(mapper -> ((DockerAuthV2AttributeMapper) mapper.getValue()).appliesTo(finalResponseToken.get()))
|
||||||
if (mapper instanceof DockerAuthV2AttributeMapper) {
|
.forEach(mapper -> finalResponseToken.set(((DockerAuthV2AttributeMapper) mapper.getValue())
|
||||||
final DockerAuthV2AttributeMapper dockerAttributeMapper = (DockerAuthV2AttributeMapper) mapper;
|
.transformDockerResponseToken(finalResponseToken.get(), mapper.getKey(), session, userSession, clientSession)));
|
||||||
if (dockerAttributeMapper.appliesTo(responseToken)) {
|
responseToken = finalResponseToken.get();
|
||||||
responseToken = dockerAttributeMapper.transformDockerResponseToken(responseToken, mapping, session, userSession, clientSession);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Finally, construct the response to the docker client with the token + metadata
|
// Finally, construct the response to the docker client with the token + metadata
|
||||||
|
|
|
@ -43,7 +43,6 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientScopeModel;
|
import org.keycloak.models.ClientScopeModel;
|
||||||
import org.keycloak.models.ClientSessionContext;
|
import org.keycloak.models.ClientSessionContext;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.TokenRevocationStoreProvider;
|
import org.keycloak.models.TokenRevocationStoreProvider;
|
||||||
|
@ -53,7 +52,6 @@ import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.models.UserSessionProvider;
|
import org.keycloak.models.UserSessionProvider;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.RoleUtils;
|
import org.keycloak.models.utils.RoleUtils;
|
||||||
import org.keycloak.protocol.ProtocolMapper;
|
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
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;
|
||||||
|
@ -78,11 +76,13 @@ import org.keycloak.util.TokenUtil;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
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.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ public class TokenManager {
|
||||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
|
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
|
||||||
|
|
||||||
// Check user didn't revoke granted consent
|
// Check user didn't revoke granted consent
|
||||||
if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopes())) {
|
if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopesStream())) {
|
||||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
|
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Set<RoleModel> getAccess(UserModel user, ClientModel client, Set<ClientScopeModel> clientScopes) {
|
public static Set<RoleModel> getAccess(UserModel user, ClientModel client, Stream<ClientScopeModel> clientScopes) {
|
||||||
Set<RoleModel> roleMappings = RoleUtils.getDeepUserRoleMappings(user);
|
Set<RoleModel> roleMappings = RoleUtils.getDeepUserRoleMappings(user);
|
||||||
|
|
||||||
if (client.isFullScopeAllowed()) {
|
if (client.isFullScopeAllowed()) {
|
||||||
|
@ -525,12 +525,17 @@ public class TokenManager {
|
||||||
Stream<RoleModel> scopeMappings = client.getRolesStream();
|
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) {
|
Stream<RoleModel> clientScopesMappings;
|
||||||
if (logger.isTraceEnabled()) {
|
if (!logger.isTraceEnabled()) {
|
||||||
logger.tracef("Adding client scope role mappings of client scope '%s' to client '%s'", clientScope.getName(), client.getClientId());
|
clientScopesMappings = clientScopes.flatMap(clientScope -> clientScope.getScopeMappingsStream());
|
||||||
}
|
} else {
|
||||||
scopeMappings = Stream.concat(scopeMappings, clientScope.getScopeMappingsStream());
|
clientScopesMappings = clientScopes.flatMap(clientScope -> {
|
||||||
|
logger.tracef("Adding client scope role mappings of client scope '%s' to client '%s'",
|
||||||
|
clientScope.getName(), client.getClientId());
|
||||||
|
return clientScope.getScopeMappingsStream();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
scopeMappings = Stream.concat(scopeMappings, clientScopesMappings);
|
||||||
|
|
||||||
// 3 - Expand scope mappings
|
// 3 - Expand scope mappings
|
||||||
scopeMappings = RoleUtils.expandCompositeRolesStream(scopeMappings);
|
scopeMappings = RoleUtils.expandCompositeRolesStream(scopeMappings);
|
||||||
|
@ -544,28 +549,20 @@ public class TokenManager {
|
||||||
|
|
||||||
|
|
||||||
/** Return client itself + all default client scopes of client + optional client scopes requested by scope parameter **/
|
/** Return client itself + all default client scopes of client + optional client scopes requested by scope parameter **/
|
||||||
public static Set<ClientScopeModel> getRequestedClientScopes(String scopeParam, ClientModel client) {
|
public static Stream<ClientScopeModel> getRequestedClientScopes(String scopeParam, ClientModel client) {
|
||||||
// Add all default client scopes automatically
|
// Add all default client scopes automatically and client itself
|
||||||
Set<ClientScopeModel> clientScopes = new HashSet<>(client.getClientScopes(true, true).values());
|
Stream<ClientScopeModel> clientScopes = Stream.concat(
|
||||||
|
client.getClientScopes(true, true).values().stream(),
|
||||||
// Add client itself
|
Stream.of(client)).distinct();
|
||||||
clientScopes.add(client);
|
|
||||||
|
|
||||||
if (scopeParam == null) {
|
if (scopeParam == null) {
|
||||||
return clientScopes;
|
return clientScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add optional client scopes requested by scope parameter
|
|
||||||
Collection<String> scopeParamParts = parseScopeParameter(scopeParam);
|
|
||||||
Map<String, ClientScopeModel> allOptionalScopes = client.getClientScopes(false, true);
|
Map<String, ClientScopeModel> allOptionalScopes = client.getClientScopes(false, true);
|
||||||
for (String scopeParamPart : scopeParamParts) {
|
// Add optional client scopes requested by scope parameter
|
||||||
ClientScopeModel scope = allOptionalScopes.get(scopeParamPart);
|
return Stream.concat(parseScopeParameter(scopeParam).map(allOptionalScopes::get).filter(Objects::nonNull),
|
||||||
if (scope != null) {
|
clientScopes).distinct();
|
||||||
clientScopes.add(scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientScopes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isValidScope(String scopes, ClientModel client) {
|
public static boolean isValidScope(String scopes, ClientModel client) {
|
||||||
|
@ -573,11 +570,11 @@ public class TokenManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> clientScopes = getRequestedClientScopes(scopes, client).stream()
|
Set<String> clientScopes = getRequestedClientScopes(scopes, client)
|
||||||
.filter(obj -> !ClientModel.class.isInstance(obj))
|
.filter(((Predicate<ClientScopeModel>) ClientModel.class::isInstance).negate())
|
||||||
.map(ClientScopeModel::getName)
|
.map(ClientScopeModel::getName)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
Collection<String> requestedScopes = TokenManager.parseScopeParameter(scopes);
|
Collection<String> requestedScopes = TokenManager.parseScopeParameter(scopes).collect(Collectors.toSet());
|
||||||
|
|
||||||
if (TokenUtil.isOIDCRequest(scopes)) {
|
if (TokenUtil.isOIDCRequest(scopes)) {
|
||||||
requestedScopes.remove(OAuth2Constants.SCOPE_OPENID);
|
requestedScopes.remove(OAuth2Constants.SCOPE_OPENID);
|
||||||
|
@ -597,73 +594,61 @@ public class TokenManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<String> parseScopeParameter(String scopeParam) {
|
public static Stream<String> parseScopeParameter(String scopeParam) {
|
||||||
return new HashSet<>(Arrays.asList(scopeParam.split(" ")));
|
return Arrays.stream(scopeParam.split(" ")).distinct();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user still has granted consents to all requested client scopes
|
// Check if user still has granted consents to all requested client scopes
|
||||||
public static boolean verifyConsentStillAvailable(KeycloakSession session, UserModel user, ClientModel client, Set<ClientScopeModel> requestedClientScopes) {
|
public static boolean verifyConsentStillAvailable(KeycloakSession session, UserModel user, ClientModel client,
|
||||||
|
Stream<ClientScopeModel> requestedClientScopes) {
|
||||||
if (!client.isConsentRequired()) {
|
if (!client.isConsentRequired()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserConsentModel grantedConsent = session.users().getConsentByClient(client.getRealm(), user.getId(), client.getId());
|
UserConsentModel grantedConsent = session.users().getConsentByClient(client.getRealm(), user.getId(), client.getId());
|
||||||
|
|
||||||
for (ClientScopeModel requestedScope : requestedClientScopes) {
|
return requestedClientScopes
|
||||||
if (!requestedScope.isDisplayOnConsentScreen()) {
|
.filter(ClientScopeModel::isDisplayOnConsentScreen)
|
||||||
continue;
|
.noneMatch(requestedScope -> {
|
||||||
}
|
if (grantedConsent == null || !grantedConsent.getGrantedClientScopes().contains(requestedScope)) {
|
||||||
|
logger.debugf("Client '%s' no longer has requested consent from user '%s' for client scope '%s'",
|
||||||
if (grantedConsent == null || !grantedConsent.getGrantedClientScopes().contains(requestedScope)) {
|
client.getClientId(), user.getUsername(), requestedScope.getName());
|
||||||
logger.debugf("Client '%s' no longer has requested consent from user '%s' for client scope '%s'",
|
return true;
|
||||||
client.getClientId(), user.getUsername(), requestedScope.getName());
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessToken transformAccessToken(KeycloakSession session, AccessToken token,
|
public AccessToken transformAccessToken(KeycloakSession session, AccessToken token,
|
||||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
AtomicReference<AccessToken> finalToken = new AtomicReference<>(token);
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapper mapper = entry.getValue();
|
.filter(mapper -> mapper.getValue() instanceof OIDCAccessTokenMapper)
|
||||||
if (mapper instanceof OIDCAccessTokenMapper) {
|
.forEach(mapper -> finalToken.set(((OIDCAccessTokenMapper) mapper.getValue())
|
||||||
token = ((OIDCAccessTokenMapper) mapper).transformAccessToken(token, mapping, session, userSession, clientSessionCtx);
|
.transformAccessToken(finalToken.get(), mapper.getKey(), session, userSession, clientSessionCtx)));
|
||||||
}
|
return finalToken.get();
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessToken transformUserInfoAccessToken(KeycloakSession session, AccessToken token,
|
public AccessToken transformUserInfoAccessToken(KeycloakSession session, AccessToken token,
|
||||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
AtomicReference<AccessToken> finalToken = new AtomicReference<>(token);
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapper mapper = entry.getValue();
|
.filter(mapper -> mapper.getValue() instanceof UserInfoTokenMapper)
|
||||||
|
.forEach(mapper -> finalToken.set(((UserInfoTokenMapper) mapper.getValue())
|
||||||
if (mapper instanceof UserInfoTokenMapper) {
|
.transformUserInfoToken(finalToken.get(), mapper.getKey(), session, userSession, clientSessionCtx)));
|
||||||
token = ((UserInfoTokenMapper) mapper).transformUserInfoToken(token, mapping, session, userSession, clientSessionCtx);
|
return finalToken.get();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void transformIDToken(KeycloakSession session, IDToken token,
|
public void transformIDToken(KeycloakSession session, IDToken token,
|
||||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
AtomicReference<IDToken> finalToken = new AtomicReference<>(token);
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapper mapper = entry.getValue();
|
.filter(mapper -> mapper.getValue() instanceof OIDCIDTokenMapper)
|
||||||
|
.forEach(mapper -> finalToken.set(((OIDCIDTokenMapper) mapper.getValue())
|
||||||
if (mapper instanceof OIDCIDTokenMapper) {
|
.transformIDToken(finalToken.get(), mapper.getKey(), session, userSession, clientSessionCtx)));
|
||||||
token = ((OIDCIDTokenMapper) mapper).transformIDToken(token, mapping, session, userSession, clientSessionCtx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session,
|
protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session,
|
||||||
|
|
|
@ -127,9 +127,11 @@ 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.Supplier;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
|
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
|
||||||
|
@ -420,13 +422,13 @@ public class TokenEndpoint {
|
||||||
// Compute client scopes again from scope parameter. Check if user still has them granted
|
// Compute client scopes again from scope parameter. Check if user still has them granted
|
||||||
// (but in code-to-token request, it could just theoretically happen that they are not available)
|
// (but in code-to-token request, it could just theoretically happen that they are not available)
|
||||||
String scopeParam = codeData.getScope();
|
String scopeParam = codeData.getScope();
|
||||||
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client);
|
Supplier<Stream<ClientScopeModel>> clientScopesSupplier = () -> TokenManager.getRequestedClientScopes(scopeParam, client);
|
||||||
if (!TokenManager.verifyConsentStillAvailable(session, user, client, clientScopes)) {
|
if (!TokenManager.verifyConsentStillAvailable(session, user, client, clientScopesSupplier.get())) {
|
||||||
event.error(Errors.NOT_ALLOWED);
|
event.error(Errors.NOT_ALLOWED);
|
||||||
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
|
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopes(clientSession, clientScopes, session);
|
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopes(clientSession, clientScopesSupplier.get(), session);
|
||||||
|
|
||||||
// Set nonce as an attribute in the ClientSessionContext. Will be used for the token generation
|
// Set nonce as an attribute in the ClientSessionContext. Will be used for the token generation
|
||||||
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, codeData.getNonce());
|
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, codeData.getNonce());
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.protocol.ClientInstallationProvider;
|
import org.keycloak.protocol.ClientInstallationProvider;
|
||||||
|
@ -41,6 +40,7 @@ import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -110,15 +110,11 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
|
||||||
// Check if there is client scope with audience protocol mapper created for particular client. If yes, admin wants verifying token audience
|
// Check if there is client scope with audience protocol mapper created for particular client. If yes, admin wants verifying token audience
|
||||||
String clientId = client.getClientId();
|
String clientId = client.getClientId();
|
||||||
|
|
||||||
return client.getRealm().getClientScopesStream().anyMatch(clientScope -> {
|
return client.getRealm().getClientScopesStream().anyMatch(clientScope ->
|
||||||
for (ProtocolMapperModel protocolMapper : clientScope.getProtocolMappers()) {
|
clientScope.getProtocolMappersStream().anyMatch(protocolMapper ->
|
||||||
if (AudienceProtocolMapper.PROVIDER_ID.equals(protocolMapper.getProtocolMapper()) &&
|
Objects.equals(protocolMapper.getProtocolMapper(), AudienceProtocolMapper.PROVIDER_ID) &&
|
||||||
(clientId.equals(protocolMapper.getConfig().get(AudienceProtocolMapper.INCLUDED_CLIENT_AUDIENCE)))) {
|
Objects.equals(clientId, protocolMapper.getConfig().get(AudienceProtocolMapper.INCLUDED_CLIENT_AUDIENCE)))
|
||||||
return true;
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -420,22 +421,23 @@ public class SamlProtocol implements LoginProtocol {
|
||||||
|
|
||||||
List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>();
|
List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>();
|
||||||
List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>();
|
List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>();
|
||||||
ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper = null;
|
AtomicReference<ProtocolMapperProcessor<SAMLRoleListMapper>> roleListMapper = new AtomicReference<>(null);
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
.forEach(entry -> {
|
||||||
ProtocolMapper mapper = entry.getValue();
|
ProtocolMapperModel mapping = entry.getKey();
|
||||||
|
ProtocolMapper mapper = entry.getValue();
|
||||||
|
|
||||||
if (mapper instanceof SAMLAttributeStatementMapper) {
|
if (mapper instanceof SAMLAttributeStatementMapper) {
|
||||||
attributeStatementMappers.add(new ProtocolMapperProcessor<SAMLAttributeStatementMapper>((SAMLAttributeStatementMapper) mapper, mapping));
|
attributeStatementMappers.add(new ProtocolMapperProcessor<>((SAMLAttributeStatementMapper) mapper, mapping));
|
||||||
}
|
}
|
||||||
if (mapper instanceof SAMLLoginResponseMapper) {
|
if (mapper instanceof SAMLLoginResponseMapper) {
|
||||||
loginResponseMappers.add(new ProtocolMapperProcessor<SAMLLoginResponseMapper>((SAMLLoginResponseMapper) mapper, mapping));
|
loginResponseMappers.add(new ProtocolMapperProcessor<>((SAMLLoginResponseMapper) mapper, mapping));
|
||||||
}
|
}
|
||||||
if (mapper instanceof SAMLRoleListMapper) {
|
if (mapper instanceof SAMLRoleListMapper) {
|
||||||
roleListMapper = new ProtocolMapperProcessor<SAMLRoleListMapper>((SAMLRoleListMapper) mapper, mapping);
|
roleListMapper.set(new ProtocolMapperProcessor<>((SAMLRoleListMapper) mapper, mapping));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
Document samlDocument = null;
|
Document samlDocument = null;
|
||||||
KeyManager keyManager = session.keys();
|
KeyManager keyManager = session.keys();
|
||||||
|
@ -450,7 +452,7 @@ public class SamlProtocol implements LoginProtocol {
|
||||||
|
|
||||||
ResponseType samlModel = builder.buildModel();
|
ResponseType samlModel = builder.buildModel();
|
||||||
final AttributeStatementType attributeStatement = populateAttributeStatements(attributeStatementMappers, session, userSession, clientSession);
|
final AttributeStatementType attributeStatement = populateAttributeStatements(attributeStatementMappers, session, userSession, clientSession);
|
||||||
populateRoles(roleListMapper, session, userSession, clientSessionCtx, attributeStatement);
|
populateRoles(roleListMapper.get(), session, userSession, clientSessionCtx, attributeStatement);
|
||||||
|
|
||||||
// SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
|
// SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
|
||||||
if (attributeStatement.getAttributes().size() > 0) {
|
if (attributeStatement.getAttributes().size() > 0) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ 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.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,32 +113,34 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo
|
||||||
boolean singleAttribute = Boolean.parseBoolean(single);
|
boolean singleAttribute = Boolean.parseBoolean(single);
|
||||||
|
|
||||||
List<SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper>> roleNameMappers = new LinkedList<>();
|
List<SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper>> roleNameMappers = new LinkedList<>();
|
||||||
AttributeType singleAttributeType = null;
|
AtomicReference<AttributeType> singleAttributeType = new AtomicReference<>(null);
|
||||||
|
|
||||||
for (Map.Entry<ProtocolMapperModel, ProtocolMapper> entry : ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)) {
|
ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx)
|
||||||
ProtocolMapperModel mapping = entry.getKey();
|
.forEach(entry -> {
|
||||||
ProtocolMapper mapper = entry.getValue();
|
ProtocolMapperModel mapping = entry.getKey();
|
||||||
|
ProtocolMapper mapper = entry.getValue();
|
||||||
|
|
||||||
if (mapper instanceof SAMLRoleNameMapper) {
|
if (mapper instanceof SAMLRoleNameMapper) {
|
||||||
roleNameMappers.add(new SamlProtocol.ProtocolMapperProcessor<>((SAMLRoleNameMapper) mapper,mapping));
|
roleNameMappers.add(new SamlProtocol.ProtocolMapperProcessor<>((SAMLRoleNameMapper) mapper,mapping));
|
||||||
}
|
|
||||||
|
|
||||||
if (mapper instanceof HardcodedRole) {
|
|
||||||
AttributeType attributeType;
|
|
||||||
if (singleAttribute) {
|
|
||||||
if (singleAttributeType == null) {
|
|
||||||
singleAttributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
|
||||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType));
|
|
||||||
}
|
}
|
||||||
attributeType = singleAttributeType;
|
|
||||||
} else {
|
|
||||||
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
|
||||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
|
||||||
}
|
|
||||||
|
|
||||||
attributeType.addAttributeValue(mapping.getConfig().get(HardcodedRole.ROLE_ATTRIBUTE));
|
if (mapper instanceof HardcodedRole) {
|
||||||
}
|
AttributeType attributeType;
|
||||||
}
|
if (singleAttribute) {
|
||||||
|
if (singleAttributeType.get() == null) {
|
||||||
|
singleAttributeType.set(AttributeStatementHelper.createAttributeType(mappingModel));
|
||||||
|
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType.get()));
|
||||||
|
}
|
||||||
|
attributeType = singleAttributeType.get();
|
||||||
|
} else {
|
||||||
|
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
||||||
|
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
||||||
|
}
|
||||||
|
|
||||||
|
attributeType.addAttributeValue(mapping.getConfig().get(HardcodedRole.ROLE_ATTRIBUTE));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
List<String> allRoleNames = clientSessionCtx.getRolesStream()
|
List<String> allRoleNames = clientSessionCtx.getRolesStream()
|
||||||
// todo need a role mapping
|
// todo need a role mapping
|
||||||
|
@ -151,11 +154,11 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo
|
||||||
for (String roleName : allRoleNames) {
|
for (String roleName : allRoleNames) {
|
||||||
AttributeType attributeType;
|
AttributeType attributeType;
|
||||||
if (singleAttribute) {
|
if (singleAttribute) {
|
||||||
if (singleAttributeType == null) {
|
if (singleAttributeType.get() == null) {
|
||||||
singleAttributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
singleAttributeType.set(AttributeStatementHelper.createAttributeType(mappingModel));
|
||||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType));
|
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType.get()));
|
||||||
}
|
}
|
||||||
attributeType = singleAttributeType;
|
attributeType = singleAttributeType.get();
|
||||||
} else {
|
} else {
|
||||||
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
||||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
||||||
|
|
|
@ -48,9 +48,9 @@ import javax.ws.rs.Produces;
|
||||||
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.net.URI;
|
import java.net.URI;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
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>
|
||||||
|
@ -143,7 +143,7 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
|
||||||
// See if we have existing pairwise mapper and update it. Otherwise create new
|
// See if we have existing pairwise mapper and update it. Otherwise create new
|
||||||
AtomicBoolean foundPairwise = new AtomicBoolean(false);
|
AtomicBoolean foundPairwise = new AtomicBoolean(false);
|
||||||
|
|
||||||
clientModel.getProtocolMappers().stream().filter((ProtocolMapperModel mapping) -> {
|
clientModel.getProtocolMappersStream().filter((ProtocolMapperModel mapping) -> {
|
||||||
if (mapping.getProtocolMapper().endsWith(AbstractPairwiseSubMapper.PROVIDER_ID_SUFFIX)) {
|
if (mapping.getProtocolMapper().endsWith(AbstractPairwiseSubMapper.PROVIDER_ID_SUFFIX)) {
|
||||||
foundPairwise.set(true);
|
foundPairwise.set(true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -163,19 +163,16 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Rather find and remove all pairwise mappers
|
// Rather find and remove all pairwise mappers
|
||||||
clientModel.getProtocolMappers().stream().filter((ProtocolMapperModel mapperRep) -> {
|
clientModel.getProtocolMappersStream()
|
||||||
return mapperRep.getProtocolMapper().endsWith(AbstractPairwiseSubMapper.PROVIDER_ID_SUFFIX);
|
.filter(mapperRep -> mapperRep.getProtocolMapper().endsWith(AbstractPairwiseSubMapper.PROVIDER_ID_SUFFIX))
|
||||||
}).forEach((ProtocolMapperModel mapping) -> {
|
.collect(Collectors.toList())
|
||||||
clientModel.getProtocolMappers().remove(mapping);
|
.forEach(clientModel::removeProtocolMapper);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClientRepWithProtocolMappers(ClientModel clientModel, ClientRepresentation rep) {
|
private void updateClientRepWithProtocolMappers(ClientModel clientModel, ClientRepresentation rep) {
|
||||||
List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
|
List<ProtocolMapperRepresentation> mappings =
|
||||||
for (ProtocolMapperModel model : clientModel.getProtocolMappers()) {
|
clientModel.getProtocolMappersStream().map(ModelToRepresentation::toRepresentation).collect(Collectors.toList());
|
||||||
mappings.add(ModelToRepresentation.toRepresentation(model));
|
|
||||||
}
|
|
||||||
rep.setProtocolMappers(mappings);
|
rep.setProtocolMappers(mappings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,12 @@
|
||||||
package org.keycloak.services.clientregistration.policy.impl;
|
package org.keycloak.services.clientregistration.policy.impl;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
|
||||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
import org.keycloak.services.clientregistration.ClientRegistrationContext;
|
||||||
|
@ -75,19 +74,12 @@ public class ProtocolMappersClientRegistrationPolicy implements ClientRegistrati
|
||||||
public void afterRegister(ClientRegistrationContext context, ClientModel clientModel) {
|
public void afterRegister(ClientRegistrationContext context, ClientModel clientModel) {
|
||||||
// Remove mappers of unsupported type, which were added "automatically"
|
// Remove mappers of unsupported type, which were added "automatically"
|
||||||
List<String> allowedMapperProviders = getAllowedMapperProviders();
|
List<String> allowedMapperProviders = getAllowedMapperProviders();
|
||||||
Set<ProtocolMapperModel> createdMappers = clientModel.getProtocolMappers();
|
clientModel.getProtocolMappersStream()
|
||||||
|
.filter(mapper -> !allowedMapperProviders.contains(mapper.getProtocolMapper()))
|
||||||
createdMappers.stream().filter((ProtocolMapperModel mapper) -> {
|
.peek(mapperToRemove -> logger.debugf("Removing builtin mapper '%s' of type '%s' as type is not permitted",
|
||||||
|
mapperToRemove.getName(), mapperToRemove.getProtocolMapper()))
|
||||||
return !allowedMapperProviders.contains(mapper.getProtocolMapper());
|
.collect(Collectors.toList())
|
||||||
|
.forEach(clientModel::removeProtocolMapper);
|
||||||
}).forEach((ProtocolMapperModel mapperToRemove) -> {
|
|
||||||
|
|
||||||
logger.debugf("Removing builtin mapper '%s' of type '%s' as type is not permitted", mapperToRemove.getName(), mapperToRemove.getProtocolMapper());
|
|
||||||
clientModel.removeProtocolMapper(mapperToRemove);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't take already existing protocolMappers into consideration for now
|
// We don't take already existing protocolMappers into consideration for now
|
||||||
|
|
|
@ -91,7 +91,6 @@ import javax.ws.rs.core.UriInfo;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -1098,10 +1097,9 @@ public class AuthenticationManager {
|
||||||
// todo scope param protocol independent
|
// todo scope param protocol independent
|
||||||
String scopeParam = authSession.getClientNote(OAuth2Constants.SCOPE);
|
String scopeParam = authSession.getClientNote(OAuth2Constants.SCOPE);
|
||||||
|
|
||||||
Set<String> requestedClientScopes = new HashSet<String>();
|
Set<String> requestedClientScopes = TokenManager.getRequestedClientScopes(scopeParam, client)
|
||||||
for (ClientScopeModel clientScope : org.keycloak.protocol.oidc.TokenManager.getRequestedClientScopes(scopeParam, client)) {
|
.map(ClientScopeModel::getId).collect(Collectors.toSet());
|
||||||
requestedClientScopes.add(clientScope.getId());
|
|
||||||
}
|
|
||||||
authSession.setClientScopes(requestedClientScopes);
|
authSession.setClientScopes(requestedClientScopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
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>
|
||||||
|
@ -85,8 +86,7 @@ public class ClientManager {
|
||||||
|
|
||||||
// remove default mappers if there is a template
|
// remove default mappers if there is a template
|
||||||
if (rep.getProtocolMappers() == null && rep.getClientTemplate() != null) {
|
if (rep.getProtocolMappers() == null && rep.getClientTemplate() != null) {
|
||||||
Set<ProtocolMapperModel> mappers = client.getProtocolMappers();
|
client.getProtocolMappersStream().collect(Collectors.toList()).forEach(client::removeProtocolMapper);
|
||||||
for (ProtocolMapperModel mapper : mappers) client.removeProtocolMapper(mapper);
|
|
||||||
}
|
}
|
||||||
return client;
|
return client;
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,8 @@ package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
import static org.keycloak.protocol.ProtocolMapperUtils.isEnabled;
|
import static org.keycloak.protocol.ProtocolMapperUtils.isEnabled;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.Objects;
|
||||||
import java.util.List;
|
import java.util.stream.Stream;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
|
@ -114,43 +113,36 @@ public class ClientScopeEvaluateResource {
|
||||||
@Path("protocol-mappers")
|
@Path("protocol-mappers")
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<ProtocolMapperEvaluationRepresentation> getGrantedProtocolMappers(@QueryParam("scope") String scopeParam) {
|
public Stream<ProtocolMapperEvaluationRepresentation> getGrantedProtocolMappers(@QueryParam("scope") String scopeParam) {
|
||||||
auth.clients().requireView(client);
|
auth.clients().requireView(client);
|
||||||
|
|
||||||
List<ProtocolMapperEvaluationRepresentation> protocolMappers = new LinkedList<>();
|
return TokenManager.getRequestedClientScopes(scopeParam, client)
|
||||||
|
.flatMap(mapperContainer -> mapperContainer.getProtocolMappersStream()
|
||||||
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client);
|
.filter(current -> isEnabled(session, current) && Objects.equals(current.getProtocol(), client.getProtocol()))
|
||||||
|
.map(current -> toProtocolMapperEvaluationRepresentation(current, mapperContainer)));
|
||||||
for (ClientScopeModel mapperContainer : clientScopes) {
|
|
||||||
Set<ProtocolMapperModel> currentMappers = mapperContainer.getProtocolMappers();
|
|
||||||
for (ProtocolMapperModel current : currentMappers) {
|
|
||||||
if (isEnabled(session, current) && current.getProtocol().equals(client.getProtocol())) {
|
|
||||||
ProtocolMapperEvaluationRepresentation rep = new ProtocolMapperEvaluationRepresentation();
|
|
||||||
rep.setMapperId(current.getId());
|
|
||||||
rep.setMapperName(current.getName());
|
|
||||||
rep.setProtocolMapper(current.getProtocolMapper());
|
|
||||||
|
|
||||||
if (mapperContainer.getId().equals(client.getId())) {
|
|
||||||
// Must be this client
|
|
||||||
rep.setContainerId(client.getId());
|
|
||||||
rep.setContainerName("");
|
|
||||||
rep.setContainerType("client");
|
|
||||||
} else {
|
|
||||||
ClientScopeModel clientScope = (ClientScopeModel) mapperContainer;
|
|
||||||
rep.setContainerId(clientScope.getId());
|
|
||||||
rep.setContainerName(clientScope.getName());
|
|
||||||
rep.setContainerType("client-scope");
|
|
||||||
}
|
|
||||||
|
|
||||||
protocolMappers.add(rep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return protocolMappers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ProtocolMapperEvaluationRepresentation toProtocolMapperEvaluationRepresentation(ProtocolMapperModel mapper,
|
||||||
|
ClientScopeModel mapperContainer) {
|
||||||
|
ProtocolMapperEvaluationRepresentation rep = new ProtocolMapperEvaluationRepresentation();
|
||||||
|
rep.setMapperId(mapper.getId());
|
||||||
|
rep.setMapperName(mapper.getName());
|
||||||
|
rep.setProtocolMapper(mapper.getProtocolMapper());
|
||||||
|
|
||||||
|
if (mapperContainer.getId().equals(client.getId())) {
|
||||||
|
// Must be this client
|
||||||
|
rep.setContainerId(client.getId());
|
||||||
|
rep.setContainerName("");
|
||||||
|
rep.setContainerType("client");
|
||||||
|
} else {
|
||||||
|
ClientScopeModel clientScope = mapperContainer;
|
||||||
|
rep.setContainerId(clientScope.getId());
|
||||||
|
rep.setContainerName(clientScope.getName());
|
||||||
|
rep.setContainerType("client-scope");
|
||||||
|
}
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create JSON with payload of example access token
|
* Create JSON with payload of example access token
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.services.resources.admin;
|
package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -73,12 +72,8 @@ public class ClientScopeEvaluateScopeMappingsResource {
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@NoCache
|
@NoCache
|
||||||
public List<RoleRepresentation> getGrantedScopeMappings() {
|
public Stream<RoleRepresentation> getGrantedScopeMappings() {
|
||||||
return getGrantedRoles().stream().map((RoleModel role) -> {
|
return getGrantedRoles().map(ModelToRepresentation::toBriefRepresentation);
|
||||||
|
|
||||||
return ModelToRepresentation.toBriefRepresentation(role);
|
|
||||||
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,31 +88,30 @@ public class ClientScopeEvaluateScopeMappingsResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@NoCache
|
@NoCache
|
||||||
public Stream<RoleRepresentation> getNotGrantedScopeMappings() {
|
public Stream<RoleRepresentation> getNotGrantedScopeMappings() {
|
||||||
Set<RoleModel> grantedRoles = getGrantedRoles();
|
Set<RoleModel> grantedRoles = getGrantedRoles().collect(Collectors.toSet());
|
||||||
|
|
||||||
return roleContainer.getRolesStream()
|
return roleContainer.getRolesStream()
|
||||||
.filter(r -> !grantedRoles.contains(r))
|
.filter(((Predicate<RoleModel>) grantedRoles::contains).negate())
|
||||||
.map(ModelToRepresentation::toBriefRepresentation);
|
.map(ModelToRepresentation::toBriefRepresentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Set<RoleModel> getGrantedRoles() {
|
private Stream<RoleModel> getGrantedRoles() {
|
||||||
if (client.isFullScopeAllowed()) {
|
if (client.isFullScopeAllowed()) {
|
||||||
// intentionally using deprecated method as a set is more appropriate here
|
return roleContainer.getRolesStream();
|
||||||
return roleContainer.getRoles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client);
|
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(scopeParam, client)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
BiPredicate<Set<ClientScopeModel>, RoleModel> hasClientScope = (scopes, role) ->
|
Predicate<RoleModel> hasClientScope = role ->
|
||||||
scopes.stream().anyMatch(scopeContainer -> scopeContainer.hasScope(role));
|
clientScopes.stream().anyMatch(scopeContainer -> scopeContainer.hasScope(role));
|
||||||
|
|
||||||
return roleContainer.getRolesStream()
|
return roleContainer.getRolesStream()
|
||||||
.filter(auth.roles()::canView)
|
.filter(auth.roles()::canView)
|
||||||
.filter(r -> hasClientScope.test(clientScopes, r))
|
.filter(hasClientScope);
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,10 @@ 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.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base resource for managing users
|
* Base resource for managing users
|
||||||
|
@ -99,14 +100,12 @@ public class ProtocolMappersResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Path("protocol/{protocol}")
|
@Path("protocol/{protocol}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) {
|
public Stream<ProtocolMapperRepresentation> getMappersPerProtocol(@PathParam("protocol") String protocol) {
|
||||||
viewPermission.require();
|
viewPermission.require();
|
||||||
|
|
||||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
return client.getProtocolMappersStream()
|
||||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
.filter(mapper -> isEnabled(session, mapper) && Objects.equals(mapper.getProtocol(), protocol))
|
||||||
if (isEnabled(session, mapper) && mapper.getProtocol().equals(protocol)) mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
.map(ModelToRepresentation::toRepresentation);
|
||||||
}
|
|
||||||
return mappers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,16 +162,12 @@ public class ProtocolMappersResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Path("models")
|
@Path("models")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<ProtocolMapperRepresentation> getMappers() {
|
public Stream<ProtocolMapperRepresentation> getMappers() {
|
||||||
viewPermission.require();
|
viewPermission.require();
|
||||||
|
|
||||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
return client.getProtocolMappersStream()
|
||||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
.filter(mapper -> isEnabled(session, mapper))
|
||||||
if (isEnabled(session, mapper)) {
|
.map(ModelToRepresentation::toRepresentation);
|
||||||
mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mappers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,9 @@ package org.keycloak.services.util;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
|
|
||||||
|
|
||||||
public static DefaultClientSessionContext fromClientSessionAndScopeParameter(AuthenticatedClientSessionModel clientSession, String scopeParam, KeycloakSession session) {
|
public static DefaultClientSessionContext fromClientSessionAndScopeParameter(AuthenticatedClientSessionModel clientSession, String scopeParam, KeycloakSession session) {
|
||||||
Set<ClientScopeModel> requestedClientScopes = TokenManager.getRequestedClientScopes(scopeParam, clientSession.getClient());
|
Stream<ClientScopeModel> requestedClientScopes = TokenManager.getRequestedClientScopes(scopeParam, clientSession.getClient());
|
||||||
return fromClientSessionAndClientScopes(clientSession, requestedClientScopes, session);
|
return fromClientSessionAndClientScopes(clientSession, requestedClientScopes, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +93,10 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static DefaultClientSessionContext fromClientSessionAndClientScopes(AuthenticatedClientSessionModel clientSession, Set<ClientScopeModel> clientScopes, KeycloakSession session) {
|
public static DefaultClientSessionContext fromClientSessionAndClientScopes(AuthenticatedClientSessionModel clientSession,
|
||||||
Set<String> clientScopeIds = new HashSet<>();
|
Stream<ClientScopeModel> clientScopes,
|
||||||
for (ClientScopeModel clientScope : clientScopes) {
|
KeycloakSession session) {
|
||||||
clientScopeIds.add(clientScope.getId());
|
Set<String> clientScopeIds = clientScopes.map(ClientScopeModel::getId).collect(Collectors.toSet());
|
||||||
}
|
|
||||||
|
|
||||||
return new DefaultClientSessionContext(clientSession, clientScopeIds, session);
|
return new DefaultClientSessionContext(clientSession, clientScopeIds, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,12 +114,12 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ClientScopeModel> getClientScopes() {
|
public Stream<ClientScopeModel> getClientScopesStream() {
|
||||||
// Load client scopes if not yet present
|
// Load client scopes if not yet present
|
||||||
if (clientScopes == null) {
|
if (clientScopes == null) {
|
||||||
clientScopes = loadClientScopes();
|
clientScopes = loadClientScopes();
|
||||||
}
|
}
|
||||||
return clientScopes;
|
return clientScopes.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,12 +134,12 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
// Load protocolMappers if not yet present
|
// Load protocolMappers if not yet present
|
||||||
if (protocolMappers == null) {
|
if (protocolMappers == null) {
|
||||||
protocolMappers = loadProtocolMappers();
|
protocolMappers = loadProtocolMappers();
|
||||||
}
|
}
|
||||||
return protocolMappers;
|
return protocolMappers.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,28 +154,12 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getScopeString() {
|
public String getScopeString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
// Add both default and optional scopes to scope parameter. Don't add client itself
|
// Add both default and optional scopes to scope parameter. Don't add client itself
|
||||||
boolean first = true;
|
String scopeParam = getClientScopesStream()
|
||||||
for (ClientScopeModel clientScope : getClientScopes()) {
|
.filter(((Predicate<ClientScopeModel>) ClientModel.class::isInstance).negate())
|
||||||
if (clientScope instanceof ClientModel) {
|
.filter(ClientScopeModel::isIncludeInTokenScope)
|
||||||
continue;
|
.map(ClientScopeModel::getName)
|
||||||
}
|
.collect(Collectors.joining(" "));
|
||||||
|
|
||||||
if (!clientScope.isIncludeInTokenScope()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
builder.append(" ");
|
|
||||||
}
|
|
||||||
builder.append(clientScope.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
String scopeParam = builder.toString();
|
|
||||||
|
|
||||||
// See if "openid" scope is requested
|
// See if "openid" scope is requested
|
||||||
String scopeSent = clientSession.getNote(OAuth2Constants.SCOPE);
|
String scopeSent = clientSession.getNote(OAuth2Constants.SCOPE);
|
||||||
|
@ -246,34 +230,26 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
||||||
private Set<RoleModel> loadRoles() {
|
private Set<RoleModel> loadRoles() {
|
||||||
UserModel user = clientSession.getUserSession().getUser();
|
UserModel user = clientSession.getUserSession().getUser();
|
||||||
ClientModel client = clientSession.getClient();
|
ClientModel client = clientSession.getClient();
|
||||||
|
return TokenManager.getAccess(user, client, getClientScopesStream());
|
||||||
Set<ClientScopeModel> clientScopes = getClientScopes();
|
|
||||||
|
|
||||||
return TokenManager.getAccess(user, client, clientScopes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Set<ProtocolMapperModel> loadProtocolMappers() {
|
private Set<ProtocolMapperModel> loadProtocolMappers() {
|
||||||
Set<ClientScopeModel> clientScopes = getClientScopes();
|
|
||||||
String protocol = clientSession.getClient().getProtocol();
|
String protocol = clientSession.getClient().getProtocol();
|
||||||
|
|
||||||
// Being rather defensive. But protocol should normally always be there
|
// Being rather defensive. But protocol should normally always be there
|
||||||
if (protocol == null) {
|
if (protocol == null) {
|
||||||
logger.warnf("Client '%s' doesn't have protocol set. Fallback to openid-connect. Please fix client configuration", clientSession.getClient().getClientId());
|
logger.warnf("Client '%s' doesn't have protocol set. Fallback to openid-connect. Please fix client configuration",
|
||||||
|
clientSession.getClient().getClientId());
|
||||||
protocol = OIDCLoginProtocol.LOGIN_PROTOCOL;
|
protocol = OIDCLoginProtocol.LOGIN_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ProtocolMapperModel> protocolMappers = new HashSet<>();
|
String finalProtocol = protocol;
|
||||||
for (ClientScopeModel clientScope : clientScopes) {
|
return getClientScopesStream()
|
||||||
Set<ProtocolMapperModel> currentMappers = clientScope.getProtocolMappers();
|
.flatMap(clientScope -> clientScope.getProtocolMappersStream()
|
||||||
for (ProtocolMapperModel currentMapper : currentMappers) {
|
.filter(mapper -> Objects.equals(finalProtocol, mapper.getProtocol()) &&
|
||||||
if (protocol.equals(currentMapper.getProtocol()) && ProtocolMapperUtils.isEnabled(session, currentMapper)) {
|
ProtocolMapperUtils.isEnabled(session, mapper)))
|
||||||
protocolMappers.add(currentMapper);
|
.collect(Collectors.toSet());
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return protocolMappers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,13 +62,12 @@ public final class OpenshiftSAClientAdapter extends AbstractReadOnlyClientStorag
|
||||||
private static final String ANNOTATION_OAUTH_REDIRECT_REFERENCE = "serviceaccounts.openshift.io/oauth-redirectreference";
|
private static final String ANNOTATION_OAUTH_REDIRECT_REFERENCE = "serviceaccounts.openshift.io/oauth-redirectreference";
|
||||||
private static final Pattern ROLE_SCOPE_PATTERN = Pattern.compile("role:([^:]+):([^:!]+)(:[!])?");
|
private static final Pattern ROLE_SCOPE_PATTERN = Pattern.compile("role:([^:]+):([^:!]+)(:[!])?");
|
||||||
private static final Set<String> OPTIONAL_SCOPES = Stream.of("user:info", "user:check-access").collect(Collectors.toSet());
|
private static final Set<String> OPTIONAL_SCOPES = Stream.of("user:info", "user:check-access").collect(Collectors.toSet());
|
||||||
private static final Set<ProtocolMapperModel> DEFAULT_PROTOCOL_MAPPERS = createDefaultProtocolMappers();
|
|
||||||
|
|
||||||
private static Set<ProtocolMapperModel> createDefaultProtocolMappers() {
|
private static Set<ProtocolMapperModel> createDefaultProtocolMappers() {
|
||||||
Set<ProtocolMapperModel> mappers = new HashSet<>();
|
Set<ProtocolMapperModel> mappers = new HashSet<>();
|
||||||
|
|
||||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper("username", "username", "preferred_username", "string", true, true, UserPropertyMapper.PROVIDER_ID);
|
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper("username", "username",
|
||||||
|
"preferred_username", "string", true, true, UserPropertyMapper.PROVIDER_ID);
|
||||||
mapper.setId(KeycloakModelUtils.generateId());
|
mapper.setId(KeycloakModelUtils.generateId());
|
||||||
|
|
||||||
mappers.add(mapper);
|
mappers.add(mapper);
|
||||||
|
@ -315,34 +314,33 @@ public final class OpenshiftSAClientAdapter extends AbstractReadOnlyClientStorag
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
return getConfigOrDefault(() -> {
|
|
||||||
List<ProtocolMapperRepresentation> mappers = defaultConfig.getProtocolMappers();
|
List<ProtocolMapperRepresentation> mappers = defaultConfig.getProtocolMappers();
|
||||||
|
|
||||||
if (mappers == null) {
|
if (mappers == null) {
|
||||||
return null;
|
Set<ProtocolMapperModel> defaultProtocolMappers = createDefaultProtocolMappers();
|
||||||
|
defaultConfig.setProtocolMappers(defaultProtocolMappers.stream()
|
||||||
|
.map(ModelToRepresentation::toRepresentation).collect(Collectors.toList()));
|
||||||
|
return defaultProtocolMappers.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ProtocolMapperModel> model = new HashSet<>();
|
return mappers.stream().map(RepresentationToModel::toModel);
|
||||||
|
|
||||||
for (ProtocolMapperRepresentation mapper : mappers) {
|
|
||||||
model.add(RepresentationToModel.toModel(mapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}, (Consumer<Set<ProtocolMapperModel>>) mappers -> {
|
|
||||||
defaultConfig.setProtocolMappers(mappers.stream().map(ModelToRepresentation::toRepresentation).collect(Collectors.toList()));
|
|
||||||
}, (Supplier<Set<ProtocolMapperModel>>) () -> DEFAULT_PROTOCOL_MAPPERS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||||
return getProtocolMappers().stream().filter(protocolMapperModel -> id.equals(protocolMapperModel.getId())).findAny().get();
|
return getProtocolMappersStream()
|
||||||
|
.filter(protocolMapperModel -> Objects.equals(id, protocolMapperModel.getId()))
|
||||||
|
.findAny()
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
||||||
return getProtocolMappers().stream().filter(protocolMapperModel -> name.equals(protocolMapperModel.getName())).findAny().get();
|
return getProtocolMappersStream()
|
||||||
|
.filter(protocolMapperModel -> Objects.equals(name, protocolMapperModel.getName()))
|
||||||
|
.findAny()
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -452,8 +450,8 @@ public final class OpenshiftSAClientAdapter extends AbstractReadOnlyClientStorag
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
return DEFAULT_PROTOCOL_MAPPERS;
|
return createDefaultProtocolMappers().stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -261,8 +261,8 @@ public class HardcodedClientStorageProvider implements ClientStorageProvider, Cl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
public Stream<ProtocolMapperModel> getProtocolMappersStream() {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
|
||||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
@ -52,6 +51,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
||||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
|
||||||
|
@ -108,14 +108,14 @@ public class UserStorageConsentTest extends AbstractServletsAdapterTest {
|
||||||
product.setConsentRequired(true);
|
product.setConsentRequired(true);
|
||||||
ClientScopeModel clientScope = realm.addClientScope("clientScope");
|
ClientScopeModel clientScope = realm.addClientScope("clientScope");
|
||||||
clientScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
clientScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||||
System.err.println("client scope protocol mappers size: " + clientScope.getProtocolMappers().size());
|
System.err.println("client scope protocol mappers size: " + clientScope.getProtocolMappersStream().count());
|
||||||
|
|
||||||
for (ProtocolMapperModel mapper : product.getProtocolMappers()) {
|
for (ProtocolMapperModel mapper : product.getProtocolMappersStream().collect(Collectors.toList())) {
|
||||||
if (mapper.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
|
if (mapper.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
|
||||||
if (mapper.getName().equals(OIDCLoginProtocolFactory.USERNAME)
|
if (mapper.getName().equals(OIDCLoginProtocolFactory.USERNAME)
|
||||||
|| mapper.getName().equals(OIDCLoginProtocolFactory.EMAIL)
|
|| mapper.getName().equals(OIDCLoginProtocolFactory.EMAIL)
|
||||||
|| mapper.getName().equals(OIDCLoginProtocolFactory.GIVEN_NAME)
|
|| mapper.getName().equals(OIDCLoginProtocolFactory.GIVEN_NAME)
|
||||||
) {
|
) {
|
||||||
ProtocolMapperModel copy = new ProtocolMapperModel();
|
ProtocolMapperModel copy = new ProtocolMapperModel();
|
||||||
copy.setName(mapper.getName());
|
copy.setName(mapper.getName());
|
||||||
copy.setProtocol(mapper.getProtocol());
|
copy.setProtocol(mapper.getProtocol());
|
||||||
|
|
Loading…
Reference in a new issue