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 .authc .support .mapper .ExpressionRoleMapping ;
51+ import org .elasticsearch .xpack .core .security .authz .RoleMappingMetadata ;
4952import org .elasticsearch .xpack .security .SecurityFeatures ;
5053
5154import java .time .Instant ;
7477public class SecurityIndexManager implements ClusterStateListener {
7578
7679 public static final String SECURITY_VERSION_STRING = "security-version" ;
77-
80+ private static final String FILE_SETTINGS_METADATA_NAMESPACE = "file_settings" ;
81+ private static final String HANDLER_ROLE_MAPPINGS_NAME = "role_mappings" ;
7882 private static final Logger logger = LogManager .getLogger (SecurityIndexManager .class );
7983
8084 /**
@@ -267,6 +271,22 @@ private static boolean isCreatedOnLatestVersion(IndexMetadata indexMetadata) {
267271 return indexVersionCreated != null && indexVersionCreated .onOrAfter (IndexVersion .current ());
268272 }
269273
274+ private static Set <String > getFileSettingsMetadataHandlerRoleMappingKeys (ClusterState clusterState ) {
275+ ReservedStateMetadata fileSettingsMetadata = clusterState .metadata ().reservedStateMetadata ().get (FILE_SETTINGS_METADATA_NAMESPACE );
276+ if (fileSettingsMetadata != null && fileSettingsMetadata .handlers ().containsKey (HANDLER_ROLE_MAPPINGS_NAME )) {
277+ return fileSettingsMetadata .handlers ().get (HANDLER_ROLE_MAPPINGS_NAME ).keys ();
278+ }
279+ return Set .of ();
280+ }
281+
282+ private static Set <ExpressionRoleMapping > getRoleMappingMetadataMappings (ClusterState clusterState ) {
283+ RoleMappingMetadata roleMappingMetadata = RoleMappingMetadata .getFromClusterState (clusterState );
284+ if (roleMappingMetadata != null ) {
285+ return roleMappingMetadata .getRoleMappings ();
286+ }
287+ return Set .of ();
288+ }
289+
270290 @ Override
271291 public void clusterChanged (ClusterChangedEvent event ) {
272292 if (event .state ().blocks ().hasGlobalBlock (GatewayService .STATE_NOT_RECOVERED_BLOCK )) {
@@ -284,6 +304,9 @@ public void clusterChanged(ClusterChangedEvent event) {
284304 Tuple <Boolean , Boolean > available = checkIndexAvailable (event .state ());
285305 final boolean indexAvailableForWrite = available .v1 ();
286306 final boolean indexAvailableForSearch = available .v2 ();
307+ final Set <String > reservedStateRoleMappingNames = getFileSettingsMetadataHandlerRoleMappingKeys (event .state ());
308+ final boolean reservedRoleMappingsSynced = reservedStateRoleMappingNames .size () == getRoleMappingMetadataMappings (event .state ())
309+ .size ();
287310 final boolean mappingIsUpToDate = indexMetadata == null || checkIndexMappingUpToDate (event .state ());
288311 final int migrationsVersion = getMigrationVersionFromIndexMetadata (indexMetadata );
289312 final SystemIndexDescriptor .MappingsVersion minClusterMappingVersion = getMinSecurityIndexMappingVersion (event .state ());
@@ -314,6 +337,7 @@ public void clusterChanged(ClusterChangedEvent event) {
314337 indexAvailableForWrite ,
315338 mappingIsUpToDate ,
316339 createdOnLatestVersion ,
340+ reservedRoleMappingsSynced ,
317341 migrationsVersion ,
318342 minClusterMappingVersion ,
319343 indexMappingVersion ,
@@ -323,7 +347,8 @@ public void clusterChanged(ClusterChangedEvent event) {
323347 indexUUID ,
324348 allSecurityFeatures .stream ()
325349 .filter (feature -> featureService .clusterHasFeature (event .state (), feature ))
326- .collect (Collectors .toSet ())
350+ .collect (Collectors .toSet ()),
351+ reservedStateRoleMappingNames
327352 );
328353 this .state = newState ;
329354
@@ -334,6 +359,10 @@ public void clusterChanged(ClusterChangedEvent event) {
334359 }
335360 }
336361
362+ public Set <String > getReservedStateRoleMappingNames () {
363+ return state .reservedStateRoleMappingNames ;
364+ }
365+
337366 public static int getMigrationVersionFromIndexMetadata (IndexMetadata indexMetadata ) {
338367 Map <String , String > customMetadata = indexMetadata == null ? null : indexMetadata .getCustomData (MIGRATION_VERSION_CUSTOM_KEY );
339368 if (customMetadata == null ) {
@@ -438,7 +467,8 @@ private Tuple<Boolean, Boolean> checkIndexAvailable(ClusterState state) {
438467
439468 public boolean isEligibleSecurityMigration (SecurityMigrations .SecurityMigration securityMigration ) {
440469 return state .securityFeatures .containsAll (securityMigration .nodeFeaturesRequired ())
441- && state .indexMappingVersion >= securityMigration .minMappingVersion ();
470+ && state .indexMappingVersion >= securityMigration .minMappingVersion ()
471+ && securityMigration .checkPreConditions (state );
442472 }
443473
444474 public boolean isReadyForSecurityMigration (SecurityMigrations .SecurityMigration securityMigration ) {
@@ -671,13 +701,15 @@ public static class State {
671701 false ,
672702 false ,
673703 false ,
704+ false ,
674705 null ,
675706 null ,
676707 null ,
677708 null ,
678709 null ,
679710 null ,
680711 null ,
712+ Set .of (),
681713 Set .of ()
682714 );
683715 public final Instant creationTime ;
@@ -686,6 +718,7 @@ public static class State {
686718 public final boolean indexAvailableForWrite ;
687719 public final boolean mappingUpToDate ;
688720 public final boolean createdOnLatestVersion ;
721+ public final boolean reservedRoleMappingsSynced ;
689722 public final Integer migrationsVersion ;
690723 // Min mapping version supported by the descriptors in the cluster
691724 public final SystemIndexDescriptor .MappingsVersion minClusterMappingVersion ;
@@ -696,6 +729,7 @@ public static class State {
696729 public final IndexMetadata .State indexState ;
697730 public final String indexUUID ;
698731 public final Set <NodeFeature > securityFeatures ;
732+ public final Set <String > reservedStateRoleMappingNames ;
699733
700734 public State (
701735 Instant creationTime ,
@@ -704,14 +738,16 @@ public State(
704738 boolean indexAvailableForWrite ,
705739 boolean mappingUpToDate ,
706740 boolean createdOnLatestVersion ,
741+ boolean reservedRoleMappingsSynced ,
707742 Integer migrationsVersion ,
708743 SystemIndexDescriptor .MappingsVersion minClusterMappingVersion ,
709744 Integer indexMappingVersion ,
710745 String concreteIndexName ,
711746 ClusterHealthStatus indexHealth ,
712747 IndexMetadata .State indexState ,
713748 String indexUUID ,
714- Set <NodeFeature > securityFeatures
749+ Set <NodeFeature > securityFeatures ,
750+ Set <String > reservedStateRoleMappingNames
715751 ) {
716752 this .creationTime = creationTime ;
717753 this .isIndexUpToDate = isIndexUpToDate ;
@@ -720,13 +756,15 @@ public State(
720756 this .mappingUpToDate = mappingUpToDate ;
721757 this .migrationsVersion = migrationsVersion ;
722758 this .createdOnLatestVersion = createdOnLatestVersion ;
759+ this .reservedRoleMappingsSynced = reservedRoleMappingsSynced ;
723760 this .minClusterMappingVersion = minClusterMappingVersion ;
724761 this .indexMappingVersion = indexMappingVersion ;
725762 this .concreteIndexName = concreteIndexName ;
726763 this .indexHealth = indexHealth ;
727764 this .indexState = indexState ;
728765 this .indexUUID = indexUUID ;
729766 this .securityFeatures = securityFeatures ;
767+ this .reservedStateRoleMappingNames = reservedStateRoleMappingNames ;
730768 }
731769
732770 @ Override
@@ -740,13 +778,15 @@ public boolean equals(Object o) {
740778 && indexAvailableForWrite == state .indexAvailableForWrite
741779 && mappingUpToDate == state .mappingUpToDate
742780 && createdOnLatestVersion == state .createdOnLatestVersion
781+ && reservedRoleMappingsSynced == state .reservedRoleMappingsSynced
743782 && Objects .equals (indexMappingVersion , state .indexMappingVersion )
744783 && Objects .equals (migrationsVersion , state .migrationsVersion )
745784 && Objects .equals (minClusterMappingVersion , state .minClusterMappingVersion )
746785 && Objects .equals (concreteIndexName , state .concreteIndexName )
747786 && indexHealth == state .indexHealth
748787 && indexState == state .indexState
749- && Objects .equals (securityFeatures , state .securityFeatures );
788+ && Objects .equals (securityFeatures , state .securityFeatures )
789+ && Objects .equals (reservedStateRoleMappingNames , state .reservedStateRoleMappingNames );
750790 }
751791
752792 public boolean indexExists () {
@@ -762,12 +802,14 @@ public int hashCode() {
762802 indexAvailableForWrite ,
763803 mappingUpToDate ,
764804 createdOnLatestVersion ,
805+ reservedRoleMappingsSynced ,
765806 migrationsVersion ,
766807 minClusterMappingVersion ,
767808 indexMappingVersion ,
768809 concreteIndexName ,
769810 indexHealth ,
770- securityFeatures
811+ securityFeatures ,
812+ reservedStateRoleMappingNames
771813 );
772814 }
773815
@@ -786,6 +828,8 @@ public String toString() {
786828 + mappingUpToDate
787829 + ", createdOnLatestVersion="
788830 + createdOnLatestVersion
831+ + ", reservedRoleMappingsSynced="
832+ + reservedRoleMappingsSynced
789833 + ", migrationsVersion="
790834 + migrationsVersion
791835 + ", minClusterMappingVersion="
@@ -804,6 +848,8 @@ public String toString() {
804848 + '\''
805849 + ", securityFeatures="
806850 + securityFeatures
851+ + ", reservedStateRoleMappingNames="
852+ + reservedStateRoleMappingNames
807853 + '}' ;
808854 }
809855 }
0 commit comments