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 ().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 (new ClusterStateRequest ().waitForMetadataVersion (savedClusterState .v2 ().get ()))
@@ -532,12 +475,6 @@ public void testRoleMappingApplyWithSecurityIndexClosed() throws Exception {
532475 }
533476 }
534477
535- private DeleteRoleMappingRequest deleteRequest (String name ) {
536- var request = new DeleteRoleMappingRequest ();
537- request .setName (name );
538- return request ;
539- }
540-
541478 private PutRoleMappingRequest sampleRestRequest (String name ) throws Exception {
542479 var json = """
543480 {
@@ -556,17 +493,4 @@ private PutRoleMappingRequest sampleRestRequest(String name) throws Exception {
556493 return new PutRoleMappingRequestBuilder (null ).source (name , parser ).request ();
557494 }
558495 }
559-
560- private static void assertGetResponseHasMappings (boolean readOnly , String ... mappings ) throws InterruptedException , ExecutionException {
561- var request = new GetRoleMappingsRequest ();
562- request .setNames (mappings );
563- var response = client ().execute (GetRoleMappingsAction .INSTANCE , request ).get ();
564- assertTrue (response .hasMappings ());
565- assertThat (
566- Arrays .stream (response .mappings ()).map (ExpressionRoleMapping ::getName ).toList (),
567- containsInAnyOrder (
568- Arrays .stream (mappings ).map (mapping -> mapping + (readOnly ? RESERVED_ROLE_MAPPING_SUFFIX : "" )).toArray (String []::new )
569- )
570- );
571- }
572496}
0 commit comments