|  | @@ -15,6 +15,7 @@ import org.elasticsearch.action.support.PlainActionFuture;
 | 
	
		
			
				|  |  |  import org.elasticsearch.cluster.health.ClusterHealthStatus;
 | 
	
		
			
				|  |  |  import org.elasticsearch.cluster.metadata.IndexMetaData;
 | 
	
		
			
				|  |  |  import org.elasticsearch.cluster.metadata.MetaData;
 | 
	
		
			
				|  |  | +import org.elasticsearch.common.Nullable;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.bytes.BytesReference;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.io.stream.StreamOutput;
 | 
	
		
			
				|  |  |  import org.elasticsearch.common.settings.Settings;
 | 
	
	
		
			
				|  | @@ -53,6 +54,7 @@ import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
 | 
	
		
			
				|  |  | +import org.elasticsearch.xpack.core.security.support.MetadataUtils;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.user.AnonymousUser;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.user.SystemUser;
 | 
	
		
			
				|  |  |  import org.elasticsearch.xpack.core.security.user.User;
 | 
	
	
		
			
				|  | @@ -64,10 +66,14 @@ import org.elasticsearch.xpack.security.support.SecurityIndexManager;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.io.IOException;
 | 
	
		
			
				|  |  |  import java.time.Instant;
 | 
	
		
			
				|  |  | +import java.util.ArrayList;
 | 
	
		
			
				|  |  |  import java.util.Arrays;
 | 
	
		
			
				|  |  |  import java.util.Collection;
 | 
	
		
			
				|  |  |  import java.util.Collections;
 | 
	
		
			
				|  |  | +import java.util.HashMap;
 | 
	
		
			
				|  |  |  import java.util.HashSet;
 | 
	
		
			
				|  |  | +import java.util.LinkedHashSet;
 | 
	
		
			
				|  |  | +import java.util.List;
 | 
	
		
			
				|  |  |  import java.util.Map;
 | 
	
		
			
				|  |  |  import java.util.Set;
 | 
	
		
			
				|  |  |  import java.util.concurrent.ExecutionException;
 | 
	
	
		
			
				|  | @@ -84,6 +90,7 @@ import static org.hamcrest.Matchers.anyOf;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.containsInAnyOrder;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.equalTo;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.hasItem;
 | 
	
		
			
				|  |  | +import static org.hamcrest.Matchers.hasSize;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.is;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.nullValue;
 | 
	
		
			
				|  |  |  import static org.mockito.Matchers.any;
 | 
	
	
		
			
				|  | @@ -143,21 +150,14 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          }, null);
 | 
	
		
			
				|  |  |          FileRolesStore fileRolesStore = mock(FileRolesStore.class);
 | 
	
		
			
				|  |  |          doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | -        ReservedRolesStore reservedRolesStore = mock(ReservedRolesStore.class);
 | 
	
		
			
				|  |  | -        doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | -        NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
 | 
	
		
			
				|  |  | -        doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("fls"))).thenReturn(Collections.singleton(flsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("dls"))).thenReturn(Collections.singleton(dlsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
 | 
	
		
			
				|  |  |          final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
 | 
	
		
			
				|  |  | -        final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | -        CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
 | 
	
		
			
				|  |  | -                reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
 | 
	
		
			
				|  |  | -                new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
 | 
	
		
			
				|  |  | -                rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  | +        CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(Settings.EMPTY, fileRolesStore, null,
 | 
	
		
			
				|  |  | +            null, null, licenseState, null, null, rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
 | 
	
		
			
				|  |  |          compositeRolesStore.roles(Collections.singleton("fls"), roleFuture);
 | 
	
	
		
			
				|  | @@ -220,20 +220,13 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          }, null);
 | 
	
		
			
				|  |  |          FileRolesStore fileRolesStore = mock(FileRolesStore.class);
 | 
	
		
			
				|  |  |          doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | -        ReservedRolesStore reservedRolesStore = mock(ReservedRolesStore.class);
 | 
	
		
			
				|  |  | -        doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | -        NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
 | 
	
		
			
				|  |  | -        doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("fls"))).thenReturn(Collections.singleton(flsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("dls"))).thenReturn(Collections.singleton(dlsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("fls_dls"))).thenReturn(Collections.singleton(flsDlsRole));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(Collections.singleton("no_fls_dls"))).thenReturn(Collections.singleton(noFlsDlsRole));
 | 
	
		
			
				|  |  |          final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
 | 
	
		
			
				|  |  | -        final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | -        CompositeRolesStore compositeRolesStore = new CompositeRolesStore(Settings.EMPTY, fileRolesStore, nativeRolesStore,
 | 
	
		
			
				|  |  | -                reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(),
 | 
	
		
			
				|  |  | -                new ThreadContext(Settings.EMPTY), licenseState, cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
 | 
	
		
			
				|  |  | -                rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  | +        CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(Settings.EMPTY, fileRolesStore, null,
 | 
	
		
			
				|  |  | +            null, null, licenseState, null, null, rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PlainActionFuture<Role> roleFuture = new PlainActionFuture<>();
 | 
	
		
			
				|  |  |          compositeRolesStore.roles(Collections.singleton("fls"), roleFuture);
 | 
	
	
		
			
				|  | @@ -266,6 +259,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          final NativeRolesStore nativeRolesStore = mock(NativeRolesStore.class);
 | 
	
		
			
				|  |  |          doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |          when(fileRolesStore.roleDescriptors(anySetOf(String.class))).thenReturn(Collections.emptySet());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          doAnswer((invocationOnMock) -> {
 | 
	
		
			
				|  |  |              ActionListener<RoleRetrievalResult> callback = (ActionListener<RoleRetrievalResult>) invocationOnMock.getArguments()[1];
 | 
	
		
			
				|  |  |              callback.onResponse(RoleRetrievalResult.success(Collections.emptySet()));
 | 
	
	
		
			
				|  | @@ -281,12 +275,9 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          }).when(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          final AtomicReference<Collection<RoleDescriptor>> effectiveRoleDescriptors = new AtomicReference<Collection<RoleDescriptor>>();
 | 
	
		
			
				|  |  | -        final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | -        final CompositeRolesStore compositeRolesStore =
 | 
	
		
			
				|  |  | -                new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
 | 
	
		
			
				|  |  | -                        nativePrivilegeStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
 | 
	
		
			
				|  |  | -                        new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class),
 | 
	
		
			
				|  |  | -                        documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  | +        final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS,
 | 
	
		
			
				|  |  | +            fileRolesStore, nativeRolesStore, reservedRolesStore, nativePrivilegeStore, null, null, null,
 | 
	
		
			
				|  |  | +            rds -> effectiveRoleDescriptors.set(rds));
 | 
	
		
			
				|  |  |          verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          final String roleName = randomAlphaOfLengthBetween(1, 10);
 | 
	
	
		
			
				|  | @@ -322,7 +313,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          if (getSuperuserRole && numberOfTimesToCall > 0) {
 | 
	
		
			
				|  |  |              // the superuser role was requested so we get the role descriptors again
 | 
	
		
			
				|  |  |              verify(reservedRolesStore, times(2)).accept(anySetOf(String.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | -            verify(nativePrivilegeStore).getPrivileges(isA(Set.class),isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +            verify(nativePrivilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          verifyNoMoreInteractions(fileRolesStore, reservedRolesStore, nativeRolesStore, nativePrivilegeStore);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -422,9 +413,6 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          verifyNoMoreInteractions(fileRolesStore, reservedRolesStore, nativeRolesStore);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private DocumentSubsetBitsetCache buildBitsetCache() {
 | 
	
		
			
				|  |  | -        return new DocumentSubsetBitsetCache(Settings.EMPTY, mock(ThreadPool.class));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void testCustomRolesProviders() {
 | 
	
		
			
				|  |  |          final FileRolesStore fileRolesStore = mock(FileRolesStore.class);
 | 
	
	
		
			
				|  | @@ -899,12 +887,9 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          }).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |          final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | -        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 -> {});
 | 
	
		
			
				|  |  | +        final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore,
 | 
	
		
			
				|  |  | +            nativeRolesStore, reservedRolesStore, mock(NativePrivilegeStore.class), null, mock(ApiKeyService.class),
 | 
	
		
			
				|  |  | +            null, null);
 | 
	
		
			
				|  |  |          verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
 | 
	
	
		
			
				|  | @@ -940,11 +925,8 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          }).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  |          final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | -        final CompositeRolesStore compositeRolesStore =
 | 
	
		
			
				|  |  | -            new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore,
 | 
	
		
			
				|  |  | -                mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
 | 
	
		
			
				|  |  | -                new XPackLicenseState(settings), cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> {});
 | 
	
		
			
				|  |  | +        final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
 | 
	
		
			
				|  |  | +            reservedRolesStore, mock(NativePrivilegeStore.class), null, mock(ApiKeyService.class), null, null);
 | 
	
		
			
				|  |  |          verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
 | 
	
	
		
			
				|  | @@ -1124,11 +1106,9 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        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 -> {
 | 
	
		
			
				|  |  | -            });
 | 
	
		
			
				|  |  | +        final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(
 | 
	
		
			
				|  |  | +            SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore, null, null, mock(ApiKeyService.class),
 | 
	
		
			
				|  |  | +            documentSubsetBitsetCache, null);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          PlainActionFuture<Map<String, Object>> usageStatsListener = new PlainActionFuture<>();
 | 
	
		
			
				|  |  |          compositeRolesStore.usageStats(usageStatsListener);
 | 
	
	
		
			
				|  | @@ -1138,6 +1118,111 @@ public class CompositeRolesStoreTests extends ESTestCase {
 | 
	
		
			
				|  |  |          assertThat(usageStats.get("dls"), is(Map.of("bit_set_cache", documentSubsetBitsetCache.usageStats())));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    public void testLoggingOfDeprecatedRoles() {
 | 
	
		
			
				|  |  | +        List<RoleDescriptor> descriptors = new ArrayList<>();
 | 
	
		
			
				|  |  | +        Function<Map<String, Object>, RoleDescriptor> newRole = metadata -> new RoleDescriptor(
 | 
	
		
			
				|  |  | +            randomAlphaOfLengthBetween(4, 9), generateRandomStringArray(5, 5, false, true),
 | 
	
		
			
				|  |  | +            null, null, null, null, metadata, null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        RoleDescriptor deprecated1 = newRole.apply(MetadataUtils.getDeprecatedReservedMetadata("some reason"));
 | 
	
		
			
				|  |  | +        RoleDescriptor deprecated2 = newRole.apply(MetadataUtils.getDeprecatedReservedMetadata("a different reason"));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Can't use getDeprecatedReservedMetadata because `Map.of` doesn't accept null values,
 | 
	
		
			
				|  |  | +        // so we clone metadata with a real value and then remove that key
 | 
	
		
			
				|  |  | +        final Map<String, Object> nullReasonMetadata = new HashMap<>(deprecated2.getMetadata());
 | 
	
		
			
				|  |  | +        nullReasonMetadata.remove(MetadataUtils.DEPRECATED_REASON_METADATA_KEY);
 | 
	
		
			
				|  |  | +        assertThat(nullReasonMetadata.keySet(), hasSize(deprecated2.getMetadata().size() -1));
 | 
	
		
			
				|  |  | +        RoleDescriptor deprecated3 = newRole.apply(nullReasonMetadata);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        descriptors.add(deprecated1);
 | 
	
		
			
				|  |  | +        descriptors.add(deprecated2);
 | 
	
		
			
				|  |  | +        descriptors.add(deprecated3);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (int i = randomIntBetween(2, 10); i > 0; i--) {
 | 
	
		
			
				|  |  | +            // the non-deprecated metadata is randomly one of:
 | 
	
		
			
				|  |  | +            // {}, {_deprecated:null}, {_deprecated:false},
 | 
	
		
			
				|  |  | +            // {_reserved:true}, {_reserved:true,_deprecated:null}, {_reserved:true,_deprecated:false}
 | 
	
		
			
				|  |  | +            Map<String, Object> metadata = randomBoolean() ? Map.of() : MetadataUtils.DEFAULT_RESERVED_METADATA;
 | 
	
		
			
				|  |  | +            if (randomBoolean()) {
 | 
	
		
			
				|  |  | +                metadata = new HashMap<>(metadata);
 | 
	
		
			
				|  |  | +                metadata.put(MetadataUtils.DEPRECATED_METADATA_KEY, randomBoolean() ? null : false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            descriptors.add(newRole.apply(metadata));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        Collections.shuffle(descriptors, random());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        final CompositeRolesStore compositeRolesStore =
 | 
	
		
			
				|  |  | +            buildCompositeRolesStore(SECURITY_ENABLED_SETTINGS, null, null, null, null, null, null, null, null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Use a LHS so that the random-shufle-order of the list is preserved
 | 
	
		
			
				|  |  | +        compositeRolesStore.logDeprecatedRoles(new LinkedHashSet<>(descriptors));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        assertWarnings(
 | 
	
		
			
				|  |  | +            "The role [" + deprecated1.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." +
 | 
	
		
			
				|  |  | +                " some reason",
 | 
	
		
			
				|  |  | +            "The role [" + deprecated2.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." +
 | 
	
		
			
				|  |  | +                " a different reason",
 | 
	
		
			
				|  |  | +            "The role [" + deprecated3.getName() + "] is deprecated and will be removed in a future version of Elasticsearch." +
 | 
	
		
			
				|  |  | +                " Please check the documentation"
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private CompositeRolesStore buildCompositeRolesStore(Settings settings,
 | 
	
		
			
				|  |  | +                                                         @Nullable FileRolesStore fileRolesStore,
 | 
	
		
			
				|  |  | +                                                         @Nullable NativeRolesStore nativeRolesStore,
 | 
	
		
			
				|  |  | +                                                         @Nullable ReservedRolesStore reservedRolesStore,
 | 
	
		
			
				|  |  | +                                                         @Nullable NativePrivilegeStore privilegeStore,
 | 
	
		
			
				|  |  | +                                                         @Nullable XPackLicenseState licenseState,
 | 
	
		
			
				|  |  | +                                                         @Nullable ApiKeyService apiKeyService,
 | 
	
		
			
				|  |  | +                                                         @Nullable DocumentSubsetBitsetCache documentSubsetBitsetCache,
 | 
	
		
			
				|  |  | +                                                         @Nullable Consumer<Collection<RoleDescriptor>> roleConsumer) {
 | 
	
		
			
				|  |  | +        if (fileRolesStore == null) {
 | 
	
		
			
				|  |  | +            fileRolesStore = mock(FileRolesStore.class);
 | 
	
		
			
				|  |  | +            doCallRealMethod().when(fileRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +            when(fileRolesStore.roleDescriptors(anySetOf(String.class))).thenReturn(Collections.emptySet());
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (nativeRolesStore == null) {
 | 
	
		
			
				|  |  | +            nativeRolesStore = mock(NativeRolesStore.class);
 | 
	
		
			
				|  |  | +            doCallRealMethod().when(nativeRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +            doAnswer((invocationOnMock) -> {
 | 
	
		
			
				|  |  | +                ActionListener<RoleRetrievalResult> callback = (ActionListener<RoleRetrievalResult>) invocationOnMock.getArguments()[1];
 | 
	
		
			
				|  |  | +                callback.onResponse(RoleRetrievalResult.failure(new RuntimeException("intentionally failed!")));
 | 
	
		
			
				|  |  | +                return null;
 | 
	
		
			
				|  |  | +            }).when(nativeRolesStore).getRoleDescriptors(isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (reservedRolesStore == null) {
 | 
	
		
			
				|  |  | +            reservedRolesStore = mock(ReservedRolesStore.class);
 | 
	
		
			
				|  |  | +            doCallRealMethod().when(reservedRolesStore).accept(any(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (privilegeStore == null) {
 | 
	
		
			
				|  |  | +            privilegeStore = mock(NativePrivilegeStore.class);
 | 
	
		
			
				|  |  | +            doAnswer((invocationOnMock) -> {
 | 
	
		
			
				|  |  | +                ActionListener<Collection<ApplicationPrivilegeDescriptor>> callback = null;
 | 
	
		
			
				|  |  | +                callback = (ActionListener<Collection<ApplicationPrivilegeDescriptor>>) invocationOnMock.getArguments()[2];
 | 
	
		
			
				|  |  | +                callback.onResponse(Collections.emptyList());
 | 
	
		
			
				|  |  | +                return null;
 | 
	
		
			
				|  |  | +            }).when(privilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (licenseState == null) {
 | 
	
		
			
				|  |  | +            licenseState = new XPackLicenseState(settings);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (apiKeyService == null) {
 | 
	
		
			
				|  |  | +            apiKeyService = mock(ApiKeyService.class);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (documentSubsetBitsetCache == null) {
 | 
	
		
			
				|  |  | +            documentSubsetBitsetCache = buildBitsetCache();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (roleConsumer == null) {
 | 
	
		
			
				|  |  | +            roleConsumer = rds -> { };
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore, privilegeStore,
 | 
	
		
			
				|  |  | +            Collections.emptyList(), new ThreadContext(settings), licenseState, cache, apiKeyService, documentSubsetBitsetCache,
 | 
	
		
			
				|  |  | +            roleConsumer);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private DocumentSubsetBitsetCache buildBitsetCache() {
 | 
	
		
			
				|  |  | +        return new DocumentSubsetBitsetCache(Settings.EMPTY, mock(ThreadPool.class));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      private static class InMemoryRolesProvider implements BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>> {
 | 
	
		
			
				|  |  |          private final Function<Set<String>, RoleRetrievalResult> roleDescriptorsFunc;
 | 
	
		
			
				|  |  |  
 |