3131import org .elasticsearch .cluster .metadata .IndexMetadata ;
3232import org .elasticsearch .cluster .metadata .MappingMetadata ;
3333import org .elasticsearch .cluster .metadata .Metadata ;
34+ import org .elasticsearch .cluster .metadata .ReservedStateMetadata ;
3435import org .elasticsearch .cluster .routing .IndexRoutingTable ;
3536import org .elasticsearch .cluster .service .ClusterService ;
3637import org .elasticsearch .core .TimeValue ;
4647import org .elasticsearch .rest .RestStatus ;
4748import org .elasticsearch .threadpool .Scheduler ;
4849import org .elasticsearch .xcontent .XContentType ;
50+ import org .elasticsearch .xpack .core .security .authz .RoleMappingMetadata ;
4951import org .elasticsearch .xpack .security .SecurityFeatures ;
52+ import org .elasticsearch .xpack .security .action .rolemapping .ReservedRoleMappingAction ;
5053
5154import java .time .Instant ;
55+ import java .util .Arrays ;
5256import java .util .List ;
5357import java .util .Map ;
5458import java .util .Objects ;
7478public class SecurityIndexManager implements ClusterStateListener {
7579
7680 public static final String SECURITY_VERSION_STRING = "security-version" ;
77-
81+ private static final String FILE_SETTINGS_METADATA_NAMESPACE = "file_settings" ;
82+ private static final String HANDLER_ROLE_MAPPINGS_NAME = "role_mappings" ;
7883 private static final Logger logger = LogManager .getLogger (SecurityIndexManager .class );
7984
8085 /**
@@ -267,6 +272,11 @@ private static boolean isCreatedOnLatestVersion(IndexMetadata indexMetadata) {
267272 return indexVersionCreated != null && indexVersionCreated .onOrAfter (IndexVersion .current ());
268273 }
269274
275+ private static Set <String > getFileSettingsMetadataHandlerRoleMappingKeys (ClusterState clusterState ) {
276+ ReservedStateMetadata fileSettingsMetadata = clusterState .metadata ().reservedStateMetadata ().get (FILE_SETTINGS_METADATA_NAMESPACE );
277+ return fileSettingsMetadata .handlers ().get (HANDLER_ROLE_MAPPINGS_NAME ).keys ();
278+ }
279+
270280 @ Override
271281 public void clusterChanged (ClusterChangedEvent event ) {
272282 if (event .state ().blocks ().hasGlobalBlock (GatewayService .STATE_NOT_RECOVERED_BLOCK )) {
@@ -284,6 +294,10 @@ public void clusterChanged(ClusterChangedEvent event) {
284294 Tuple <Boolean , Boolean > available = checkIndexAvailable (event .state ());
285295 final boolean indexAvailableForWrite = available .v1 ();
286296 final boolean indexAvailableForSearch = available .v2 ();
297+ final Set <String > reservedStateRoleMappingNames = getFileSettingsMetadataHandlerRoleMappingKeys (event .state ());
298+ final boolean reservedRoleMappingsSynced = reservedStateRoleMappingNames .size () == RoleMappingMetadata .getFromClusterState (
299+ event .state ()
300+ ).getRoleMappings ().size ();
287301 final boolean mappingIsUpToDate = indexMetadata == null || checkIndexMappingUpToDate (event .state ());
288302 final int migrationsVersion = getMigrationVersionFromIndexMetadata (indexMetadata );
289303 final SystemIndexDescriptor .MappingsVersion minClusterMappingVersion = getMinSecurityIndexMappingVersion (event .state ());
@@ -314,6 +328,7 @@ public void clusterChanged(ClusterChangedEvent event) {
314328 indexAvailableForWrite ,
315329 mappingIsUpToDate ,
316330 createdOnLatestVersion ,
331+ reservedRoleMappingsSynced ,
317332 migrationsVersion ,
318333 minClusterMappingVersion ,
319334 indexMappingVersion ,
@@ -323,7 +338,8 @@ public void clusterChanged(ClusterChangedEvent event) {
323338 indexUUID ,
324339 allSecurityFeatures .stream ()
325340 .filter (feature -> featureService .clusterHasFeature (event .state (), feature ))
326- .collect (Collectors .toSet ())
341+ .collect (Collectors .toSet ()),
342+ reservedStateRoleMappingNames
327343 );
328344 this .state = newState ;
329345
@@ -334,6 +350,10 @@ public void clusterChanged(ClusterChangedEvent event) {
334350 }
335351 }
336352
353+ public Set <String > getReservedStateRoleMappingNames () {
354+ return state .reservedStateRoleMappingNames ;
355+ }
356+
337357 public static int getMigrationVersionFromIndexMetadata (IndexMetadata indexMetadata ) {
338358 Map <String , String > customMetadata = indexMetadata == null ? null : indexMetadata .getCustomData (MIGRATION_VERSION_CUSTOM_KEY );
339359 if (customMetadata == null ) {
@@ -438,7 +458,8 @@ private Tuple<Boolean, Boolean> checkIndexAvailable(ClusterState state) {
438458
439459 public boolean isEligibleSecurityMigration (SecurityMigrations .SecurityMigration securityMigration ) {
440460 return state .securityFeatures .containsAll (securityMigration .nodeFeaturesRequired ())
441- && state .indexMappingVersion >= securityMigration .minMappingVersion ();
461+ && state .indexMappingVersion >= securityMigration .minMappingVersion ()
462+ && securityMigration .checkPreConditions (state );
442463 }
443464
444465 public boolean isReadyForSecurityMigration (SecurityMigrations .SecurityMigration securityMigration ) {
@@ -671,13 +692,15 @@ public static class State {
671692 false ,
672693 false ,
673694 false ,
695+ false ,
674696 null ,
675697 null ,
676698 null ,
677699 null ,
678700 null ,
679701 null ,
680702 null ,
703+ Set .of (),
681704 Set .of ()
682705 );
683706 public final Instant creationTime ;
@@ -686,6 +709,7 @@ public static class State {
686709 public final boolean indexAvailableForWrite ;
687710 public final boolean mappingUpToDate ;
688711 public final boolean createdOnLatestVersion ;
712+ public final boolean reservedRoleMappingsSynced ;
689713 public final Integer migrationsVersion ;
690714 // Min mapping version supported by the descriptors in the cluster
691715 public final SystemIndexDescriptor .MappingsVersion minClusterMappingVersion ;
@@ -696,6 +720,7 @@ public static class State {
696720 public final IndexMetadata .State indexState ;
697721 public final String indexUUID ;
698722 public final Set <NodeFeature > securityFeatures ;
723+ public final Set <String > reservedStateRoleMappingNames ;
699724
700725 public State (
701726 Instant creationTime ,
@@ -704,14 +729,16 @@ public State(
704729 boolean indexAvailableForWrite ,
705730 boolean mappingUpToDate ,
706731 boolean createdOnLatestVersion ,
732+ boolean reservedRoleMappingsSynced ,
707733 Integer migrationsVersion ,
708734 SystemIndexDescriptor .MappingsVersion minClusterMappingVersion ,
709735 Integer indexMappingVersion ,
710736 String concreteIndexName ,
711737 ClusterHealthStatus indexHealth ,
712738 IndexMetadata .State indexState ,
713739 String indexUUID ,
714- Set <NodeFeature > securityFeatures
740+ Set <NodeFeature > securityFeatures ,
741+ Set <String > reservedStateRoleMappingNames
715742 ) {
716743 this .creationTime = creationTime ;
717744 this .isIndexUpToDate = isIndexUpToDate ;
@@ -720,13 +747,15 @@ public State(
720747 this .mappingUpToDate = mappingUpToDate ;
721748 this .migrationsVersion = migrationsVersion ;
722749 this .createdOnLatestVersion = createdOnLatestVersion ;
750+ this .reservedRoleMappingsSynced = reservedRoleMappingsSynced ;
723751 this .minClusterMappingVersion = minClusterMappingVersion ;
724752 this .indexMappingVersion = indexMappingVersion ;
725753 this .concreteIndexName = concreteIndexName ;
726754 this .indexHealth = indexHealth ;
727755 this .indexState = indexState ;
728756 this .indexUUID = indexUUID ;
729757 this .securityFeatures = securityFeatures ;
758+ this .reservedStateRoleMappingNames = reservedStateRoleMappingNames ;
730759 }
731760
732761 @ Override
@@ -740,13 +769,15 @@ public boolean equals(Object o) {
740769 && indexAvailableForWrite == state .indexAvailableForWrite
741770 && mappingUpToDate == state .mappingUpToDate
742771 && createdOnLatestVersion == state .createdOnLatestVersion
772+ && reservedRoleMappingsSynced == state .reservedRoleMappingsSynced
743773 && Objects .equals (indexMappingVersion , state .indexMappingVersion )
744774 && Objects .equals (migrationsVersion , state .migrationsVersion )
745775 && Objects .equals (minClusterMappingVersion , state .minClusterMappingVersion )
746776 && Objects .equals (concreteIndexName , state .concreteIndexName )
747777 && indexHealth == state .indexHealth
748778 && indexState == state .indexState
749- && Objects .equals (securityFeatures , state .securityFeatures );
779+ && Objects .equals (securityFeatures , state .securityFeatures )
780+ && Objects .equals (reservedStateRoleMappingNames , state .reservedStateRoleMappingNames );
750781 }
751782
752783 public boolean indexExists () {
@@ -762,12 +793,14 @@ public int hashCode() {
762793 indexAvailableForWrite ,
763794 mappingUpToDate ,
764795 createdOnLatestVersion ,
796+ reservedRoleMappingsSynced ,
765797 migrationsVersion ,
766798 minClusterMappingVersion ,
767799 indexMappingVersion ,
768800 concreteIndexName ,
769801 indexHealth ,
770- securityFeatures
802+ securityFeatures ,
803+ reservedStateRoleMappingNames
771804 );
772805 }
773806
@@ -786,6 +819,8 @@ public String toString() {
786819 + mappingUpToDate
787820 + ", createdOnLatestVersion="
788821 + createdOnLatestVersion
822+ + ", reservedRoleMappingsSynced="
823+ + reservedRoleMappingsSynced
789824 + ", migrationsVersion="
790825 + migrationsVersion
791826 + ", minClusterMappingVersion="
@@ -804,6 +839,9 @@ public String toString() {
804839 + '\''
805840 + ", securityFeatures="
806841 + securityFeatures
842+ + ", reservedStateRoleMappingNames=["
843+ + Arrays .toString (reservedStateRoleMappingNames .toArray (String []::new ))
844+ + "]"
807845 + '}' ;
808846 }
809847 }
0 commit comments