diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index f4bb4b7eb3b2e..df5e8dcae1b36 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -176,7 +176,6 @@ import org.elasticsearch.xpack.security.authc.TokenService; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; -import org.elasticsearch.xpack.security.authc.kerberos.KerberosRealmBootstrapCheck; import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; import org.elasticsearch.xpack.security.authz.AuthorizationService; import org.elasticsearch.xpack.security.authz.SecuritySearchOperationListener; @@ -306,8 +305,7 @@ public Security(Settings settings, final Path configPath) { new PasswordHashingAlgorithmBootstrapCheck(), new FIPS140SecureSettingsBootstrapCheck(settings, env), new FIPS140JKSKeystoreBootstrapCheck(settings), - new FIPS140PasswordHashingAlgorithmBootstrapCheck(settings), - new KerberosRealmBootstrapCheck(env))); + new FIPS140PasswordHashingAlgorithmBootstrapCheck(settings))); checks.addAll(InternalRealms.getBootstrapChecks(settings, env)); this.bootstrapChecks = Collections.unmodifiableList(checks); Automatons.updateMaxDeterminizedStates(settings); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java index 0284ae9a05fa3..8b80c1f1d1ca9 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java @@ -35,6 +35,7 @@ import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings; +import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; /** @@ -152,6 +153,7 @@ protected List initRealms() throws Exception { Settings realmsSettings = RealmSettings.get(settings); Set internalTypes = new HashSet<>(); List realms = new ArrayList<>(); + List kerberosRealmNames = new ArrayList<>(); for (String name : realmsSettings.names()) { Settings realmSettings = realmsSettings.getAsSettings(name); String type = realmSettings.get("type"); @@ -178,6 +180,13 @@ protected List initRealms() throws Exception { } internalTypes.add(type); } + if (KerberosRealmSettings.TYPE.equals(type)) { + kerberosRealmNames.add(name); + if (kerberosRealmNames.size() > 1) { + throw new IllegalArgumentException("multiple realms " + kerberosRealmNames.toString() + " configured of type [" + type + + "], [" + type + "] can only have one such realm configured"); + } + } realms.add(factory.create(config)); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java index b4a8b6aabf076..71eeb8b23980b 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealm.java @@ -25,6 +25,7 @@ import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; import org.ietf.jgss.GSSException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.List; @@ -87,6 +88,16 @@ public KerberosRealm(final RealmConfig config, final NativeRoleMappingStore nati this.kerberosTicketValidator = kerberosTicketValidator; this.threadPool = threadPool; this.keytabPath = config.env().configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(config.settings())); + + if (Files.exists(keytabPath) == false) { + throw new IllegalArgumentException("configured service key tab file [" + keytabPath + "] does not exist"); + } + if (Files.isDirectory(keytabPath)) { + throw new IllegalArgumentException("configured service key tab file [" + keytabPath + "] is a directory"); + } + if (Files.isReadable(keytabPath) == false) { + throw new IllegalArgumentException("configured service key tab file [" + keytabPath + "] must have read permission"); + } this.enableKerberosDebug = KerberosRealmSettings.SETTING_KRB_DEBUG_ENABLE.get(config.settings()); this.removeRealmName = KerberosRealmSettings.SETTING_REMOVE_REALM_NAME.get(config.settings()); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheck.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheck.java deleted file mode 100644 index bab899a866425..0000000000000 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheck.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.kerberos; - -import org.elasticsearch.bootstrap.BootstrapCheck; -import org.elasticsearch.bootstrap.BootstrapContext; -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.core.security.authc.RealmSettings; -import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.Map.Entry; - -/** - * This class is used to perform bootstrap checks for kerberos realm. - *

- * We use service keytabs for validating incoming kerberos tickets and is a - * required configuration. Due to JVM wide system properties for Kerberos we - * cannot support multiple Kerberos realms. This class adds checks for node to - * fail if service keytab does not exist or multiple kerberos realms have been - * configured. - */ -public class KerberosRealmBootstrapCheck implements BootstrapCheck { - private final Environment env; - - public KerberosRealmBootstrapCheck(final Environment env) { - this.env = env; - } - - @Override - public BootstrapCheckResult check(final BootstrapContext context) { - final Map realmsSettings = RealmSettings.getRealmSettings(context.settings); - boolean isKerberosRealmConfigured = false; - for (final Entry entry : realmsSettings.entrySet()) { - final String name = entry.getKey(); - final Settings realmSettings = entry.getValue(); - final String type = realmSettings.get("type"); - if (Strings.hasText(type) == false) { - return BootstrapCheckResult.failure("missing realm type for [" + name + "] realm"); - } - if (KerberosRealmSettings.TYPE.equals(type)) { - if (isKerberosRealmConfigured) { - return BootstrapCheckResult.failure( - "multiple [" + type + "] realms are configured. [" + type + "] can only have one such realm configured"); - } - isKerberosRealmConfigured = true; - - final Path keytabPath = env.configFile().resolve(KerberosRealmSettings.HTTP_SERVICE_KEYTAB_PATH.get(realmSettings)); - if (Files.exists(keytabPath) == false) { - return BootstrapCheckResult.failure("configured service key tab file [" + keytabPath + "] does not exist"); - } - } - } - return BootstrapCheckResult.success(); - } - - @Override - public boolean alwaysEnforce() { - return true; - } -} diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java index a71f5cb1cf761..9d795826298ab 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/RealmsTests.java @@ -27,6 +27,7 @@ import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; import org.junit.Before; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -51,13 +52,16 @@ public class RealmsTests extends ESTestCase { private XPackLicenseState licenseState; private ThreadContext threadContext; private ReservedRealm reservedRealm; + private int randomRealmTypesCount; @Before public void init() throws Exception { factories = new HashMap<>(); factories.put(FileRealmSettings.TYPE, config -> new DummyRealm(FileRealmSettings.TYPE, config)); factories.put(NativeRealmSettings.TYPE, config -> new DummyRealm(NativeRealmSettings.TYPE, config)); - for (int i = 0; i < randomIntBetween(1, 5); i++) { + factories.put(KerberosRealmSettings.TYPE, config -> new DummyRealm(KerberosRealmSettings.TYPE, config)); + randomRealmTypesCount = randomIntBetween(1, 5); + for (int i = 0; i < randomRealmTypesCount; i++) { String name = "type_" + i; factories.put(name, config -> new DummyRealm(name, config)); } @@ -73,13 +77,13 @@ public void init() throws Exception { public void testWithSettings() throws Exception { Settings.Builder builder = Settings.builder() .put("path.home", createTempDir()); - List orders = new ArrayList<>(factories.size() - 2); - for (int i = 0; i < factories.size() - 2; i++) { + List orders = new ArrayList<>(randomRealmTypesCount); + for (int i = 0; i < randomRealmTypesCount; i++) { orders.add(i); } Collections.shuffle(orders, random()); Map orderToIndex = new HashMap<>(); - for (int i = 0; i < factories.size() - 2; i++) { + for (int i = 0; i < randomRealmTypesCount; i++) { builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i); builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i)); orderToIndex.put(orders.get(i), i); @@ -107,14 +111,14 @@ public void testWithSettings() throws Exception { public void testWithSettingsWhereDifferentRealmsHaveSameOrder() throws Exception { Settings.Builder builder = Settings.builder() .put("path.home", createTempDir()); - List randomSeq = new ArrayList<>(factories.size() - 2); - for (int i = 0; i < factories.size() - 2; i++) { + List randomSeq = new ArrayList<>(randomRealmTypesCount); + for (int i = 0; i < randomRealmTypesCount; i++) { randomSeq.add(i); } Collections.shuffle(randomSeq, random()); TreeMap nameToRealmId = new TreeMap<>(); - for (int i = 0; i < factories.size() - 2; i++) { + for (int i = 0; i < randomRealmTypesCount; i++) { int randomizedRealmId = randomSeq.get(i); String randomizedRealmName = randomAlphaOfLengthBetween(12,32); nameToRealmId.put("realm_" + randomizedRealmName, randomizedRealmId); @@ -181,13 +185,13 @@ public void testWithEmptySettings() throws Exception { public void testUnlicensedWithOnlyCustomRealms() throws Exception { Settings.Builder builder = Settings.builder() .put("path.home", createTempDir()); - List orders = new ArrayList<>(factories.size() - 2); - for (int i = 0; i < factories.size() - 2; i++) { + List orders = new ArrayList<>(randomRealmTypesCount); + for (int i = 0; i < randomRealmTypesCount; i++) { orders.add(i); } Collections.shuffle(orders, random()); Map orderToIndex = new HashMap<>(); - for (int i = 0; i < factories.size() - 2; i++) { + for (int i = 0; i < randomRealmTypesCount; i++) { builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i); builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i)); orderToIndex.put(orders.get(i), i); @@ -384,13 +388,13 @@ public void testUnlicensedWithNonStandardRealms() throws Exception { public void testDisabledRealmsAreNotAdded() throws Exception { Settings.Builder builder = Settings.builder() .put("path.home", createTempDir()); - List orders = new ArrayList<>(factories.size() - 2); - for (int i = 0; i < factories.size() - 2; i++) { + List orders = new ArrayList<>(randomRealmTypesCount); + for (int i = 0; i < randomRealmTypesCount; i++) { orders.add(i); } Collections.shuffle(orders, random()); Map orderToIndex = new HashMap<>(); - for (int i = 0; i < factories.size() - 2; i++) { + for (int i = 0; i < randomRealmTypesCount; i++) { builder.put("xpack.security.authc.realms.realm_" + i + ".type", "type_" + i); builder.put("xpack.security.authc.realms.realm_" + i + ".order", orders.get(i)); boolean enabled = randomBoolean(); @@ -520,6 +524,20 @@ public void testUsageStats() throws Exception { } } + public void testInitRealmsFailsForMultipleKerberosRealms() throws IOException { + final Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); + builder.put("xpack.security.authc.realms.realm_1.type", "kerberos"); + builder.put("xpack.security.authc.realms.realm_1.order", 1); + builder.put("xpack.security.authc.realms.realm_2.type", "kerberos"); + builder.put("xpack.security.authc.realms.realm_2.order", 2); + final Settings settings = builder.build(); + Environment env = TestEnvironment.newEnvironment(settings); + final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> new Realms(settings, env, factories, licenseState, threadContext, reservedRealm)); + assertThat(iae.getMessage(), is(equalTo( + "multiple realms [realm_1, realm_2] configured of type [kerberos], [kerberos] can only have one such realm configured"))); + } + static class DummyRealm extends Realm { DummyRealm(String type, RealmConfig config) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheckTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheckTests.java deleted file mode 100644 index b6e1df9ddbb79..0000000000000 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmBootstrapCheckTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.kerberos; - -import org.elasticsearch.bootstrap.BootstrapCheck; -import org.elasticsearch.bootstrap.BootstrapContext; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.TestEnvironment; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.security.authc.RealmSettings; -import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; -import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings; - -import java.io.IOException; -import java.nio.file.Path; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; - -public class KerberosRealmBootstrapCheckTests extends ESTestCase { - - public void testBootstrapCheckFailsForMultipleKerberosRealms() throws IOException { - final Path tempDir = createTempDir(); - final Settings settings1 = buildKerberosRealmSettings("kerb1", false, tempDir); - final Settings settings2 = buildKerberosRealmSettings("kerb2", false, tempDir); - final Settings settings3 = realm("pki1", PkiRealmSettings.TYPE, Settings.builder()).build(); - final Settings settings = - Settings.builder().put("path.home", tempDir).put(settings1).put(settings2).put(settings3).build(); - final BootstrapContext context = new BootstrapContext(settings, null); - final KerberosRealmBootstrapCheck kerbRealmBootstrapCheck = - new KerberosRealmBootstrapCheck(TestEnvironment.newEnvironment(settings)); - final BootstrapCheck.BootstrapCheckResult result = kerbRealmBootstrapCheck.check(context); - assertThat(result, is(notNullValue())); - assertThat(result.isFailure(), is(true)); - assertThat(result.getMessage(), equalTo("multiple [" + KerberosRealmSettings.TYPE + "] realms are configured. [" - + KerberosRealmSettings.TYPE + "] can only have one such realm configured")); - } - - public void testBootstrapCheckFailsForMissingKeytabFile() throws IOException { - final Path tempDir = createTempDir(); - final Settings settings = - Settings.builder().put("path.home", tempDir).put(buildKerberosRealmSettings("kerb1", true, tempDir)).build(); - final BootstrapContext context = new BootstrapContext(settings, null); - final KerberosRealmBootstrapCheck kerbRealmBootstrapCheck = - new KerberosRealmBootstrapCheck(TestEnvironment.newEnvironment(settings)); - final BootstrapCheck.BootstrapCheckResult result = kerbRealmBootstrapCheck.check(context); - assertThat(result, is(notNullValue())); - assertThat(result.isFailure(), is(true)); - assertThat(result.getMessage(), - equalTo("configured service key tab file [" + tempDir.resolve("kerb1.keytab").toString() + "] does not exist")); - } - - public void testBootstrapCheckFailsForMissingRealmType() throws IOException { - final Path tempDir = createTempDir(); - final String name = "kerb1"; - final Settings settings1 = buildKerberosRealmSettings("kerb1", false, tempDir); - final Settings settings2 = realm(name, randomFrom("", " "), Settings.builder()).build(); - final Settings settings = - Settings.builder().put("path.home", tempDir).put(settings1).put(settings2).build(); - final BootstrapContext context = new BootstrapContext(settings, null); - final KerberosRealmBootstrapCheck kerbRealmBootstrapCheck = - new KerberosRealmBootstrapCheck(TestEnvironment.newEnvironment(settings)); - final BootstrapCheck.BootstrapCheckResult result = kerbRealmBootstrapCheck.check(context); - assertThat(result, is(notNullValue())); - assertThat(result.isFailure(), is(true)); - assertThat(result.getMessage(), equalTo("missing realm type for [" + name + "] realm")); - } - - public void testBootstrapCheckSucceedsForCorrectConfiguration() throws IOException { - final Path tempDir = createTempDir(); - final Settings finalSettings = - Settings.builder().put("path.home", tempDir).put(buildKerberosRealmSettings("kerb1", false, tempDir)).build(); - final BootstrapContext context = new BootstrapContext(finalSettings, null); - final KerberosRealmBootstrapCheck kerbRealmBootstrapCheck = - new KerberosRealmBootstrapCheck(TestEnvironment.newEnvironment(finalSettings)); - final BootstrapCheck.BootstrapCheckResult result = kerbRealmBootstrapCheck.check(context); - assertThat(result, is(notNullValue())); - assertThat(result.isSuccess(), is(true)); - } - - public void testBootstrapCheckSucceedsForNoKerberosRealms() throws IOException { - final Path tempDir = createTempDir(); - final Settings finalSettings = Settings.builder().put("path.home", tempDir).build(); - final BootstrapContext context = new BootstrapContext(finalSettings, null); - final KerberosRealmBootstrapCheck kerbRealmBootstrapCheck = - new KerberosRealmBootstrapCheck(TestEnvironment.newEnvironment(finalSettings)); - final BootstrapCheck.BootstrapCheckResult result = kerbRealmBootstrapCheck.check(context); - assertThat(result, is(notNullValue())); - assertThat(result.isSuccess(), is(true)); - } - - private Settings buildKerberosRealmSettings(final String name, final boolean missingKeytab, final Path tempDir) throws IOException { - final Settings.Builder builder = Settings.builder(); - if (missingKeytab == false) { - KerberosTestCase.writeKeyTab(tempDir.resolve(name + ".keytab"), null); - } - builder.put(KerberosTestCase.buildKerberosRealmSettings(tempDir.resolve(name + ".keytab").toString())); - return realm(name, KerberosRealmSettings.TYPE, builder).build(); - } - - private Settings.Builder realm(final String name, final String type, final Settings.Builder settings) { - final String prefix = RealmSettings.PREFIX + name + "."; - if (type != null) { - settings.put("type", type); - } - final Settings.Builder builder = Settings.builder().put(settings.normalizePrefix(prefix).build(), false); - return builder; - } -} diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java index 43536abaf29e1..0f972498ab3a9 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosRealmTests.java @@ -11,17 +11,30 @@ import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; +import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.kerberos.KerberosRealmSettings; import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper.UserData; import org.ietf.jgss.GSSException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.Arrays; +import java.util.EnumSet; +import java.util.Set; import javax.security.auth.login.LoginException; @@ -31,6 +44,7 @@ import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -94,4 +108,44 @@ public void testLookupUser() { assertThat(future.actionGet(), is(nullValue())); } + public void testKerberosRealmWithInvalidKeytabPathConfigurations() throws IOException { + final String keytabPathCase = randomFrom("keytabPathAsDirectory", "keytabFileDoesNotExist", "keytabPathWithNoReadPermissions"); + final String expectedErrorMessage; + final String keytabPath; + final Set filePerms; + switch (keytabPathCase) { + case "keytabPathAsDirectory": + final String dirName = randomAlphaOfLength(5); + Files.createDirectory(dir.resolve(dirName)); + keytabPath = dir.resolve(dirName).toString(); + expectedErrorMessage = "configured service key tab file [" + keytabPath + "] is a directory"; + break; + case "keytabFileDoesNotExist": + keytabPath = dir.resolve(randomAlphaOfLength(5) + ".keytab").toString(); + expectedErrorMessage = "configured service key tab file [" + keytabPath + "] does not exist"; + break; + case "keytabPathWithNoReadPermissions": + filePerms = PosixFilePermissions.fromString("---------"); + final String keytabFileName = randomAlphaOfLength(5) + ".keytab"; + final FileAttribute> fileAttributes = PosixFilePermissions.asFileAttribute(filePerms); + try (SeekableByteChannel byteChannel = Files.newByteChannel(dir.resolve(keytabFileName), + EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE), fileAttributes)) { + byteChannel.write(ByteBuffer.wrap(randomByteArrayOfLength(10))); + } + keytabPath = dir.resolve(keytabFileName).toString(); + expectedErrorMessage = "configured service key tab file [" + keytabPath + "] must have read permission"; + break; + default: + throw new IllegalArgumentException("Unknown test case :" + keytabPathCase); + } + + settings = KerberosTestCase.buildKerberosRealmSettings(keytabPath, 100, "10m", true, randomBoolean()); + config = new RealmConfig("test-kerb-realm", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), + new ThreadContext(globalSettings)); + mockNativeRoleMappingStore = roleMappingStore(Arrays.asList("user")); + mockKerberosTicketValidator = mock(KerberosTicketValidator.class); + final IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> new KerberosRealm(config, mockNativeRoleMappingStore, mockKerberosTicketValidator, threadPool, null)); + assertThat(iae.getMessage(), is(equalTo(expectedErrorMessage))); + } } \ No newline at end of file