From aeb1951abad784bb51a0f2bc1f77fed7d33e14b4 Mon Sep 17 00:00:00 2001 From: Stefan Guilhen Date: Thu, 1 Aug 2024 13:11:24 -0300 Subject: [PATCH] Replace calls to deprecated RealmModel IDP methods - use the new provider instead Closes #31254 Signed-off-by: Stefan Guilhen --- .../infinispan/idp/InfinispanIDPProvider.java | 7 ++ .../keycloak/models/jpa/JpaIDPProvider.java | 113 ++++++++++++++---- .../org/keycloak/models/jpa/RealmAdapter.java | 2 +- .../jpa/JpaOrganizationProvider.java | 10 +- .../organization/jpa/OrganizationAdapter.java | 2 +- .../migration/migrators/MigrateTo1_7_0.java | 22 +++- .../migration/migrators/MigrateTo2_2_0.java | 26 ++-- .../datastore/DefaultExportImportManager.java | 4 +- .../AuthenticationManagementResource.java | 14 +-- .../ui/rest/model/AuthenticationMapper.java | 9 +- .../models/utils/KeycloakModelUtils.java | 6 +- .../models/utils/ModelToRepresentation.java | 2 +- .../models/utils/RepresentationToModel.java | 6 +- .../java/org/keycloak/models/IDPProvider.java | 14 +++ .../models/IdentityProviderModel.java | 30 ++--- .../SerializedBrokeredIdentityContext.java | 6 +- .../IdentityProviderAuthenticator.java | 9 +- .../login/freemarker/LoginFormsUtil.java | 10 +- ...OrganizationIdentityProvidersResource.java | 10 +- ...OrganizationAwareIdentityProviderBean.java | 7 +- .../organization/utils/Organizations.java | 2 +- .../IdentityProvidersPartialImport.java | 9 +- .../oidc/DefaultTokenExchangeProvider.java | 47 +++++--- .../keycloak/protocol/oidc/TokenManager.java | 2 +- .../managers/AuthenticationManager.java | 4 +- .../resources/IdentityBrokerService.java | 20 ++-- .../account/LinkedAccountsResource.java | 5 +- .../admin/IdentityProviderResource.java | 60 ++++++---- .../admin/IdentityProvidersResource.java | 8 +- .../resources/admin/UserResource.java | 3 +- .../rest/TestingResourceProvider.java | 2 +- .../broker/BrokerRunOnServerUtil.java | 16 +-- .../broker/KcOidcBrokerTokenExchangeTest.java | 2 +- .../testsuite/broker/SocialLoginTest.java | 2 +- .../OrganizationIdentityProviderTest.java | 2 +- .../AbstractUserSessionLimitsBrokerTest.java | 4 +- .../org/keycloak/testsuite/util/FlowUtil.java | 6 +- .../model/FederatedIdentityModelTest.java | 2 +- 38 files changed, 310 insertions(+), 195 deletions(-) diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/idp/InfinispanIDPProvider.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/idp/InfinispanIDPProvider.java index 4d6e1fe3395..c976ed5cba2 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/idp/InfinispanIDPProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/idp/InfinispanIDPProvider.java @@ -88,6 +88,8 @@ public class InfinispanIDPProvider implements IDPProvider { @Override public IdentityProviderModel getById(String internalId) { + if (internalId == null) + return null; CachedIdentityProvider cached = realmCache.getCache().get(internalId, CachedIdentityProvider.class); String realmId = getRealm().getId(); if (cached != null && !cached.getRealm().equals(realmId)) { @@ -130,6 +132,11 @@ public class InfinispanIDPProvider implements IDPProvider { return cached.getIdentityProvider(); } + @Override + public Stream getByFlow(String flowId, String search, Integer first, Integer max) { + return idpDelegate.getByFlow(flowId, search, first, max); + } + @Override public Stream getAllStream(String search, Integer first, Integer max) { return idpDelegate.getAllStream(search, first, max); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIDPProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIDPProvider.java index 662f2159f0f..79564d4aebe 100644 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIDPProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIDPProvider.java @@ -28,10 +28,11 @@ import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Join; -import jakarta.persistence.criteria.JoinType; +import jakarta.persistence.criteria.MapJoin; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.Session; import org.jboss.logging.Logger; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; @@ -46,6 +47,11 @@ import org.keycloak.models.jpa.entities.IdentityProviderEntity; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.utils.StringUtil; +import static org.keycloak.models.IdentityProviderModel.ALIAS; +import static org.keycloak.models.IdentityProviderModel.AUTHENTICATE_BY_DEFAULT; +import static org.keycloak.models.IdentityProviderModel.ENABLED; +import static org.keycloak.models.IdentityProviderModel.FIRST_BROKER_LOGIN_FLOW_ID; +import static org.keycloak.models.IdentityProviderModel.POST_BROKER_LOGIN_FLOW_ID; import static org.keycloak.models.jpa.PaginationUtils.paginateQuery; import static org.keycloak.utils.StreamsUtil.closing; @@ -203,21 +209,10 @@ public class JpaIDPProvider implements IDPProvider { predicates.add(builder.equal(idp.get("realmId"), getRealm().getId())); if (StringUtil.isNotBlank(search)) { - if (search.startsWith("\"") && search.endsWith("\"")) { - // exact search - alias must be an exact match - search = search.substring(1, search.length() - 1); - predicates.add(builder.equal(idp.get("alias"), search)); - } else { - search = search.replace("%", "\\%").replace("_", "\\_").replace("*", "%"); - if (!search.endsWith("%")) { - search += "%"; // default to prefix search - } - - predicates.add(builder.like(builder.lower(idp.get("alias")), search.toLowerCase(), '\\')); - } + predicates.add(this.getAliasSearchPredicate(search, builder, idp)); } - query.orderBy(builder.asc(idp.get("alias"))); + query.orderBy(builder.asc(idp.get(ALIAS))); TypedQuery typedQuery = em.createQuery(query.select(idp).where(predicates.toArray(Predicate[]::new))); return closing(paginateQuery(typedQuery, first, max).getResultStream()).map(this::toModel); } @@ -233,21 +228,74 @@ public class JpaIDPProvider implements IDPProvider { if (attrs != null) { for (Map.Entry entry : attrs.entrySet()) { - if (StringUtil.isBlank(entry.getKey())) { + String key = entry.getKey(); + String value = entry.getValue(); + if (StringUtil.isBlank(key)) { continue; } - Join configJoin = idp.join("config", JoinType.LEFT); - predicates.add(builder.and( - builder.equal(configJoin.get("name"), entry.getKey()), - builder.equal(configJoin.get("value"), entry.getValue()))); + switch(key) { + case ENABLED: + case AUTHENTICATE_BY_DEFAULT: { + predicates.add(builder.equal(idp.get(key), Boolean.valueOf(value))); + break; + } case FIRST_BROKER_LOGIN_FLOW_ID: { + if (StringUtils.isBlank(value)) { + predicates.add(builder.isNull(idp.get(key))); + } else { + predicates.add(builder.equal(idp.get(key), value)); + } + break; + } default: { + String dbProductName = em.unwrap(Session.class).doReturningWork(connection -> connection.getMetaData().getDatabaseProductName()); + MapJoin configJoin = idp.joinMap("config"); + Predicate configNamePredicate = builder.equal(configJoin.key(), key); + + if (dbProductName.equals("Oracle")) { + // SELECT * FROM identity_provider_config WHERE ... DBMS_LOB.COMPARE(value, '0') = 0 ...; + // Oracle is not able to compare a CLOB with a VARCHAR unless it being converted with TO_CHAR + // But for this all values in the table need to be smaller than 4K, otherwise the cast will fail with + // "ORA-22835: Buffer too small for CLOB to CHAR" (even if it is in another row). + // This leaves DBMS_LOB.COMPARE as the option to compare the CLOB with the value. + Predicate configValuePredicate = builder.equal(builder.function("DBMS_LOB.COMPARE", Integer.class, configJoin.value(), builder.literal(value)), 0); + predicates.add(builder.and(configNamePredicate, configValuePredicate)); + } else { + predicates.add(builder.and(configNamePredicate, builder.equal(configJoin.value(), value))); + } + } + } } } - query.orderBy(builder.asc(idp.get("alias"))); + query.orderBy(builder.asc(idp.get(ALIAS))); TypedQuery typedQuery = em.createQuery(query.select(idp).where(predicates.toArray(Predicate[]::new))); return closing(paginateQuery(typedQuery, first, max).getResultStream()).map(this::toModel); } + @Override + public Stream getByFlow(String flowId, String search, Integer first, Integer max) { + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery query = builder.createQuery(String.class); + Root idp = query.from(IdentityProviderEntity.class); + + List predicates = new ArrayList<>(); + predicates.add(builder.equal(idp.get("realmId"), getRealm().getId())); + + if (StringUtil.isNotBlank(flowId)) { + predicates.add(builder.or( + builder.equal(idp.get(FIRST_BROKER_LOGIN_FLOW_ID), flowId), + builder.equal(idp.get(POST_BROKER_LOGIN_FLOW_ID), flowId) + )); + } + + if (StringUtil.isNotBlank(search)) { + predicates.add(this.getAliasSearchPredicate(search, builder, idp)); + } + + query.orderBy(builder.asc(idp.get(ALIAS))); + TypedQuery typedQuery = em.createQuery(query.select(idp.get(ALIAS)).where(predicates.toArray(Predicate[]::new))); + return closing(paginateQuery(typedQuery, first, max).getResultStream()); + } + @Override public long count() { CriteriaBuilder builder = em.getCriteriaBuilder(); @@ -263,6 +311,13 @@ public class JpaIDPProvider implements IDPProvider { } private IdentityProviderEntity getEntityById(String id, boolean failIfNotFound) { + if (id == null) { + if (failIfNotFound) { + throw new ModelException("Identity Provider with null internal id does not exist"); + } + return null; + } + IdentityProviderEntity entity = em.find(IdentityProviderEntity.class, id); if (entity == null) { if (failIfNotFound) { @@ -284,7 +339,7 @@ public class JpaIDPProvider implements IDPProvider { Root idp = query.from(IdentityProviderEntity.class); Predicate predicate = builder.and(builder.equal(idp.get("realmId"), getRealm().getId()), - builder.equal(idp.get("alias"), alias)); + builder.equal(idp.get(ALIAS), alias)); TypedQuery typedQuery = em.createQuery(query.select(idp).where(predicate)); try { @@ -294,6 +349,20 @@ public class JpaIDPProvider implements IDPProvider { } } + private Predicate getAliasSearchPredicate(String search, CriteriaBuilder builder, Root idp) { + if (search.startsWith("\"") && search.endsWith("\"")) { + // exact search - alias must be an exact match + search = search.substring(1, search.length() - 1); + return builder.equal(idp.get(ALIAS), search); + } else { + search = search.replace("%", "\\%").replace("_", "\\_").replace("*", "%"); + if (!search.endsWith("%")) { + search += "%"; // default to prefix search + } + return builder.like(builder.lower(idp.get(ALIAS)), search.toLowerCase(), '\\'); + } + } + private IdentityProviderModel toModel(IdentityProviderEntity entity) { if (entity == null) { return null; diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index eed5c620639..292abfd9cfa 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -1508,7 +1508,7 @@ public class RealmAdapter implements StorageProviderRealmModel, JpaModel organizationEntity.getId().equals(model.getOrganizationId())); + return session.identityProviders().getByOrganization(organizationEntity.getId(), null, null); } @Override @@ -362,7 +362,7 @@ public class JpaOrganizationProvider implements OrganizationProvider { identityProvider.setOrganizationId(null); identityProvider.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE); identityProvider.getConfig().remove(BROKER_PUBLIC); - getRealm().updateIdentityProvider(identityProvider); + session.identityProviders().update(identityProvider); return true; } @@ -510,9 +510,7 @@ public class JpaOrganizationProvider implements OrganizationProvider { // return true only if the organization realm and the identity provider realm is the same private boolean checkOrgIdpAndRealm(OrganizationEntity orgEntity, IdentityProviderModel idp) { - RealmModel orgRealm = session.realms().getRealm(orgEntity.getRealmId()); - IdentityProviderModel orgIdpByAlias = orgRealm.getIdentityProviderByAlias(idp.getAlias()); - + IdentityProviderModel orgIdpByAlias = session.identityProviders().getByAlias(idp.getAlias()); return orgIdpByAlias != null && orgIdpByAlias.getInternalId().equals(idp.getInternalId()); } diff --git a/model/jpa/src/main/java/org/keycloak/organization/jpa/OrganizationAdapter.java b/model/jpa/src/main/java/org/keycloak/organization/jpa/OrganizationAdapter.java index 2c1b178adfd..b7e91324e78 100644 --- a/model/jpa/src/main/java/org/keycloak/organization/jpa/OrganizationAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/organization/jpa/OrganizationAdapter.java @@ -195,7 +195,7 @@ public final class OrganizationAdapter implements OrganizationModel, JpaModel Objects.equals(domainEntity.getName(), idp.getConfig().get(ORGANIZATION_DOMAIN_ATTRIBUTE))) .forEach(idp -> { idp.getConfig().remove(ORGANIZATION_DOMAIN_ATTRIBUTE); - realm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }); } } diff --git a/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java index 5d56897a843..86689aac251 100644 --- a/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java +++ b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java @@ -17,10 +17,13 @@ package org.keycloak.migration.migrators; +import java.util.Map; + import org.keycloak.migration.MigrationProvider; import org.keycloak.migration.ModelVersion; import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.Constants; +import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultAuthenticationFlows; @@ -38,12 +41,20 @@ public class MigrateTo1_7_0 implements Migration { } public void migrate(KeycloakSession session) { - session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm)); + RealmModel sessionRealm = session.getContext().getRealm(); + session.realms().getRealmsStream().forEach(realm -> { + session.getContext().setRealm(realm); + migrateRealm(session, realm); + }); + session.getContext().setRealm(sessionRealm); } @Override public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + RealmModel sessionRealm = session.getContext().getRealm(); + session.getContext().setRealm(realm); migrateRealm(session, realm); + session.getContext().setRealm(sessionRealm); } protected void migrateRealm(KeycloakSession session, RealmModel realm) { @@ -58,11 +69,10 @@ public class MigrateTo1_7_0 implements Migration { DefaultAuthenticationFlows.migrateFlows(realm); AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW); - realm.getIdentityProvidersStream() - .filter(provider -> provider.getFirstBrokerLoginFlowId() == null) - .forEach(provider -> { - provider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId()); - realm.updateIdentityProvider(provider); + session.identityProviders().getAllStream(Map.of(IdentityProviderModel.FIRST_BROKER_LOGIN_FLOW_ID, ""), null, null) + .forEach(provider -> { + provider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId()); + session.identityProviders().update(provider); }); } } diff --git a/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java index 762c7c9641f..878e7a976b7 100644 --- a/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java +++ b/model/storage-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java @@ -17,6 +17,8 @@ package org.keycloak.migration.migrators; +import java.util.Map; + import org.jboss.logging.Logger; import org.keycloak.migration.ModelVersion; import org.keycloak.models.IdentityProviderModel; @@ -35,23 +37,27 @@ public class MigrateTo2_2_0 implements Migration { } public void migrate(KeycloakSession session) { - session.realms().getRealmsStream().forEach(this::addIdentityProviderAuthenticator); + RealmModel sessionRealm = session.getContext().getRealm(); + session.realms().getRealmsStream().forEach(realm -> { + session.getContext().setRealm(realm); + addIdentityProviderAuthenticator(session, realm); + }); + session.getContext().setRealm(sessionRealm); } @Override public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { - addIdentityProviderAuthenticator(realm); - + RealmModel sessionRealm = session.getContext().getRealm(); + session.getContext().setRealm(realm); + addIdentityProviderAuthenticator(session, realm); + session.getContext().setRealm(sessionRealm); } - private void addIdentityProviderAuthenticator(RealmModel realm) { - String defaultProvider = realm.getIdentityProvidersStream() - .filter(IdentityProviderModel::isEnabled) - .filter(IdentityProviderModel::isAuthenticateByDefault) + private void addIdentityProviderAuthenticator(KeycloakSession session, RealmModel realm) { + String defaultProvider = session.identityProviders() + .getAllStream(Map.of(IdentityProviderModel.ENABLED, "true", IdentityProviderModel.AUTHENTICATE_BY_DEFAULT, "true"), 0, 1) .map(IdentityProviderModel::getAlias) - .findFirst() - .orElse(null); - + .findFirst().orElse(null); DefaultAuthenticationFlows.addIdentityProviderAuthenticator(realm, defaultProvider); } diff --git a/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultExportImportManager.java b/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultExportImportManager.java index f5fa34a8cfe..fba0beef3d9 100644 --- a/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultExportImportManager.java +++ b/model/storage-private/src/main/java/org/keycloak/storage/datastore/DefaultExportImportManager.java @@ -556,7 +556,7 @@ public class DefaultExportImportManager implements ExportImportManager { private static void importIdentityProviders(RealmRepresentation rep, RealmModel newRealm, KeycloakSession session) { if (rep.getIdentityProviders() != null) { for (IdentityProviderRepresentation representation : rep.getIdentityProviders()) { - newRealm.addIdentityProvider(RepresentationToModel.toModel(newRealm, representation, session)); + session.identityProviders().create(RepresentationToModel.toModel(newRealm, representation, session)); } } } @@ -1595,7 +1595,7 @@ public class DefaultExportImportManager implements ExportImportManager { org.setDomains(orgRep.getDomains().stream().map(r -> new OrganizationDomainModel(r.getName(), r.isVerified())).collect(Collectors.toSet())); for (IdentityProviderRepresentation identityProvider : Optional.ofNullable(orgRep.getIdentityProviders()).orElse(Collections.emptyList())) { - IdentityProviderModel idp = newRealm.getIdentityProviderByAlias(identityProvider.getAlias()); + IdentityProviderModel idp = session.identityProviders().getByAlias(identityProvider.getAlias()); provider.addIdentityProvider(org, idp); } diff --git a/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/AuthenticationManagementResource.java b/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/AuthenticationManagementResource.java index e134a579c61..8abe6a80816 100644 --- a/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/AuthenticationManagementResource.java +++ b/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/AuthenticationManagementResource.java @@ -64,7 +64,7 @@ public class AuthenticationManagementResource extends RoleMappingResource { return realm.getAuthenticationFlowsStream() .filter(flow -> flow.isTopLevel() && !Objects.equals(flow.getAlias(), DefaultAuthenticationFlows.SAML_ECP_FLOW)) - .map(flow -> AuthenticationMapper.convertToModel(flow, realm)) + .map(flow -> AuthenticationMapper.convertToModel(super.session, flow, realm)) .collect(Collectors.toList()); } @@ -88,11 +88,11 @@ public class AuthenticationManagementResource extends RoleMappingResource { ) )} ) - public final List listUsed(@PathParam("id") String id, @PathParam("type") String type, @QueryParam("first") @DefaultValue("0") long first, - @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + public final List listUsed(@PathParam("id") String id, @PathParam("type") String type, @QueryParam("first") @DefaultValue("0") int first, + @QueryParam("max") @DefaultValue("10") int max, @QueryParam("search") @DefaultValue("") String search) { auth.realm().requireViewAuthenticationFlows(); - final AuthenticationFlowModel flow = realm.getAuthenticationFlowsStream().filter(f -> id.equals(f.getId())).collect(Collectors.toList()).get(0); + final AuthenticationFlowModel flow = realm.getAuthenticationFlowsStream().filter(f -> id.equals(f.getId())).toList().get(0); if ("clients".equals(type)) { final Stream clients = realm.getClientsStream(); @@ -105,11 +105,7 @@ public class AuthenticationManagementResource extends RoleMappingResource { } if ("idp".equals(type)) { - final Stream identityProviders = realm.getIdentityProvidersStream(); - return identityProviders.filter(idp -> flow.getId().equals(idp.getFirstBrokerLoginFlowId()) - || flow.getId().equals(idp.getPostBrokerLoginFlowId())) - .map(IdentityProviderModel::getAlias).filter(f -> f.contains(search)) - .skip("".equals(search) ? first : 0).limit(max).collect(Collectors.toList()); + return session.identityProviders().getByFlow(flow.getId(), search, first, max).toList(); } throw new IllegalArgumentException("Invalid type"); diff --git a/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/model/AuthenticationMapper.java b/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/model/AuthenticationMapper.java index 93c2728ecbc..8df4fdbe0f4 100644 --- a/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/model/AuthenticationMapper.java +++ b/rest/admin-ui-ext/src/main/java/org/keycloak/admin/ui/rest/model/AuthenticationMapper.java @@ -8,14 +8,13 @@ import java.util.stream.Stream; import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.ClientModel; import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; public class AuthenticationMapper { private static final int MAX_USED_BY = 9; - public static Authentication convertToModel(AuthenticationFlowModel flow, RealmModel realm) { - - final Stream identityProviders = realm.getIdentityProvidersStream(); + public static Authentication convertToModel(KeycloakSession session, AuthenticationFlowModel flow, RealmModel realm) { final Authentication authentication = new Authentication(); authentication.setId(flow.getId()); @@ -23,9 +22,7 @@ public class AuthenticationMapper { authentication.setBuiltIn(flow.isBuiltIn()); authentication.setDescription(flow.getDescription()); - final List usedByIdp = identityProviders.filter(idp -> flow.getId().equals(idp.getFirstBrokerLoginFlowId()) - || flow.getId().equals(idp.getPostBrokerLoginFlowId())) - .map(IdentityProviderModel::getAlias).limit(MAX_USED_BY).collect(Collectors.toList()); + final List usedByIdp = session.identityProviders().getByFlow(flow.getId(), null,0, MAX_USED_BY).toList(); if (!usedByIdp.isEmpty()) { authentication.setUsedBy(new UsedBy(UsedBy.UsedByType.SPECIFIC_PROVIDERS, usedByIdp)); } diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index a574495d949..8e320087a40 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -909,7 +909,7 @@ public final class KeycloakModelUtils { * @param model * @return */ - public static boolean isFlowUsed(RealmModel realm, AuthenticationFlowModel model) { + public static boolean isFlowUsed(KeycloakSession session, RealmModel realm, AuthenticationFlowModel model) { AuthenticationFlowModel realmFlow = null; if ((realmFlow = realm.getBrowserFlow()) != null && realmFlow.getId().equals(model.getId())) return true; @@ -931,9 +931,7 @@ public final class KeycloakModelUtils { return true; } - return realm.getIdentityProvidersStream().anyMatch(idp -> - Objects.equals(idp.getFirstBrokerLoginFlowId(), model.getId()) || - Objects.equals(idp.getPostBrokerLoginFlowId(), model.getId())); + return session.identityProviders().getByFlow(model.getId(), null,0, 1).findAny().isPresent(); } /** diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index b612e2c148f..dde2c2a9a22 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -504,7 +504,7 @@ public class ModelToRepresentation { } if (export) { - List identityProviders = realm.getIdentityProvidersStream() + List identityProviders = session.identityProviders().getAllStream() .map(provider -> toRepresentation(realm, provider, export)).collect(Collectors.toList()); rep.setIdentityProviders(identityProviders); List identityProviderMappers = realm.getIdentityProviderMappersStream() diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index f58cec0dcfc..ed51c4763e0 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -27,6 +27,7 @@ import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; @@ -1643,9 +1644,8 @@ public class RepresentationToModel { return; } - IdentityProviderModel existing = realm.getIdentityProvidersStream() - .filter(p -> Objects.equals(p.getAlias(), representation.getAlias()) || Objects.equals(p.getInternalId(), representation.getInternalId())) - .findFirst().orElse(null); + IdentityProviderModel existing = Optional.ofNullable(session.identityProviders().getByAlias(representation.getAlias())) + .orElse(session.identityProviders().getById(representation.getInternalId())); String orgId = existing == null ? representation.getConfig().get(OrganizationModel.ORGANIZATION_ATTRIBUTE) : existing.getOrganizationId(); if (orgId != null) { diff --git a/server-spi/src/main/java/org/keycloak/models/IDPProvider.java b/server-spi/src/main/java/org/keycloak/models/IDPProvider.java index b944450be3f..e3d59378510 100644 --- a/server-spi/src/main/java/org/keycloak/models/IDPProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/IDPProvider.java @@ -132,6 +132,20 @@ public interface IDPProvider extends Provider { return getAllStream(Map.of(OrganizationModel.ORGANIZATION_ATTRIBUTE, orgId), first, max); } + /** + * Returns the aliases of all identity providers whose {@code firstBrokerLoginFlowId} or {@code postBrokerLoginFlowId} + * matches the provided {@code flowId}. + * + * @param flowId the id of the flow. + * @param search an optional {@link String} representing an identity provider alias (partial or exact). If the value is enclosed + * in double quotes, the method treats it as an exact search (e.g. {@code "name"}). If the value is enclosed in + * wildcards, the method treats it as an infix search (e.g. {@code *name*}). Otherwise, the method treats it as a + * prefix search (i.e. {@code name*} and {@code name} return the same results). + * @param first the position of the first result to be processed (pagination offset). Ignored if negative or {@code null}. + * @param max the maximum number of results to be returned. Ignored if negative or {@code null}. + * @return a non-null stream of {@link IdentityProviderModel}s that match the search criteria. + */ + Stream getByFlow(String flowId, String search, Integer first, Integer max); /** * Returns the number of IDPs in the realm. diff --git a/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java b/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java index 56ff725fa28..ddd8e54bfa6 100755 --- a/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java +++ b/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java @@ -31,20 +31,22 @@ import java.util.Objects; */ public class IdentityProviderModel implements Serializable { + public static final String ALIAS = "alias"; public static final String ALLOWED_CLOCK_SKEW = "allowedClockSkew"; - public static final String LOGIN_HINT = "loginHint"; - public static final String PASS_MAX_AGE = "passMaxAge"; - - public static final String SYNC_MODE = "syncMode"; - - public static final String HIDE_ON_LOGIN = "hideOnLoginPage"; - - public static final String FILTERED_BY_CLAIMS = "filteredByClaim"; + public static final String AUTHENTICATE_BY_DEFAULT = "authenticateByDefault"; + public static final String CASE_SENSITIVE_ORIGINAL_USERNAME = "caseSensitiveOriginalUsername"; public static final String CLAIM_FILTER_NAME = "claimFilterName"; public static final String CLAIM_FILTER_VALUE = "claimFilterValue"; public static final String DO_NOT_STORE_USERS = "doNotStoreUsers"; + public static final String ENABLED = "enabled"; + public static final String FILTERED_BY_CLAIMS = "filteredByClaim"; + public static final String FIRST_BROKER_LOGIN_FLOW_ID = "firstBrokerLoginFlowId"; + public static final String HIDE_ON_LOGIN = "hideOnLoginPage"; + public static final String LOGIN_HINT = "loginHint"; public static final String METADATA_DESCRIPTOR_URL = "metadataDescriptorUrl"; - public static final String CASE_SENSITIVE_ORIGINAL_USERNAME = "caseSensitiveOriginalUsername"; + public static final String PASS_MAX_AGE = "passMaxAge"; + public static final String POST_BROKER_LOGIN_FLOW_ID = "postBrokerLoginFlowId"; + public static final String SYNC_MODE = "syncMode"; private String internalId; @@ -60,7 +62,7 @@ public class IdentityProviderModel implements Serializable { private String providerId; private boolean enabled; - + private boolean trustEmail; private boolean storeToken; @@ -232,14 +234,14 @@ public class IdentityProviderModel implements Serializable { /** *

