Skip to content

Commit c020ba6

Browse files
committed
Security: Simplify security index listeners (#30466)
This commit adds a general state listener to the SecurityIndexManager, and replaces the existing health and up-to-date listeners with that. It also moves helper methods relating to health to SecurityIndexManager from SecurityLifecycleService.
1 parent 40e7648 commit c020ba6

File tree

39 files changed

+423
-596
lines changed

39 files changed

+423
-596
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityLifecycleServiceField.java

-13
This file was deleted.

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@
234234
import static java.util.Collections.singletonList;
235235
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
236236
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
237-
import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField.SECURITY_INDEX_NAME;
238-
import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField.SECURITY_TEMPLATE_NAME;
237+
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
238+
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
239239
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT;
240240

241241
public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin, DiscoveryPlugin, MapperPlugin,
@@ -442,8 +442,7 @@ Collection<Object> createComponents(Client client, ThreadPool threadPool, Cluste
442442
components.add(realms);
443443
components.add(reservedRealm);
444444

445-
securityLifecycleService.securityIndex().addIndexHealthChangeListener(nativeRoleMappingStore::onSecurityIndexHealthChange);
446-
securityLifecycleService.securityIndex().addIndexOutOfDateListener(nativeRoleMappingStore::onSecurityIndexOutOfDateChange);
445+
securityLifecycleService.securityIndex().addIndexStateListener(nativeRoleMappingStore::onSecurityIndexStateChange);
447446

448447
AuthenticationFailureHandler failureHandler = null;
449448
String extensionName = null;
@@ -475,8 +474,7 @@ Collection<Object> createComponents(Client client, ThreadPool threadPool, Cluste
475474
}
476475
final CompositeRolesStore allRolesStore = new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
477476
reservedRolesStore, rolesProviders, threadPool.getThreadContext(), getLicenseState());
478-
securityLifecycleService.securityIndex().addIndexHealthChangeListener(allRolesStore::onSecurityIndexHealthChange);
479-
securityLifecycleService.securityIndex().addIndexOutOfDateListener(allRolesStore::onSecurityIndexOutOfDateChange);
477+
securityLifecycleService.securityIndex().addIndexStateListener(allRolesStore::onSecurityIndexStateChange);
480478
// to keep things simple, just invalidate all cached entries on license change. this happens so rarely that the impact should be
481479
// minimal
482480
getLicenseState().addListener(allRolesStore::invalidateAll);

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java

-36
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@
2727
import java.util.Arrays;
2828
import java.util.Collections;
2929
import java.util.List;
30-
import java.util.function.BiConsumer;
31-
import java.util.function.Consumer;
32-
import java.util.function.Predicate;
33-
34-
import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField.SECURITY_INDEX_NAME;
3530

3631
/**
3732
* This class is used to provide a lifecycle for services that is based on the cluster's state
@@ -51,8 +46,6 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
5146
public static final String INTERNAL_SECURITY_INDEX = SecurityIndexManager.INTERNAL_SECURITY_INDEX;
5247
public static final String SECURITY_INDEX_NAME = ".security";
5348

54-
private static final Version MIN_READ_VERSION = Version.V_5_0_0;
55-
5649
private final Settings settings;
5750
private final ThreadPool threadPool;
5851
private final IndexAuditTrail indexAuditTrail;
@@ -127,36 +120,7 @@ private void close() {
127120
}
128121
}
129122

130-
public static boolean securityIndexMappingSufficientToRead(ClusterState clusterState, Logger logger) {
131-
return checkMappingVersions(clusterState, logger, MIN_READ_VERSION::onOrBefore);
132-
}
133-
134-
static boolean securityIndexMappingUpToDate(ClusterState clusterState, Logger logger) {
135-
return checkMappingVersions(clusterState, logger, Version.CURRENT::equals);
136-
}
137-
138-
private static boolean checkMappingVersions(ClusterState clusterState, Logger logger, Predicate<Version> versionPredicate) {
139-
return SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, versionPredicate);
140-
}
141-
142123
public static List<String> indexNames() {
143124
return Collections.unmodifiableList(Arrays.asList(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX));
144125
}
145-
146-
/**
147-
* Is the move from {@code previousHealth} to {@code currentHealth} a move from an unhealthy ("RED") index state to a healthy
148-
* ("non-RED") state.
149-
*/
150-
public static boolean isMoveFromRedToNonRed(ClusterIndexHealth previousHealth, ClusterIndexHealth currentHealth) {
151-
return (previousHealth == null || previousHealth.getStatus() == ClusterHealthStatus.RED)
152-
&& currentHealth != null && currentHealth.getStatus() != ClusterHealthStatus.RED;
153-
}
154-
155-
/**
156-
* Is the move from {@code previousHealth} to {@code currentHealth} a move from index-exists to index-deleted
157-
*/
158-
public static boolean isIndexDeleted(ClusterIndexHealth previousHealth, ClusterIndexHealth currentHealth) {
159-
return previousHealth != null && currentHealth == null;
160-
}
161-
162126
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ExpiredTokenRemover.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.elasticsearch.index.reindex.ScrollableHitSource;
2323
import org.elasticsearch.threadpool.ThreadPool;
2424
import org.elasticsearch.threadpool.ThreadPool.Names;
25-
import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField;
2625

2726
import java.time.Instant;
2827
import java.time.temporal.ChronoUnit;
@@ -31,6 +30,7 @@
3130
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
3231
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
3332
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
33+
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
3434

3535
/**
3636
* Responsible for cleaning the invalidated tokens from the invalidated tokens index.
@@ -50,7 +50,7 @@ final class ExpiredTokenRemover extends AbstractRunnable {
5050

5151
@Override
5252
public void doRun() {
53-
SearchRequest searchRequest = new SearchRequest(SecurityLifecycleServiceField.SECURITY_INDEX_NAME);
53+
SearchRequest searchRequest = new SearchRequest(SECURITY_INDEX_NAME);
5454
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(searchRequest);
5555
if (timeout != TimeValue.MINUS_ONE) {
5656
expiredDbq.setTimeout(timeout);

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public static Map<String, Realm.Factory> getFactories(ThreadPool threadPool, Res
9696
map.put(FileRealmSettings.TYPE, config -> new FileRealm(config, resourceWatcherService));
9797
map.put(NativeRealmSettings.TYPE, config -> {
9898
final NativeRealm nativeRealm = new NativeRealm(config, nativeUsersStore);
99-
securityLifecycleService.securityIndex().addIndexHealthChangeListener(nativeRealm::onSecurityIndexHealthChange);
99+
securityLifecycleService.securityIndex().addIndexStateListener(nativeRealm::onSecurityIndexStateChange);
100100
return nativeRealm;
101101
});
102102
map.put(LdapRealmSettings.AD_TYPE, config -> new LdapRealm(LdapRealmSettings.AD_TYPE, config, sslService,

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
import org.elasticsearch.xpack.core.XPackField;
6969
import org.elasticsearch.xpack.core.XPackSettings;
7070
import org.elasticsearch.xpack.core.security.ScrollHelper;
71-
import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField;
7271
import org.elasticsearch.xpack.core.security.authc.Authentication;
7372
import org.elasticsearch.xpack.core.security.authc.KeyAndTimestamp;
7473
import org.elasticsearch.xpack.core.security.authc.TokenMetaData;
@@ -118,6 +117,7 @@
118117
import static org.elasticsearch.gateway.GatewayService.STATE_NOT_RECOVERED_BLOCK;
119118
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
120119
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
120+
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
121121

122122
/**
123123
* Service responsible for the creation, validation, and other management of {@link UserToken}
@@ -256,7 +256,7 @@ public void createUserToken(Authentication authentication, Authentication origin
256256
.endObject();
257257
builder.endObject();
258258
IndexRequest request =
259-
client.prepareIndex(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(userToken))
259+
client.prepareIndex(SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(userToken))
260260
.setOpType(OpType.CREATE)
261261
.setSource(builder)
262262
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL)
@@ -372,7 +372,7 @@ void decodeToken(String token, ActionListener<UserToken> listener) throws IOExce
372372
decryptTokenId(in, cipher, version, ActionListener.wrap(tokenId ->
373373
lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
374374
final GetRequest getRequest =
375-
client.prepareGet(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE,
375+
client.prepareGet(SECURITY_INDEX_NAME, TYPE,
376376
getTokenDocumentId(tokenId)).request();
377377
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, getRequest,
378378
ActionListener.<GetResponse>wrap(response -> {
@@ -533,7 +533,7 @@ private void indexBwcInvalidation(UserToken userToken, ActionListener<Boolean> l
533533
listener.onFailure(invalidGrantException("failed to invalidate token"));
534534
} else {
535535
final String invalidatedTokenId = getInvalidatedTokenDocumentId(userToken);
536-
IndexRequest indexRequest = client.prepareIndex(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, invalidatedTokenId)
536+
IndexRequest indexRequest = client.prepareIndex(SECURITY_INDEX_NAME, TYPE, invalidatedTokenId)
537537
.setOpType(OpType.CREATE)
538538
.setSource("doc_type", INVALIDATED_TOKEN_DOC_TYPE, "expiration_time", expirationEpochMilli)
539539
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL)
@@ -577,7 +577,7 @@ private void indexInvalidation(String tokenDocId, Version version, ActionListene
577577
if (attemptCount.get() > 5) {
578578
listener.onFailure(invalidGrantException("failed to invalidate token"));
579579
} else {
580-
UpdateRequest request = client.prepareUpdate(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, tokenDocId)
580+
UpdateRequest request = client.prepareUpdate(SECURITY_INDEX_NAME, TYPE, tokenDocId)
581581
.setDoc(srcPrefix, Collections.singletonMap("invalidated", true))
582582
.setVersion(documentVersion)
583583
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL)
@@ -609,7 +609,7 @@ private void indexInvalidation(String tokenDocId, Version version, ActionListene
609609
|| isShardNotAvailableException(cause)) {
610610
attemptCount.incrementAndGet();
611611
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
612-
client.prepareGet(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, tokenDocId).request(),
612+
client.prepareGet(SECURITY_INDEX_NAME, TYPE, tokenDocId).request(),
613613
ActionListener.<GetResponse>wrap(getResult -> {
614614
if (getResult.isExists()) {
615615
Map<String, Object> source = getResult.getSource();
@@ -674,7 +674,7 @@ private void findTokenFromRefreshToken(String refreshToken, ActionListener<Tuple
674674
if (attemptCount.get() > 5) {
675675
listener.onFailure(invalidGrantException("could not refresh the requested token"));
676676
} else {
677-
SearchRequest request = client.prepareSearch(SecurityLifecycleServiceField.SECURITY_INDEX_NAME)
677+
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
678678
.setQuery(QueryBuilders.boolQuery()
679679
.filter(QueryBuilders.termQuery("doc_type", "token"))
680680
.filter(QueryBuilders.termQuery("refresh_token.token", refreshToken)))
@@ -718,7 +718,7 @@ private void innerRefresh(String tokenDocId, Authentication userAuth, ActionList
718718
if (attemptCount.getAndIncrement() > 5) {
719719
listener.onFailure(invalidGrantException("could not refresh the requested token"));
720720
} else {
721-
GetRequest getRequest = client.prepareGet(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, tokenDocId).request();
721+
GetRequest getRequest = client.prepareGet(SECURITY_INDEX_NAME, TYPE, tokenDocId).request();
722722
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, getRequest,
723723
ActionListener.<GetResponse>wrap(response -> {
724724
if (response.isExists()) {
@@ -739,7 +739,7 @@ private void innerRefresh(String tokenDocId, Authentication userAuth, ActionList
739739
in.setVersion(authVersion);
740740
Authentication authentication = new Authentication(in);
741741
UpdateRequest updateRequest =
742-
client.prepareUpdate(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, tokenDocId)
742+
client.prepareUpdate(SECURITY_INDEX_NAME, TYPE, tokenDocId)
743743
.setVersion(response.getVersion())
744744
.setDoc("refresh_token", Collections.singletonMap("refreshed", true))
745745
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL)
@@ -854,7 +854,7 @@ public void findActiveTokensForRealm(String realmName, ActionListener<Collection
854854
.should(QueryBuilders.termQuery("refresh_token.invalidated", false))
855855
);
856856

857-
final SearchRequest request = client.prepareSearch(SecurityLifecycleServiceField.SECURITY_INDEX_NAME)
857+
final SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
858858
.setScroll(TimeValue.timeValueSeconds(10L))
859859
.setQuery(boolQuery)
860860
.setVersion(false)
@@ -936,8 +936,8 @@ private void checkIfTokenIsRevoked(UserToken userToken, ActionListener<UserToken
936936
} else {
937937
lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
938938
MultiGetRequest mGetRequest = client.prepareMultiGet()
939-
.add(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, getInvalidatedTokenDocumentId(userToken))
940-
.add(SecurityLifecycleServiceField.SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(userToken))
939+
.add(SECURITY_INDEX_NAME, TYPE, getInvalidatedTokenDocumentId(userToken))
940+
.add(SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(userToken))
941941
.request();
942942
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
943943
mGetRequest,

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealm.java

+6-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
package org.elasticsearch.xpack.security.authc.esnative;
77

88
import org.elasticsearch.action.ActionListener;
9-
import org.elasticsearch.cluster.health.ClusterHealthStatus;
10-
import org.elasticsearch.cluster.health.ClusterIndexHealth;
119
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
1210
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
1311
import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
1412
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
1513
import org.elasticsearch.xpack.core.security.user.User;
1614
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
15+
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
16+
17+
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isIndexDeleted;
18+
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isMoveFromRedToNonRed;
1719

1820
/**
1921
* User/password realm that is backed by an Elasticsearch index
@@ -37,12 +39,8 @@ protected void doAuthenticate(UsernamePasswordToken token, ActionListener<Authen
3739
userStore.verifyPassword(token.principal(), token.credentials(), listener);
3840
}
3941

40-
public void onSecurityIndexHealthChange(ClusterIndexHealth previousHealth, ClusterIndexHealth currentHealth) {
41-
final boolean movedFromRedToNonRed = (previousHealth == null || previousHealth.getStatus() == ClusterHealthStatus.RED)
42-
&& currentHealth != null && currentHealth.getStatus() != ClusterHealthStatus.RED;
43-
final boolean indexDeleted = previousHealth != null && currentHealth == null;
44-
45-
if (movedFromRedToNonRed || indexDeleted) {
42+
public void onSecurityIndexStateChange(SecurityIndexManager.State previousState, SecurityIndexManager.State currentState) {
43+
if (isMoveFromRedToNonRed(previousState, currentState) || isIndexDeleted(previousState, currentState)) {
4644
clearCache();
4745
}
4846
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
6767
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
6868
import static org.elasticsearch.xpack.core.ClientHelper.stashWithOrigin;
69-
import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField.SECURITY_INDEX_NAME;
69+
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
7070

7171
/**
7272
* NativeUsersStore is a store for users that reads from an Elasticsearch index. This store is responsible for fetching the full

0 commit comments

Comments
 (0)