From 4d2de342662db7082619dee4142d86d700e0ed53 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Fri, 6 Jul 2018 17:34:10 +1000 Subject: [PATCH 1/2] Restrict authorizing_realms to platinum only --- .../license/XPackLicenseState.java | 9 ++++ .../xpack/core/security/authc/Realm.java | 3 +- .../xpack/security/Security.java | 1 - .../xpack/security/authc/Realms.java | 2 +- .../xpack/security/authc/pki/PkiRealm.java | 5 ++- .../DelegatedAuthorizationSupport.java | 20 +++++++-- .../security/authc/pki/PkiRealmTests.java | 12 ++++-- .../DelegatedAuthorizationSupportTests.java | 42 ++++++++++++++++--- 8 files changed, 76 insertions(+), 18 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java index ea30e30ae3cd9..9f8f86ecf1ae3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java @@ -391,6 +391,15 @@ public boolean isCustomRoleProvidersAllowed() { && localStatus.active; } + /** + * @return whether "authorizing_realms" are allowed based on the license {@link OperationMode} + */ + public boolean isAuthorizingRealmAllowed() { + final Status localStatus = status; + return (localStatus.mode == OperationMode.PLATINUM || localStatus.mode == OperationMode.TRIAL ) + && localStatus.active; + } + /** * Determine if Watcher is available based on the current license. *

diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java index b2e69751ecae6..cc8853135d9d6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Realm.java @@ -8,6 +8,7 @@ import org.apache.logging.log4j.Logger; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings; import org.elasticsearch.xpack.core.security.user.User; @@ -137,7 +138,7 @@ public String toString() { * * @see DelegatedAuthorizationSettings */ - public void initialize(Iterable realms) { + public void initialize(Iterable realms, XPackLicenseState licenseState) { } /** 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 3115c08a9469d..afa83794c7a32 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 @@ -205,7 +205,6 @@ import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4ServerTransport; -import org.elasticsearch.xpack.core.template.TemplateUtils; import org.elasticsearch.xpack.security.transport.nio.SecurityNioHttpServerTransport; import org.elasticsearch.xpack.security.transport.nio.SecurityNioTransport; import org.joda.time.DateTime; 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 3ea75a15d3613..1eeb8f32126b0 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 @@ -92,7 +92,7 @@ public Realms(Settings settings, Environment env, Map fac this.standardRealmsOnly = Collections.unmodifiableList(standardRealms); this.nativeRealmsOnly = Collections.unmodifiableList(nativeRealms); - realms.forEach(r -> r.initialize(this)); + realms.forEach(r -> r.initialize(this, licenseState)); } @Override diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index 5f37a426bbadc..4d13f332ffe20 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -19,6 +19,7 @@ import org.elasticsearch.common.util.concurrent.ReleasableLock; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.AuthenticationToken; @@ -96,11 +97,11 @@ public PkiRealm(RealmConfig config, ResourceWatcherService watcherService, Nativ } @Override - public void initialize(Iterable realms) { + public void initialize(Iterable realms, XPackLicenseState licenseState) { if (delegatedRealms != null) { throw new IllegalStateException("Realm has already been initialized"); } - delegatedRealms = new DelegatedAuthorizationSupport(realms, config); + delegatedRealms = new DelegatedAuthorizationSupport(realms, config, licenseState); } @Override diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java index d6e8e5be5f2e6..f843e747bb8db 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupport.java @@ -11,6 +11,8 @@ import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.license.LicenseUtils; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.Realm; import org.elasticsearch.xpack.core.security.authc.RealmConfig; @@ -34,13 +36,14 @@ public class DelegatedAuthorizationSupport { private final RealmUserLookup lookup; private final Logger logger; + private final XPackLicenseState licenseState; /** * Resolves the {@link DelegatedAuthorizationSettings#AUTHZ_REALMS} setting from {@code config} and calls - * {@link #DelegatedAuthorizationSupport(Iterable, List, ThreadContext)} + * {@link #DelegatedAuthorizationSupport(Iterable, List, ThreadContext, XPackLicenseState)} */ - public DelegatedAuthorizationSupport(Iterable allRealms, RealmConfig config) { - this(allRealms, DelegatedAuthorizationSettings.AUTHZ_REALMS.get(config.settings()), config.threadContext()); + public DelegatedAuthorizationSupport(Iterable allRealms, RealmConfig config, XPackLicenseState licenseState) { + this(allRealms, DelegatedAuthorizationSettings.AUTHZ_REALMS.get(config.settings()), config.threadContext(), licenseState); } /** @@ -48,9 +51,11 @@ public DelegatedAuthorizationSupport(Iterable allRealms, RealmC * {@code allRealms}. * @throws IllegalArgumentException if one of the specified realms does not exist */ - protected DelegatedAuthorizationSupport(Iterable allRealms, List lookupRealms, ThreadContext threadContext) { + protected DelegatedAuthorizationSupport(Iterable allRealms, List lookupRealms, ThreadContext threadContext, + XPackLicenseState licenseState) { this.lookup = new RealmUserLookup(resolveRealms(allRealms, lookupRealms), threadContext); this.logger = Loggers.getLogger(getClass()); + this.licenseState = licenseState; } /** @@ -69,6 +74,13 @@ public boolean hasDelegation() { * with a meaningful diagnostic message. */ public void resolve(String username, ActionListener resultListener) { + if (licenseState.isAuthorizingRealmAllowed() == false) { + resultListener.onResponse(AuthenticationResult.unsuccessful( + DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey() + " are not permitted", + LicenseUtils.newComplianceException(DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey()) + )); + return; + } if (hasDelegation() == false) { resultListener.onResponse(AuthenticationResult.unsuccessful( "No [" + DelegatedAuthorizationSettings.AUTHZ_REALMS.getKey() + "] have been configured", null)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java index f5cba810387c8..00545deb9d66e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java @@ -15,6 +15,7 @@ import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.TestEnvironment; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.Realm; @@ -61,12 +62,15 @@ public class PkiRealmTests extends ESTestCase { private Settings globalSettings; + private XPackLicenseState licenseState; @Before public void setup() throws Exception { globalSettings = Settings.builder() .put("path.home", createTempDir()) .build(); + licenseState = mock(XPackLicenseState.class); + when(licenseState.isAuthorizingRealmAllowed()).thenReturn(true); } public void testTokenSupport() { @@ -161,7 +165,7 @@ private PkiRealm buildRealm(UserRoleMapper roleMapper, Settings realmSettings, R List allRealms = CollectionUtils.arrayAsArrayList(otherRealms); allRealms.add(realm); Collections.shuffle(allRealms, random()); - realm.initialize(allRealms); + realm.initialize(allRealms, licenseState); return realm; } @@ -182,7 +186,7 @@ public void testCustomUsernamePattern() throws Exception { UserRoleMapper roleMapper = mock(UserRoleMapper.class); PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings, TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); - realm.initialize(Collections.emptyList()); + realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; listener.onResponse(Collections.emptySet()); @@ -213,7 +217,7 @@ public void testVerificationUsingATruststore() throws Exception { ThreadContext threadContext = new ThreadContext(globalSettings); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); - realm.initialize(Collections.emptyList()); + realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; listener.onResponse(Collections.emptySet()); @@ -245,7 +249,7 @@ public void testVerificationFailsUsingADifferentTruststore() throws Exception { final ThreadContext threadContext = new ThreadContext(globalSettings); PkiRealm realm = new PkiRealm(new RealmConfig("", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings), threadContext), roleMapper); - realm.initialize(Collections.emptyList()); + realm.initialize(Collections.emptyList(), licenseState); Mockito.doAnswer(invocation -> { ActionListener> listener = (ActionListener>) invocation.getArguments()[1]; listener.onResponse(Collections.emptySet()); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java index d7e033952ac3b..3b852c63853c0 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/DelegatedAuthorizationSupportTests.java @@ -5,11 +5,13 @@ */ package org.elasticsearch.xpack.security.authc.support; +import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.env.Environment; import org.elasticsearch.env.TestEnvironment; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.Realm; @@ -26,8 +28,11 @@ import static org.elasticsearch.common.Strings.collectionToDelimitedString; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class DelegatedAuthorizationSupportTests extends ESTestCase { @@ -62,7 +67,8 @@ private RealmConfig buildRealmConfig(String name, Settings settings) { } public void testEmptyDelegationList() throws ExecutionException, InterruptedException { - final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", Settings.EMPTY)); + final XPackLicenseState license = getLicenseState(true); + final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", Settings.EMPTY), license); assertThat(das.hasDelegation(), equalTo(false)); final PlainActionFuture future = new PlainActionFuture<>(); das.resolve("any", future); @@ -73,23 +79,25 @@ public void testEmptyDelegationList() throws ExecutionException, InterruptedExce } public void testMissingRealmInDelegationList() { + final XPackLicenseState license = getLicenseState(true); final Settings settings = Settings.builder() .putList("authorizing_realms", "no-such-realm") .build(); final IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> - new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings)) + new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings), license) ); assertThat(ex.getMessage(), equalTo("configured authorizing realm [no-such-realm] does not exist (or is not enabled)")); } public void testMatchInDelegationList() throws Exception { + final XPackLicenseState license = getLicenseState(true); final List useRealms = shuffle(randomSubsetOf(randomIntBetween(1, realms.size()), realms)); final Settings settings = Settings.builder() .putList("authorizing_realms", useRealms.stream().map(Realm::name).collect(Collectors.toList())) .build(); final User user = new User("my_user"); randomFrom(useRealms).registerUser(user); - final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings)); + final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings), license); assertThat(das.hasDelegation(), equalTo(true)); final PlainActionFuture future = new PlainActionFuture<>(); das.resolve("my_user", future); @@ -99,6 +107,7 @@ public void testMatchInDelegationList() throws Exception { } public void testRealmsAreOrdered() throws Exception { + final XPackLicenseState license = getLicenseState(true); final List useRealms = shuffle(randomSubsetOf(randomIntBetween(3, realms.size()), realms)); final List names = useRealms.stream().map(Realm::name).collect(Collectors.toList()); final Settings settings = Settings.builder() @@ -112,7 +121,7 @@ public void testRealmsAreOrdered() throws Exception { r.registerUser(user); } - final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings)); + final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings), license); assertThat(das.hasDelegation(), equalTo(true)); final PlainActionFuture future = new PlainActionFuture<>(); das.resolve(username, future); @@ -123,11 +132,12 @@ public void testRealmsAreOrdered() throws Exception { } public void testNoMatchInDelegationList() throws Exception { + final XPackLicenseState license = getLicenseState(true); final List useRealms = shuffle(randomSubsetOf(randomIntBetween(1, realms.size()), realms)); final Settings settings = Settings.builder() .putList("authorizing_realms", useRealms.stream().map(Realm::name).collect(Collectors.toList())) .build(); - final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings)); + final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings), license); assertThat(das.hasDelegation(), equalTo(true)); final PlainActionFuture future = new PlainActionFuture<>(); das.resolve("my_user", future); @@ -138,4 +148,26 @@ public void testNoMatchInDelegationList() throws Exception { collectionToDelimitedString(useRealms.stream().map(Realm::toString).collect(Collectors.toList()), ",") + "]")); } + public void testLicenseRejection() throws Exception { + final XPackLicenseState license = getLicenseState(false); + final Settings settings = Settings.builder() + .putList("authorizing_realms", realms.get(0).name()) + .build(); + final DelegatedAuthorizationSupport das = new DelegatedAuthorizationSupport(realms, buildRealmConfig("r", settings), license); + assertThat(das.hasDelegation(), equalTo(true)); + final PlainActionFuture future = new PlainActionFuture<>(); + das.resolve("my_user", future); + final AuthenticationResult result = future.get(); + assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.CONTINUE)); + assertThat(result.getUser(), nullValue()); + assertThat(result.getMessage(), equalTo("authorizing_realms are not permitted")); + assertThat(result.getException(), instanceOf(ElasticsearchSecurityException.class)); + assertThat(result.getException().getMessage(), equalTo("current license is non-compliant for [authorizing_realms]")); + } + + private XPackLicenseState getLicenseState(boolean authzRealmsAllowed) { + final XPackLicenseState license = mock(XPackLicenseState.class); + when(license.isAuthorizingRealmAllowed()).thenReturn(authzRealmsAllowed); + return license; + } } From 2584ac3f0e2f2f3413efe0f56ef396a1021f1ac9 Mon Sep 17 00:00:00 2001 From: Tim Vernum Date: Wed, 18 Jul 2018 14:54:38 +1000 Subject: [PATCH 2/2] Remove extra spaces --- .../java/org/elasticsearch/license/XPackLicenseState.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java index 9f8f86ecf1ae3..a3b9bc0eabe4c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/XPackLicenseState.java @@ -387,7 +387,7 @@ public AllowedRealmType allowedRealmType() { */ public boolean isCustomRoleProvidersAllowed() { final Status localStatus = status; - return (localStatus.mode == OperationMode.PLATINUM || localStatus.mode == OperationMode.TRIAL ) + return (localStatus.mode == OperationMode.PLATINUM || localStatus.mode == OperationMode.TRIAL) && localStatus.active; } @@ -396,7 +396,7 @@ public boolean isCustomRoleProvidersAllowed() { */ public boolean isAuthorizingRealmAllowed() { final Status localStatus = status; - return (localStatus.mode == OperationMode.PLATINUM || localStatus.mode == OperationMode.TRIAL ) + return (localStatus.mode == OperationMode.PLATINUM || localStatus.mode == OperationMode.TRIAL) && localStatus.active; }