From b278dbbb3d6f6882194abf00849e60c7c9e17470 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Wed, 5 Nov 2025 14:13:40 +0100 Subject: [PATCH] Allow identity provider configuration without defaults for user authentication (#43963) Closes #43552 Signed-off-by: stianst --- .../idm/IdentityProviderRepresentation.java | 42 +++++----- .../main/java/org/keycloak/util/Booleans.java | 38 +++++++++ .../topics/changes/changes-26_5_0.adoc | 4 + .../JpaIdentityProviderStorageProvider.java | 6 +- .../jpa/entities/IdentityProviderEntity.java | 36 ++++---- .../META-INF/jpa-changelog-26.5.0.xml | 15 ++++ .../datastore/DefaultExportImportManager.java | 3 +- .../provider/AbstractIdentityProvider.java | 3 +- ...dentityProviderMapperSyncModeDelegate.java | 6 +- .../models/utils/ModelToRepresentation.java | 5 -- .../models/IdentityProviderModel.java | 82 +++++++++++-------- .../IdentityProviderStorageProvider.java | 5 +- .../KubernetesIdentityProviderConfig.java | 2 +- .../oidc/AbstractOAuth2IdentityProvider.java | 9 +- .../broker/oidc/OIDCIdentityProvider.java | 9 +- .../keycloak/broker/saml/SAMLEndpoint.java | 3 +- .../broker/saml/SAMLIdentityProvider.java | 3 +- .../browser/OrganizationAuthenticator.java | 4 +- ...OrganizationAwareIdentityProviderBean.java | 5 +- .../AbstractTokenExchangeProvider.java | 3 +- .../resources/IdentityBrokerService.java | 13 +-- .../admin/IdentityProvidersResource.java | 7 +- .../twitter/TwitterIdentityProvider.java | 5 +- .../AbstractIdentityProviderTest.java | 7 +- .../IdentityProviderOidcTest.java | 16 ++-- .../IdentityProviderSamlTest.java | 2 +- .../external/SpiffeConfigTest.java | 20 +++++ .../testsuite/broker/KcOidcBrokerTest.java | 4 +- .../testsuite/cli/admin/KcAdmCreateTest.java | 2 +- 29 files changed, 228 insertions(+), 131 deletions(-) create mode 100644 core/src/main/java/org/keycloak/util/Booleans.java diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java index b9bcbbe904b..65d361c1def 100755 --- a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java @@ -49,14 +49,14 @@ public class IdentityProviderRepresentation { * @see #UPFLM_OFF */ @Deprecated - protected String updateProfileFirstLoginMode = UPFLM_ON; + protected String updateProfileFirstLoginMode; - protected boolean trustEmail; - protected boolean storeToken; - protected boolean addReadTokenRoleOnCreate; - protected boolean authenticateByDefault; - protected boolean linkOnly; - protected boolean hideOnLogin; + protected Boolean trustEmail; + protected Boolean storeToken; + protected Boolean addReadTokenRoleOnCreate; + protected Boolean authenticateByDefault; + protected Boolean linkOnly; + protected Boolean hideOnLogin; protected String firstBrokerLoginFlowAlias; protected String postBrokerLoginFlowAlias; protected String organizationId; @@ -103,19 +103,19 @@ public class IdentityProviderRepresentation { this.enabled = enabled; } - public boolean isLinkOnly() { + public Boolean isLinkOnly() { return linkOnly; } - public void setLinkOnly(boolean linkOnly) { + public void setLinkOnly(Boolean linkOnly) { this.linkOnly = linkOnly; } - public boolean isHideOnLogin() { + public Boolean isHideOnLogin() { return this.hideOnLogin; } - public void setHideOnLogin(boolean hideOnLogin) { + public void setHideOnLogin(Boolean hideOnLogin) { this.hideOnLogin = hideOnLogin; } @@ -126,8 +126,8 @@ public class IdentityProviderRepresentation { * @deprecated {@link #setUpdateProfileFirstLoginMode(String)} */ @Deprecated - public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) { - this.updateProfileFirstLoginMode = updateProfileFirstLogin ? UPFLM_ON : UPFLM_OFF; + public void setUpdateProfileFirstLogin(Boolean updateProfileFirstLogin) { + this.updateProfileFirstLoginMode = updateProfileFirstLogin == null ? null : (updateProfileFirstLogin ? UPFLM_ON : UPFLM_OFF); } /** @@ -150,12 +150,12 @@ public class IdentityProviderRepresentation { * @deprecated Replaced by configuration option in identity provider authenticator */ @Deprecated - public boolean isAuthenticateByDefault() { + public Boolean isAuthenticateByDefault() { return authenticateByDefault; } @Deprecated - public void setAuthenticateByDefault(boolean authenticateByDefault) { + public void setAuthenticateByDefault(Boolean authenticateByDefault) { this.authenticateByDefault = authenticateByDefault; } @@ -175,27 +175,27 @@ public class IdentityProviderRepresentation { this.postBrokerLoginFlowAlias = postBrokerLoginFlowAlias; } - public boolean isStoreToken() { + public Boolean isStoreToken() { return this.storeToken; } - public void setStoreToken(boolean storeToken) { + public void setStoreToken(Boolean storeToken) { this.storeToken = storeToken; } - public boolean isAddReadTokenRoleOnCreate() { + public Boolean isAddReadTokenRoleOnCreate() { return addReadTokenRoleOnCreate; } - public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) { + public void setAddReadTokenRoleOnCreate(Boolean addReadTokenRoleOnCreate) { this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate; } - public boolean isTrustEmail() { + public Boolean isTrustEmail() { return trustEmail; } - public void setTrustEmail(boolean trustEmail) { + public void setTrustEmail(Boolean trustEmail) { this.trustEmail = trustEmail; } diff --git a/core/src/main/java/org/keycloak/util/Booleans.java b/core/src/main/java/org/keycloak/util/Booleans.java new file mode 100644 index 00000000000..0522d70bb17 --- /dev/null +++ b/core/src/main/java/org/keycloak/util/Booleans.java @@ -0,0 +1,38 @@ +package org.keycloak.util; + +public class Booleans { + + /** + * Checks if a boolean is true, including support for null values where null is considered false + * + * @param b the boolean to check + * @return true if non-null and true + */ + public static Boolean isTrue(Boolean b) { + return b != null && b; + } + + /** + * Checks if a boolean is false, including support for null values where null is considered false + * + * @param b the boolean to check + * @return true if null and false + */ + public static Boolean isFalse(Boolean b) { + return b == null || !b; + } + + /** + * Compares two boolean, including support for null values where null is considered false + * + * @param a the first boolean to compare + * @param b the second boolean to compare + * @return true if both values have resolves to the same value + */ + public static Boolean equals(Boolean a, Boolean b) { + a = a != null && a; + b = b != null && b; + return a.equals(b); + } + +} diff --git a/docs/documentation/upgrading/topics/changes/changes-26_5_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_5_0.adoc index cda158fe78a..dd97da6a99e 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_5_0.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_5_0.adoc @@ -30,6 +30,10 @@ For anyone implementing a custom federated user authentication identity provider by Keycloak or `AbstractIdentityProvider` you need to update your implementation to implement the new `UserAuthenticationIdentityProvider` interface (all methods remain the same, they have just been moved). +Additionally, both `IdentityProviderModel` and `IdentityProviderRepresentation` are now using Boolean values to allow +configuration like `isHideOnLogin` to be null in order to not include these in Identity Provider types that do +not need these configurations. + === Accepting only normalized paths in requests Previously {project_name} accepted HTTP requests with paths containing double dots (`..`) or double slashes (`//`). When processing them, it normalized the path by collapsing double slashes and normalized the path according to RFC3986. diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIdentityProviderStorageProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIdentityProviderStorageProvider.java index ec4b41812d8..15119de061f 100644 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIdentityProviderStorageProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaIdentityProviderStorageProvider.java @@ -31,6 +31,7 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.MapJoin; +import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import org.hibernate.Session; @@ -252,10 +253,11 @@ public class JpaIdentityProviderStorageProvider implements IdentityProviderStora case ENABLED: case HIDE_ON_LOGIN: case LINK_ONLY: { + Path path = idp.get(key); if (Boolean.parseBoolean(value)) { - predicates.add(builder.isTrue(idp.get(key))); + predicates.add(builder.isTrue(path)); } else { - predicates.add(builder.isFalse(idp.get(key))); + predicates.add(builder.or(builder.isNull(path), builder.equal(path, Boolean.FALSE))); } break; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java index 640ff4e30c3..1b5f37d1f3a 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java @@ -57,22 +57,22 @@ public class IdentityProviderEntity { private boolean enabled; @Column(name = "TRUST_EMAIL") - private boolean trustEmail; + private Boolean trustEmail; @Column(name="STORE_TOKEN") - private boolean storeToken; + private Boolean storeToken; @Column(name="LINK_ONLY") - private boolean linkOnly; + private Boolean linkOnly; @Column(name="HIDE_ON_LOGIN") - private boolean hideOnLogin; + private Boolean hideOnLogin; @Column(name="ADD_TOKEN_ROLE") - protected boolean addReadTokenRoleOnCreate; + protected Boolean addReadTokenRoleOnCreate; @Column(name="AUTHENTICATE_BY_DEFAULT") - private boolean authenticateByDefault; + private Boolean authenticateByDefault; @Column(name="FIRST_BROKER_LOGIN_FLOW_ID") private String firstBrokerLoginFlowId; @@ -129,27 +129,27 @@ public class IdentityProviderEntity { this.enabled = enabled; } - public boolean isStoreToken() { + public Boolean isStoreToken() { return this.storeToken; } - public void setStoreToken(boolean storeToken) { + public void setStoreToken(Boolean storeToken) { this.storeToken = storeToken; } - public boolean isAuthenticateByDefault() { + public Boolean isAuthenticateByDefault() { return authenticateByDefault; } - public void setAuthenticateByDefault(boolean authenticateByDefault) { + public void setAuthenticateByDefault(Boolean authenticateByDefault) { this.authenticateByDefault = authenticateByDefault; } - public boolean isLinkOnly() { + public Boolean isLinkOnly() { return linkOnly; } - public void setLinkOnly(boolean linkOnly) { + public void setLinkOnly(Boolean linkOnly) { this.linkOnly = linkOnly; } @@ -177,11 +177,11 @@ public class IdentityProviderEntity { this.organizationId = organizationId; } - public boolean isHideOnLogin() { + public Boolean isHideOnLogin() { return this.hideOnLogin; } - public void setHideOnLogin(boolean hideOnLogin) { + public void setHideOnLogin(Boolean hideOnLogin) { this.hideOnLogin = hideOnLogin; } @@ -193,19 +193,19 @@ public class IdentityProviderEntity { this.config = config; } - public boolean isAddReadTokenRoleOnCreate() { + public Boolean isAddReadTokenRoleOnCreate() { return addReadTokenRoleOnCreate; } - public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) { + public void setAddReadTokenRoleOnCreate(Boolean addReadTokenRoleOnCreate) { this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate; } - public boolean isTrustEmail() { + public Boolean isTrustEmail() { return trustEmail; } - public void setTrustEmail(boolean trustEmail) { + public void setTrustEmail(Boolean trustEmail) { this.trustEmail = trustEmail; } diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-26.5.0.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-26.5.0.xml index a125cbed0c3..3d072b5c517 100644 --- a/model/jpa/src/main/resources/META-INF/jpa-changelog-26.5.0.xml +++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-26.5.0.xml @@ -58,4 +58,19 @@ + + + + + + + + + + + + + + + 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 90076b39ac4..9e4ff35bfda 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 @@ -110,6 +110,7 @@ import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageUtil; import org.keycloak.storage.federated.UserFederatedStorageProvider; +import org.keycloak.util.Booleans; import org.keycloak.util.JsonSerialization; import org.keycloak.utils.StringUtil; import org.keycloak.validation.ValidationUtil; @@ -1514,7 +1515,7 @@ public class DefaultExportImportManager implements ExportImportManager { String defaultProvider = null; if (rep.getIdentityProviders() != null) { for (IdentityProviderRepresentation i : rep.getIdentityProviders()) { - if (i.isEnabled() && i.isAuthenticateByDefault()) { + if (i.isEnabled() && Booleans.isTrue(i.isAuthenticateByDefault())) { defaultProvider = i.getProviderId(); break; } diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java index ad16071ac2d..40458edf95a 100755 --- a/server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java +++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java @@ -28,6 +28,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.sessions.AuthenticationSessionModel; +import org.keycloak.util.Booleans; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -206,7 +207,7 @@ public abstract class AbstractIdentityProvider if (isNewUser || federatedEmail != null && !federatedEmail.equalsIgnoreCase(localEmail)) { IdentityProviderModel config = context.getIdpConfig(); - boolean trustEmail = config.isTrustEmail(); + boolean trustEmail = Booleans.isTrue(config.isTrustEmail()); if (logger.isTraceEnabled()) { logger.tracef("Email %s verified automatically after updating user '%s' through Identity provider '%s' ", trustEmail ? "" : "not", user.getUsername(), config.getAlias()); diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSyncModeDelegate.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSyncModeDelegate.java index b27d1f469d8..7a9374c7f8b 100644 --- a/server-spi-private/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSyncModeDelegate.java +++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSyncModeDelegate.java @@ -13,7 +13,11 @@ public final class IdentityProviderMapperSyncModeDelegate { protected static final Logger logger = Logger.getLogger(IdentityProviderMapperSyncModeDelegate.class); public static void delegateUpdateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context, IdentityProviderMapper mapper) { - IdentityProviderSyncMode effectiveSyncMode = combineIdpAndMapperSyncMode(context.getIdpConfig().getSyncMode(), mapperModel.getSyncMode()); + IdentityProviderSyncMode idpSyncMode = context.getIdpConfig().getSyncMode(); + if (idpSyncMode == null) { + idpSyncMode = IdentityProviderSyncMode.LEGACY; + } + IdentityProviderSyncMode effectiveSyncMode = combineIdpAndMapperSyncMode(idpSyncMode, mapperModel.getSyncMode()); if (!mapper.supportsSyncMode(effectiveSyncMode)) { logger.warnf("The mapper %s does not explicitly support sync mode %s. Please ensure that the SPI supports the sync mode correctly and update it to reflect this.", mapper.getDisplayType(), effectiveSyncMode); 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 ef73e75b1a2..a42980e2337 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 @@ -890,11 +890,6 @@ public class ModelToRepresentation { providerRep.setConfig(config); providerRep.setAddReadTokenRoleOnCreate(identityProviderModel.isAddReadTokenRoleOnCreate()); - String syncMode = config.get(IdentityProviderModel.SYNC_MODE); - if (syncMode == null) { - config.put(IdentityProviderModel.SYNC_MODE, "LEGACY"); - } - String firstBrokerLoginFlowId = identityProviderModel.getFirstBrokerLoginFlowId(); if (firstBrokerLoginFlowId != null) { AuthenticationFlowModel flow = realm.getAuthenticationFlowById(firstBrokerLoginFlowId); 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 8e107b50d48..23df31ea67d 100755 --- a/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java +++ b/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java @@ -75,18 +75,18 @@ public class IdentityProviderModel implements Serializable { private boolean enabled; - private boolean trustEmail; + private Boolean trustEmail; - private boolean storeToken; + private Boolean storeToken; - protected boolean addReadTokenRoleOnCreate; + protected Boolean addReadTokenRoleOnCreate; - protected boolean linkOnly; + protected Boolean linkOnly; /** * Specifies if particular provider should be used by default for authentication even before displaying login screen */ - private boolean authenticateByDefault; + private Boolean authenticateByDefault; private String firstBrokerLoginFlowId; @@ -98,7 +98,7 @@ public class IdentityProviderModel implements Serializable { private String displayIconClasses; - private boolean hideOnLogin; + private Boolean hideOnLogin; /** *

A map containing the configuration and properties for a specific identity provider instance and implementation. The items @@ -162,29 +162,29 @@ public class IdentityProviderModel implements Serializable { this.enabled = enabled; } - public boolean isStoreToken() { + public Boolean isStoreToken() { return this.storeToken; } - public void setStoreToken(boolean storeToken) { + public void setStoreToken(Boolean storeToken) { this.storeToken = storeToken; } - public boolean isLinkOnly() { + public Boolean isLinkOnly() { return linkOnly; } - public void setLinkOnly(boolean linkOnly) { + public void setLinkOnly(Boolean linkOnly) { this.linkOnly = linkOnly; } @Deprecated - public boolean isAuthenticateByDefault() { + public Boolean isAuthenticateByDefault() { return authenticateByDefault; } @Deprecated - public void setAuthenticateByDefault(boolean authenticateByDefault) { + public void setAuthenticateByDefault(Boolean authenticateByDefault) { this.authenticateByDefault = authenticateByDefault; } @@ -212,19 +212,19 @@ public class IdentityProviderModel implements Serializable { this.config = config; } - public boolean isAddReadTokenRoleOnCreate() { + public Boolean isAddReadTokenRoleOnCreate() { return addReadTokenRoleOnCreate; } - public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) { + public void setAddReadTokenRoleOnCreate(Boolean addReadTokenRoleOnCreate) { this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate; } - public boolean isTrustEmail() { + public Boolean isTrustEmail() { return trustEmail; } - public void setTrustEmail(boolean trustEmail) { + public void setTrustEmail(Boolean trustEmail) { this.trustEmail = trustEmail; } @@ -259,35 +259,35 @@ public class IdentityProviderModel implements Serializable { } public IdentityProviderSyncMode getSyncMode() { - return IdentityProviderSyncMode.valueOf(getConfig().getOrDefault(SYNC_MODE, "LEGACY")); + String syncMode = getConfig().get(SYNC_MODE); + return syncMode != null ? IdentityProviderSyncMode.valueOf(syncMode) : null; } public void setSyncMode(IdentityProviderSyncMode syncMode) { - getConfig().put(SYNC_MODE, syncMode.toString()); + getConfig().put(SYNC_MODE, syncMode != null ? syncMode.toString() : null); } public boolean isLoginHint() { - return Boolean.valueOf(getConfig().get(LOGIN_HINT)); + return getBooleanConfig(LOGIN_HINT); } - public void setLoginHint(boolean loginHint) { - getConfig().put(LOGIN_HINT, String.valueOf(loginHint)); + public void setLoginHint(Boolean loginHint) { + setBooleanConfig(LOGIN_HINT, loginHint); } public boolean isPassMaxAge() { - return Boolean.valueOf(getConfig().get(PASS_MAX_AGE)); + return getBooleanConfig(PASS_MAX_AGE); } - public void setPassMaxAge(boolean passMaxAge) { - getConfig().put(PASS_MAX_AGE, String.valueOf(passMaxAge)); + public void setPassMaxAge(Boolean passMaxAge) { + setBooleanConfig(PASS_MAX_AGE, passMaxAge); } - - public boolean isHideOnLogin() { + public Boolean isHideOnLogin() { return this.hideOnLogin; } - public void setHideOnLogin(boolean hideOnLogin) { + public void setHideOnLogin(Boolean hideOnLogin) { this.hideOnLogin = hideOnLogin; } @@ -297,23 +297,23 @@ public class IdentityProviderModel implements Serializable { * @return */ public boolean isTransientUsers() { - return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && Boolean.valueOf(getConfig().get(DO_NOT_STORE_USERS)); + return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && getBooleanConfig(DO_NOT_STORE_USERS); } /** * Configures the IdP to not store users in Keycloak database. Default value: {@code false}. * @return */ - public void setTransientUsers(boolean transientUsers) { - getConfig().put(DO_NOT_STORE_USERS, String.valueOf(transientUsers)); + public void setTransientUsers(Boolean transientUsers) { + setBooleanConfig(DO_NOT_STORE_USERS, transientUsers); } public boolean isFilteredByClaims() { - return Boolean.valueOf(getConfig().getOrDefault(FILTERED_BY_CLAIMS, Boolean.toString(false))); + return getBooleanConfig(FILTERED_BY_CLAIMS); } - public void setFilteredByClaims(boolean filteredByClaims) { - getConfig().put(FILTERED_BY_CLAIMS, String.valueOf(filteredByClaims)); + public void setFilteredByClaims(Boolean filteredByClaims) { + setBooleanConfig(FILTERED_BY_CLAIMS, filteredByClaims); } public String getClaimFilterName() { @@ -341,11 +341,11 @@ public class IdentityProviderModel implements Serializable { } public boolean isCaseSensitiveOriginalUsername() { - return Boolean.parseBoolean(getConfig().getOrDefault(CASE_SENSITIVE_ORIGINAL_USERNAME, Boolean.FALSE.toString())); + return getBooleanConfig(CASE_SENSITIVE_ORIGINAL_USERNAME); } - public void setCaseSensitiveOriginalUsername(boolean caseSensitive) { - getConfig().put(CASE_SENSITIVE_ORIGINAL_USERNAME, Boolean.valueOf(caseSensitive).toString()); + public void setCaseSensitiveOriginalUsername(Boolean caseSensitive) { + setBooleanConfig(CASE_SENSITIVE_ORIGINAL_USERNAME, caseSensitive); } public void setMinValidityToken(int minValidityToken) { @@ -386,4 +386,14 @@ public class IdentityProviderModel implements Serializable { return Objects.equals(getInternalId(), ((IdentityProviderModel) obj).getInternalId()) && Objects.equals(getAlias(), ((IdentityProviderModel) obj).getAlias()); } + + private boolean getBooleanConfig(String key) { + String value = getConfig().get(key); + return value != null ? Boolean.parseBoolean(value) : Boolean.FALSE; + } + + private void setBooleanConfig(String key, Boolean value) { + getConfig().put(key, value != null ? String.valueOf(value) : null); + } + } diff --git a/server-spi/src/main/java/org/keycloak/models/IdentityProviderStorageProvider.java b/server-spi/src/main/java/org/keycloak/models/IdentityProviderStorageProvider.java index 52fbd2400e6..1775d080ebf 100644 --- a/server-spi/src/main/java/org/keycloak/models/IdentityProviderStorageProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/IdentityProviderStorageProvider.java @@ -23,6 +23,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.keycloak.util.Booleans; import org.keycloak.provider.Provider; /** @@ -236,9 +237,9 @@ public interface IdentityProviderStorageProvider extends Provider { ENABLED(IdentityProviderModel.ENABLED, Boolean.TRUE.toString(), IdentityProviderModel::isEnabled), - LINK_ONLY(IdentityProviderModel.LINK_ONLY, Boolean.FALSE.toString(), Predicate.not(IdentityProviderModel::isLinkOnly)), + LINK_ONLY(IdentityProviderModel.LINK_ONLY, Boolean.FALSE.toString(), m -> Booleans.isFalse(m.isLinkOnly())), - HIDE_ON_LOGIN(IdentityProviderModel.HIDE_ON_LOGIN, Boolean.FALSE.toString(), Predicate.not(IdentityProviderModel::isHideOnLogin)); + HIDE_ON_LOGIN(IdentityProviderModel.HIDE_ON_LOGIN, Boolean.FALSE.toString(), m -> Booleans.isFalse(m.isHideOnLogin())); private final String key; private final String value; diff --git a/services/src/main/java/org/keycloak/broker/kubernetes/KubernetesIdentityProviderConfig.java b/services/src/main/java/org/keycloak/broker/kubernetes/KubernetesIdentityProviderConfig.java index fddd5c6ad1a..33be94f3972 100644 --- a/services/src/main/java/org/keycloak/broker/kubernetes/KubernetesIdentityProviderConfig.java +++ b/services/src/main/java/org/keycloak/broker/kubernetes/KubernetesIdentityProviderConfig.java @@ -17,7 +17,7 @@ public class KubernetesIdentityProviderConfig extends OIDCIdentityProviderConfig } @Override - public boolean isHideOnLogin() { + public Boolean isHideOnLogin() { return true; } diff --git a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java index 92f76b0d50e..511a7ad525a 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java @@ -90,6 +90,7 @@ import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.RealmsResource; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.urls.UrlType; +import org.keycloak.util.Booleans; import org.keycloak.util.JsonSerialization; import org.keycloak.utils.StringUtil; import org.keycloak.vault.VaultStringSecret; @@ -357,7 +358,7 @@ public abstract class AbstractOAuth2IdentityProvider 0) { @@ -512,7 +513,7 @@ public abstract class AbstractOAuth2IdentityProvider 0) { long accessTokenExpiration = Time.currentTime() + tokenResponse.getExpiresIn(); tokenResponse.getOtherClaims().put(ACCESS_TOKEN_EXPIRATION, accessTokenExpiration); @@ -976,7 +977,7 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider contextData.get(VALIDATED_ACCESS_TOKEN)); Boolean emailVerified = getEmailVerifiedClaim(token); - if (!config.isTrustEmail() || emailVerified == null) { + if (Booleans.isFalse(config.isTrustEmail()) || emailVerified == null) { // fallback to the default behavior if trust is disabled or there is no email_verified claim super.setEmailVerified(user, context); return; diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java index 6f79b663a4a..8928a9e35af 100755 --- a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java +++ b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java @@ -119,6 +119,7 @@ import org.keycloak.saml.validators.ConditionsValidator; import org.keycloak.saml.validators.DestinationValidator; import org.keycloak.services.util.CacheControlUtil; import org.keycloak.sessions.AuthenticationSessionModel; +import org.keycloak.util.Booleans; import org.keycloak.utils.StringUtil; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -658,7 +659,7 @@ public class SAMLEndpoint { identity.setEmail(subjectNameID.getValue()); } - if (config.isStoreToken()) { + if (Booleans.isTrue(config.isStoreToken())) { identity.setToken(samlResponse); } diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java index 7020252714e..c74415eea7d 100755 --- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java @@ -84,6 +84,7 @@ import org.keycloak.saml.processing.core.saml.v2.util.SAMLMetadataUtil; import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator; import org.keycloak.saml.validators.DestinationValidator; import org.keycloak.sessions.AuthenticationSessionModel; +import org.keycloak.util.Booleans; import org.keycloak.util.JsonSerialization; import org.w3c.dom.Document; @@ -159,7 +160,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider Booleans.isFalse(i.isHideOnLogin())); } private OrganizationProvider getOrganizationProvider() { 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 3117c75f1fa..129e5a3be09 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 @@ -25,6 +25,7 @@ import org.keycloak.forms.login.freemarker.model.IdentityProviderBean; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.OrganizationModel; import org.keycloak.organization.utils.Organizations; +import org.keycloak.util.Booleans; import static org.keycloak.models.IdentityProviderStorageProvider.FetchMode.ALL; import static org.keycloak.models.IdentityProviderStorageProvider.FetchMode.ORG_ONLY; @@ -64,7 +65,7 @@ public class OrganizationAwareIdentityProviderBean extends IdentityProviderBean // we already have the organization, just fetch the organization's public enabled IDPs. if (this.organization != null) { return organization.getIdentityProviders() - .filter(idp -> idp.isEnabled() && !idp.isLinkOnly() && !idp.isHideOnLogin()) + .filter(idp -> idp.isEnabled() && Booleans.isFalse(idp.isLinkOnly()) && Booleans.isFalse(idp.isHideOnLogin())) .filter(idp -> !Objects.equals(existingIDP, idp.getAlias())) .map(idp -> createIdentityProvider(super.realm, super.baseURI, idp)) .sorted(IDP_COMPARATOR_INSTANCE).toList(); @@ -103,6 +104,6 @@ public class OrganizationAwareIdentityProviderBean extends IdentityProviderBean if (organization != null && !Objects.equals(organization.getId(),idp.getOrganizationId())) { return false; } - return !idp.isHideOnLogin(); + return Booleans.isFalse(idp.isHideOnLogin()); } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/tokenexchange/AbstractTokenExchangeProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/tokenexchange/AbstractTokenExchangeProvider.java index 527ca098a64..0a8fbf6eff5 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/tokenexchange/AbstractTokenExchangeProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/tokenexchange/AbstractTokenExchangeProvider.java @@ -63,6 +63,7 @@ import org.keycloak.services.resources.admin.fgap.AdminPermissions; import org.keycloak.services.validation.Validation; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel; +import org.keycloak.util.Booleans; import static org.keycloak.authentication.authenticators.util.AuthenticatorUtils.getDisabledByBruteForceEventError; import static org.keycloak.models.IdentityProviderType.EXCHANGE_EXTERNAL_TOKEN; @@ -389,7 +390,7 @@ public abstract class AbstractTokenExchangeProvider implements TokenExchangeProv target.importNewUser(session, realm, user, mapper, context); } - if (context.getIdpConfig().isTrustEmail() && !Validation.isBlank(user.getEmail())) { + if (Booleans.isTrue(context.getIdpConfig().isTrustEmail()) && !Validation.isBlank(user.getEmail())) { logger.debugf("Email verified automatically after registration of user '%s' through Identity provider '%s' ", user.getUsername(), context.getIdpConfig().getAlias()); user.setEmailVerified(true); } 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 85189ee2600..90e80e34119 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -96,6 +96,7 @@ import org.keycloak.services.util.DefaultClientSessionContext; import org.keycloak.services.validation.Validation; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel; +import org.keycloak.util.Booleans; import org.keycloak.util.JsonSerialization; import jakarta.ws.rs.GET; @@ -395,7 +396,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider if (identityProviderModel == null) { throw new IdentityBrokerException("Identity Provider [" + providerAlias + "] not found."); } - if (identityProviderModel.isLinkOnly()) { + if (Booleans.isTrue(identityProviderModel.isLinkOnly())) { throw new IdentityBrokerException("Identity Provider [" + providerAlias + "] is not allowed to perform a login."); } if (clientSessionCode.getClientSession() != null && loginHint != null) { @@ -504,7 +505,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider UserAuthenticationIdentityProvider identityProvider = getIdentityProvider(session, providerAlias); IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerAlias); - if (identityProviderConfig.isStoreToken()) { + if (Booleans.isTrue(identityProviderConfig.isStoreToken())) { FederatedIdentityModel identity = this.session.users().getFederatedIdentity(this.realmModel, authResult.user(), providerAlias); if (identity == null) { @@ -553,7 +554,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider AuthenticationSessionModel authenticationSession = context.getAuthenticationSession(); String providerAlias = identityProviderConfig.getAlias(); - if (!identityProviderConfig.isStoreToken()) { + if (Booleans.isFalse(identityProviderConfig.isStoreToken())) { if (isDebugEnabled()) { logger.debugf("Token will not be stored for identity provider [%s].", providerAlias); } @@ -731,7 +732,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider event.user(federatedUser); event.detail(Details.USERNAME, federatedUser.getUsername()); - if (context.getIdpConfig().isAddReadTokenRoleOnCreate()) { + if (Booleans.isTrue(context.getIdpConfig().isAddReadTokenRoleOnCreate())) { ClientModel brokerClient = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID); if (brokerClient == null) { throw new IdentityBrokerException("Client 'broker' not available. Maybe realm has not migrated to support the broker token exchange service"); @@ -1014,7 +1015,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider if (federatedUser != null) { - if (context.getIdpConfig().isStoreToken()) { + if (Booleans.isTrue(context.getIdpConfig().isStoreToken())) { FederatedIdentityModel oldModel = this.session.users().getFederatedIdentity(this.realmModel, federatedUser, context.getIdpConfig().getAlias()); if (!ObjectUtil.isEqualOrBothNull(context.getToken(), oldModel.getToken())) { this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, newModel); @@ -1155,7 +1156,7 @@ public class IdentityBrokerService implements UserAuthenticationIdentityProvider } private void updateToken(BrokeredIdentityContext context, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) { - if (context.getIdpConfig().isStoreToken() && !ObjectUtil.isEqualOrBothNull(context.getToken(), federatedIdentityModel.getToken())) { + if (Booleans.isTrue(context.getIdpConfig().isStoreToken()) && !ObjectUtil.isEqualOrBothNull(context.getToken(), federatedIdentityModel.getToken())) { // like in OIDCIdentityProvider.exchangeStoredToken() // we shouldn't override the refresh token if it is null in the context and not null in the DB // as for google IDP it will be lost forever 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 fc62e69aa06..343abcf828a 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 @@ -129,12 +129,7 @@ public class IdentityProvidersResource { String providerId = formDataMap.getFirst("providerId").asString(); String config = StreamUtil.readString(formDataMap.getFirst("file").asInputStream()); IdentityProviderFactory providerFactory = getProviderFactoryById(providerId); - final Map parsedConfig = providerFactory.parseConfig(session, config); - String syncMode = parsedConfig.get(IdentityProviderModel.SYNC_MODE); - if (syncMode == null) { - parsedConfig.put(IdentityProviderModel.SYNC_MODE, "LEGACY"); - } - return parsedConfig; + return providerFactory.parseConfig(session, config); } /** diff --git a/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java index 256dfc7d812..f8aeed98038 100755 --- a/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java +++ b/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java @@ -42,6 +42,7 @@ import org.keycloak.services.ErrorPage; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import org.keycloak.sessions.AuthenticationSessionModel; +import org.keycloak.util.Booleans; import org.keycloak.vault.VaultStringSecret; import twitter4j.AccessToken; import twitter4j.OAuthAuthorization; @@ -132,7 +133,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider s.identityProviders().getByAlias("new-identity-provider").getConfig().get("clientSecret"), String.class)); @@ -211,8 +211,8 @@ public class IdentityProviderOidcTest extends AbstractIdentityProviderTest { assertEquals(OIDCLoginProtocol.CLIENT_SECRET_BASIC, representation.getConfig().get("clientAuthMethod")); assertTrue(representation.isEnabled()); - assertFalse(representation.isStoreToken()); - assertFalse(representation.isTrustEmail()); + assertNull(representation.isStoreToken()); + assertNull(representation.isTrustEmail()); assertEquals("some secret value", runOnServer.fetch(s -> s.identityProviders().getByAlias("new-identity-provider").getConfig().get("clientSecret"), String.class)); @@ -249,8 +249,8 @@ public class IdentityProviderOidcTest extends AbstractIdentityProviderTest { assertEquals(OIDCLoginProtocol.PRIVATE_KEY_JWT, representation.getConfig().get("clientAuthMethod")); assertNull(representation.getConfig().get("jwtX509HeadersEnabled")); assertTrue(representation.isEnabled()); - assertFalse(representation.isStoreToken()); - assertFalse(representation.isTrustEmail()); + assertNull(representation.isStoreToken()); + assertNull(representation.isTrustEmail()); managedRealm.cleanup().add(r -> r.identityProviders().get(id).remove()); } @@ -283,8 +283,8 @@ public class IdentityProviderOidcTest extends AbstractIdentityProviderTest { assertEquals(OIDCLoginProtocol.PRIVATE_KEY_JWT, representation.getConfig().get("clientAuthMethod")); assertEquals("true", representation.getConfig().get("jwtX509HeadersEnabled")); assertTrue(representation.isEnabled()); - assertFalse(representation.isStoreToken()); - assertFalse(representation.isTrustEmail()); + assertNull(representation.isStoreToken()); + assertNull(representation.isTrustEmail()); managedRealm.cleanup().add(r -> r.identityProviders().get(id).remove()); } diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/identityprovider/IdentityProviderSamlTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/identityprovider/IdentityProviderSamlTest.java index 73a0eef4ebe..5bdda3489dd 100644 --- a/tests/base/src/test/java/org/keycloak/tests/admin/identityprovider/IdentityProviderSamlTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/admin/identityprovider/IdentityProviderSamlTest.java @@ -417,7 +417,7 @@ public class IdentityProviderSamlTest extends AbstractIdentityProviderTest { // import endpoint simply converts IDPSSODescriptor into key value pairs. // check that saml-idp-metadata.xml was properly converted into key value pairs //System.out.println(config); - List keys = new ArrayList<>(List.of("syncMode", + List keys = new ArrayList<>(List.of( "validateSignature", "singleLogoutServiceUrl", "postBindingLogout", diff --git a/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java b/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java index 540cee0bb88..7aa3349a3ce 100644 --- a/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/client/authentication/external/SpiffeConfigTest.java @@ -2,6 +2,9 @@ package org.keycloak.tests.client.authentication.external; import com.fasterxml.jackson.databind.JsonNode; import jakarta.ws.rs.core.Response; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; @@ -29,6 +32,7 @@ import org.keycloak.testsuite.util.IdentityProviderBuilder; import org.openqa.selenium.NoSuchElementException; import java.io.IOException; +import java.util.Map; @KeycloakIntegrationTest(config = SpiffeClientAuthTest.SpiffeServerConfig.class) @TestMethodOrder(MethodOrderer.MethodName.class) @@ -58,6 +62,22 @@ public class SpiffeConfigTest { IdentityProviderRepresentation rep = createConfig("testConfig", "spiffe://test", "https://localhost"); Assertions.assertEquals(201, idps.create(rep).getStatus()); + IdentityProviderRepresentation createdRep = realm.admin().identityProviders().get(rep.getAlias()).toRepresentation(); + + Assertions.assertTrue(createdRep.isEnabled()); + MatcherAssert.assertThat(createdRep.getConfig(), Matchers.equalTo(Map.of("bundleEndpoint", "https://localhost", "issuer", "spiffe://test"))); + + Assertions.assertNull(createdRep.getUpdateProfileFirstLoginMode()); + Assertions.assertNull(createdRep.getFirstBrokerLoginFlowAlias()); + Assertions.assertNull(createdRep.getPostBrokerLoginFlowAlias()); + Assertions.assertNull(createdRep.getOrganizationId()); + Assertions.assertNull(createdRep.isAddReadTokenRoleOnCreate()); + Assertions.assertNull(createdRep.isAuthenticateByDefault()); + Assertions.assertNull(createdRep.isHideOnLogin()); + Assertions.assertNull(createdRep.isLinkOnly()); + Assertions.assertNull(createdRep.isTrustEmail()); + Assertions.assertNull(createdRep.isStoreToken()); + checkNotDisplayOnLoginPages("testConfig"); checkNoIdpsInAccountConsole(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java index 9b26f521205..97b4944e0c8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTest.java @@ -857,13 +857,13 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest { } private void updateIdPSyncMode(IdentityProviderRepresentation idProvider, IdentityProviderResource idProviderResource, - IdentityProviderSyncMode syncMode, boolean trustEmail) { + IdentityProviderSyncMode syncMode, Boolean trustEmail) { assertThat(idProvider, Matchers.notNullValue()); assertThat(idProviderResource, Matchers.notNullValue()); assertThat(syncMode, Matchers.notNullValue()); if (idProvider.getConfig().get(IdentityProviderModel.SYNC_MODE).equals(syncMode.name()) - && idProvider.isTrustEmail() == trustEmail) { + && trustEmail.equals(idProvider.isTrustEmail())) { return; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmCreateTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmCreateTest.java index 9bafd62da20..c758ca8dda7 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmCreateTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cli/admin/KcAdmCreateTest.java @@ -55,7 +55,7 @@ public class KcAdmCreateTest extends AbstractAdmCliTest { } // If the sync mode is not present on creating the idp, it will never be stored automatically. However, the model will always report behaviour as "LEGACY", so no errors should occur. - Assert.assertEquals("LEGACY", realmResource.identityProviders().get("idpAlias").toRepresentation().getConfig().get(IdentityProviderModel.SYNC_MODE)); + Assert.assertNull(realmResource.identityProviders().get("idpAlias").toRepresentation().getConfig().get(IdentityProviderModel.SYNC_MODE)); } @Test