diff --git a/docs/build.gradle b/docs/build.gradle index 0cfd97cb9ca..35f98fe6c64 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -143,6 +143,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant -> integTestCluster { plugin ':x-pack-elasticsearch:plugin' + setting 'xpack.security.authc.token.enabled', 'true' setupCommand 'setupTestAdmin', 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'x-pack-test-password', '-r', 'superuser' waitCondition = waitWithAuth diff --git a/docs/en/settings/security-settings.asciidoc b/docs/en/settings/security-settings.asciidoc index 8d738b9cfac..ae5a8367bef 100644 --- a/docs/en/settings/security-settings.asciidoc +++ b/docs/en/settings/security-settings.asciidoc @@ -72,7 +72,9 @@ You can set the following token service settings in `elasticsearch.yml`. `xpack.security.authc.token.enabled`:: -Set to `false` to disable the built-in token service. Defaults to `true`. +Set to `false` to disable the built-in token service. Defaults to `true` unless + `xpack.security.http.ssl.enabled` is `false` and `http.enabled` is `true`. + This prevents sniffing the token from a connection over plain http. `xpack.security.authc.token.passphrase`:: A secure passphrase that must be the same on each node and greater than diff --git a/plugin/build.gradle b/plugin/build.gradle index c7c452ac25f..b1ff8227b44 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -204,6 +204,7 @@ integTestCluster { setting 'xpack.monitoring.exporters._local.type', 'local' setting 'xpack.monitoring.exporters._local.enabled', 'false' setting 'xpack.monitoring.collection.interval', '-1' + setting 'xpack.security.authc.token.enabled', 'true' keystoreSetting 'bootstrap.password', 'x-pack-test-password' keystoreSetting 'xpack.security.authc.token.passphrase', 'x-pack-token-service-password' distribution = 'zip' // this is important since we use the reindex module in ML diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java index 71d29147315..b700eadaed9 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackSettings.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack; import org.elasticsearch.common.Booleans; +import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.xpack.security.Security; @@ -79,8 +80,13 @@ public class XPackSettings { true, Setting.Property.NodeScope); /** Setting for enabling or disabling the token service. Defaults to true */ - public static final Setting TOKEN_SERVICE_ENABLED_SETTING = Setting.boolSetting("xpack.security.authc.token.enabled", true, - Setting.Property.NodeScope); + public static final Setting TOKEN_SERVICE_ENABLED_SETTING = Setting.boolSetting("xpack.security.authc.token.enabled", (s) -> { + if (NetworkModule.HTTP_ENABLED.get(s)) { + return XPackSettings.HTTP_SSL_ENABLED.getRaw(s); + } else { + return Boolean.TRUE.toString(); + } + }, Setting.Property.NodeScope); /* * SSL settings. These are the settings that are specifically registered for SSL. Many are private as we do not explicitly use them diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/TokenSSLBootstrapCheck.java b/plugin/src/main/java/org/elasticsearch/xpack/security/TokenSSLBootstrapCheck.java index c34a45a4206..dfeeb05805c 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/TokenSSLBootstrapCheck.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/TokenSSLBootstrapCheck.java @@ -6,11 +6,10 @@ package org.elasticsearch.xpack.security; import org.elasticsearch.bootstrap.BootstrapCheck; +import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.XPackSettings; -import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED; - /** * Bootstrap check to ensure that the user has enabled HTTPS when using the token service */ @@ -24,12 +23,16 @@ final class TokenSSLBootstrapCheck implements BootstrapCheck { @Override public boolean check() { - return XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.get(settings) && HTTP_SSL_ENABLED.get(settings) == false; + if (NetworkModule.HTTP_ENABLED.get(settings)) { + return XPackSettings.HTTP_SSL_ENABLED.get(settings) == false && XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.get(settings); + } + return false; } @Override public String errorMessage() { - return "HTTPS is required in order to use the token service. Please enable HTTPS using the [" + HTTP_SSL_ENABLED.getKey() + - "] setting or disable the token service using the [" + XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey() + "] setting."; + return "HTTPS is required in order to use the token service. Please enable HTTPS using the [" + + XPackSettings.HTTP_SSL_ENABLED.getKey() + "] setting or disable the token service using the [" + + XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey() + "] setting."; } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java index 7c21d74e943..887475d5aa2 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenPassphraseBootstrapCheckTests.java @@ -20,7 +20,8 @@ public class TokenPassphraseBootstrapCheckTests extends ESTestCase { assertFalse(new TokenPassphraseBootstrapCheck(Settings.EMPTY).check()); MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString("foo", "bar"); // leniency in setSecureSettings... if its empty it's skipped - Settings settings = Settings.builder().setSecureSettings(secureSettings).build(); + Settings settings = Settings.builder() + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).setSecureSettings(secureSettings).build(); assertFalse(new TokenPassphraseBootstrapCheck(settings).check()); secureSettings.setString(TokenService.TOKEN_PASSPHRASE.getKey(), randomAlphaOfLengthBetween(MINIMUM_PASSPHRASE_LENGTH, 30)); @@ -31,7 +32,8 @@ public class TokenPassphraseBootstrapCheckTests extends ESTestCase { } public void testTokenPassphraseCheckServiceDisabled() throws Exception { - Settings settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false).build(); + Settings settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false) + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); assertFalse(new TokenPassphraseBootstrapCheck(settings).check()); MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString("foo", "bar"); // leniency in setSecureSettings... if its empty it's skipped @@ -40,11 +42,10 @@ public class TokenPassphraseBootstrapCheckTests extends ESTestCase { secureSettings.setString(TokenService.TOKEN_PASSPHRASE.getKey(), randomAlphaOfLengthBetween(1, 30)); assertFalse(new TokenPassphraseBootstrapCheck(settings).check()); - } public void testTokenPassphraseCheckAfterSecureSettingsClosed() throws Exception { - Settings settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); + Settings settings = Settings.builder().put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString("foo", "bar"); // leniency in setSecureSettings... if its empty it's skipped settings = Settings.builder().put(settings).setSecureSettings(secureSettings).build(); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenSSLBootsrapCheckTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenSSLBootsrapCheckTests.java index c80120dafbe..a795498b2b4 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/TokenSSLBootsrapCheckTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/TokenSSLBootsrapCheckTests.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.security; +import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.XPackSettings; @@ -14,15 +15,29 @@ public class TokenSSLBootsrapCheckTests extends ESTestCase { public void testTokenSSLBootstrapCheck() { Settings settings = Settings.EMPTY; - assertTrue(new TokenSSLBootstrapCheck(settings).check()); + assertFalse(new TokenSSLBootstrapCheck(settings).check()); - settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false).build(); + settings = Settings.builder() + .put(NetworkModule.HTTP_ENABLED.getKey(), false) + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); assertFalse(new TokenSSLBootstrapCheck(settings).check()); settings = Settings.builder().put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).build(); assertFalse(new TokenSSLBootstrapCheck(settings).check()); - settings = Settings.builder().put(XPackSettings.HTTP_SSL_ENABLED.getKey(), false).build(); + // XPackSettings.HTTP_SSL_ENABLED default false + settings = Settings.builder().put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); assertTrue(new TokenSSLBootstrapCheck(settings).check()); + + settings = Settings.builder() + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), false) + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); + assertTrue(new TokenSSLBootstrapCheck(settings).check()); + + settings = Settings.builder() + .put(XPackSettings.HTTP_SSL_ENABLED.getKey(), false) + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true) + .put(NetworkModule.HTTP_ENABLED.getKey(), false).build(); + assertFalse(new TokenSSLBootstrapCheck(settings).check()); } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index 973d7675f65..96592d47b55 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -46,6 +46,7 @@ import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportMessage; +import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.audit.AuditTrailService; @@ -121,6 +122,7 @@ public class AuthenticationServiceTests extends ESTestCase { Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("node.name", "authc_test") + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true) .build(); XPackLicenseState licenseState = mock(XPackLicenseState.class); when(licenseState.allowedRealmType()).thenReturn(XPackLicenseState.AllowedRealmType.ALL); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java index e3afcde92d2..e5df63c1429 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenAuthIntegTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecuritySettingsSource; +import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.action.token.CreateTokenResponse; import org.elasticsearch.xpack.security.action.token.InvalidateTokenResponse; @@ -44,6 +45,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase { .put(TokenService.TOKEN_EXPIRATION.getKey(), TimeValue.timeValueSeconds(1L)) .put(TokenService.DELETE_INTERVAL.getKey(), TimeValue.timeValueSeconds(1L)) .put(TokenService.DELETE_TIMEOUT.getKey(), TimeValue.timeValueSeconds(2L)) + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true) .build(); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java index 5b806b659de..8f5ea2d2c0c 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java @@ -31,7 +31,6 @@ import org.elasticsearch.xpack.security.authc.Authentication.RealmRef; import org.elasticsearch.xpack.security.authc.TokenService.BytesKey; import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.support.clock.ClockMock; -import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -56,14 +55,17 @@ public class TokenServiceTests extends ESTestCase { private InternalClient internalClient; private static ThreadPool threadPool; - private static final Settings settings = Settings.builder().put(Node.NODE_NAME_SETTING.getKey(), "TokenServiceTests").build(); + private static final Settings settings = Settings.builder().put(Node.NODE_NAME_SETTING.getKey(), "TokenServiceTests") + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); private Client client; private SecurityLifecycleService lifecycleService; private ClusterService clusterService; + private Settings tokenServiceEnabledSettings = Settings.builder() + .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); @Before - public void setupClient() { + public void setupClient() throws GeneralSecurityException { client = mock(Client.class); internalClient = new InternalClient(settings, threadPool, client); lifecycleService = mock(SecurityLifecycleService.class); @@ -93,7 +95,8 @@ public class TokenServiceTests extends ESTestCase { } public void testAttachAndGetToken() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -110,7 +113,7 @@ public class TokenServiceTests extends ESTestCase { try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) { // verify a second separate token service with its own salt can also verify - TokenService anotherService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService + TokenService anotherService = new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService , clusterService); anotherService.refreshMetaData(tokenService.getTokenMetaData()); PlainActionFuture future = new PlainActionFuture<>(); @@ -121,7 +124,8 @@ public class TokenServiceTests extends ESTestCase { } public void testRotateKey() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -167,12 +171,13 @@ public class TokenServiceTests extends ESTestCase { } public void testKeyExchange() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); int numRotations = 0;randomIntBetween(1, 5); for (int i = 0; i < numRotations; i++) { rotateKeys(tokenService); } - TokenService otherTokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, + TokenService otherTokenService = new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); otherTokenService.refreshMetaData(tokenService.getTokenMetaData()); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); @@ -201,7 +206,8 @@ public class TokenServiceTests extends ESTestCase { } public void testPruneKeys() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -257,7 +263,8 @@ public class TokenServiceTests extends ESTestCase { } public void testPassphraseWorks() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -286,7 +293,8 @@ public class TokenServiceTests extends ESTestCase { public void testInvalidatedToken() throws Exception { when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -323,7 +331,7 @@ public class TokenServiceTests extends ESTestCase { public void testTokenExpiry() throws Exception { ClockMock clock = ClockMock.frozen(); - TokenService tokenService = new TokenService(Settings.EMPTY, clock, internalClient, lifecycleService, clusterService); + TokenService tokenService = new TokenService(tokenServiceEnabledSettings, clock, internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); @@ -426,7 +434,8 @@ public class TokenServiceTests extends ESTestCase { } public void testIndexNotAvailable() throws Exception { - TokenService tokenService = new TokenService(Settings.EMPTY, Clock.systemUTC(), internalClient, lifecycleService, clusterService); + TokenService tokenService = + new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); final UserToken token = tokenService.createUserToken(authentication); assertNotNull(token); @@ -454,7 +463,7 @@ public class TokenServiceTests extends ESTestCase { "J1fxg/JZNQDPufePg1GxV/RAQm2Gr8mYAelijEVlWIdYaQ3R76U+P/w6Q1v90dGVZQn6DKMOfgmkfwAFNY"; MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString(TokenService.TOKEN_PASSPHRASE.getKey(), "xpack_token_passpharse"); - Settings settings = Settings.builder().setSecureSettings(secureSettings).build(); + Settings settings = Settings.builder().put(XPackSettings.HTTP_SSL_ENABLED.getKey(), true).setSecureSettings(secureSettings).build(); TokenService tokenService = new TokenService(settings, Clock.systemUTC(), internalClient, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); ThreadContext requestContext = new ThreadContext(Settings.EMPTY); diff --git a/qa/rolling-upgrade/build.gradle b/qa/rolling-upgrade/build.gradle index 6c6da27e0e3..a1f3d9d7b87 100644 --- a/qa/rolling-upgrade/build.gradle +++ b/qa/rolling-upgrade/build.gradle @@ -122,6 +122,7 @@ subprojects { clusterName = 'rolling-upgrade' waitCondition = waitWithAuth setting 'xpack.security.transport.ssl.enabled', 'true' + setting 'xpack.security.authc.token.enabled', 'true' setting 'xpack.ssl.keystore.path', 'testnode.jks' setting 'xpack.ssl.keystore.password', 'testnode' dependsOn copyTestNodeKeystore @@ -161,6 +162,7 @@ subprojects { setting 'xpack.ssl.keystore.path', 'testnode.jks' keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' setting 'node.attr.upgraded', 'first' + setting 'xpack.security.authc.token.enabled', 'true' dependsOn copyTestNodeKeystore extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks') if (withSystemKey) { @@ -190,6 +192,7 @@ subprojects { waitCondition = waitWithAuth setting 'xpack.ssl.keystore.path', 'testnode.jks' keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode' + setting 'xpack.security.authc.token.enabled', 'true' dependsOn copyTestNodeKeystore extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks') if (withSystemKey) {