34
34
import org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingAction ;
35
35
import org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingRequest ;
36
36
import org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingRequestBuilder ;
37
- import org .elasticsearch .xpack .core .security .action .rolemapping .PutRoleMappingResponse ;
38
37
import org .elasticsearch .xpack .core .security .authc .RealmConfig ;
39
38
import org .elasticsearch .xpack .core .security .authc .support .UserRoleMapper ;
40
39
import org .elasticsearch .xpack .core .security .authc .support .mapper .ExpressionRoleMapping ;
59
58
import static org .elasticsearch .indices .recovery .RecoverySettings .INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING ;
60
59
import static org .elasticsearch .xcontent .XContentType .JSON ;
61
60
import 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 ;
63
61
import static org .hamcrest .Matchers .allOf ;
62
+ import static org .hamcrest .Matchers .contains ;
64
63
import static org .hamcrest .Matchers .containsInAnyOrder ;
65
64
import static org .hamcrest .Matchers .containsString ;
66
65
import static org .hamcrest .Matchers .empty ;
66
+ import static org .hamcrest .Matchers .emptyArray ;
67
67
import static org .hamcrest .Matchers .equalTo ;
68
68
import static org .hamcrest .Matchers .hasSize ;
69
69
import static org .hamcrest .Matchers .notNullValue ;
@@ -270,28 +270,21 @@ private void assertRoleMappingsSaveOK(CountDownLatch savedClusterState, AtomicLo
270
270
assertThat (resolveRolesFuture .get (), containsInAnyOrder ("kibana_user" , "fleet_user" ));
271
271
}
272
272
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 ());
292
285
}
293
286
294
- public void testClusterStateRoleMappingsAddedThenDeleted () throws Exception {
287
+ public void testRoleMappingsApplied () throws Exception {
295
288
ensureGreen ();
296
289
297
290
var savedClusterState = setupClusterStateListener (internalCluster ().getMasterName (), "everyone_kibana" );
@@ -300,12 +293,6 @@ public void testClusterStateRoleMappingsAddedThenDeleted() throws Exception {
300
293
assertRoleMappingsSaveOK (savedClusterState .v1 (), savedClusterState .v2 ());
301
294
logger .info ("---> cleanup cluster settings..." );
302
295
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
-
309
296
savedClusterState = setupClusterStateListenerForCleanup (internalCluster ().getMasterName ());
310
297
311
298
writeJSONFile (internalCluster ().getMasterName (), emptyJSON , logger , versionCounter );
@@ -320,95 +307,48 @@ public void testClusterStateRoleMappingsAddedThenDeleted() throws Exception {
320
307
clusterStateResponse .getState ().metadata ().persistentSettings ().get (INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING .getKey ())
321
308
);
322
309
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
324
311
{
325
312
var request = new GetRoleMappingsRequest ();
326
313
request .setNames ("everyone_kibana" , "everyone_fleet" );
327
314
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
+ );
329
320
}
330
321
331
- // no role mappings means no roles are resolved
322
+ // and roles are resolved based on the native role mappings
332
323
for (UserRoleMapper userRoleMapper : internalCluster ().getInstances (UserRoleMapper .class )) {
333
324
PlainActionFuture <Set <String >> resolveRolesFuture = new PlainActionFuture <>();
334
325
userRoleMapper .resolveRoles (
335
326
new UserRoleMapper .UserData ("anyUsername" , null , List .of (), Map .of (), mock (RealmConfig .class )),
336
327
resolveRolesFuture
337
328
);
338
- assertThat (resolveRolesFuture .get (), empty ( ));
329
+ assertThat (resolveRolesFuture .get (), contains ( "kibana_user_native" ));
339
330
}
340
- }
341
331
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 ());
348
341
}
349
342
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 ());
374
351
}
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
- );
412
352
}
413
353
414
354
public static Tuple <CountDownLatch , AtomicLong > setupClusterStateListenerForError (
@@ -493,8 +433,11 @@ public void testRoleMappingApplyWithSecurityIndexClosed() throws Exception {
493
433
boolean awaitSuccessful = savedClusterState .v1 ().await (20 , TimeUnit .SECONDS );
494
434
assertTrue (awaitSuccessful );
495
435
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 ());
498
441
499
442
// cluster state settings are also applied
500
443
var clusterStateResponse = clusterAdmin ().state (new ClusterStateRequest ().waitForMetadataVersion (savedClusterState .v2 ().get ()))
@@ -532,12 +475,6 @@ public void testRoleMappingApplyWithSecurityIndexClosed() throws Exception {
532
475
}
533
476
}
534
477
535
- private DeleteRoleMappingRequest deleteRequest (String name ) {
536
- var request = new DeleteRoleMappingRequest ();
537
- request .setName (name );
538
- return request ;
539
- }
540
-
541
478
private PutRoleMappingRequest sampleRestRequest (String name ) throws Exception {
542
479
var json = """
543
480
{
@@ -556,17 +493,4 @@ private PutRoleMappingRequest sampleRestRequest(String name) throws Exception {
556
493
return new PutRoleMappingRequestBuilder (null ).source (name , parser ).request ();
557
494
}
558
495
}
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
- }
572
496
}
0 commit comments