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:
parent
16efd4e474
commit
407cc3a9d7
|
@ -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>
|
||||
|
|
|
@ -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) -> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue