3434import  org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingAction ;
3535import  org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingRequest ;
3636import  org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingRequestBuilder ;
37- import  org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingResponse ;
3837import  org .elasticsearch .xpack .core .security .authc .RealmConfig ;
3938import  org .elasticsearch .xpack .core .security .authc .support .UserRoleMapper ;
4039import  org .elasticsearch .xpack .core .security .authc .support .mapper .ExpressionRoleMapping ;
5958import  static  org .elasticsearch .indices .recovery .RecoverySettings .INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING ;
6059import  static  org .elasticsearch .xcontent .XContentType .JSON ;
6160import  static  org .elasticsearch .xpack .core .security .test .TestRestrictedIndices .INTERNAL_SECURITY_MAIN_INDEX_7 ;
62- import  static  org .elasticsearch .xpack .security .authc .support .mapper .ClusterStateRoleMapper .RESERVED_ROLE_MAPPING_SUFFIX ;
6361import  static  org .hamcrest .Matchers .allOf ;
62+ import  static  org .hamcrest .Matchers .contains ;
6463import  static  org .hamcrest .Matchers .containsInAnyOrder ;
6564import  static  org .hamcrest .Matchers .containsString ;
6665import  static  org .hamcrest .Matchers .empty ;
66+ import  static  org .hamcrest .Matchers .emptyArray ;
6767import  static  org .hamcrest .Matchers .equalTo ;
6868import  static  org .hamcrest .Matchers .hasSize ;
6969import  static  org .hamcrest .Matchers .notNullValue ;
@@ -270,28 +270,21 @@ private void assertRoleMappingsSaveOK(CountDownLatch savedClusterState, AtomicLo
270270            assertThat (resolveRolesFuture .get (), containsInAnyOrder ("kibana_user" , "fleet_user" ));
271271        }
272272
273-         // the role mappings are retrievable by the role mapping action for BWC 
274-         assertGetResponseHasMappings (true , "everyone_kibana" , "everyone_fleet" );
275- 
276-         // role mappings (with the same names) can be stored in the "native" store 
277-         {
278-             PutRoleMappingResponse  response  = client ().execute (PutRoleMappingAction .INSTANCE , sampleRestRequest ("everyone_kibana" ))
279-                 .actionGet ();
280-             assertTrue (response .isCreated ());
281-             response  = client ().execute (PutRoleMappingAction .INSTANCE , sampleRestRequest ("everyone_fleet" )).actionGet ();
282-             assertTrue (response .isCreated ());
283-         }
284-         {
285-             // deleting role mappings that exist in the native store and in cluster-state should result in success 
286-             var  response  = client ().execute (DeleteRoleMappingAction .INSTANCE , deleteRequest ("everyone_kibana" )).actionGet ();
287-             assertTrue (response .isFound ());
288-             response  = client ().execute (DeleteRoleMappingAction .INSTANCE , deleteRequest ("everyone_fleet" )).actionGet ();
289-             assertTrue (response .isFound ());
290-         }
291- 
273+         // the role mappings are not retrievable by the role mapping action (which only accesses "native" i.e. index-based role mappings) 
274+         var  request  = new  GetRoleMappingsRequest ();
275+         request .setNames ("everyone_kibana" , "everyone_fleet" );
276+         var  response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
277+         assertFalse (response .hasMappings ());
278+         assertThat (response .mappings (), emptyArray ());
279+ 
280+         // role mappings (with the same names) can also be stored in the "native" store 
281+         var  putRoleMappingResponse  = client ().execute (PutRoleMappingAction .INSTANCE , sampleRestRequest ("everyone_kibana" )).actionGet ();
282+         assertTrue (putRoleMappingResponse .isCreated ());
283+         putRoleMappingResponse  = client ().execute (PutRoleMappingAction .INSTANCE , sampleRestRequest ("everyone_fleet" )).actionGet ();
284+         assertTrue (putRoleMappingResponse .isCreated ());
292285    }
293286
294-     public  void  testClusterStateRoleMappingsAddedThenDeleted () throws  Exception  {
287+     public  void  testRoleMappingsApplied () throws  Exception  {
295288        ensureGreen ();
296289
297290        var  savedClusterState  = setupClusterStateListener (internalCluster ().getMasterName (), "everyone_kibana" );
@@ -300,12 +293,6 @@ public void testClusterStateRoleMappingsAddedThenDeleted() throws Exception {
300293        assertRoleMappingsSaveOK (savedClusterState .v1 (), savedClusterState .v2 ());
301294        logger .info ("---> cleanup cluster settings..." );
302295
303-         {
304-             // Deleting non-existent native role mappings returns not found even if they exist in config file 
305-             var  response  = client ().execute (DeleteRoleMappingAction .INSTANCE , deleteRequest ("everyone_kibana" )).get ();
306-             assertFalse (response .isFound ());
307-         }
308- 
309296        savedClusterState  = setupClusterStateListenerForCleanup (internalCluster ().getMasterName ());
310297
311298        writeJSONFile (internalCluster ().getMasterName (), emptyJSON , logger , versionCounter );
@@ -320,95 +307,48 @@ public void testClusterStateRoleMappingsAddedThenDeleted() throws Exception {
320307            clusterStateResponse .getState ().metadata ().persistentSettings ().get (INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING .getKey ())
321308        );
322309
323-         // cluster-state  role mapping was removed and is not returned in  the API anymore  
310+         // native  role mappings are not affected by the removal of  the cluster-state based ones  
324311        {
325312            var  request  = new  GetRoleMappingsRequest ();
326313            request .setNames ("everyone_kibana" , "everyone_fleet" );
327314            var  response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
328-             assertFalse (response .hasMappings ());
315+             assertTrue (response .hasMappings ());
316+             assertThat (
317+                 Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
318+                 containsInAnyOrder ("everyone_kibana" , "everyone_fleet" )
319+             );
329320        }
330321
331-         // no role mappings means no roles are resolved  
322+         // and roles are resolved based on the native role mappings  
332323        for  (UserRoleMapper  userRoleMapper  : internalCluster ().getInstances (UserRoleMapper .class )) {
333324            PlainActionFuture <Set <String >> resolveRolesFuture  = new  PlainActionFuture <>();
334325            userRoleMapper .resolveRoles (
335326                new  UserRoleMapper .UserData ("anyUsername" , null , List .of (), Map .of (), mock (RealmConfig .class )),
336327                resolveRolesFuture 
337328            );
338-             assertThat (resolveRolesFuture .get (), empty ( ));
329+             assertThat (resolveRolesFuture .get (), contains ( "kibana_user_native" ));
339330        }
340-     }
341331
342-     public  void  testGetRoleMappings () throws  Exception  {
343-         ensureGreen ();
344- 
345-         final  List <String > nativeMappings  = List .of ("everyone_kibana" , "_everyone_kibana" , "zzz_mapping" , "123_mapping" );
346-         for  (var  mapping  : nativeMappings ) {
347-             client ().execute (PutRoleMappingAction .INSTANCE , sampleRestRequest (mapping )).actionGet ();
332+         {
333+             var  request  = new  DeleteRoleMappingRequest ();
334+             request .setName ("everyone_kibana" );
335+             var  response  = client ().execute (DeleteRoleMappingAction .INSTANCE , request ).get ();
336+             assertTrue (response .isFound ());
337+             request  = new  DeleteRoleMappingRequest ();
338+             request .setName ("everyone_fleet" );
339+             response  = client ().execute (DeleteRoleMappingAction .INSTANCE , request ).get ();
340+             assertTrue (response .isFound ());
348341        }
349342
350-         var  savedClusterState  = setupClusterStateListener (internalCluster ().getMasterName (), "everyone_kibana" );
351-         writeJSONFile (internalCluster ().getMasterName (), testJSON , logger , versionCounter );
352-         boolean  awaitSuccessful  = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
353-         assertTrue (awaitSuccessful );
354- 
355-         var  request  = new  GetRoleMappingsRequest ();
356-         var  response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
357-         assertTrue (response .hasMappings ());
358-         assertThat (
359-             Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
360-             containsInAnyOrder (
361-                 "everyone_kibana" ,
362-                 "everyone_kibana"  + RESERVED_ROLE_MAPPING_SUFFIX ,
363-                 "_everyone_kibana" ,
364-                 "everyone_fleet"  + RESERVED_ROLE_MAPPING_SUFFIX ,
365-                 "zzz_mapping" ,
366-                 "123_mapping" 
367-             )
368-         );
369- 
370-         int  readOnlyCount  = 0 ;
371-         // assert that cluster-state role mappings come last 
372-         for  (ExpressionRoleMapping  mapping  : response .mappings ()) {
373-             readOnlyCount  = mapping .getName ().endsWith (RESERVED_ROLE_MAPPING_SUFFIX ) ? readOnlyCount  + 1  : readOnlyCount ;
343+         // no roles are resolved now, because both native and cluster-state based stores have been cleared 
344+         for  (UserRoleMapper  userRoleMapper  : internalCluster ().getInstances (UserRoleMapper .class )) {
345+             PlainActionFuture <Set <String >> resolveRolesFuture  = new  PlainActionFuture <>();
346+             userRoleMapper .resolveRoles (
347+                 new  UserRoleMapper .UserData ("anyUsername" , null , List .of (), Map .of (), mock (RealmConfig .class )),
348+                 resolveRolesFuture 
349+             );
350+             assertThat (resolveRolesFuture .get (), empty ());
374351        }
375-         // Two sourced from cluster-state 
376-         assertEquals (readOnlyCount , 2 );
377- 
378-         // it's possible to delete overlapping native role mapping 
379-         assertTrue (client ().execute (DeleteRoleMappingAction .INSTANCE , deleteRequest ("everyone_kibana" )).actionGet ().isFound ());
380- 
381-         // Fetch a specific file based role 
382-         request  = new  GetRoleMappingsRequest ();
383-         request .setNames ("everyone_kibana"  + RESERVED_ROLE_MAPPING_SUFFIX );
384-         response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
385-         assertTrue (response .hasMappings ());
386-         assertThat (
387-             Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
388-             containsInAnyOrder ("everyone_kibana"  + RESERVED_ROLE_MAPPING_SUFFIX )
389-         );
390- 
391-         savedClusterState  = setupClusterStateListenerForCleanup (internalCluster ().getMasterName ());
392-         writeJSONFile (internalCluster ().getMasterName (), emptyJSON , logger , versionCounter );
393-         awaitSuccessful  = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
394-         assertTrue (awaitSuccessful );
395- 
396-         final  ClusterStateResponse  clusterStateResponse  = clusterAdmin ().state (
397-             new  ClusterStateRequest (TEST_REQUEST_TIMEOUT ).waitForMetadataVersion (savedClusterState .v2 ().get ())
398-         ).get ();
399- 
400-         assertNull (
401-             clusterStateResponse .getState ().metadata ().persistentSettings ().get (INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING .getKey ())
402-         );
403- 
404-         // Make sure remaining native mappings can still be fetched 
405-         request  = new  GetRoleMappingsRequest ();
406-         response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
407-         assertTrue (response .hasMappings ());
408-         assertThat (
409-             Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
410-             containsInAnyOrder ("_everyone_kibana" , "zzz_mapping" , "123_mapping" )
411-         );
412352    }
413353
414354    public  static  Tuple <CountDownLatch , AtomicLong > setupClusterStateListenerForError (
@@ -493,8 +433,11 @@ public void testRoleMappingApplyWithSecurityIndexClosed() throws Exception {
493433            boolean  awaitSuccessful  = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
494434            assertTrue (awaitSuccessful );
495435
496-             // even if index is closed, cluster-state role mappings are still returned 
497-             assertGetResponseHasMappings (true , "everyone_kibana" , "everyone_fleet" );
436+             // no native role mappings exist 
437+             var  request  = new  GetRoleMappingsRequest ();
438+             request .setNames ("everyone_kibana" , "everyone_fleet" );
439+             var  response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
440+             assertFalse (response .hasMappings ());
498441
499442            // cluster state settings are also applied 
500443            var  clusterStateResponse  = clusterAdmin ().state (
@@ -533,12 +476,6 @@ public void testRoleMappingApplyWithSecurityIndexClosed() throws Exception {
533476        }
534477    }
535478
536-     private  DeleteRoleMappingRequest  deleteRequest (String  name ) {
537-         var  request  = new  DeleteRoleMappingRequest ();
538-         request .setName (name );
539-         return  request ;
540-     }
541- 
542479    private  PutRoleMappingRequest  sampleRestRequest (String  name ) throws  Exception  {
543480        var  json  = """ 
544481            { 
@@ -557,17 +494,4 @@ private PutRoleMappingRequest sampleRestRequest(String name) throws Exception {
557494            return  new  PutRoleMappingRequestBuilder (null ).source (name , parser ).request ();
558495        }
559496    }
560- 
561-     private  static  void  assertGetResponseHasMappings (boolean  readOnly , String ... mappings ) throws  InterruptedException , ExecutionException  {
562-         var  request  = new  GetRoleMappingsRequest ();
563-         request .setNames (mappings );
564-         var  response  = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
565-         assertTrue (response .hasMappings ());
566-         assertThat (
567-             Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
568-             containsInAnyOrder (
569-                 Arrays .stream (mappings ).map (mapping  -> mapping  + (readOnly  ? RESERVED_ROLE_MAPPING_SUFFIX  : "" )).toArray (String []::new )
570-             )
571-         );
572-     }
573497}
0 commit comments