Only allow platinum licenses to use custom role providers (elastic/x-pack-elasticsearch#748)

This commit restricts custom role providers to only apply to those
instances of x-pack with a platinum level license.  All other license
types will not be allowed to use custom role providers.  Any custom role
providers implemented via the XPackExtension will not take effect unless
the license is platinum.

relates elastic/x-pack-elasticsearch#720

Original commit: elastic/x-pack-elasticsearch@4fc35494ee
This commit is contained in:
Ali Beyad 2017-03-16 13:47:35 -04:00 committed by GitHub
parent 16efd4e474
commit 407cc3a9d7
5 changed files with 96 additions and 1 deletions

View File

@ -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.
* <p>

View File

@ -152,7 +152,7 @@ public class CompositeRolesStore extends AbstractComponent {
if (builtInRoleDescriptors.size() != filteredRoleNames.size()) {
final Set<String> 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) -> {

View File

@ -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);
}
}
}

View File

@ -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() {

View File

@ -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<Set<RoleDescriptor>> callback = (ActionListener<Set<RoleDescriptor>>) 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<RoleDescriptor> 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<String> roleNames = Sets.newHashSet("roleA");
PlainActionFuture<Role> 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<Set<String>, ActionListener<Set<RoleDescriptor>>> {
private final Function<Set<String>, Set<RoleDescriptor>> roleDescriptorsFunc;