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.
This commit is contained in:
Tim Vernum 2018-10-05 12:10:42 +10:00 committed by GitHub
parent 6608992523
commit 63dbd1dce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 7 deletions
docs/reference/settings
x-pack/plugin
core/src/main/java/org/elasticsearch/xpack/core/security/authc
security/src
main/java/org/elasticsearch/xpack/security/authc/support
test/java/org/elasticsearch/xpack/security/authc/support

@ -204,6 +204,11 @@ cache at any given time. Defaults to 100,000.
in-memory cached user credentials. For possible values, see <<cache-hash-algo>>.
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]]
@ -228,6 +233,12 @@ Defaults to 100,000.
(Expert Setting) The hashing algorithm that is used for the in-memory cached
user credentials. See <<cache-hash-algo>>. 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
@ -490,6 +501,12 @@ Defaults to `100000`.
(Expert Setting) Specifies the hashing algorithm that is used for the
in-memory cached user credentials. See <<cache-hash-algo>>. 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
@ -731,6 +748,12 @@ Defaults to `100000`.
(Expert Setting) Specifies the hashing algorithm that is used for
the in-memory cached user credentials. See <<cache-hash-algo>>. 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

@ -19,6 +19,6 @@ public final class NativeRealmSettings {
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
return CachingUsernamePasswordRealmSettings.getCachingSettings();
return CachingUsernamePasswordRealmSettings.getSettings();
}
}

@ -19,6 +19,6 @@ public final class FileRealmSettings {
* @return The {@link Setting setting configuration} for this realm type
*/
public static Set<Setting<?>> getSettings() {
return CachingUsernamePasswordRealmSettings.getCachingSettings();
return CachingUsernamePasswordRealmSettings.getSettings();
}
}

@ -29,7 +29,7 @@ public final class LdapRealmSettings {
*/
public static Set<Setting<?>> getSettings(String type) {
Set<Setting<?>> 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)) {

@ -21,12 +21,15 @@ public final class CachingUsernamePasswordRealmSettings {
public static final Setting<Integer> CACHE_MAX_USERS_SETTING = Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS,
Setting.Property.NodeScope);
public static final Setting<Boolean> 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<Setting<?>> getCachingSettings() {
return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING));
public static Set<Setting<?>> getSettings() {
return new HashSet<>(Arrays.asList(CACHE_HASH_ALGO_SETTING, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, AUTHC_ENABLED_SETTING));
}
}

@ -11,6 +11,7 @@ import org.elasticsearch.common.cache.CacheBuilder;
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<String, ListenableFuture<UserWithHash>> cache;
private final ThreadPool threadPool;
private final boolean authenticationEnabled;
final Hasher cacheHasher;
protected CachingUsernamePasswordRealm(String type, RealmConfig config, ThreadPool threadPool) {
@ -45,6 +47,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
} else {
cache = null;
}
this.authenticationEnabled = CachingUsernamePasswordRealmSettings.AUTHC_ENABLED_SETTING.get(config.settings());
}
@Override
@ -63,15 +66,34 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
}
}
@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<AuthenticationResult> listener) {
if (authenticationEnabled == false) {
listener.onResponse(AuthenticationResult.notHandled());
return;
}
final UsernamePasswordToken token = (UsernamePasswordToken) authToken;
try {
if (cache == null) {

@ -11,6 +11,7 @@ import org.elasticsearch.common.settings.SecureString;
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 class CachingUsernamePasswordRealmTests extends ESTestCase {
}
}
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 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
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<AuthenticationResult> 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<User> 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) {