This commit initializes DocumentSubsetBitsetCache even if DLS is disabled. Previously it would throw null pointer when querying usage stats if we explicitly disabled DLS as there would be no instance of DocumentSubsetBitsetCache to query. It is okay to initialize DocumentSubsetBitsetCache which will be empty as the license enforcement would prevent usage of DLS feature and it will not fail when accessing usage stats. Closes #45147
This commit is contained in:
parent
03ed18a010
commit
d5acb15a71
|
@ -406,10 +406,6 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
securityContext.set(new SecurityContext(settings, threadPool.getThreadContext()));
|
securityContext.set(new SecurityContext(settings, threadPool.getThreadContext()));
|
||||||
components.add(securityContext.get());
|
components.add(securityContext.get());
|
||||||
|
|
||||||
if (XPackSettings.DLS_FLS_ENABLED.get(settings)) {
|
|
||||||
dlsBitsetCache.set(new DocumentSubsetBitsetCache(settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
// audit trail service construction
|
// audit trail service construction
|
||||||
final List<AuditTrail> auditTrails = XPackSettings.AUDIT_ENABLED.get(settings)
|
final List<AuditTrail> auditTrails = XPackSettings.AUDIT_ENABLED.get(settings)
|
||||||
? Collections.singletonList(new LoggingAuditTrail(settings, clusterService, threadPool))
|
? Collections.singletonList(new LoggingAuditTrail(settings, clusterService, threadPool))
|
||||||
|
@ -453,6 +449,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
final NativePrivilegeStore privilegeStore = new NativePrivilegeStore(settings, client, securityIndex.get());
|
final NativePrivilegeStore privilegeStore = new NativePrivilegeStore(settings, client, securityIndex.get());
|
||||||
components.add(privilegeStore);
|
components.add(privilegeStore);
|
||||||
|
|
||||||
|
dlsBitsetCache.set(new DocumentSubsetBitsetCache(settings));
|
||||||
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(settings);
|
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(settings);
|
||||||
final FileRolesStore fileRolesStore = new FileRolesStore(settings, env, resourceWatcherService, getLicenseState());
|
final FileRolesStore fileRolesStore = new FileRolesStore(settings, env, resourceWatcherService, getLicenseState());
|
||||||
final NativeRolesStore nativeRolesStore = new NativeRolesStore(settings, client, getLicenseState(), securityIndex.get());
|
final NativeRolesStore nativeRolesStore = new NativeRolesStore(settings, client, getLicenseState(), securityIndex.get());
|
||||||
|
|
|
@ -106,17 +106,17 @@ public class CompositeRolesStore {
|
||||||
ReservedRolesStore reservedRolesStore, NativePrivilegeStore privilegeStore,
|
ReservedRolesStore reservedRolesStore, NativePrivilegeStore privilegeStore,
|
||||||
List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> rolesProviders,
|
List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> rolesProviders,
|
||||||
ThreadContext threadContext, XPackLicenseState licenseState, FieldPermissionsCache fieldPermissionsCache,
|
ThreadContext threadContext, XPackLicenseState licenseState, FieldPermissionsCache fieldPermissionsCache,
|
||||||
ApiKeyService apiKeyService, @Nullable DocumentSubsetBitsetCache dlsBitsetCache,
|
ApiKeyService apiKeyService, DocumentSubsetBitsetCache dlsBitsetCache,
|
||||||
Consumer<Collection<RoleDescriptor>> effectiveRoleDescriptorsConsumer) {
|
Consumer<Collection<RoleDescriptor>> effectiveRoleDescriptorsConsumer) {
|
||||||
this.fileRolesStore = fileRolesStore;
|
this.fileRolesStore = Objects.requireNonNull(fileRolesStore);
|
||||||
this.dlsBitsetCache = dlsBitsetCache;
|
this.dlsBitsetCache = Objects.requireNonNull(dlsBitsetCache);
|
||||||
fileRolesStore.addListener(this::invalidate);
|
fileRolesStore.addListener(this::invalidate);
|
||||||
this.nativeRolesStore = nativeRolesStore;
|
this.nativeRolesStore = Objects.requireNonNull(nativeRolesStore);
|
||||||
this.privilegeStore = privilegeStore;
|
this.privilegeStore = Objects.requireNonNull(privilegeStore);
|
||||||
this.licenseState = licenseState;
|
this.licenseState = Objects.requireNonNull(licenseState);
|
||||||
this.fieldPermissionsCache = fieldPermissionsCache;
|
this.fieldPermissionsCache = Objects.requireNonNull(fieldPermissionsCache);
|
||||||
this.apiKeyService = apiKeyService;
|
this.apiKeyService = Objects.requireNonNull(apiKeyService);
|
||||||
this.effectiveRoleDescriptorsConsumer = effectiveRoleDescriptorsConsumer;
|
this.effectiveRoleDescriptorsConsumer = Objects.requireNonNull(effectiveRoleDescriptorsConsumer);
|
||||||
CacheBuilder<RoleKey, Role> builder = CacheBuilder.builder();
|
CacheBuilder<RoleKey, Role> builder = CacheBuilder.builder();
|
||||||
final int cacheSize = CACHE_SIZE_SETTING.get(settings);
|
final int cacheSize = CACHE_SIZE_SETTING.get(settings);
|
||||||
if (cacheSize >= 0) {
|
if (cacheSize >= 0) {
|
||||||
|
@ -415,9 +415,7 @@ public class CompositeRolesStore {
|
||||||
try (ReleasableLock ignored = roleCacheHelper.acquireUpdateLock()) {
|
try (ReleasableLock ignored = roleCacheHelper.acquireUpdateLock()) {
|
||||||
roleCache.invalidateAll();
|
roleCache.invalidateAll();
|
||||||
}
|
}
|
||||||
if (dlsBitsetCache != null) {
|
dlsBitsetCache.clear("role store invalidation");
|
||||||
dlsBitsetCache.clear("role store invalidation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidate(String role) {
|
public void invalidate(String role) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.elasticsearch.xpack.core.security.authc.Authentication.Authentication
|
||||||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
||||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.IndicesPrivileges;
|
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.IndicesPrivileges;
|
||||||
|
import org.elasticsearch.xpack.core.security.authz.accesscontrol.DocumentSubsetBitsetCache;
|
||||||
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
|
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
|
||||||
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
|
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
|
||||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsCache;
|
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsCache;
|
||||||
|
@ -65,6 +66,7 @@ import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -151,9 +153,10 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
|
when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
|
||||||
when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
|
when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
|
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
|
||||||
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
|
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
|
||||||
new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), null,
|
new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
|
|
||||||
PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
|
PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
|
||||||
|
@ -226,9 +229,10 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
|
when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
|
||||||
when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
|
when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
|
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
|
||||||
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
|
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
|
||||||
new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), null,
|
new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
|
|
||||||
PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
|
PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
|
||||||
|
@ -277,11 +281,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}).when(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
|
}).when(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
|
||||||
|
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
nativePrivilegeStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
nativePrivilegeStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class),
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
final String roleName = randomAlphaOfLengthBetween(1, 10);
|
final String roleName = randomAlphaOfLengthBetween(1, 10);
|
||||||
|
@ -339,9 +344,11 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
.put("xpack.security.authz.store.roles.negative_lookup_cache.max_size", 0)
|
.put("xpack.security.authz.store.roles.negative_lookup_cache.max_size", 0)
|
||||||
.build();
|
.build();
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore = new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
|
final CompositeRolesStore compositeRolesStore = new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
|
||||||
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
|
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
|
||||||
new XPackLicenseState(settings), cache, mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
new XPackLicenseState(settings), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
final String roleName = randomAlphaOfLengthBetween(1, 10);
|
final String roleName = randomAlphaOfLengthBetween(1, 10);
|
||||||
|
@ -375,10 +382,11 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
|
@ -460,11 +468,13 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, inMemoryProvider2),
|
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, inMemoryProvider2),
|
||||||
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
|
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
|
||||||
cache, mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
|
|
||||||
final Set<String> roleNames = Sets.newHashSet("roleA", "roleB", "unknown");
|
final Set<String> roleNames = Sets.newHashSet("roleA", "roleB", "unknown");
|
||||||
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
||||||
|
@ -687,11 +697,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
(roles, listener) -> listener.onFailure(new Exception("fake failure"));
|
(roles, listener) -> listener.onFailure(new Exception("fake failure"));
|
||||||
|
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, failingProvider),
|
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, failingProvider),
|
||||||
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
|
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
|
||||||
cache, mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
|
||||||
|
|
||||||
final Set<String> roleNames = Sets.newHashSet("roleA", "roleB", "unknown");
|
final Set<String> roleNames = Sets.newHashSet("roleA", "roleB", "unknown");
|
||||||
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
||||||
|
@ -734,10 +745,11 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
// these licenses don't allow custom role providers
|
// these licenses don't allow custom role providers
|
||||||
xPackLicenseState.update(randomFrom(OperationMode.BASIC, OperationMode.GOLD, OperationMode.STANDARD), true, null);
|
xPackLicenseState.update(randomFrom(OperationMode.BASIC, OperationMode.GOLD, OperationMode.STANDARD), true, null);
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
|
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
|
||||||
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
||||||
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
||||||
mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
|
||||||
|
|
||||||
Set<String> roleNames = Sets.newHashSet("roleA");
|
Set<String> roleNames = Sets.newHashSet("roleA");
|
||||||
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
PlainActionFuture<Role> future = new PlainActionFuture<>();
|
||||||
|
@ -752,7 +764,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
compositeRolesStore = new CompositeRolesStore(
|
compositeRolesStore = new CompositeRolesStore(
|
||||||
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
||||||
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
||||||
mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
|
||||||
// these licenses allow custom role providers
|
// these licenses allow custom role providers
|
||||||
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), true, null);
|
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), true, null);
|
||||||
roleNames = Sets.newHashSet("roleA");
|
roleNames = Sets.newHashSet("roleA");
|
||||||
|
@ -769,7 +781,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
compositeRolesStore = new CompositeRolesStore(
|
compositeRolesStore = new CompositeRolesStore(
|
||||||
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class),
|
||||||
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState, cache,
|
||||||
mock(ApiKeyService.class), null, rds -> effectiveRoleDescriptors.set(rds));
|
mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
|
||||||
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), false, null);
|
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), false, null);
|
||||||
roleNames = Sets.newHashSet("roleA");
|
roleNames = Sets.newHashSet("roleA");
|
||||||
future = new PlainActionFuture<>();
|
future = new PlainActionFuture<>();
|
||||||
|
@ -797,10 +809,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
|
doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||||
NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
||||||
doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
|
doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
|
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
|
||||||
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(Settings.EMPTY),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(Settings.EMPTY),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null, rds -> {}) {
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
|
rds -> {}) {
|
||||||
@Override
|
@Override
|
||||||
public void invalidateAll() {
|
public void invalidateAll() {
|
||||||
numInvalidation.incrementAndGet();
|
numInvalidation.incrementAndGet();
|
||||||
|
@ -849,10 +863,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
|
doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||||
NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
||||||
doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
|
doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(SECURITY_ENABLED_SETTINGS,
|
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(SECURITY_ENABLED_SETTINGS,
|
||||||
fileRolesStore, nativeRolesStore, reservedRolesStore,
|
fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null, rds -> {}) {
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class),
|
||||||
|
documentSubsetBitsetCache, rds -> {}) {
|
||||||
@Override
|
@Override
|
||||||
public void invalidateAll() {
|
public void invalidateAll() {
|
||||||
numInvalidation.incrementAndGet();
|
numInvalidation.incrementAndGet();
|
||||||
|
@ -879,10 +895,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
||||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null, rds -> {});
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
|
rds -> {});
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
|
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
|
||||||
|
@ -918,10 +936,11 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
||||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
|
||||||
new XPackLicenseState(settings), cache, mock(ApiKeyService.class), null, rds -> {});
|
new XPackLicenseState(settings), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> {});
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
|
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
|
||||||
|
@ -945,11 +964,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
||||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
|
|
||||||
|
@ -975,11 +995,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
}).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
|
||||||
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
|
||||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
|
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
|
||||||
|
@ -1010,11 +1031,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
return Void.TYPE;
|
return Void.TYPE;
|
||||||
}).when(nativePrivStore).getPrivileges(any(Collection.class), any(Collection.class), any(ActionListener.class));
|
}).when(nativePrivStore).getPrivileges(any(Collection.class), any(Collection.class), any(ActionListener.class));
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
AuditUtil.getOrGenerateRequestId(threadContext);
|
AuditUtil.getOrGenerateRequestId(threadContext);
|
||||||
final Authentication authentication = new Authentication(new User("test api key user", "superuser"),
|
final Authentication authentication = new Authentication(new User("test api key user", "superuser"),
|
||||||
|
@ -1055,11 +1077,12 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
return Void.TYPE;
|
return Void.TYPE;
|
||||||
}).when(nativePrivStore).getPrivileges(any(Collection.class), any(Collection.class), any(ActionListener.class));
|
}).when(nativePrivStore).getPrivileges(any(Collection.class), any(Collection.class), any(ActionListener.class));
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
|
||||||
final CompositeRolesStore compositeRolesStore =
|
final CompositeRolesStore compositeRolesStore =
|
||||||
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, null,
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, documentSubsetBitsetCache,
|
||||||
rds -> effectiveRoleDescriptors.set(rds));
|
rds -> effectiveRoleDescriptors.set(rds));
|
||||||
AuditUtil.getOrGenerateRequestId(threadContext);
|
AuditUtil.getOrGenerateRequestId(threadContext);
|
||||||
final Authentication authentication = new Authentication(new User("test api key user", "api_key"),
|
final Authentication authentication = new Authentication(new User("test api key user", "api_key"),
|
||||||
|
@ -1081,6 +1104,39 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
verify(apiKeyService).getRoleForApiKey(eq(authentication), any(ActionListener.class));
|
verify(apiKeyService).getRoleForApiKey(eq(authentication), any(ActionListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUsageStats() {
|
||||||
|
final FileRolesStore fileRolesStore = mock(FileRolesStore.class);
|
||||||
|
final Map<String, Object> fileRolesStoreUsageStats = new HashMap<>();
|
||||||
|
fileRolesStoreUsageStats.put("size", "1");
|
||||||
|
fileRolesStoreUsageStats.put("fls", Boolean.FALSE);
|
||||||
|
fileRolesStoreUsageStats.put("dls", Boolean.TRUE);
|
||||||
|
when(fileRolesStore.usageStats()).thenReturn(fileRolesStoreUsageStats);
|
||||||
|
|
||||||
|
final NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
|
||||||
|
final Map<String, Object> nativeRolesStoreUsageStats = Collections.emptyMap();
|
||||||
|
doAnswer((invocationOnMock) -> {
|
||||||
|
ActionListener<Map<String, Object>> usageStats = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
|
||||||
|
usageStats.onResponse(nativeRolesStoreUsageStats);
|
||||||
|
return Void.TYPE;
|
||||||
|
}).when(nativeRolesStore).usageStats(any(ActionListener.class));
|
||||||
|
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
|
||||||
|
|
||||||
|
final DocumentSubsetBitsetCache documentSubsetBitsetCache = new DocumentSubsetBitsetCache(Settings.EMPTY);
|
||||||
|
|
||||||
|
final CompositeRolesStore compositeRolesStore =
|
||||||
|
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
|
||||||
|
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
|
||||||
|
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> {
|
||||||
|
});
|
||||||
|
|
||||||
|
PlainActionFuture<Map<String, Object>> usageStatsListener = new PlainActionFuture<>();
|
||||||
|
compositeRolesStore.usageStats(usageStatsListener);
|
||||||
|
Map<String, Object> usageStats = usageStatsListener.actionGet();
|
||||||
|
assertThat(usageStats.get("file"), is(fileRolesStoreUsageStats));
|
||||||
|
assertThat(usageStats.get("native"), is(nativeRolesStoreUsageStats));
|
||||||
|
assertThat(usageStats.get("dls"), is(Collections.singletonMap("bit_set_cache", documentSubsetBitsetCache.usageStats())));
|
||||||
|
}
|
||||||
|
|
||||||
private static class InMemoryRolesProvider implements BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>> {
|
private static class InMemoryRolesProvider implements BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>> {
|
||||||
private final Function<Set<String>, RoleRetrievalResult> roleDescriptorsFunc;
|
private final Function<Set<String>, RoleRetrievalResult> roleDescriptorsFunc;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue