From fdce33b37fc108415e286d06f72163c919e0f587 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Tue, 25 Sep 2018 17:18:02 +1000 Subject: [PATCH 1/2] Allow User/Password realms to disable authc The "lookupUser" method on a realm facilitates the "run-as" and "authorization_realms" features. This commit allows a realm to be used for "lookup only", in which case the "authenticate" method (and associated token methods) are disabled. It does this through the introduction of a new "authentication.enabled" setting, which defaults to true. --- .../authc/esnative/NativeRealmSettings.java | 2 +- .../authc/file/FileRealmSettings.java | 2 +- .../authc/ldap/LdapRealmSettings.java | 2 +- .../CachingUsernamePasswordRealmSettings.java | 7 +++-- .../support/CachingUsernamePasswordRealm.java | 24 ++++++++++++++- .../CachingUsernamePasswordRealmTests.java | 30 ++++++++++++++++++- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java index e41b14099813a..eebcb6db7af87 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/esnative/NativeRealmSettings.java @@ -19,6 +19,6 @@ private NativeRealmSettings() {} * @return The {@link Setting setting configuration} for this realm type */ public static Set> getSettings() { - return CachingUsernamePasswordRealmSettings.getCachingSettings(); + return CachingUsernamePasswordRealmSettings.getSettings(); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java index 110b8af9d7bcb..ed81d07d4ccc9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/file/FileRealmSettings.java @@ -19,6 +19,6 @@ private FileRealmSettings() {} * @return The {@link Setting setting configuration} for this realm type */ public static Set> getSettings() { - return CachingUsernamePasswordRealmSettings.getCachingSettings(); + return CachingUsernamePasswordRealmSettings.getSettings(); } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java index 3f79c722be3f0..272b4115b285e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/LdapRealmSettings.java @@ -29,7 +29,7 @@ private LdapRealmSettings() {} */ public static Set> getSettings(String type) { Set> settings = new HashSet<>(); - settings.addAll(CachingUsernamePasswordRealmSettings.getCachingSettings()); + settings.addAll(CachingUsernamePasswordRealmSettings.getSettings()); settings.addAll(CompositeRoleMapperSettings.getSettings()); settings.add(LdapRealmSettings.EXECUTION_TIMEOUT); if (AD_TYPE.equals(type)) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java index 6d060b0febbd4..6b7867e421180 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/CachingUsernamePasswordRealmSettings.java @@ -21,12 +21,15 @@ public final class CachingUsernamePasswordRealmSettings { public static final Setting CACHE_MAX_USERS_SETTING = Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS, Setting.Property.NodeScope); + public static final Setting AUTHC_ENABLED_SETTING = Setting.boolSetting("authentication.enabled", true, + Setting.Property.NodeScope); + private CachingUsernamePasswordRealmSettings() {} /** * Returns the {@link Setting setting configuration} that is common for all caching realms */ - public static Set> getCachingSettings() { - return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING)); + public static Set> getSettings() { + return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, AUTHC_ENABLED_SETTING)); } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java index af93a180072aa..0d8609d61d9b2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealm.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.ListenableFuture; +import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; @@ -30,6 +31,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm private final Cache> cache; private final ThreadPool threadPool; + private final boolean authenticationEnabled; final Hasher cacheHasher; protected CachingUsernamePasswordRealm(String type, RealmConfig config, ThreadPool threadPool) { @@ -45,6 +47,7 @@ protected CachingUsernamePasswordRealm(String type, RealmConfig config, ThreadPo } else { cache = null; } + this.authenticationEnabled = CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING.get(config.settings()); } @Override @@ -63,15 +66,34 @@ public final void expireAll() { } } + @Override + public UsernamePasswordToken token(ThreadContext threadContext) { + if (authenticationEnabled == false) { + return null; + } + return super.token(threadContext); + } + + @Override + public boolean supports(AuthenticationToken token) { + return authenticationEnabled && super.supports(token); + } + /** * If the user exists in the cache (keyed by the principle name), then the password is validated * against a hash also stored in the cache. Otherwise the subclass authenticates the user via - * doAuthenticate + * doAuthenticate. + * This method will respond with {@link AuthenticationResult#notHandled()} if + * {@link CachingUsernamePasswordRealmSettings#AUTHC_ENABLED_SETTING authentication is not enabled}. * @param authToken The authentication token * @param listener to be called at completion */ @Override public final void authenticate(AuthenticationToken authToken, ActionListener listener) { + if (authenticationEnabled == false) { + listener.onResponse(AuthenticationResult.notHandled()); + return; + } final UsernamePasswordToken token = (UsernamePasswordToken) authToken; try { if (cache == null) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java index e9e8908c584a9..6d84dfb2a8048 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/CachingUsernamePasswordRealmTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.env.Environment; import org.elasticsearch.env.TestEnvironment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.SecuritySettingsSourceField; @@ -62,7 +63,7 @@ public void stop() throws InterruptedException { } } - public void testSettings() throws Exception { + public void testCacheSettings() throws Exception { String cachingHashAlgo = Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT); int maxUsers = randomIntBetween(10, 100); TimeValue ttl = TimeValue.timeValueMinutes(randomIntBetween(10, 20)); @@ -560,6 +561,33 @@ protected void doLookupUser(String username, ActionListener listener) { assertEquals(1, lookupCounter.get()); } + public void testAuthenticateDisabled() throws Exception { + final Settings settings = Settings.builder() + .put(CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING.getKey(), false) + .build(); + final Environment env = TestEnvironment.newEnvironment(globalSettings); + final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + final RealmConfig config = new RealmConfig("test_authentication_disabled", settings, globalSettings, env, threadContext); + final AlwaysAuthenticateCachingRealm realm = new AlwaysAuthenticateCachingRealm(config, threadPool); + + final UsernamePasswordToken token = new UsernamePasswordToken("phil", new SecureString("tahiti")); + UsernamePasswordToken.putTokenHeader(threadContext, token); + assertThat(realm.token(threadContext), nullValue()); + assertThat(realm.supports(token), equalTo(false)); + + PlainActionFuture authFuture = new PlainActionFuture<>(); + realm.authenticate(token, authFuture); + final AuthenticationResult authResult = authFuture.get(); + assertThat(authResult.isAuthenticated(), equalTo(false)); + assertThat(authResult.getStatus(), equalTo(AuthenticationResult.Status.CONTINUE)); + + PlainActionFuture lookupFuture = new PlainActionFuture<>(); + realm.lookupUser(token.principal(), lookupFuture); + final User user = lookupFuture.get(); + assertThat(user, notNullValue()); + assertThat(user.principal(), equalTo(token.principal())); + } + static class FailingAuthenticationRealm extends CachingUsernamePasswordRealm { FailingAuthenticationRealm(Settings settings, Settings global, ThreadPool threadPool) { From ccd4d6722fc74fdf8c34a24f50cd349be5561332 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Tue, 25 Sep 2018 20:27:24 +1000 Subject: [PATCH 2/2] Add "authentication.enabled" to docs --- .../settings/security-settings.asciidoc | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/reference/settings/security-settings.asciidoc b/docs/reference/settings/security-settings.asciidoc index 2176d0d3ee62e..110acbc58aa12 100644 --- a/docs/reference/settings/security-settings.asciidoc +++ b/docs/reference/settings/security-settings.asciidoc @@ -176,6 +176,11 @@ cache at any given time. Defaults to 100,000. in-memory cached user credentials. For possible values, see <>. Defaults to `ssha256`. +`authentication.enabled`:: If set to `false`, disables authentication support in +this realm, so that it only supports user lookups. +(See the {xpack-ref}/run-as-privilege.html[run as] and +{stack-ov}/realm-chains.html#authorization_realms[authorization realms] features). +Defaults to `true`. [[ref-users-settings]] @@ -200,6 +205,12 @@ Defaults to 100,000. (Expert Setting) The hashing algorithm that is used for the in-memory cached user credentials. See <>. Defaults to `ssha256`. +`authentication.enabled`:: If set to `false`, disables authentication support in +this realm, so that it only supports user lookups. +(See the {xpack-ref}/run-as-privilege.html[run as] and +{stack-ov}/realm-chains.html#authorization_realms[authorization realms] features). +Defaults to `true`. + [[ref-ldap-settings]] [float] ===== LDAP realm settings @@ -460,6 +471,12 @@ Defaults to `100000`. (Expert Setting) Specifies the hashing algorithm that is used for the in-memory cached user credentials. See <>. Defaults to `ssha256`. +`authentication.enabled`:: If set to `false`, disables authentication support in +this realm, so that it only supports user lookups. +(See the {xpack-ref}/run-as-privilege.html[run as] and +{stack-ov}/realm-chains.html#authorization_realms[authorization realms] features). +Defaults to `true`. + [[ref-ad-settings]] [float] ===== Active Directory realm settings @@ -699,6 +716,12 @@ Defaults to `100000`. (Expert Setting) Specifies the hashing algorithm that is used for the in-memory cached user credentials. See <>. Defaults to `ssha256`. +`authentication.enabled`:: If set to `false`, disables authentication support in +this realm, so that it only supports user lookups. +(See the {xpack-ref}/run-as-privilege.html[run as] and +{stack-ov}/realm-chains.html#authorization_realms[authorization realms] features). +Defaults to `true`. + `follow_referrals`:: If set to `true` {security} follows referrals returned by the LDAP server. Referrals are URLs returned by the server that are to be used to continue the