Validates this configuration. - * + * *

Sub-classes can override this method in order to enforce provider specific validations. - * + * * @param realm the realm */ public void validate(RealmModel realm) { } - + public IdentityProviderSyncMode getSyncMode() { return IdentityProviderSyncMode.valueOf(getConfig().getOrDefault(SYNC_MODE, "LEGACY")); } @@ -264,7 +266,7 @@ public class IdentityProviderModel implements Serializable { getConfig().put(PASS_MAX_AGE, String.valueOf(passMaxAge)); } - + public boolean isHideOnLogin() { return Boolean.valueOf(getConfig().get(HIDE_ON_LOGIN)); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java index aaf5d0e9360..14e1a7c0929 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java @@ -72,7 +72,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext { public UserProfileContext getUserProfileContext() { return UserProfileContext.IDP_REVIEW; } - + public String getId() { return id; } @@ -265,7 +265,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext { public BrokeredIdentityContext deserialize(KeycloakSession session, AuthenticationSessionModel authSession) { RealmModel realm = authSession.getRealm(); - IdentityProviderModel idpConfig = realm.getIdentityProviderByAlias(getIdentityProviderId()); + IdentityProviderModel idpConfig = session.identityProviders().getByAlias(getIdentityProviderId()); if (idpConfig == null) { throw new ModelException("Can't find identity provider with ID " + getIdentityProviderId() + " in realm " + realm.getName()); @@ -282,7 +282,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext { ctx.setBrokerUserId(getBrokerUserId()); ctx.setToken(getToken()); - IdentityProvider idp = IdentityBrokerService.getIdentityProvider(session, realm, idpConfig.getAlias()); + IdentityProvider idp = IdentityBrokerService.getIdentityProvider(session, idpConfig.getAlias()); ctx.setIdp(idp); IdentityProviderDataMarshaller serializer = idp.getMarshaller(); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java index 4d9e9cee1e5..ee0876c1132 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java @@ -79,11 +79,8 @@ public class IdentityProviderAuthenticator implements Authenticator { } protected void redirect(AuthenticationFlowContext context, String providerId, String loginHint) { - Optional idp = context.getRealm().getIdentityProvidersStream() - .filter(IdentityProviderModel::isEnabled) - .filter(identityProvider -> Objects.equals(providerId, identityProvider.getAlias())) - .findFirst(); - if (idp.isPresent()) { + IdentityProviderModel idp = context.getSession().identityProviders().getByAlias(providerId); + if (idp != null && idp.isEnabled()) { String accessCode = new ClientSessionCode<>(context.getSession(), context.getRealm(), context.getAuthenticationSession()).getOrGenerateCode(); String clientId = context.getAuthenticationSession().getClient().getClientId(); String tabId = context.getAuthenticationSession().getTabId(); @@ -93,7 +90,7 @@ public class IdentityProviderAuthenticator implements Authenticator { .build(); // will forward the request to the IDP with prompt=none if the IDP accepts forwards with prompt=none. if ("none".equals(context.getAuthenticationSession().getClientNote(OIDCLoginProtocol.PROMPT_PARAM)) && - Boolean.valueOf(idp.get().getConfig().get(ACCEPTS_PROMPT_NONE))) { + Boolean.parseBoolean(idp.getConfig().get(ACCEPTS_PROMPT_NONE))) { context.getAuthenticationSession().setAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN, "true"); } LOG.debugf("Redirecting to %s", providerId); diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/LoginFormsUtil.java b/services/src/main/java/org/keycloak/forms/login/freemarker/LoginFormsUtil.java index c073464283c..24aaacd677a 100755 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/LoginFormsUtil.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/LoginFormsUtil.java @@ -51,12 +51,12 @@ public class LoginFormsUtil { // If the current user is not null, then it's a re-auth, and we should filter the possible options with the pre-14173 logic // If the current user is null, then it's one of the following cases: // - either connecting a new IdP to the user's account. - // - in this case the currentUser is null AND the current flow is the FIRST_BROKER_LOGIN_PATH - // - so we should filter out the one they just used for login, as they need to re-auth themself with an already linked IdP account + // - in this case the currentUser is null AND the current flow is the FIRST_BROKER_LOGIN_PATH + // - so we should filter out the one they just used for login, as they need to re-auth themselves with an already linked IdP account // - or we're on the Login page - // - in this case the current user is null AND the current flow is NOT the FIRST_BROKER_LOGIN_PATH - // - so we should show all the possible IdPs to the user trying to log in (this is the bug in #14173) - // - so we're skipping this branch, and retunring everything at the end of the method + // - in this case the current user is null AND the current flow is NOT the FIRST_BROKER_LOGIN_PATH + // - so we should show all the possible IdPs to the user trying to log in (this is the bug in #14173) + // - so we're skipping this branch, and returning everything at the end of the method if (currentUser != null || Objects.equals(LoginActionsService.FIRST_BROKER_LOGIN_PATH, currentFlowPath)) { return filterIdentityProviders(providers, session, context); } diff --git a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationIdentityProvidersResource.java b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationIdentityProvidersResource.java index b8e4776a52e..0619b1ee393 100644 --- a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationIdentityProvidersResource.java +++ b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationIdentityProvidersResource.java @@ -53,6 +53,7 @@ import org.keycloak.services.resources.admin.AdminEventBuilder; public class OrganizationIdentityProvidersResource { private final RealmModel realm; + private final KeycloakSession session; private final OrganizationProvider organizationProvider; private final OrganizationModel organization; @@ -63,6 +64,7 @@ public class OrganizationIdentityProvidersResource { public OrganizationIdentityProvidersResource(KeycloakSession session, OrganizationModel organization, AdminEventBuilder adminEvent) { this.realm = session == null ? null : session.getContext().getRealm(); + this.session = session; this.organizationProvider = session == null ? null : session.getProvider(OrganizationProvider.class); this.organization = organization; } @@ -75,9 +77,7 @@ public class OrganizationIdentityProvidersResource { "or if it is already associated with the organization, an error response is returned") public Response addIdentityProvider(String id) { try { - IdentityProviderModel identityProvider = this.realm.getIdentityProvidersStream() - .filter(p -> Objects.equals(p.getAlias(), id) || Objects.equals(p.getInternalId(), id)) - .findFirst().orElse(null); + IdentityProviderModel identityProvider = session.identityProviders().getByIdOrAlias(id); if (identityProvider == null) { throw ErrorResponse.error("Identity provider not found with the given alias", Status.BAD_REQUEST); @@ -111,7 +111,7 @@ public class OrganizationIdentityProvidersResource { description = "Searches for an identity provider with the given alias. If one is found and is associated with the " + "organization, it is returned. Otherwise, an error response with status NOT_FOUND is returned") public IdentityProviderRepresentation getIdentityProvider(@PathParam("alias") String alias) { - IdentityProviderModel broker = realm.getIdentityProviderByAlias(alias); + IdentityProviderModel broker = session.identityProviders().getByAlias(alias); if (!isOrganizationBroker(broker)) { throw ErrorResponse.error("Identity provider not associated with the organization", Status.NOT_FOUND); @@ -128,7 +128,7 @@ public class OrganizationIdentityProvidersResource { description = "Breaks the association between the identity provider and the organization. The provider itself is not deleted. " + "If no provider is found, or if it is not currently associated with the org, an error response is returned") public Response delete(@PathParam("alias") String alias) { - IdentityProviderModel broker = realm.getIdentityProviderByAlias(alias); + IdentityProviderModel broker = session.identityProviders().getByAlias(alias); if (!isOrganizationBroker(broker)) { throw ErrorResponse.error("Identity provider not found with the given alias", Status.NOT_FOUND); diff --git a/services/src/main/java/org/keycloak/organization/forms/login/freemarker/model/OrganizationAwareIdentityProviderBean.java b/services/src/main/java/org/keycloak/organization/forms/login/freemarker/model/OrganizationAwareIdentityProviderBean.java index e14556982e0..07189790f6e 100644 --- a/services/src/main/java/org/keycloak/organization/forms/login/freemarker/model/OrganizationAwareIdentityProviderBean.java +++ b/services/src/main/java/org/keycloak/organization/forms/login/freemarker/model/OrganizationAwareIdentityProviderBean.java @@ -68,8 +68,7 @@ public class OrganizationAwareIdentityProviderBean extends IdentityProviderBean } private boolean isPublicOrganizationBroker(IdentityProvider idp) { - RealmModel realm = session.getContext().getRealm(); - IdentityProviderModel model = realm.getIdentityProviderByAlias(idp.getAlias()); + IdentityProviderModel model = session.identityProviders().getByAlias(idp.getAlias()); if (model.getOrganizationId() == null) { return false; @@ -85,9 +84,7 @@ public class OrganizationAwareIdentityProviderBean extends IdentityProviderBean } private boolean isRealmBroker(IdentityProvider idp) { - RealmModel realm = session.getContext().getRealm(); - IdentityProviderModel model = realm.getIdentityProviderByAlias(idp.getAlias()); - + IdentityProviderModel model = session.identityProviders().getByAlias(idp.getAlias()); return model.getOrganizationId() == null; } } diff --git a/services/src/main/java/org/keycloak/organization/utils/Organizations.java b/services/src/main/java/org/keycloak/organization/utils/Organizations.java index 10ab14cc09c..ed6bde83f23 100644 --- a/services/src/main/java/org/keycloak/organization/utils/Organizations.java +++ b/services/src/main/java/org/keycloak/organization/utils/Organizations.java @@ -94,7 +94,7 @@ public class Organizations { List organizationBrokers = organization.getIdentityProviders().toList(); session.users().getFederatedIdentitiesStream(realm, user) .map(f -> { - IdentityProviderModel broker = realm.getIdentityProviderByAlias(f.getIdentityProvider()); + IdentityProviderModel broker = session.identityProviders().getByAlias(f.getIdentityProvider()); if (!organizationBrokers.contains(broker)) { return null; diff --git a/services/src/main/java/org/keycloak/partialimport/IdentityProvidersPartialImport.java b/services/src/main/java/org/keycloak/partialimport/IdentityProvidersPartialImport.java index 0a40cfb1c2e..a4b2686635d 100644 --- a/services/src/main/java/org/keycloak/partialimport/IdentityProvidersPartialImport.java +++ b/services/src/main/java/org/keycloak/partialimport/IdentityProvidersPartialImport.java @@ -46,12 +46,12 @@ public class IdentityProvidersPartialImport extends AbstractPartialImport provider = IdentityBrokerService.getIdentityProvider(session, requestedIssuer); if (!(provider instanceof ExchangeTokenToIdentityProviderToken)) { event.detail(Details.REASON, "exchange unsupported by requested_issuer"); event.error(Errors.UNKNOWN_IDENTITY_PROVIDER); @@ -518,20 +518,26 @@ public class DefaultTokenExchangeProvider implements TokenExchangeProvider { AtomicReference externalIdp = new AtomicReference<>(null); AtomicReference externalIdpModel = new AtomicReference<>(null); - realm.getIdentityProvidersStream().filter(idpModel -> { - IdentityProviderFactory factory = IdentityBrokerService.getIdentityProviderFactory(session, idpModel); - IdentityProvider idp = factory.create(session, idpModel); - if (idp instanceof ExchangeExternalToken) { - ExchangeExternalToken external = (ExchangeExternalToken) idp; - if (idpModel.getAlias().equals(issuer) || external.isIssuer(issuer, formParams)) { - externalIdp.set(external); - externalIdpModel.set(idpModel); - return true; - } - } - return false; - }).findFirst(); + // try to find the IDP whose alias matches the issuer or the subject issuer in the form params. + this.locateExchangeExternalTokenByAlias(issuer, externalIdp, externalIdpModel); + if (externalIdp.get() == null && formParams.getFirst(OAuth2Constants.SUBJECT_ISSUER) != null) { + this.locateExchangeExternalTokenByAlias(formParams.getFirst(OAuth2Constants.SUBJECT_ISSUER), externalIdp, externalIdpModel); + } + if (externalIdp.get() == null) { // searching by alias didn't work, search all IDPs using ExchangeExternalToken.isIssuer to find a match + session.identityProviders().getAllStream().filter(idpModel -> { + IdentityProvider idp = IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel); + if (idp instanceof ExchangeExternalToken) { + ExchangeExternalToken external = (ExchangeExternalToken) idp; + if (external.isIssuer(issuer, formParams)) { + externalIdp.set(external); + externalIdpModel.set(idpModel); + return true; + } + } + return false; + }).findFirst(); + } if (externalIdp.get() == null) { event.error(Errors.INVALID_ISSUER); @@ -687,4 +693,15 @@ public class DefaultTokenExchangeProvider implements TokenExchangeProvider { } } + private void locateExchangeExternalTokenByAlias(String alias, AtomicReference externalIdp, + AtomicReference externalIdpModel) { + + IdentityProviderModel idpModel = session.identityProviders().getByAlias(alias); + IdentityProvider idp = IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel); + if (idp instanceof ExchangeExternalToken) { + externalIdp.set((ExchangeExternalToken) idp); + externalIdpModel.set(idpModel); + } + } + } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java index 42fe6bc93bf..978b1edfa0a 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java @@ -1505,7 +1505,7 @@ public class TokenManager { private Stream getOIDCIdentityProviders(RealmModel realm, KeycloakSession session) { try { - return realm.getIdentityProvidersStream() + return session.identityProviders().getAllStream() .map(idpModel -> IdentityBrokerService.getIdentityProviderFactory(session, idpModel).create(session, idpModel)) .filter(OIDCIdentityProvider.class::isInstance) diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 0a519df0174..0d162312072 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -417,7 +417,7 @@ public class AuthenticationManager { if (logoutBroker) { String brokerId = userSession.getNote(Details.IDENTITY_PROVIDER); if (brokerId != null) { - IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId); + IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, brokerId); try { identityProvider.backchannelLogout(session, userSession, uriInfo, realm); } catch (Exception e) { @@ -648,7 +648,7 @@ public class AuthenticationManager { String brokerId = userSession.getNote(Details.IDENTITY_PROVIDER); String initiatingIdp = logoutAuthSession.getAuthNote(AuthenticationManager.LOGOUT_INITIATING_IDP); if (brokerId != null && !brokerId.equals(initiatingIdp)) { - IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId); + IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, brokerId); Response response = identityProvider.keycloakInitiatedBrowserLogout(session, userSession, uriInfo, realm); if (response != null) { return response; diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index 65cec70351d..4440ff65cb1 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -293,7 +293,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } - IdentityProviderModel identityProviderModel = realmModel.getIdentityProviderByAlias(providerAlias); + IdentityProviderModel identityProviderModel = session.identityProviders().getByAlias(providerAlias); if (identityProviderModel == null) { event.error(Errors.UNKNOWN_IDENTITY_PROVIDER); UriBuilder builder = UriBuilder.fromUri(redirectUri) @@ -330,7 +330,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal event.success(); try { - IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerAlias); + IdentityProvider identityProvider = getIdentityProvider(session, providerAlias); Response response = identityProvider.performLogin(createAuthenticationRequest(identityProvider, providerAlias, clientSessionCode)); if (response != null) { @@ -381,14 +381,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal ClientSessionCode clientSessionCode = new ClientSessionCode<>(session, realmModel, authSession); clientSessionCode.setAction(AuthenticationSessionModel.Action.AUTHENTICATE.name()); - IdentityProviderModel identityProviderModel = realmModel.getIdentityProviderByAlias(providerAlias); + IdentityProviderModel identityProviderModel = session.identityProviders().getByAlias(providerAlias); if (identityProviderModel == null) { throw new IdentityBrokerException("Identity Provider [" + providerAlias + "] not found."); } if (identityProviderModel.isLinkOnly()) { throw new IdentityBrokerException("Identity Provider [" + providerAlias + "] is not allowed to perform a login."); } - if (clientSessionCode != null && clientSessionCode.getClientSession() != null && loginHint != null) { + if (clientSessionCode.getClientSession() != null && loginHint != null) { clientSessionCode.getClientSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint); } @@ -437,7 +437,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal IdentityProvider identityProvider; try { - identityProvider = getIdentityProvider(session, realmModel, providerAlias); + identityProvider = getIdentityProvider(session, providerAlias); } catch (IdentityBrokerException e) { throw new NotFoundException(e.getMessage()); } @@ -490,7 +490,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } - IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerAlias); + IdentityProvider identityProvider = getIdentityProvider(session, providerAlias); IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerAlias); if (identityProviderConfig.isStoreToken()) { @@ -1247,7 +1247,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal fireErrorEvent(message, throwable); - if (throwable != null && throwable instanceof WebApplicationException) { + if (throwable instanceof WebApplicationException) { WebApplicationException webEx = (WebApplicationException) throwable; return webEx.getResponse(); } @@ -1312,8 +1312,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal throw ErrorResponse.error(message, Response.Status.NOT_FOUND); } - public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) { - IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(alias); + public static IdentityProvider getIdentityProvider(KeycloakSession session, String alias) { + IdentityProviderModel identityProviderModel = session.identityProviders().getByAlias(alias); if (identityProviderModel != null) { IdentityProviderFactory providerFactory = getIdentityProviderFactory(session, identityProviderModel); @@ -1338,7 +1338,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } private IdentityProviderModel getIdentityProviderConfig(String providerAlias) { - IdentityProviderModel model = this.realmModel.getIdentityProviderByAlias(providerAlias); + IdentityProviderModel model = session.identityProviders().getByAlias(providerAlias); if (model == null) { throw new IdentityBrokerException("Configuration for identity provider [" + providerAlias + "] not found."); } diff --git a/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java b/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java index 7415fee75f7..03965c7430b 100644 --- a/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/account/LinkedAccountsResource.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.SortedSet; @@ -113,7 +114,7 @@ public class LinkedAccountsResource { public SortedSet getLinkedAccounts(KeycloakSession session, RealmModel realm, UserModel user) { Set socialIds = findSocialIds(); - return realm.getIdentityProvidersStream().filter(IdentityProviderModel::isEnabled) + return session.identityProviders().getAllStream(Map.of(IdentityProviderModel.ENABLED, "true"), null, null) .map(provider -> toLinkedAccountRepresentation(provider, socialIds, session.users().getFederatedIdentitiesStream(realm, user))) .collect(Collectors.toCollection(TreeSet::new)); } @@ -266,6 +267,6 @@ public class LinkedAccountsResource { } private boolean isValidProvider(String providerAlias) { - return realm.getIdentityProvidersStream().anyMatch(model -> Objects.equals(model.getAlias(), providerAlias)); + return session.identityProviders().getByAlias(providerAlias) != null; } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java index 5d1a541ef09..3d93e46d14b 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java @@ -65,10 +65,11 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; + import java.util.Collections; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -134,7 +135,7 @@ public class IdentityProviderResource { String alias = this.identityProviderModel.getAlias(); session.users().preRemove(realm, identityProviderModel); - this.realm.removeIdentityProviderByAlias(alias); + session.identityProviders().remove(alias); realm.getIdentityProviderMappersByAliasStream(alias) .collect(Collectors.toList()).forEach(realm::removeIdentityProviderMapper); @@ -182,12 +183,11 @@ public class IdentityProviderResource { } private void updateIdpFromRep(IdentityProviderRepresentation providerRep, RealmModel realm, KeycloakSession session) { - String internalId = providerRep.getInternalId(); - String newProviderId = providerRep.getAlias(); - String oldProviderId = getProviderIdByInternalId(realm, internalId); + String newProviderAlias = providerRep.getAlias(); + String oldProviderAlias = getAliasByInternalId(providerRep.getInternalId()); - if (oldProviderId == null) { - lookUpProviderIdByAlias(realm, providerRep); + if (oldProviderAlias == null) { + providerRep.setInternalId(getInternalIdByAlias(providerRep.getAlias())); } IdentityProviderModel updated = RepresentationToModel.toModel(realm, providerRep, session); @@ -196,34 +196,44 @@ public class IdentityProviderResource { updated.getConfig().put("clientSecret", identityProviderModel.getConfig() != null ? identityProviderModel.getConfig().get("clientSecret") : null); } - realm.updateIdentityProvider(updated); + session.identityProviders().update(updated); - if (oldProviderId != null && !oldProviderId.equals(newProviderId)) { + if (oldProviderAlias != null && !oldProviderAlias.equals(newProviderAlias)) { // Admin changed the ID (alias) of identity provider. We must update all clients and users - logger.debug("Changing providerId in all clients and linked users. oldProviderId=" + oldProviderId + ", newProviderId=" + newProviderId); + logger.debug("Changing providerId in all clients and linked users. oldProviderId=" + oldProviderAlias + ", newProviderId=" + newProviderAlias); updateUsersAfterProviderAliasChange(session.users().searchForUserStream(realm, Collections.singletonMap(UserModel.INCLUDE_SERVICE_ACCOUNT, Boolean.FALSE.toString())), - oldProviderId, newProviderId, realm, session); + oldProviderAlias, newProviderAlias, realm, session); } } - // return ID of IdentityProvider from realm based on internalId of this provider - private static String getProviderIdByInternalId(RealmModel realm, String providerInternalId) { - return realm.getIdentityProvidersStream().filter(p -> Objects.equals(p.getInternalId(), providerInternalId)) - .map(IdentityProviderModel::getAlias) - .findFirst() - .orElse(null); + /** + * Returns the alias of the IDP whose internal ID matches the specified ID. + * + * @param providerInternalId the IDP's internal ID. + * @return the provider's alias, if an IDP is located with the given ID; {@code null} otherwise. + */ + private String getAliasByInternalId(String providerInternalId) { + IdentityProviderModel identityProviderModel = session.identityProviders().getById(providerInternalId); + return identityProviderModel != null ? identityProviderModel.getAlias() : null; } - // sets internalId to IdentityProvider based on alias - private static void lookUpProviderIdByAlias(RealmModel realm, IdentityProviderRepresentation providerRep) { - IdentityProviderModel identityProviderModel = realm.getIdentityProvidersStream() - .filter(p -> Objects.equals(p.getAlias(), providerRep.getAlias())) - .findFirst() - .orElseThrow(NotFoundException::new); - - providerRep.setInternalId(identityProviderModel.getInternalId()); + /** + * Returns the internal ID of the IDP whose alias matches the specified alias. + * + * @param alias the IDP's alias. + * @return the provider's internal ID. + * @throws NotFoundException if an IDP with a matching alias is not found. + */ + private String getInternalIdByAlias(String alias) { + if (alias != null) { + IdentityProviderModel identityProviderModel = session.identityProviders().getByAlias(alias); + if (identityProviderModel != null) { + return identityProviderModel.getInternalId(); + } + } + throw new NotFoundException("Identity provider not found with alias: " + alias); } private static void updateUsersAfterProviderAliasChange(Stream users, String oldProviderId, String newProviderId, RealmModel realm, KeycloakSession session) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java index 5b58cbd31a9..651bb49ea86 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java @@ -212,7 +212,7 @@ public class IdentityProvidersResource { try { IdentityProviderModel identityProvider = RepresentationToModel.toModel(realm, representation, session); - this.realm.addIdentityProvider(identityProvider); + session.identityProviders().create(identityProvider); representation.setInternalId(identityProvider.getInternalId()); adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), identityProvider.getAlias()) @@ -235,14 +235,12 @@ public class IdentityProvidersResource { @Path("instances/{alias}") public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) { this.auth.realm().requireViewIdentityProviders(); - IdentityProviderModel identityProviderModel = this.realm.getIdentityProvidersStream() - .filter(p -> Objects.equals(p.getAlias(), alias) || Objects.equals(p.getInternalId(), alias)) - .findFirst().orElse(null); + IdentityProviderModel identityProviderModel = session.identityProviders().getByIdOrAlias(alias); return new IdentityProviderResource(this.auth, realm, session, identityProviderModel, adminEvent); } - private IdentityProviderFactory getProviderFactoryById(String providerId) { + private IdentityProviderFactory getProviderFactoryById(String providerId) { return getProviderFactories() .filter(providerFactory -> Objects.equals(providerId, providerFactory.getId())) .map(IdentityProviderFactory.class::cast) diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java index db113dfbc67..c28c181ecde 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java @@ -468,9 +468,8 @@ public class UserResource { } private Stream getFederatedIdentities(UserModel user) { - Set idps = realm.getIdentityProvidersStream().map(IdentityProviderModel::getAlias).collect(Collectors.toSet()); return session.users().getFederatedIdentitiesStream(realm, user) - .filter(identity -> idps.contains(identity.getIdentityProvider())) + .filter(identity -> session.identityProviders().getByAlias(identity.getIdentityProvider()) != null) .map(ModelToRepresentation::toRepresentation); } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java index 44e87d7f84e..211e05f9b97 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java @@ -730,7 +730,7 @@ public class TestingResourceProvider implements RealmResourceProvider { @Path("/identity-config") @Produces(MediaType.APPLICATION_JSON) public Map getIdentityProviderConfig(@QueryParam("alias") String alias) { - return session.getContext().getRealm().getIdentityProviderByAlias(alias).getConfig(); + return session.identityProviders().getByAlias(alias).getConfig(); } @PUT diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java index 4e0ebfb317b..9e493fd844d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerRunOnServerUtil.java @@ -60,9 +60,9 @@ final class BrokerRunOnServerUtil { execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); - IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setPostBrokerLoginFlowId(postBrokerFlow.getId()); - realm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }; } @@ -70,9 +70,9 @@ final class BrokerRunOnServerUtil { return session -> { RealmModel realm = session.getContext().getRealm(); - IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setPostBrokerLoginFlowId(null); - realm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }; } @@ -123,9 +123,9 @@ final class BrokerRunOnServerUtil { execution2.setParentFlow(newFlow.getId()); execution2 = appRealm.addAuthenticatorExecution(execution2); - IdentityProviderModel idp = appRealm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setFirstBrokerLoginFlowId(newFlow.getId()); - appRealm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }); } @@ -165,9 +165,9 @@ final class BrokerRunOnServerUtil { execution.setParentFlow(newFlow.getId()); appRealm.addAuthenticatorExecution(execution); - IdentityProviderModel idp = appRealm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setFirstBrokerLoginFlowId(newFlow.getId()); - appRealm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTokenExchangeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTokenExchangeTest.java index 89f36ddee39..1af0067914d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTokenExchangeTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTokenExchangeTest.java @@ -190,7 +190,7 @@ public final class KcOidcBrokerTokenExchangeTest extends AbstractInitializedBase private static void setupRealm(KeycloakSession session) { RealmModel realm = session.getContext().getRealm(); - IdentityProviderModel idp = realm.getIdentityProviderByAlias(IDP_OIDC_ALIAS); + IdentityProviderModel idp = session.identityProviders().getByAlias(IDP_OIDC_ALIAS); org.junit.Assert.assertNotNull(idp); ClientModel client = realm.addClient("test-app"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java index 6f68e2db1d1..d7029b3f2e6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java @@ -240,7 +240,7 @@ public class SocialLoginTest extends AbstractKeycloakTest { Policy clientPolicy = management.authz().getStoreFactory().getPolicyStore().create(server, clientPolicyRep); management.users().adminImpersonatingPermission().addAssociatedPolicy(clientPolicy); management.users().adminImpersonatingPermission().setDecisionStrategy(DecisionStrategy.AFFIRMATIVE); - realm.getIdentityProvidersStream().forEach(idp -> { + session.identityProviders().getAllStream().forEach(idp -> { management.idps().setPermissionsEnabled(idp, true); management.idps().exchangeToPermission(idp).addAssociatedPolicy(clientPolicy); }); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/broker/OrganizationIdentityProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/broker/OrganizationIdentityProviderTest.java index 254c0b3be0c..037728adaf3 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/broker/OrganizationIdentityProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/broker/OrganizationIdentityProviderTest.java @@ -252,7 +252,7 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest { RealmModel realm = session.realms().getRealmByName("master"); RealmModel current = session.getContext().getRealm(); session.getContext().setRealm(realm); - IdentityProviderModel idp = realm.getIdentityProviderByAlias("master-identity-provider"); + IdentityProviderModel idp = session.identityProviders().getByAlias("master-identity-provider"); // restore the context and try to add the idp. session.getContext().setRealm(current); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/sessionlimits/AbstractUserSessionLimitsBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/sessionlimits/AbstractUserSessionLimitsBrokerTest.java index dccacc851e2..df3a3afec5a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/sessionlimits/AbstractUserSessionLimitsBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/sessionlimits/AbstractUserSessionLimitsBrokerTest.java @@ -56,9 +56,9 @@ public abstract class AbstractUserSessionLimitsBrokerTest extends AbstractInitia configureSessionLimits(realm, postBrokerFlow, behavior, realmLimit, clientLimit); - IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setPostBrokerLoginFlowId(postBrokerFlow.getId()); - realm.updateIdentityProvider(idp); + session.identityProviders().update(idp); }); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/FlowUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/FlowUtil.java index 2cd8844babd..7fd1db1ca6b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/FlowUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/FlowUtil.java @@ -203,9 +203,9 @@ public class FlowUtil { public FlowUtil usesInIdentityProvider(String idpAlias) { // Setup new FirstBrokerLogin flow to identity provider - IdentityProviderModel idp = realm.getIdentityProviderByAlias(idpAlias); + IdentityProviderModel idp = session.identityProviders().getByAlias(idpAlias); idp.setFirstBrokerLoginFlowId(currentFlow.getId()); - realm.updateIdentityProvider(idp); + session.identityProviders().update(idp); return this; } @@ -329,4 +329,4 @@ public class FlowUtil { setFlow.accept(realm.getFlowByAlias(defaultFlowAlias)); } } -} \ No newline at end of file +} diff --git a/testsuite/model/src/test/java/org/keycloak/testsuite/model/FederatedIdentityModelTest.java b/testsuite/model/src/test/java/org/keycloak/testsuite/model/FederatedIdentityModelTest.java index 350cf8441af..223916c2b87 100644 --- a/testsuite/model/src/test/java/org/keycloak/testsuite/model/FederatedIdentityModelTest.java +++ b/testsuite/model/src/test/java/org/keycloak/testsuite/model/FederatedIdentityModelTest.java @@ -58,7 +58,7 @@ public class FederatedIdentityModelTest extends KeycloakModelTest { IdentityProviderModel identityProviderModel = identityProviderFactory.createConfig(); identityProviderModel.setAlias(IDENTITY_PROVIDER_ALIAS); - realm.addIdentityProvider(identityProviderModel); + s.identityProviders().create(identityProviderModel); userId = s.users().addUser(realm, USERNAME).getId(); }