Browse Source

Fix kerberos setting registration (#35986)

In #30241 Realm settings were changed, but the Kerberos realm settings
were not registered correctly. This change fixes the registration of
those Kerberos settings.

Also adds a new integration test that ensures every internal realm can
be configured in a test cluster.

Also fixes the QA test for kerberos.

Resolves: #35942
Tim Vernum 6 years ago
parent
commit
609f742e5f

+ 2 - 0
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/InternalRealmsSettings.java

@@ -8,6 +8,7 @@ package org.elasticsearch.xpack.core.security.authc;
 import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
 import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings;
+import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings;
 import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
 import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
 import org.elasticsearch.xpack.core.security.authc.saml.SamlRealmSettings;
@@ -32,6 +33,7 @@ public final class InternalRealmsSettings {
         set.addAll(LdapRealmSettings.getSettings(LdapRealmSettings.LDAP_TYPE));
         set.addAll(PkiRealmSettings.getSettings());
         set.addAll(SamlRealmSettings.getSettings());
+        set.addAll(KerberosRealmSettings.getSettings());
         return Collections.unmodifiableSet(set);
     }
 }

+ 1 - 0
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/kerberos/KerberosRealmSettings.java

@@ -53,6 +53,7 @@ public final class KerberosRealmSettings {
         final Set<Setting.AffixSetting<?>> settings = Sets.newHashSet(HTTP_SERVICE_KEYTAB_PATH, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING,
                 SETTING_KRB_DEBUG_ENABLE, SETTING_REMOVE_REALM_NAME);
         settings.addAll(DelegatedAuthorizationSettings.getSettings(TYPE));
+        settings.addAll(RealmSettings.getStandardSettings(TYPE));
         return settings;
     }
 }

+ 5 - 0
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java

@@ -33,6 +33,7 @@ import org.elasticsearch.xpack.security.authc.support.RoleMappingFileBootstrapCh
 import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
 import org.elasticsearch.xpack.security.support.SecurityIndexManager;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -73,6 +74,10 @@ public final class InternalRealms {
         return ReservedRealm.TYPE.equals(type);
     }
 
