Added KERBEROS feature. Disable it when running tests on FIPS

closes #14966
This commit is contained in:
mposolda 2023-01-13 14:14:08 +01:00 committed by Marek Posolda
parent 9176308d79
commit a804400c84
27 changed files with 212 additions and 28 deletions

View file

@ -22,6 +22,7 @@ import org.keycloak.common.profile.ProfileConfigResolver;
import org.keycloak.common.profile.ProfileException; import org.keycloak.common.profile.ProfileException;
import org.keycloak.common.profile.PropertiesFileProfileConfigResolver; import org.keycloak.common.profile.PropertiesFileProfileConfigResolver;
import org.keycloak.common.profile.PropertiesProfileConfigResolver; import org.keycloak.common.profile.PropertiesProfileConfigResolver;
import org.keycloak.common.util.KerberosJdkProvider;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -81,6 +82,9 @@ public class Profile {
STEP_UP_AUTHENTICATION("Step-up Authentication", Type.DEFAULT), 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), RECOVERY_CODES("Recovery codes", Type.PREVIEW),
UPDATE_EMAIL("Update Email Action", Type.PREVIEW), UPDATE_EMAIL("Update Email Action", Type.PREVIEW),

View file

@ -20,6 +20,8 @@ package org.keycloak.common.util;
import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName; import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import org.jboss.logging.Logger;
import org.keycloak.common.constants.KerberosConstants; import org.keycloak.common.constants.KerberosConstants;
import javax.security.auth.Subject; import javax.security.auth.Subject;
@ -31,9 +33,11 @@ import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -44,6 +48,8 @@ import java.util.Set;
*/ */
public abstract class KerberosJdkProvider { 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 createJaasConfigurationForServer(String keytab, String serverPrincipal, boolean debug);
public abstract Configuration createJaasConfigurationForUsernamePasswordLogin(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 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<Oid> 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 // Actually can use same on both JDKs
public GSSCredential kerberosTicketToGSSCredential(KerberosTicket kerberosTicket, final int lifetime, final int usage) { public GSSCredential kerberosTicketToGSSCredential(KerberosTicket kerberosTicket, final int lifetime, final int usage) {
try { try {

View file

@ -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, 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 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 In case you want to run Client Registration CLI (`kcreg.sh/bat` script) or Admin CLI (`kcadm.sh/bat` script), it is needed

View file

@ -19,6 +19,7 @@ package org.keycloak.federation.kerberos;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.common.constants.KerberosConstants; import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.federation.kerberos.impl.KerberosServerSubjectAuthenticator; 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.KeycloakSessionFactory;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.provider.ProviderConfigurationBuilder;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
@ -45,7 +47,7 @@ import java.util.List;
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class KerberosFederationProviderFactory implements UserStorageProviderFactory<KerberosFederationProvider> { public class KerberosFederationProviderFactory implements UserStorageProviderFactory<KerberosFederationProvider>, EnvironmentDependentProviderFactory {
private static final Logger logger = Logger.getLogger(KerberosFederationProviderFactory.class); private static final Logger logger = Logger.getLogger(KerberosFederationProviderFactory.class);
public static final String PROVIDER_NAME = "kerberos"; public static final String PROVIDER_NAME = "kerberos";
@ -60,6 +62,11 @@ public class KerberosFederationProviderFactory implements UserStorageProviderFac
return PROVIDER_NAME; return PROVIDER_NAME;
} }
@Override
public boolean isSupported() {
return Profile.isFeatureEnabled(Profile.Feature.KERBEROS);
}
protected static final List<ProviderConfigProperty> configProperties; protected static final List<ProviderConfigProperty> configProperties;
static { static {

View file

@ -46,14 +46,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -46,14 +46,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -69,14 +69,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -69,14 +69,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -127,14 +127,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -127,14 +127,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -75,14 +75,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -75,14 +75,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -133,14 +133,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -133,14 +133,14 @@ Feature:
--features <feature> Enables a set of one or more features. Possible values are: account-api, --features <feature> Enables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.
--features-disabled <feature> --features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api, Disables a set of one or more features. Possible values are: account-api,
account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization, account2, admin, admin-api, admin-fine-grained-authz, admin2, authorization,
ciba, client-policies, client-secret-rotation, declarative-user-profile, 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, openshift-integration, par, preview, recovery-codes, scripts,
step-up-authentication, token-exchange, update-email, web-authn. step-up-authentication, token-exchange, update-email, web-authn.

View file

@ -43,7 +43,6 @@ import java.util.Map;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator implements Authenticator{ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator implements Authenticator{
public static final String KERBEROS_DISABLED = "kerberos_disabled";
private static final Logger logger = Logger.getLogger(SpnegoAuthenticator.class); private static final Logger logger = Logger.getLogger(SpnegoAuthenticator.class);
@Override @Override

View file

@ -20,10 +20,12 @@ package org.keycloak.authentication.authenticators.browser;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.common.Profile;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigProperty;
import java.util.List; import java.util.List;
@ -32,7 +34,7 @@ import java.util.List;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SpnegoAuthenticatorFactory implements AuthenticatorFactory { public class SpnegoAuthenticatorFactory implements AuthenticatorFactory, EnvironmentDependentProviderFactory {
public static final String PROVIDER_ID = "auth-spnego"; public static final String PROVIDER_ID = "auth-spnego";
public static final SpnegoAuthenticator SINGLETON = new SpnegoAuthenticator(); public static final SpnegoAuthenticator SINGLETON = new SpnegoAuthenticator();
@ -98,4 +100,8 @@ public class SpnegoAuthenticatorFactory implements AuthenticatorFactory {
return false; return false;
} }
@Override
public boolean isSupported() {
return Profile.isFeatureEnabled(Profile.Feature.KERBEROS);
}
} }

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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");
}
}
}

View file

@ -94,7 +94,7 @@ public class ProviderManager {
List<ProviderFactory> f = loader.load(spi); List<ProviderFactory> f = loader.load(spi);
if (f != null) { if (f != null) {
for (ProviderFactory pf: f) { for (ProviderFactory pf: f) {
String uniqueId = spi.getName() + "-" + pf.getId(); String uniqueId = spi.getName() + "-" + pf.getId() + "-" + pf.getClass().getName();
if (!loaded.contains(uniqueId)) { if (!loaded.contains(uniqueId)) {
cache.add(spi.getProviderClass(), pf); cache.add(spi.getProviderClass(), pf);
loaded.add(uniqueId); loaded.add(uniqueId);

View file

@ -21,6 +21,7 @@ org.keycloak.authentication.authenticators.browser.UsernameFormFactory
org.keycloak.authentication.authenticators.browser.PasswordFormFactory org.keycloak.authentication.authenticators.browser.PasswordFormFactory
org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory
org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory
org.keycloak.authentication.authenticators.browser.SpnegoDisabledAuthenticatorFactory
org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory org.keycloak.authentication.authenticators.browser.IdentityProviderAuthenticatorFactory
org.keycloak.authentication.authenticators.conditional.ConditionalRoleAuthenticatorFactory org.keycloak.authentication.authenticators.conditional.ConditionalRoleAuthenticatorFactory
org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticatorFactory org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticatorFactory

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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));
}
}

View file

@ -44,6 +44,8 @@ import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.List; import java.util.List;
import static org.keycloak.testsuite.util.KerberosUtils.assumeKerberosSupportExpected;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -84,6 +86,8 @@ public class UserStorageRestTest extends AbstractAdminTest {
@Test @Test
public void testKerberosAuthenticatorEnabledAutomatically() { public void testKerberosAuthenticatorEnabledAutomatically() {
assumeKerberosSupportExpected();
// Assert kerberos authenticator DISABLED // Assert kerberos authenticator DISABLED
AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString()); Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString());
@ -141,6 +145,8 @@ public class UserStorageRestTest extends AbstractAdminTest {
@Test @Test
public void testKerberosAuthenticatorChangedOnlyIfDisabled() { public void testKerberosAuthenticatorChangedOnlyIfDisabled() {
assumeKerberosSupportExpected();
// Change kerberos to REQUIRED // Change kerberos to REQUIRED
AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString()); kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString());
@ -179,6 +185,8 @@ public class UserStorageRestTest extends AbstractAdminTest {
// KEYCLOAK-4438 // KEYCLOAK-4438
@Test @Test
public void testKerberosAuthenticatorDisabledWhenProviderRemoved() { public void testKerberosAuthenticatorDisabledWhenProviderRemoved() {
assumeKerberosSupportExpected();
// Assert kerberos authenticator DISABLED // Assert kerberos authenticator DISABLED
AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution(); AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString()); Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString());

View file

@ -23,6 +23,7 @@ import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentat
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.testsuite.util.KerberosUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -119,6 +120,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
private LinkedList<FlowExecutions> expectedFlows() { private LinkedList<FlowExecutions> expectedFlows() {
LinkedList<FlowExecutions> expected = new LinkedList<>(); LinkedList<FlowExecutions> 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); AuthenticationFlowRepresentation flow = newFlow("browser", "browser based authentication", "basic-flow", true, true);
addExecExport(flow, null, false, "auth-cookie", false, null, ALTERNATIVE, 10); addExecExport(flow, null, false, "auth-cookie", false, null, ALTERNATIVE, 10);
@ -128,7 +130,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
List<AuthenticationExecutionInfoRepresentation> execs = new LinkedList<>(); List<AuthenticationExecutionInfoRepresentation> execs = new LinkedList<>();
addExecInfo(execs, "Cookie", "auth-cookie", false, 0, 0, ALTERNATIVE, null, new String[]{REQUIRED, ALTERNATIVE, DISABLED}); 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, "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, "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}); 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, "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 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, "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)); expected.add(new FlowExecutions(flow, execs));
flow = newFlow("registration", "registration flow", "basic-flow", true, true); flow = newFlow("registration", "registration flow", "basic-flow", true, true);

View file

@ -24,6 +24,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.util.KerberosUtils;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
@ -145,7 +146,10 @@ public class ProvidersTest extends AbstractAuthenticationTest {
if (ProfileAssume.isFeatureEnabled(Profile.Feature.SCRIPTS)) { 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-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", addProviderInfo(result, "auth-username-password-form", "Username Password Form",
"Validates a username and password from login form."); "Validates a username and password from login form.");
addProviderInfo(result, "auth-x509-client-username-form", "X509/Validate Username Form", addProviderInfo(result, "auth-x509-client-username-form", "X509/Validate Username Form",

View file

@ -71,6 +71,7 @@ import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.KerberosRule; import org.keycloak.testsuite.util.KerberosRule;
import org.keycloak.testsuite.util.KerberosUtils;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -132,6 +133,11 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
ProfileAssume.assumeFeatureDisabled(Feature.MAP_STORAGE); ProfileAssume.assumeFeatureDisabled(Feature.MAP_STORAGE);
} }
@BeforeClass
public static void checkKerberosSupportedByAuthServer() {
KerberosUtils.assumeKerberosSupportExpected();
}
@Before @Before
@Override @Override
public void beforeAbstractKeycloakTest() throws Exception { public void beforeAbstractKeycloakTest() throws Exception {

View file

@ -20,3 +20,4 @@ KcSamlFirstBrokerLoginTest
KcSamlEncryptedIdTest KcSamlEncryptedIdTest
KcSamlSignedBrokerTest KcSamlSignedBrokerTest
KcSamlSpDescriptorTest KcSamlSpDescriptorTest
KerberosLdapTest

View file

@ -266,6 +266,7 @@
<auth.server.fips.mode>disabled</auth.server.fips.mode> <auth.server.fips.mode>disabled</auth.server.fips.mode>
<auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types> <auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types>
<auth.server.supported.rsa.key.sizes>1024,2048,4096</auth.server.supported.rsa.key.sizes> <auth.server.supported.rsa.key.sizes>1024,2048,4096</auth.server.supported.rsa.key.sizes>
<auth.server.kerberos.supported>true</auth.server.kerberos.supported>
</properties> </properties>
<build> <build>
@ -692,6 +693,7 @@
<auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type> <auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type>
<auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types> <auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types>
<auth.server.supported.rsa.key.sizes>${auth.server.supported.rsa.key.sizes}</auth.server.supported.rsa.key.sizes> <auth.server.supported.rsa.key.sizes>${auth.server.supported.rsa.key.sizes}</auth.server.supported.rsa.key.sizes>
<auth.server.kerberos.supported>${auth.server.kerberos.supported}</auth.server.kerberos.supported>
<!-- <!--
~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration. ~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration.
@ -1570,6 +1572,7 @@
<auth.server.fips.mode>enabled</auth.server.fips.mode> <auth.server.fips.mode>enabled</auth.server.fips.mode>
<auth.server.supported.keystore.types>PKCS12,BCFKS</auth.server.supported.keystore.types> <auth.server.supported.keystore.types>PKCS12,BCFKS</auth.server.supported.keystore.types>
<auth.server.kerberos.supported>false</auth.server.kerberos.supported>
<auth.server.keystore.type>pkcs12</auth.server.keystore.type> <auth.server.keystore.type>pkcs12</auth.server.keystore.type>
<auth.server.keystore>${auth.server.config.dir}/keycloak-fips.keystore.${auth.server.keystore.type}</auth.server.keystore> <auth.server.keystore>${auth.server.config.dir}/keycloak-fips.keystore.${auth.server.keystore.type}</auth.server.keystore>

View file

@ -312,7 +312,7 @@
</div> </div>
</fieldset> </fieldset>
<fieldset> <fieldset data-ng-show="serverInfo.featureEnabled('KERBEROS')">
<legend id="kerberosIntegrationHeader" collapsed><span class="text">{{:: 'kerberos-integration' | translate}}</span></legend> <legend id="kerberosIntegrationHeader" collapsed><span class="text">{{:: 'kerberos-integration' | translate}}</span></legend>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="allowKerberosAuthentication">{{:: 'allow-kerberos-authentication' | translate}} </label> <label class="col-md-2 control-label" for="allowKerberosAuthentication">{{:: 'allow-kerberos-authentication' | translate}} </label>