diff --git a/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java
index 7826235d175..099dc4f7aaa 100644
--- a/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java
+++ b/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java
@@ -283,6 +283,14 @@ public class XPackLicenseState {
}
}
+ /**
+ * @return whether custom role providers are allowed based on the license {@link OperationMode}
+ */
+ public boolean isCustomRoleProvidersAllowed() {
+ 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/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java
index 161c42152b9..0cb17f47079 100644
--- a/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java
+++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java
@@ -152,7 +152,7 @@ public class CompositeRolesStore extends AbstractComponent {
if (builtInRoleDescriptors.size() != filteredRoleNames.size()) {
final Set missing = difference(filteredRoleNames, builtInRoleDescriptors);
assert missing.isEmpty() == false : "the missing set should not be empty if the sizes didn't match";
- if (!customRolesProviders.isEmpty()) {
+ if (licenseState.isCustomRoleProvidersAllowed() && !customRolesProviders.isEmpty()) {
new IteratingActionListener<>(roleDescriptorActionListener, (rolesProvider, listener) -> {
// resolve descriptors with role provider
rolesProvider.accept(missing, ActionListener.wrap((resolvedDescriptors) -> {
diff --git a/plugin/src/test/java/org/elasticsearch/license/TestUtils.java b/plugin/src/test/java/org/elasticsearch/license/TestUtils.java
index 4fda068be73..cb4a7b80c50 100644
--- a/plugin/src/test/java/org/elasticsearch/license/TestUtils.java
+++ b/plugin/src/test/java/org/elasticsearch/license/TestUtils.java
@@ -334,4 +334,15 @@ public class TestUtils {
activeUpdates.add(active);
}
}
+
+ /**
+ * A license state that makes the {@link #update(License.OperationMode, boolean)}
+ * method public for use in tests.
+ */
+ public static class UpdatableLicenseState extends XPackLicenseState {
+ @Override
+ public void update(License.OperationMode mode, boolean active) {
+ super.update(mode, active);
+ }
+ }
}
diff --git a/plugin/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java b/plugin/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java
index 4208244bf9d..1fd56876859 100644
--- a/plugin/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java
+++ b/plugin/src/test/java/org/elasticsearch/license/XPackLicenseStateTests.java
@@ -68,6 +68,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(true));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.ALL));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(true));
}
public void testSecurityBasic() {
@@ -80,6 +81,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.NONE));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityBasicExpired() {
@@ -92,6 +94,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(false));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.NONE));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityStandard() {
@@ -104,6 +107,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.NATIVE));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityStandardExpired() {
@@ -116,6 +120,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(false));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.NATIVE));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityGold() {
@@ -128,6 +133,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.DEFAULT));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityGoldExpired() {
@@ -140,6 +146,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(false));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(false));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.DEFAULT));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityPlatinum() {
@@ -152,6 +159,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(true));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.ALL));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(true));
}
public void testSecurityPlatinumExpired() {
@@ -164,6 +172,7 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isStatsAndHealthAllowed(), is(false));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(true));
assertThat(licenseState.allowedRealmType(), Matchers.is(XPackLicenseState.AllowedRealmType.ALL));
+ assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testSecurityAckBasicToNotGoldOrStandard() {
diff --git a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java
index 6baade5266d..68de9010958 100644
--- a/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java
+++ b/plugin/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java
@@ -11,6 +11,8 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.license.License.OperationMode;
+import org.elasticsearch.license.TestUtils.UpdatableLicenseState;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.authz.RoleDescriptor.IndicesPrivileges;
@@ -319,6 +321,71 @@ public class CompositeRolesStoreTests extends ESTestCase {
}
}
+ public void testCustomRolesProvidersLicensing() {
+ final FileRolesStore fileRolesStore = mock(FileRolesStore.class);
+ when(fileRolesStore.roleDescriptors(anySetOf(String.class))).thenReturn(Collections.emptySet());
+ final NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
+ doAnswer((invocationOnMock) -> {
+ ActionListener> callback = (ActionListener>) invocationOnMock.getArguments()[1];
+ callback.onResponse(Collections.emptySet());
+ return null;
+ }).when(nativeRolesStore).getRoleDescriptors(isA(String[].class), any(ActionListener.class));
+ final ReservedRolesStore reservedRolesStore = new ReservedRolesStore();
+
+ final InMemoryRolesProvider inMemoryProvider = new InMemoryRolesProvider((roles) -> {
+ Set descriptors = new HashSet<>();
+ if (roles.contains("roleA")) {
+ descriptors.add(new RoleDescriptor("roleA", null,
+ new IndicesPrivileges[] {
+ IndicesPrivileges.builder().privileges("READ").indices("foo").grantedFields("*").build()
+ }, null));
+ }
+ return descriptors;
+ });
+
+ UpdatableLicenseState xPackLicenseState = new UpdatableLicenseState();
+ // these licenses don't allow custom role providers
+ xPackLicenseState.update(randomFrom(OperationMode.BASIC, OperationMode.GOLD, OperationMode.STANDARD), true);
+ CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
+ Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
+ Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
+
+ Set roleNames = Sets.newHashSet("roleA");
+ PlainActionFuture future = new PlainActionFuture<>();
+ FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
+ compositeRolesStore.roles(roleNames, fieldPermissionsCache, future);
+ Role role = future.actionGet();
+
+ // no roles should've been populated, as the license doesn't permit custom role providers
+ assertEquals(0, role.indices().groups().length);
+
+ compositeRolesStore = new CompositeRolesStore(
+ Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
+ Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
+ // these licenses allow custom role providers
+ xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), true);
+ roleNames = Sets.newHashSet("roleA");
+ future = new PlainActionFuture<>();
+ fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
+ compositeRolesStore.roles(roleNames, fieldPermissionsCache, future);
+ role = future.actionGet();
+
+ // roleA should've been populated by the custom role provider, because the license allows it
+ assertEquals(1, role.indices().groups().length);
+
+ // license expired, don't allow custom role providers
+ compositeRolesStore = new CompositeRolesStore(
+ Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
+ Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
+ xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), false);
+ roleNames = Sets.newHashSet("roleA");
+ future = new PlainActionFuture<>();
+ fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
+ compositeRolesStore.roles(roleNames, fieldPermissionsCache, future);
+ role = future.actionGet();
+ assertEquals(0, role.indices().groups().length);
+ }
+
private static class InMemoryRolesProvider implements BiConsumer, ActionListener>> {
private final Function, Set> roleDescriptorsFunc;