+    static Collection<String> getConfigurableRealmsTypes() {
+        return Collections.unmodifiableSet(XPACK_TYPES);
+    }
+
     /**
      * Determines whether <code>type</code> is an internal realm-type that is provided by x-pack,
      * excluding the {@link ReservedRealm} and realms that have extensive interaction with

+ 119 - 0
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/SecurityRealmSettingsTests.java

@@ -0,0 +1,119 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.security.authc;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.test.SecurityIntegTestCase;
+import org.elasticsearch.xpack.core.security.action.user.AuthenticateAction;
+import org.elasticsearch.xpack.core.security.action.user.AuthenticateRequest;
+import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse;
+import org.elasticsearch.xpack.core.security.authc.Realm;
+import org.elasticsearch.xpack.core.security.authc.RealmConfig;
+import org.elasticsearch.xpack.core.security.authc.RealmSettings;
+import org.elasticsearch.xpack.security.authc.kerberos.KerberosRealmTestCase;
+import org.elasticsearch.xpack.security.authc.saml.SamlRealmTestHelper;
+import org.hamcrest.Matchers;
+import org.junit.AfterClass;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+/**
+ * An integration test that configures one of each realm type.
+ * This acts as a basic smoke test that every realm is supported, and can be configured.
+ */
+public class SecurityRealmSettingsTests extends SecurityIntegTestCase {
+
+    @Override
+    protected Settings nodeSettings(int nodeOrdinal) {
+        final Settings settings;
+        try {
+            final String samlIdpEntityId = "urn:idp:entity";
+            final Path samlIdpPath = createTempFile("idp", "xml");
+            SamlRealmTestHelper.writeIdpMetaData(samlIdpPath, samlIdpEntityId);
+
+            final Path kerbKeyTab = createTempFile("es", "keytab");
+            KerberosRealmTestCase.writeKeyTab(kerbKeyTab, null);
+
+            settings = Settings.builder()
+                .put(super.nodeSettings(nodeOrdinal).filter(s -> s.startsWith("xpack.security.authc.realms.") == false))
+                .put("xpack.security.authc.token.enabled", true)
+                .put("xpack.security.authc.realms.file.file1.order", 1)
+                .put("xpack.security.authc.realms.native.native1.order", 2)
+                .put("xpack.security.authc.realms.ldap.ldap1.order", 3)
+                .put("xpack.security.authc.realms.ldap.ldap1.url", "ldap://127.0.0.1:389")
+                .put("xpack.security.authc.realms.ldap.ldap1.user_dn_templates", "cn={0},dc=example,dc=com")
+                .put("xpack.security.authc.realms.active_directory.ad1.order", 4)
+                .put("xpack.security.authc.realms.active_directory.ad1.url", "ldap://127.0.0.1:389")
+                .put("xpack.security.authc.realms.pki.pki1.order", 5)
+                .put("xpack.security.authc.realms.saml.saml1.order", 6)
+                .put("xpack.security.authc.realms.saml.saml1.idp.metadata.path", samlIdpPath.toAbsolutePath())
+                .put("xpack.security.authc.realms.saml.saml1.idp.entity_id", samlIdpEntityId)
+                .put("xpack.security.authc.realms.saml.saml1.sp.entity_id", "urn:sp:entity")
+                .put("xpack.security.authc.realms.saml.saml1.sp.acs", "http://localhost/acs")
+                .put("xpack.security.authc.realms.saml.saml1.attributes.principal", "uid")
+                .put("xpack.security.authc.realms.kerberos.kerb1.order", 7)
+                .put("xpack.security.authc.realms.kerberos.kerb1.keytab.path", kerbKeyTab.toAbsolutePath())
+                .build();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
+        final Set<String> configuredRealmTypes = RealmSettings.getRealmSettings(settings)
+            .keySet()
+            .stream()
+            .map(RealmConfig.RealmIdentifier::getType)
+            .collect(Collectors.toSet());
+        assertThat("One or more realm type are not configured " + configuredRealmTypes,
+            configuredRealmTypes, Matchers.containsInAnyOrder(InternalRealms.getConfigurableRealmsTypes().toArray(Strings.EMPTY_ARRAY)));
+
+        return settings;
+    }
+
+    /**
+     * Some realms (currently only SAML, but maybe more in the future) hold on to resources that may need to be explicitly closed.
+     */
+    @AfterClass
+    public static void closeRealms() throws IOException {
+        final Logger logger = LogManager.getLogger(SecurityRealmSettingsTests.class);
+        final Iterable<Realms> realms = internalCluster().getInstances(Realms.class);
+        for (Realms rx : realms) {
+            for (Realm r : rx) {
+                if (r instanceof Closeable) {
+                    logger.info("Closing realm [{}] [{} @ {}]", r, r.getClass().getSimpleName(), System.identityHashCode(r));
+                    ((Closeable) r).close();
+                }
+            }
+        }
+    }
+
+    /**
+     * Always enable transport SSL so that it is possible to have a PKI Realm
+     */
+    protected boolean transportSSLEnabled() {
+        return true;
+    }
+
+    public void testClusterStarted() {
+        final AuthenticateRequest request = new AuthenticateRequest();
+        request.username(nodeClientUsername());
+        final AuthenticateResponse authenticate = client().execute(AuthenticateAction.INSTANCE, request).actionGet(10, TimeUnit.SECONDS);
+        assertThat(authenticate.authentication(), notNullValue());
+        assertThat(authenticate.authentication().getUser(), notNullValue());
+        assertThat(authenticate.authentication().getUser().enabled(), is(true));
+    }
+
+}

+ 14 - 0
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTestHelper.java

@@ -5,6 +5,9 @@
  */
 package org.elasticsearch.xpack.security.authc.saml;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collections;
 
@@ -42,4 +45,15 @@ public class SamlRealmTestHelper {
         return new SamlRealm(realmConfig, mock(UserRoleMapper.class), mock(SamlAuthenticator.class),
                 mock(SamlLogoutRequestHandler.class), () -> idpDescriptor, spConfiguration);
     }
+
+    public static void writeIdpMetaData(Path path, String idpEntityId) throws IOException {
+        Files.write(path, Arrays.asList(
+            "<?xml version=\"1.0\"?>",
+            "<md:EntityDescriptor xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata' entityID='" + idpEntityId + "'>",
+            "<md:IDPSSODescriptor protocolSupportEnumeration='urn:oasis:names:tc:SAML:2.0:protocol'>",
+            "<md:SingleSignOnService Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect' Location='http://localhost/sso/' />",
+            "</md:IDPSSODescriptor>",
+            "</md:EntityDescriptor>"
+        ));
+    }
 }

+ 5 - 7
x-pack/qa/kerberos-tests/build.gradle

@@ -87,16 +87,14 @@ integTestCluster {
     setting 'http.host', '127.0.0.1'
     setting 'xpack.license.self_generated.type', 'trial'
     setting 'xpack.security.enabled', 'true'
-    setting 'xpack.security.authc.realms.file.type', 'file'
-    setting 'xpack.security.authc.realms.file.order', '0'
+    setting 'xpack.security.authc.realms.file.file1.order', '0'
     setting 'xpack.ml.enabled', 'false'
     setting 'xpack.security.audit.enabled', 'true'
     // Kerberos realm
-    setting 'xpack.security.authc.realms.kerberos.type', 'kerberos'
-    setting 'xpack.security.authc.realms.kerberos.order', '1'
-    setting 'xpack.security.authc.realms.kerberos.keytab.path', 'es.keytab'
-    setting 'xpack.security.authc.realms.kerberos.krb.debug', 'true'
-    setting 'xpack.security.authc.realms.kerberos.remove_realm_name', 'false'
+    setting 'xpack.security.authc.realms.kerberos.kerberos.order', '1'
+    setting 'xpack.security.authc.realms.kerberos.kerberos.keytab.path', 'es.keytab'
+    setting 'xpack.security.authc.realms.kerberos.kerberos.krb.debug', 'true'
+    setting 'xpack.security.authc.realms.kerberos.kerberos.remove_realm_name', 'false'
 
     Path krb5conf = project(':test:fixtures:krb5kdc-fixture').buildDir.toPath().resolve("conf").resolve("krb5.conf").toAbsolutePath()
     String jvmArgsStr = " -Djava.security.krb5.conf=${krb5conf}" + " -Dsun.security.krb5.debug=true"