From a804400c842d9e1198a1c24b520498b1466c877f Mon Sep 17 00:00:00 2001 From: mposolda Date: Fri, 13 Jan 2023 14:14:08 +0100 Subject: [PATCH] Added KERBEROS feature. Disable it when running tests on FIPS closes #14966 --- .../java/org/keycloak/common/Profile.java | 4 ++ .../common/util/KerberosJdkProvider.java | 20 ++++++ docs/fips.md | 18 +++++ .../KerberosFederationProviderFactory.java | 9 ++- ...ndDistTest.testBuildHelp.unix.approved.txt | 4 +- ...istTest.testBuildHelp.windows.approved.txt | 4 +- ...istTest.testStartDevHelp.unix.approved.txt | 4 +- ...Test.testStartDevHelp.windows.approved.txt | 4 +- ...Test.testStartDevHelpAll.unix.approved.txt | 4 +- ...t.testStartDevHelpAll.windows.approved.txt | 4 +- ...ndDistTest.testStartHelp.unix.approved.txt | 4 +- ...istTest.testStartHelp.windows.approved.txt | 4 +- ...istTest.testStartHelpAll.unix.approved.txt | 4 +- ...Test.testStartHelpAll.windows.approved.txt | 4 +- .../browser/SpnegoAuthenticator.java | 1 - .../browser/SpnegoAuthenticatorFactory.java | 8 ++- .../SpnegoDisabledAuthenticatorFactory.java | 65 +++++++++++++++++++ .../keycloak/provider/ProviderManager.java | 2 +- ...ycloak.authentication.AuthenticatorFactory | 1 + .../testsuite/util/KerberosUtils.java | 40 ++++++++++++ .../testsuite/admin/UserStorageRestTest.java | 8 +++ .../authentication/InitialFlowsTest.java | 6 +- .../admin/authentication/ProvidersTest.java | 6 +- .../kerberos/AbstractKerberosTest.java | 6 ++ .../tests/base/testsuites/fips-suite | 1 + .../integration-arquillian/tests/pom.xml | 3 + .../resources/partials/user-storage-ldap.html | 2 +- 27 files changed, 212 insertions(+), 28 deletions(-) create mode 100644 services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoDisabledAuthenticatorFactory.java create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosUtils.java diff --git a/common/src/main/java/org/keycloak/common/Profile.java b/common/src/main/java/org/keycloak/common/Profile.java index 44c6108410..242619e3eb 100755 --- a/common/src/main/java/org/keycloak/common/Profile.java +++ b/common/src/main/java/org/keycloak/common/Profile.java @@ -22,6 +22,7 @@ import org.keycloak.common.profile.ProfileConfigResolver; import org.keycloak.common.profile.ProfileException; import org.keycloak.common.profile.PropertiesFileProfileConfigResolver; import org.keycloak.common.profile.PropertiesProfileConfigResolver; +import org.keycloak.common.util.KerberosJdkProvider; import java.util.Arrays; import java.util.Collections; @@ -81,6 +82,9 @@ public class Profile { STEP_UP_AUTHENTICATION("Step-up Authentication", Type.DEFAULT), + // Check if kerberos is available in underlying JVM and auto-detect if feature should be enabled or disabled by default based on that + KERBEROS("Kerberos", KerberosJdkProvider.getProvider().isKerberosAvailable() ? Type.DEFAULT : Type.DISABLED_BY_DEFAULT), + RECOVERY_CODES("Recovery codes", Type.PREVIEW), UPDATE_EMAIL("Update Email Action", Type.PREVIEW), diff --git a/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java b/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java index f84f4d906d..d152e4a605 100644 --- a/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java +++ b/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java @@ -20,6 +20,8 @@ package org.keycloak.common.util; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; +import org.jboss.logging.Logger; import org.keycloak.common.constants.KerberosConstants; import javax.security.auth.Subject; @@ -31,9 +33,11 @@ import java.io.File; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.security.PrivilegedExceptionAction; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; @@ -44,6 +48,8 @@ import java.util.Set; */ public abstract class KerberosJdkProvider { + private static final Logger logger = Logger.getLogger(KerberosJdkProvider.class); + public abstract Configuration createJaasConfigurationForServer(String keytab, String serverPrincipal, boolean debug); public abstract Configuration createJaasConfigurationForUsernamePasswordLogin(boolean debug); @@ -55,6 +61,20 @@ public abstract class KerberosJdkProvider { return kerberosTicketToGSSCredential(kerberosTicket, GSSCredential.DEFAULT_LIFETIME, GSSCredential.INITIATE_ONLY); } + /** + * @return true if Kerberos (GSS API) is available in underlying JDK and it is possible to use it. False otherwise + */ + public boolean isKerberosAvailable() { + GSSManager gssManager = GSSManager.getInstance(); + List supportedMechs = Arrays.asList(gssManager.getMechs()); + if (supportedMechs.contains(KerberosConstants.KRB5_OID)) { + return true; + } else { + logger.warnf("Kerberos feature not supported by JDK. Check security providers for your JDK in java.security. Supported mechanisms: %s", supportedMechs); + return false; + } + } + // Actually can use same on both JDKs public GSSCredential kerberosTicketToGSSCredential(KerberosTicket kerberosTicket, final int lifetime, final int usage) { try { diff --git a/docs/fips.md b/docs/fips.md index 46fb2768de..8474e5e93e 100644 --- a/docs/fips.md +++ b/docs/fips.md @@ -97,6 +97,24 @@ When starting server at startup, you can check that startup log contains `KC` pr KC(BCFIPS version 1.000203 Approved Mode) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider, ``` +Other considerations +-------------------- +#### SAML and Kerberos +In order to have SAML working, there is a need to have `XMLDSig` security provider to be available in your `JAVA_HOME/conf/security/java.security`. +In order to have Kerberos working, there is a need to have `SunJGSS` security provider available. In FIPS enabled RHEL 8.6 in OpenJDK 17.0.5, these +security providers are not by default in the `java.security`, which means that they effectively cannot work. + +To have SAML working, you can manually add the provider into `java.security` into the list fips providers. For example add the line like: +``` +fips.provider.7=XMLDSig +``` +Adding this security provider should be fine as in fact it is FIPS compliant and likely will be added by default in the future OpenJDK micro version. +Details: https://bugzilla.redhat.com/show_bug.cgi?id=1940064 + +For Kerberos, there are few more things to be done to have security provider FIPS compliant. Hence it is not recommended to add security provider +if you want to be FIPS compliant. The `KERBEROS` feature is disabled by default in Keycloak when it is executed on this platform and when security provider is not +available. Details: https://bugzilla.redhat.com/show_bug.cgi?id=2051628 + Run the CLI on the FIPS host ---------------------------- In case you want to run Client Registration CLI (`kcreg.sh/bat` script) or Admin CLI (`kcadm.sh/bat` script), it is needed diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java index 75e9d181bc..b07f60b6da 100755 --- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java +++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProviderFactory.java @@ -19,6 +19,7 @@ package org.keycloak.federation.kerberos; import org.jboss.logging.Logger; import org.keycloak.Config; +import org.keycloak.common.Profile; import org.keycloak.common.constants.KerberosConstants; import org.keycloak.component.ComponentModel; import org.keycloak.federation.kerberos.impl.KerberosServerSubjectAuthenticator; @@ -29,6 +30,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.representations.idm.CredentialRepresentation; @@ -45,7 +47,7 @@ import java.util.List; * * @author Marek Posolda */ -public class KerberosFederationProviderFactory implements UserStorageProviderFactory { +public class KerberosFederationProviderFactory implements UserStorageProviderFactory, EnvironmentDependentProviderFactory { private static final Logger logger = Logger.getLogger(KerberosFederationProviderFactory.class); public static final String PROVIDER_NAME = "kerberos"; @@ -60,6 +62,11 @@ public class KerberosFederationProviderFactory implements UserStorageProviderFac return PROVIDER_NAME; } + @Override + public boolean isSupported() { + return Profile.isFeatureEnabled(Profile.Feature.KERBEROS); + } + protected static final List configProperties; static { diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt index cdc25b6715..caae3ba5cf 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.unix.approved.txt @@ -46,14 +46,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt index f98a2a2059..839bde4527 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testBuildHelp.windows.approved.txt @@ -46,14 +46,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt index 46a4f86975..b89d6fa085 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.unix.approved.txt @@ -69,14 +69,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt index 18900a1ab1..db0809b796 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelp.windows.approved.txt @@ -69,14 +69,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt index 4a896540ec..ce8bceadd5 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.unix.approved.txt @@ -127,14 +127,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt index 7ae3be9d21..abbd5af81c 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.windows.approved.txt @@ -127,14 +127,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt index 017355efe4..038352fd32 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.unix.approved.txt @@ -75,14 +75,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt index bca320ecb1..12c999ebce 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelp.windows.approved.txt @@ -75,14 +75,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt index 2fb37108f7..3ec881f5ad 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.unix.approved.txt @@ -133,14 +133,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt index f93678c440..337ab9b1a1 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.windows.approved.txt @@ -133,14 +133,14 @@ Feature: --features Enables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. --features-disabled Disables a set of one or more features. Possible values are: account-api, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, ciba, client-policies, client-secret-rotation, declarative-user-profile, - docker, dynamic-scopes, impersonation, js-adapter, map-storage, + docker, dynamic-scopes, impersonation, js-adapter, kerberos, map-storage, openshift-integration, par, preview, recovery-codes, scripts, step-up-authentication, token-exchange, update-email, web-authn. diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java index 378476016f..7cadf33f5e 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java @@ -43,7 +43,6 @@ import java.util.Map; * @version $Revision: 1 $ */ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator implements Authenticator{ - public static final String KERBEROS_DISABLED = "kerberos_disabled"; private static final Logger logger = Logger.getLogger(SpnegoAuthenticator.class); @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java index 549f04e7fa..80d01b7da2 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java @@ -20,10 +20,12 @@ package org.keycloak.authentication.authenticators.browser; import org.keycloak.Config; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.common.Profile; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.UserCredentialModel; +import org.keycloak.provider.EnvironmentDependentProviderFactory; import org.keycloak.provider.ProviderConfigProperty; import java.util.List; @@ -32,7 +34,7 @@ import java.util.List; * @author Bill Burke * @version $Revision: 1 $ */ -public class SpnegoAuthenticatorFactory implements AuthenticatorFactory { +public class SpnegoAuthenticatorFactory implements AuthenticatorFactory, EnvironmentDependentProviderFactory { public static final String PROVIDER_ID = "auth-spnego"; public static final SpnegoAuthenticator SINGLETON = new SpnegoAuthenticator(); @@ -98,4 +100,8 @@ public class SpnegoAuthenticatorFactory implements AuthenticatorFactory { return false; } + @Override + public boolean isSupported() { + return Profile.isFeatureEnabled(Profile.Feature.KERBEROS); + } } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoDisabledAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoDisabledAuthenticatorFactory.java new file mode 100644 index 0000000000..2011df910c --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoDisabledAuthenticatorFactory.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.keycloak.authentication.authenticators.browser; + + +import org.keycloak.authentication.AuthenticationFlowContext; +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.common.Profile; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; + +/** + * Factory used only when KERBEROS feature is disabled. This exists due the KERBEROS authenticator is added by default to realm browser flow (even if DISABLED by default) + * + * @author Marek Posolda + */ +public class SpnegoDisabledAuthenticatorFactory extends SpnegoAuthenticatorFactory implements AuthenticatorFactory { + + @Override + public Authenticator create(KeycloakSession session) { + return new SpnegoDisabledAuthenticator(); + } + + @Override + public String getHelpText() { + return "DISABLED. Please enable Kerberos feature and make sure Kerberos available in your platform. Initiates the SPNEGO protocol. Most often used with Kerberos."; + } + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return new AuthenticationExecutionModel.Requirement[]{ AuthenticationExecutionModel.Requirement.DISABLED }; + } + + @Override + public boolean isSupported() { + return !Profile.isFeatureEnabled(Profile.Feature.KERBEROS); + } + + public static class SpnegoDisabledAuthenticator extends SpnegoAuthenticator { + + @Override + public void authenticate(AuthenticationFlowContext context) { + throw new IllegalStateException("Not possible to authenticate as Kerberos feature is disabled"); + } + } + +} diff --git a/services/src/main/java/org/keycloak/provider/ProviderManager.java b/services/src/main/java/org/keycloak/provider/ProviderManager.java index ea1479b7c8..2a24597fed 100644 --- a/services/src/main/java/org/keycloak/provider/ProviderManager.java +++ b/services/src/main/java/org/keycloak/provider/ProviderManager.java @@ -94,7 +94,7 @@ public class ProviderManager { List f = loader.load(spi); if (f != null) { for (ProviderFactory pf: f) { - String uniqueId = spi.getName() + "-" + pf.getId(); + String uniqueId = spi.getName() + "-" + pf.getId() + "-" + pf.getClass().getName(); if (!loaded.contains(uniqueId)) { cache.add(spi.getProviderClass(), pf); loaded.add(uniqueId); diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory index 999a7696b6..c18d1e01fe 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory @@ -21,6 +21,7 @@ org.keycloak.authentication.authenticators.browser.UsernameFormFactory org.keycloak.authentication.authenticators.browser.PasswordFormFactory org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory +org.keycloak.authentication.authenticators.browser.SpnegoDisabledAuthenticatorFactory org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory org.keycloak.authentication.authenticators.conditional.ConditionalRoleAuthenticatorFactory org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticatorFactory diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosUtils.java new file mode 100644 index 0000000000..9b50f38baa --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosUtils.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.keycloak.testsuite.util; + +import org.junit.Assume; + +import static org.hamcrest.Matchers.is; + +/** + * @author Marek Posolda + */ +public class KerberosUtils { + + public static boolean isKerberosSupportExpected() { + String kerberosSupported = System.getProperty("auth.server.kerberos.supported"); + // Supported by default. It is considered unsupported just if explicitly disabled + return !"false".equals(kerberosSupported); + } + + public static void assumeKerberosSupportExpected() { + Assume.assumeThat("Kerberos feature is not expected to be supported by auth server", isKerberosSupportExpected(), is(true)); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserStorageRestTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserStorageRestTest.java index 71510abd99..856a9a8830 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserStorageRestTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserStorageRestTest.java @@ -44,6 +44,8 @@ import javax.ws.rs.BadRequestException; import javax.ws.rs.core.Response; import java.util.List; +import static org.keycloak.testsuite.util.KerberosUtils.assumeKerberosSupportExpected; + /** * @author Marek Posolda */ @@ -84,6 +86,8 @@ public class UserStorageRestTest extends AbstractAdminTest { @Test public void testKerberosAuthenticatorEnabledAutomatically() { + assumeKerberosSupportExpected(); + // Assert kerberos authenticator DISABLED AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString()); @@ -141,6 +145,8 @@ public class UserStorageRestTest extends AbstractAdminTest { @Test public void testKerberosAuthenticatorChangedOnlyIfDisabled() { + assumeKerberosSupportExpected(); + // Change kerberos to REQUIRED AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString()); @@ -179,6 +185,8 @@ public class UserStorageRestTest extends AbstractAdminTest { // KEYCLOAK-4438 @Test public void testKerberosAuthenticatorDisabledWhenProviderRemoved() { + assumeKerberosSupportExpected(); + // Assert kerberos authenticator DISABLED AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java index 028d5395f4..fa81b4b689 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java @@ -23,6 +23,7 @@ import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentat import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; +import org.keycloak.testsuite.util.KerberosUtils; import java.util.ArrayList; import java.util.Collections; @@ -119,6 +120,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest { private LinkedList expectedFlows() { LinkedList expected = new LinkedList<>(); + String[] kerberosAuthExpectedChoices = KerberosUtils.isKerberosSupportExpected() ? new String[]{REQUIRED, ALTERNATIVE, DISABLED} : new String[]{DISABLED}; AuthenticationFlowRepresentation flow = newFlow("browser", "browser based authentication", "basic-flow", true, true); addExecExport(flow, null, false, "auth-cookie", false, null, ALTERNATIVE, 10); @@ -128,7 +130,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest { List execs = new LinkedList<>(); addExecInfo(execs, "Cookie", "auth-cookie", false, 0, 0, ALTERNATIVE, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); - addExecInfo(execs, "Kerberos", "auth-spnego", false, 0, 1, DISABLED, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); + addExecInfo(execs, "Kerberos", "auth-spnego", false, 0, 1, DISABLED, null, kerberosAuthExpectedChoices); addExecInfo(execs, "Identity Provider Redirector", "identity-provider-redirector", true, 0, 2, ALTERNATIVE, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); addExecInfo(execs, "forms", null, false, 0, 3, ALTERNATIVE, true, new String[]{REQUIRED, ALTERNATIVE, DISABLED, CONDITIONAL}); addExecInfo(execs, "Username Password Form", "auth-username-password-form", false, 1, 0, REQUIRED, null, new String[]{REQUIRED}); @@ -199,7 +201,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest { addExecInfo(execs, "Authentication Options", null, false, 0, 1, REQUIRED, true, new String[]{REQUIRED, ALTERNATIVE, DISABLED, CONDITIONAL}); addExecInfo(execs, "Basic Auth Challenge", "basic-auth", false, 1, 0, REQUIRED, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); addExecInfo(execs, "Basic Auth Password+OTP", "basic-auth-otp", false, 1, 1, DISABLED, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); - addExecInfo(execs, "Kerberos", "auth-spnego", false, 1, 2, DISABLED, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); + addExecInfo(execs, "Kerberos", "auth-spnego", false, 1, 2, DISABLED, null, kerberosAuthExpectedChoices); expected.add(new FlowExecutions(flow, execs)); flow = newFlow("registration", "registration flow", "basic-flow", true, true); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java index f6459d05c8..5dbea7f90d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java @@ -24,6 +24,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.ProfileAssume; +import org.keycloak.testsuite.util.KerberosUtils; import javax.ws.rs.NotFoundException; import java.util.ArrayList; @@ -145,7 +146,10 @@ public class ProvidersTest extends AbstractAuthenticationTest { if (ProfileAssume.isFeatureEnabled(Profile.Feature.SCRIPTS)) { addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript."); } - addProviderInfo(result, "auth-spnego", "Kerberos", "Initiates the SPNEGO protocol. Most often used with Kerberos."); + String kerberosHelpMessage = (KerberosUtils.isKerberosSupportExpected()) + ? "Initiates the SPNEGO protocol. Most often used with Kerberos." + : "DISABLED. Please enable Kerberos feature and make sure Kerberos available in your platform. Initiates the SPNEGO protocol. Most often used with Kerberos."; + addProviderInfo(result, "auth-spnego", "Kerberos", kerberosHelpMessage); addProviderInfo(result, "auth-username-password-form", "Username Password Form", "Validates a username and password from login form."); addProviderInfo(result, "auth-x509-client-username-form", "X509/Validate Username Form", diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java index db9b131c5f..30808992bb 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java @@ -71,6 +71,7 @@ import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.util.KerberosRule; +import org.keycloak.testsuite.util.KerberosUtils; import org.keycloak.testsuite.util.OAuthClient; import org.junit.BeforeClass; @@ -132,6 +133,11 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest { ProfileAssume.assumeFeatureDisabled(Feature.MAP_STORAGE); } + @BeforeClass + public static void checkKerberosSupportedByAuthServer() { + KerberosUtils.assumeKerberosSupportExpected(); + } + @Before @Override public void beforeAbstractKeycloakTest() throws Exception { diff --git a/testsuite/integration-arquillian/tests/base/testsuites/fips-suite b/testsuite/integration-arquillian/tests/base/testsuites/fips-suite index f46d240a41..6b4aa8afc0 100644 --- a/testsuite/integration-arquillian/tests/base/testsuites/fips-suite +++ b/testsuite/integration-arquillian/tests/base/testsuites/fips-suite @@ -20,3 +20,4 @@ KcSamlFirstBrokerLoginTest KcSamlEncryptedIdTest KcSamlSignedBrokerTest KcSamlSpDescriptorTest +KerberosLdapTest diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 9ac32e503c..d7b50433de 100644 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -266,6 +266,7 @@ disabled JKS,PKCS12,BCFKS 1024,2048,4096 + true @@ -692,6 +693,7 @@ ${auth.server.fips.keystore.type} ${auth.server.supported.keystore.types} ${auth.server.supported.rsa.key.sizes} + ${auth.server.kerberos.supported}