Collection createComponents()

in x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java [773:1249]


    Collection<Object> createComponents(
        Client client,
        ThreadPool threadPool,
        ClusterService clusterService,
        FeatureService featureService,
        ResourceWatcherService resourceWatcherService,
        ScriptService scriptService,
        NamedXContentRegistry xContentRegistry,
        Environment environment,
        IndexNameExpressionResolver expressionResolver,
        TelemetryProvider telemetryProvider,
        PersistentTasksService persistentTasksService,
        ProjectResolver projectResolver
    ) throws Exception {
        logger.info("Security is {}", enabled ? "enabled" : "disabled");
        if (enabled == false) {
            return Collections.singletonList(new SecurityUsageServices(null, null, null, null, null, null));
        }

        this.client.set(client);

        // The settings in `environment` may have additional values over what was provided during construction
        // See Plugin#additionalSettings()
        this.settings = environment.settings();

        systemIndices.init(client, featureService, clusterService, projectResolver);

        this.securityMigrationExecutor.set(
            new SecurityMigrationExecutor(
                SecurityMigrationTaskParams.TASK_NAME,
                threadPool.executor(ThreadPool.Names.MANAGEMENT),
                systemIndices.getMainIndexManager(),
                client,
                SecurityMigrations.MIGRATIONS_BY_VERSION
            )
        );
        this.persistentTasksService.set(persistentTasksService);

        systemIndices.getMainIndexManager().addStateListener((projectId, oldState, newState) -> {
            // Only consider applying migrations if it's the master node and the security index exists
            if (clusterService.state().nodes().isLocalNodeElectedMaster() && newState.indexExists()) {
                applyPendingSecurityMigrations(projectId, newState);
            }
        });

        scriptServiceReference.set(scriptService);
        // We need to construct the checks here while the secure settings are still available.
        // If we wait until #getBoostrapChecks the secure settings will have been cleared/closed.
        final List<BootstrapCheck> checks = new ArrayList<>();
        Collections.addAll(
            checks,
            new TokenSSLBootstrapCheck(),
            new PkiRealmBootstrapCheck(getSslService()),
            new TransportTLSBootstrapCheck()
        );
        checks.addAll(InternalRealms.getBootstrapChecks(settings, environment));
        this.bootstrapChecks.set(Collections.unmodifiableList(checks));

        threadContext.set(threadPool.getThreadContext());
        List<Object> components = new ArrayList<>();
        securityContext.set(new SecurityContext(settings, threadPool.getThreadContext()));
        components.add(securityContext.get());

        final RestrictedIndices restrictedIndices = new RestrictedIndices(expressionResolver);

        // audit trail service construction
        final AuditTrail auditTrail = XPackSettings.AUDIT_ENABLED.get(settings)
            ? new LoggingAuditTrail(settings, clusterService, threadPool)
            : null;
        final AuditTrailService auditTrailService = new AuditTrailService(auditTrail, getLicenseState());
        components.add(auditTrailService);
        this.auditTrailService.set(auditTrailService);

        final TokenService tokenService = new TokenService(
            settings,
            Clock.systemUTC(),
            client,
            getLicenseState(),
            securityContext.get(),
            systemIndices.getMainIndexManager(),
            systemIndices.getTokenIndexManager(),
            clusterService
        );
        this.tokenService.set(tokenService);
        components.add(tokenService);

        // realms construction
        final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, systemIndices.getMainIndexManager());
        final NativeRoleMappingStore nativeRoleMappingStore = new NativeRoleMappingStore(
            settings,
            client,
            systemIndices.getMainIndexManager(),
            scriptService
        );
        final ProjectStateRoleMapper projectStateRoleMapper = new ProjectStateRoleMapper(
            settings,
            scriptService,
            clusterService,
            projectResolver
        );
        final UserRoleMapper userRoleMapper = new CompositeRoleMapper(nativeRoleMappingStore, projectStateRoleMapper);
        final AnonymousUser anonymousUser = new AnonymousUser(settings);
        components.add(anonymousUser);
        final ReservedRealm reservedRealm = new ReservedRealm(environment, settings, nativeUsersStore, anonymousUser, threadPool);
        final SecurityExtension.SecurityComponents extensionComponents = new ExtensionComponents(
            environment,
            client,
            clusterService,
            resourceWatcherService,
            userRoleMapper,
            projectResolver
        );
        Map<String, Realm.Factory> realmFactories = new HashMap<>(
            InternalRealms.getFactories(
                threadPool,
                settings,
                resourceWatcherService,
                getSslService(),
                nativeUsersStore,
                userRoleMapper,
                systemIndices.getMainIndexManager()
            )
        );
        for (SecurityExtension extension : securityExtensions) {
            Map<String, Realm.Factory> newRealms = extension.getRealms(extensionComponents);
            for (Map.Entry<String, Realm.Factory> entry : newRealms.entrySet()) {
                if (realmFactories.put(entry.getKey(), entry.getValue()) != null) {
                    throw new IllegalArgumentException("Realm type [" + entry.getKey() + "] is already registered");
                }
            }
        }
        final Realms realms = new Realms(
            settings,
            environment,
            realmFactories,
            getLicenseState(),
            threadPool.getThreadContext(),
            reservedRealm
        );
        components.add(nativeUsersStore);
        components.add(new PluginComponentBinding<>(NativeRoleMappingStore.class, nativeRoleMappingStore));
        components.add(new PluginComponentBinding<>(UserRoleMapper.class, userRoleMapper));
        components.add(projectStateRoleMapper);
        components.add(reservedRealm);
        components.add(realms);
        this.realms.set(realms);

        systemIndices.getMainIndexManager().addStateListener(nativeRoleMappingStore::onSecurityIndexStateChange);
        final CacheInvalidatorRegistry cacheInvalidatorRegistry = new CacheInvalidatorRegistry();
        components.add(cacheInvalidatorRegistry);

        ServiceAccountService serviceAccountService = createServiceAccountService(
            components,
            cacheInvalidatorRegistry,
            extensionComponents,
            () -> new IndexServiceAccountTokenStore(
                settings,
                threadPool,
                getClock(),
                client,
                systemIndices.getMainIndexManager(),
                clusterService,
                cacheInvalidatorRegistry
            ),
            () -> new FileServiceAccountTokenStore(
                environment,
                resourceWatcherService,
                threadPool,
                clusterService,
                cacheInvalidatorRegistry
            )
        );

        components.add(serviceAccountService);

        systemIndices.getMainIndexManager().addStateListener(cacheInvalidatorRegistry::onSecurityIndexStateChange);
        final NativePrivilegeStore privilegeStore = new NativePrivilegeStore(
            settings,
            client,
            systemIndices.getMainIndexManager(),
            cacheInvalidatorRegistry,
            clusterService
        );
        components.add(privilegeStore);

        final ReservedRolesStore reservedRolesStore = new ReservedRolesStore(Set.copyOf(INCLUDED_RESERVED_ROLES_SETTING.get(settings)));
        dlsBitsetCache.set(new DocumentSubsetBitsetCache(settings, threadPool));
        final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(settings);

        RoleDescriptor.setFieldPermissionsCache(fieldPermissionsCache);
        // Need to set to default if it wasn't set by an extension
        if (putRoleRequestBuilderFactory.get() == null) {
            putRoleRequestBuilderFactory.set(new PutRoleRequestBuilderFactory.Default());
        }
        if (bulkPutRoleRequestBuilderFactory.get() == null) {
            bulkPutRoleRequestBuilderFactory.set(new BulkPutRoleRequestBuilderFactory.Default());
        }
        if (createApiKeyRequestBuilderFactory.get() == null) {
            createApiKeyRequestBuilderFactory.set(new CreateApiKeyRequestBuilderFactory.Default());
        }
        if (getBuiltinPrivilegesResponseTranslator.get() == null) {
            getBuiltinPrivilegesResponseTranslator.set(new GetBuiltinPrivilegesResponseTranslator.Default());
        }
        if (updateApiKeyRequestTranslator.get() == null) {
            updateApiKeyRequestTranslator.set(new UpdateApiKeyRequestTranslator.Default());
        }
        if (bulkUpdateApiKeyRequestTranslator.get() == null) {
            bulkUpdateApiKeyRequestTranslator.set(new BulkUpdateApiKeyRequestTranslator.Default());
        }
        if (grantApiKeyRequestTranslator.get() == null) {
            grantApiKeyRequestTranslator.set(new RestGrantApiKeyAction.RequestTranslator.Default());
        }
        if (hasPrivilegesRequestBuilderFactory.get() == null) {
            hasPrivilegesRequestBuilderFactory.trySet(new HasPrivilegesRequestBuilderFactory.Default());
        }
        if (reservedRoleNameCheckerFactory.get() == null) {
            reservedRoleNameCheckerFactory.set(new ReservedRoleNameChecker.Factory.Default());
        }
        if (fileRoleValidator.get() == null) {
            fileRoleValidator.set(new FileRoleValidator.Default());
        }
        this.fileRolesStore.set(
            new FileRolesStore(settings, environment, resourceWatcherService, getLicenseState(), xContentRegistry, fileRoleValidator.get())
        );
        ReservedRoleNameChecker reservedRoleNameChecker = reservedRoleNameCheckerFactory.get().create(fileRolesStore.get()::exists);
        components.add(new PluginComponentBinding<>(ReservedRoleNameChecker.class, reservedRoleNameChecker));

        final Map<String, List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>>> customRoleProviders = new LinkedHashMap<>();
        for (SecurityExtension extension : securityExtensions) {
            final List<BiConsumer<Set<String>, ActionListener<RoleRetrievalResult>>> providers = extension.getRolesProviders(
                extensionComponents
            );
            if (providers != null && providers.isEmpty() == false) {
                customRoleProviders.put(extension.extensionName(), providers);
            }
        }

        final NativeRolesStore nativeRolesStore = new NativeRolesStore(
            settings,
            client,
            getLicenseState(),
            systemIndices.getMainIndexManager(),
            clusterService,
            reservedRoleNameChecker,
            xContentRegistry
        );

        final ApiKeyService apiKeyService = new ApiKeyService(
            settings,
            Clock.systemUTC(),
            client,
            systemIndices.getMainIndexManager(),
            clusterService,
            cacheInvalidatorRegistry,
            threadPool,
            telemetryProvider.getMeterRegistry()
        );
        components.add(apiKeyService);

        final RoleProviders roleProviders = new RoleProviders(
            reservedRolesStore,
            fileRolesStore.get(),
            nativeRolesStore,
            customRoleProviders,
            getLicenseState()
        );
        final CompositeRolesStore allRolesStore = new CompositeRolesStore(
            settings,
            roleProviders,
            privilegeStore,
            threadPool.getThreadContext(),
            getLicenseState(),
            fieldPermissionsCache,
            apiKeyService,
            serviceAccountService,
            projectResolver,
            dlsBitsetCache.get(),
            restrictedIndices,
            buildRoleBuildingExecutor(threadPool, settings),
            new DeprecationRoleDescriptorConsumer(clusterService, projectResolver, threadPool)
        );
        systemIndices.getMainIndexManager().addStateListener(allRolesStore::onSecurityIndexStateChange);

        final ProfileService profileService = new ProfileService(
            settings,
            getClock(),
            client,
            systemIndices.getProfileIndexManager(),
            realms
        );
        components.add(profileService);

        // We use the value of the {@code ENROLLMENT_ENABLED} setting to determine if the node is starting up with auto-generated
        // certificates (which have been generated by pre-startup scripts). In this case, and further if the node forms a new cluster by
        // itself, rather than joining an existing one, we complete the auto-configuration by generating and printing credentials and
        // enrollment tokens (when the .security index becomes available).
        // The generated information is output on node's standard out (if
        InitialNodeSecurityAutoConfiguration.maybeGenerateEnrollmentTokensAndElasticCredentialsOnNodeStartup(
            nativeUsersStore,
            systemIndices.getMainIndexManager(),
            getSslService(),
            client,
            environment,
            (runnable -> nodeStartedListenable.addListener(ActionListener.running(runnable))),
            threadPool
        );

        // to keep things simple, just invalidate all cached entries on license change. this happens so rarely that the impact should be
        // minimal
        getLicenseState().addListener(allRolesStore::invalidateAll);

        final AuthenticationFailureHandler failureHandler = createAuthenticationFailureHandler(realms, extensionComponents);

        final boolean operatorPrivilegesEnabled = OPERATOR_PRIVILEGES_ENABLED.get(settings);

        if (operatorPrivilegesEnabled) {
            logger.info("operator privileges are enabled");
            if (operatorOnlyRegistry.get() == null) {
                operatorOnlyRegistry.set(new DefaultOperatorOnlyRegistry(clusterService.getClusterSettings()));
            }
            operatorPrivilegesService.set(
                new OperatorPrivileges.DefaultOperatorPrivilegesService(
                    getLicenseState(),
                    new FileOperatorUsersStore(environment, resourceWatcherService),
                    operatorOnlyRegistry.get()
                )
            );
        } else {
            operatorPrivilegesService.set(OperatorPrivileges.NOOP_OPERATOR_PRIVILEGES_SERVICE);
        }

        authcService.set(
            new AuthenticationService(
                settings,
                realms,
                auditTrailService,
                failureHandler,
                threadPool,
                anonymousUser,
                tokenService,
                apiKeyService,
                serviceAccountService,
                operatorPrivilegesService.get(),
                telemetryProvider.getMeterRegistry()
            )
        );
        components.add(authcService.get());
        systemIndices.getMainIndexManager().addStateListener(authcService.get()::onSecurityIndexStateChange);
        dlsFlsEnabled.set(XPackSettings.DLS_FLS_ENABLED.get(settings));
        Set<RequestInterceptor> requestInterceptors = Sets.newHashSet(
            new ResizeRequestInterceptor(threadPool, getLicenseState(), auditTrailService, dlsFlsEnabled.get()),
            new IndicesAliasesRequestInterceptor(threadPool.getThreadContext(), getLicenseState(), auditTrailService, dlsFlsEnabled.get())
        );

        if (dlsFlsEnabled.get()) {
            requestInterceptors.addAll(
                Arrays.asList(
                    new SearchRequestInterceptor(threadPool, getLicenseState()),
                    new ShardSearchRequestInterceptor(threadPool, getLicenseState()),
                    new UpdateRequestInterceptor(threadPool, getLicenseState()),
                    new BulkShardRequestInterceptor(threadPool, getLicenseState()),
                    new DlsFlsLicenseRequestInterceptor(threadPool.getThreadContext(), getLicenseState()),
                    new SearchRequestCacheDisablingInterceptor(threadPool, getLicenseState()),
                    new ValidateRequestInterceptor(threadPool, getLicenseState())
                )
            );
        }
        requestInterceptors = Collections.unmodifiableSet(requestInterceptors);

        if (authorizationDenialMessages.get() == null) {
            authorizationDenialMessages.set(new AuthorizationDenialMessages.Default());
        }
        final AuthorizationService authzService = new AuthorizationService(
            settings,
            allRolesStore,
            fieldPermissionsCache,
            clusterService,
            auditTrailService,
            failureHandler,
            threadPool,
            anonymousUser,
            getAuthorizationEngine(),
            requestInterceptors,
            getLicenseState(),
            expressionResolver,
            operatorPrivilegesService.get(),
            restrictedIndices,
            authorizationDenialMessages.get(),
            projectResolver
        );

        components.add(nativeRolesStore); // used by roles actions
        components.add(reservedRolesStore); // used by roles actions
        components.add(allRolesStore); // for SecurityInfoTransportAction and clear roles cache
        components.add(authzService);

        final SecondaryAuthenticator secondaryAuthenticator = new SecondaryAuthenticator(
            securityContext.get(),
            authcService.get(),
            auditTrailService
        );
        this.secondayAuthc.set(secondaryAuthenticator);
        components.add(secondaryAuthenticator);

        ipFilter.set(new IPFilter(settings, auditTrailService, clusterService.getClusterSettings(), getLicenseState()));
        components.add(ipFilter.get());

        DestructiveOperations destructiveOperations = new DestructiveOperations(settings, clusterService.getClusterSettings());
        crossClusterAccessAuthcService.set(new CrossClusterAccessAuthenticationService(clusterService, apiKeyService, authcService.get()));
        components.add(crossClusterAccessAuthcService.get());
        securityInterceptor.set(
            new SecurityServerTransportInterceptor(
                settings,
                threadPool,
                authcService.get(),
                authzService,
                getSslService(),
                securityContext.get(),
                destructiveOperations,
                crossClusterAccessAuthcService.get(),
                getLicenseState()
            )
        );

        securityActionFilter.set(
            new SecurityActionFilter(
                authcService.get(),
                authzService,
                auditTrailService,
                getLicenseState(),
                threadPool,
                securityContext.get(),
                destructiveOperations,
                secondaryAuthActions.get() == null ? Set::of : secondaryAuthActions.get()
            )
        );

        components.add(
            new SecurityUsageServices(realms, allRolesStore, nativeRoleMappingStore, ipFilter.get(), profileService, apiKeyService)
        );

        reservedRoleMappingAction.set(new ReservedRoleMappingAction());

        if (QUERYABLE_BUILT_IN_ROLES_ENABLED) {
            if (queryableRolesProviderFactory.get() == null) {
                queryableRolesProviderFactory.set(new QueryableBuiltInRolesProviderFactory.Default());
            }
            components.add(
                new QueryableBuiltInRolesSynchronizer(
                    clusterService,
                    featureService,
                    queryableRolesProviderFactory.get(),
                    nativeRolesStore,
                    reservedRolesStore,
                    fileRolesStore.get(),
                    threadPool
                )
            );
        }

        cacheInvalidatorRegistry.validate();

        final List<ReloadableSecurityComponent> reloadableComponents = new ArrayList<>();
        final List<Closeable> closableComponents = new ArrayList<>();
        for (Object component : components) {
            if (component instanceof ReloadableSecurityComponent reloadable) {
                reloadableComponents.add(reloadable);
            }
            if (component instanceof Closeable closeable) {
                closableComponents.add(closeable);
            }
        }

        this.reloadableComponents.set(List.copyOf(reloadableComponents));
        this.closableComponents.set(List.copyOf(closableComponents));
        return components;
    }