Security Tokens moved to a new separate index (#40742)

This commit introduces the `.security-tokens` and `.security-tokens-7`
alias-index pair. Because index snapshotting is at the index level granularity
(ie you cannot snapshot a subset of an index) snapshoting .`security` had
the undesirable effect of storing ephemeral security tokens. The changes
herein address this issue by moving tokens "seamlessly" (without user
intervention) to another index, so that a "Security Backup" (ie snapshot of
`.security`) would not be bloated by ephemeral data.
This commit is contained in:
Albert Zaharovits 2019-05-01 14:53:56 +03:00 committed by GitHub
parent bc333a5cbf
commit 990be1f806
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 2081 additions and 859 deletions

View File

@ -14,12 +14,15 @@ import java.util.Collections;
import java.util.Set;
public final class RestrictedIndicesNames {
public static final String INTERNAL_SECURITY_INDEX_6 = ".security-6";
public static final String INTERNAL_SECURITY_INDEX_7 = ".security-7";
public static final String SECURITY_INDEX_NAME = ".security";
public static final String INTERNAL_SECURITY_MAIN_INDEX_6 = ".security-6";
public static final String INTERNAL_SECURITY_MAIN_INDEX_7 = ".security-7";
public static final String SECURITY_MAIN_ALIAS = ".security";
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(
Sets.newHashSet(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX_6, INTERNAL_SECURITY_INDEX_7));
public static final String INTERNAL_SECURITY_TOKENS_INDEX_7 = ".security-tokens-7";
public static final String SECURITY_TOKENS_ALIAS = ".security-tokens";
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(Sets.newHashSet(SECURITY_MAIN_ALIAS,
INTERNAL_SECURITY_MAIN_INDEX_6, INTERNAL_SECURITY_MAIN_INDEX_7, INTERNAL_SECURITY_TOKENS_INDEX_7, SECURITY_TOKENS_ALIAS));
public static final Automaton NAMES_AUTOMATON = Automatons.patterns(RESTRICTED_NAMES);

View File

@ -1,5 +1,5 @@
{
"index_patterns" : [ ".security-*" ],
"index_patterns" : [ ".security-7" ],
"order" : 1000,
"settings" : {
"number_of_shards" : 1,

View File

@ -0,0 +1,96 @@
{
"index_patterns" : [ ".security-tokens-7" ],
"order" : 1000,
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : 0,
"auto_expand_replicas" : "0-1",
"index.priority": 1000,
"index.format": 7
},
"mappings" : {
"_doc" : {
"_meta": {
"security-version": "${security.template.version}"
},
"dynamic" : "strict",
"properties" : {
"doc_type" : {
"type" : "keyword"
},
"creation_time" : {
"type" : "date",
"format" : "epoch_millis"
},
"refresh_token" : {
"type" : "object",
"properties" : {
"token" : {
"type" : "keyword"
},
"refreshed" : {
"type" : "boolean"
},
"refresh_time": {
"type": "date",
"format": "epoch_millis"
},
"superseded_by": {
"type": "keyword"
},
"invalidated" : {
"type" : "boolean"
},
"client" : {
"type" : "object",
"properties" : {
"type" : {
"type" : "keyword"
},
"user" : {
"type" : "keyword"
},
"realm" : {
"type" : "keyword"
}
}
}
}
},
"access_token" : {
"type" : "object",
"properties" : {
"user_token" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "keyword"
},
"expiration_time" : {
"type" : "date",
"format" : "epoch_millis"
},
"version" : {
"type" : "integer"
},
"metadata" : {
"type" : "object",
"dynamic" : false
},
"authentication" : {
"type" : "binary"
}
}
},
"invalidated" : {
"type" : "boolean"
},
"realm" : {
"type" : "keyword"
}
}
}
}
}
}
}

View File

@ -601,14 +601,14 @@ public class ReservedRolesStoreTests extends ESTestCase {
private void assertMonitoringOnRestrictedIndices(Role role) {
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
final MetaData metaData = new MetaData.Builder()
.put(new IndexMetaData.Builder(internalSecurityIndex)
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
@ -616,10 +616,10 @@ public class ReservedRolesStoreTests extends ESTestCase {
GetSettingsAction.NAME, IndicesShardStoresAction.NAME, UpgradeStatusAction.NAME, RecoveryAction.NAME);
for (final String indexMonitoringActionName : indexMonitoringActionNamesList) {
final Map<String, IndexAccessControl> authzMap = role.indices().authorize(indexMonitoringActionName,
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_INDEX_NAME),
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS),
metaData.getAliasAndIndexLookup(), fieldPermissionsCache);
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(true));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
}
}
@ -713,8 +713,8 @@ public class ReservedRolesStoreTests extends ESTestCase {
assertThat(superuserRole.cluster().check("internal:admin/foo", request), is(false));
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
final MetaData metaData = new MetaData.Builder()
.put(new IndexMetaData.Builder("a1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
.put(new IndexMetaData.Builder("a2").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
@ -731,7 +731,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
@ -753,8 +753,8 @@ public class ReservedRolesStoreTests extends ESTestCase {
assertThat(authzMap.get("aaaaaa").isGranted(), is(true));
assertThat(authzMap.get("b").isGranted(), is(true));
authzMap = superuserRole.indices().authorize(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME),
Sets.newHashSet(RestrictedIndicesNames.SECURITY_INDEX_NAME), lookup, fieldPermissionsCache);
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(true));
Sets.newHashSet(RestrictedIndicesNames.SECURITY_MAIN_ALIAS), lookup, fieldPermissionsCache);
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
assertTrue(superuserRole.indices().check(SearchAction.NAME));
assertFalse(superuserRole.indices().check("unknown"));
@ -762,7 +762,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
assertThat(superuserRole.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(true));
assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME))
.test(RestrictedIndicesNames.SECURITY_INDEX_NAME), is(true));
.test(RestrictedIndicesNames.SECURITY_MAIN_ALIAS), is(true));
assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME))
.test(internalSecurityIndex), is(true));
}

View File

@ -258,9 +258,9 @@ import static java.util.Collections.singletonList;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
import static org.elasticsearch.xpack.core.XPackSettings.API_KEY_SERVICE_ENABLED_SETTING;
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7;
public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin,
DiscoveryPlugin, MapperPlugin, ExtensiblePlugin {
@ -406,9 +406,10 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
components.add(auditTrailService);
this.auditTrailService.set(auditTrailService);
securityIndex.set(SecurityIndexManager.buildSecurityIndexManager(client, clusterService));
securityIndex.set(SecurityIndexManager.buildSecurityMainIndexManager(client, clusterService));
final TokenService tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex.get(), clusterService);
final TokenService tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex.get(),
SecurityIndexManager.buildSecurityTokensIndexManager(client, clusterService), clusterService);
this.tokenService.set(tokenService);
components.add(tokenService);
@ -948,7 +949,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDataUpgrader() {
return templates -> {
// .security index is not managed by using templates anymore
templates.remove(SECURITY_TEMPLATE_NAME);
templates.remove(SECURITY_MAIN_TEMPLATE_7);
templates.remove("security_audit_log");
return templates;
};
@ -1015,9 +1016,9 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
@Override
public void accept(DiscoveryNode node, ClusterState state) {
if (state.getNodes().getMinNodeVersion().before(Version.V_7_0_0)) {
IndexMetaData indexMetaData = state.getMetaData().getIndices().get(SECURITY_INDEX_NAME);
if (indexMetaData != null && INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()) < INTERNAL_INDEX_FORMAT) {
throw new IllegalStateException("Security index is not on the current version [" + INTERNAL_INDEX_FORMAT + "] - " +
IndexMetaData indexMetaData = state.getMetaData().getIndices().get(SECURITY_MAIN_ALIAS);
if (indexMetaData != null && INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()) < INTERNAL_MAIN_INDEX_FORMAT) {
throw new IllegalStateException("Security index is not on the current version [" + INTERNAL_MAIN_INDEX_FORMAT + "] - " +
"The Upgrade API must be run for 7.x nodes to join the cluster");
}
}

View File

@ -98,7 +98,7 @@ import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
public class ApiKeyService {
@ -207,7 +207,7 @@ public class ApiKeyService {
.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
boolQuery.filter(expiredQuery);
final SearchRequest searchRequest = client.prepareSearch(SECURITY_INDEX_NAME)
final SearchRequest searchRequest = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(boolQuery)
.setVersion(false)
@ -286,7 +286,7 @@ public class ApiKeyService {
.endObject()
.endObject();
final IndexRequest indexRequest =
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME)
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME)
.setSource(builder)
.setRefreshPolicy(request.getRefreshPolicy())
.request();
@ -319,7 +319,7 @@ public class ApiKeyService {
if (credentials != null) {
final GetRequest getRequest = client
.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, credentials.getId())
.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, credentials.getId())
.setFetchSource(true)
.request();
executeAsyncWithOrigin(ctx, SECURITY_ORIGIN, getRequest, ActionListener.<GetResponse>wrap(response -> {
@ -727,7 +727,7 @@ public class ApiKeyService {
expiredQuery.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
boolQuery.filter(expiredQuery);
}
final SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
final SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(boolQuery)
.setVersion(false)
@ -801,7 +801,7 @@ public class ApiKeyService {
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
for (String apiKeyId : apiKeyIds) {
UpdateRequest request = client
.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, apiKeyId)
.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, apiKeyId)
.setDoc(Collections.singletonMap("api_key_invalidated", true))
.request();
bulkRequestBuilder.add(request);

View File

@ -22,7 +22,7 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.index.reindex.ScrollableHitSource;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import java.time.Duration;
import java.time.Instant;
@ -51,7 +51,7 @@ public final class ExpiredApiKeysRemover extends AbstractRunnable {
@Override
public void doRun() {
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(SecurityIndexManager.SECURITY_INDEX_NAME);
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
if (timeout != TimeValue.MINUS_ONE) {
expiredDbq.setTimeout(timeout);
expiredDbq.getSearchRequest().source().timeout(timeout);

View File

@ -26,6 +26,8 @@ import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
@ -33,25 +35,44 @@ import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
/**
* Responsible for cleaning the invalidated and expired tokens from the security index.
* The document gets deleted if it was created more than 24 hours which is the maximum
* lifetime of a refresh token
* Responsible for cleaning the invalidated and expired tokens from the security indices (`main` and `tokens`).
* The document is deleted if it was created more than {@code #MAXIMUM_TOKEN_LIFETIME_HOURS} hours in the past.
*/
final class ExpiredTokenRemover extends AbstractRunnable {
private static final Logger logger = LogManager.getLogger(ExpiredTokenRemover.class);
private final Client client;
private final AtomicBoolean inProgress = new AtomicBoolean(false);
private final TimeValue timeout;
public static final long MAXIMUM_TOKEN_LIFETIME_HOURS = 24L;
ExpiredTokenRemover(Settings settings, Client client) {
private final Client client;
private final SecurityIndexManager securityMainIndex;
private final SecurityIndexManager securityTokensIndex;
private final AtomicBoolean inProgress;
private final TimeValue timeout;
private boolean checkMainIndexForExpiredTokens;
ExpiredTokenRemover(Settings settings, Client client, SecurityIndexManager securityMainIndex,
SecurityIndexManager securityTokensIndex) {
this.client = client;
this.securityMainIndex = securityMainIndex;
this.securityTokensIndex = securityTokensIndex;
this.inProgress = new AtomicBoolean(false);
this.timeout = TokenService.DELETE_TIMEOUT.get(settings);
this.checkMainIndexForExpiredTokens = true;
}
@Override
public void doRun() {
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(SecurityIndexManager.SECURITY_INDEX_NAME);
final List<String> indicesWithTokens = new ArrayList<>();
if (securityTokensIndex.isAvailable()) {
indicesWithTokens.add(securityTokensIndex.aliasName());
}
if (securityMainIndex.isAvailable() && checkMainIndexForExpiredTokens) {
indicesWithTokens.add(securityMainIndex.aliasName());
}
if (indicesWithTokens.isEmpty()) {
return;
}
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(indicesWithTokens.toArray(new String[0]));
if (timeout != TimeValue.MINUS_ONE) {
expiredDbq.setTimeout(timeout);
expiredDbq.getSearchRequest().source().timeout(timeout);
@ -59,12 +80,20 @@ final class ExpiredTokenRemover extends AbstractRunnable {
final Instant now = Instant.now();
expiredDbq
.setQuery(QueryBuilders.boolQuery()
.filter(QueryBuilders.termsQuery("doc_type", "token"))
.filter(QueryBuilders.rangeQuery("creation_time").lte(now.minus(24L, ChronoUnit.HOURS).toEpochMilli())));
.filter(QueryBuilders.termsQuery("doc_type", TokenService.TOKEN_DOC_TYPE))
.filter(QueryBuilders.rangeQuery("creation_time")
.lte(now.minus(MAXIMUM_TOKEN_LIFETIME_HOURS, ChronoUnit.HOURS).toEpochMilli())));
logger.trace(() -> new ParameterizedMessage("Removing old tokens: [{}]", Strings.toString(expiredDbq)));
executeAsyncWithOrigin(client, SECURITY_ORIGIN, DeleteByQueryAction.INSTANCE, expiredDbq,
ActionListener.wrap(r -> {
debugDbqResponse(r);
ActionListener.wrap(bulkResponse -> {
debugDbqResponse(bulkResponse);
// tokens can still linger on the main index for their maximum lifetime after the tokens index has been created, because
// only after the tokens index has been created all nodes will store tokens there and not on the main security index
if (checkMainIndexForExpiredTokens && securityTokensIndex.indexExists()
&& securityTokensIndex.getCreationTime().isBefore(now.minus(MAXIMUM_TOKEN_LIFETIME_HOURS, ChronoUnit.HOURS))
&& bulkResponse.getBulkFailures().isEmpty() && bulkResponse.getSearchFailures().isEmpty()) {
checkMainIndexForExpiredTokens = false;
}
markComplete();
}, this::onFailure));
}

View File

@ -66,7 +66,7 @@ import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
/**
* NativeUsersStore is a store for users that reads from an Elasticsearch index. This store is responsible for fetching the full
@ -146,7 +146,7 @@ public class NativeUsersStore {
}
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(query)
.setSize(1000)
@ -171,7 +171,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SECURITY_INDEX_NAME)
client.prepareSearch(SECURITY_MAIN_ALIAS)
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE))
.setSize(0)
.setTrackTotalHits(true)
@ -205,7 +205,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, user)).request(),
client.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, user)).request(),
new ActionListener<GetResponse>() {
@Override
public void onResponse(GetResponse response) {
@ -245,7 +245,7 @@ public class NativeUsersStore {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(docType, username))
client.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(docType, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(),
String.valueOf(request.passwordHash()))
.setRefreshPolicy(request.getRefreshPolicy()).request(),
@ -283,7 +283,7 @@ public class NativeUsersStore {
private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.setSource(Fields.PASSWORD.getPreferredName(), String.valueOf(passwordHash), Fields.ENABLED.getPreferredName(),
true, Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)
.setRefreshPolicy(refresh).request(),
@ -323,7 +323,7 @@ public class NativeUsersStore {
// We must have an existing document
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
client.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
.setDoc(Requests.INDEX_CONTENT_TYPE,
Fields.USERNAME.getPreferredName(), putUserRequest.username(),
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
@ -367,7 +367,7 @@ public class NativeUsersStore {
assert putUserRequest.passwordHash() != null;
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
.setSource(Fields.USERNAME.getPreferredName(), putUserRequest.username(),
Fields.PASSWORD.getPreferredName(), String.valueOf(putUserRequest.passwordHash()),
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
@ -410,7 +410,7 @@ public class NativeUsersStore {
final ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, username))
client.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
.setRefreshPolicy(refreshPolicy)
.request(),
@ -444,7 +444,7 @@ public class NativeUsersStore {
boolean clearCache, final ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
client.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
.setUpsert(XContentType.JSON,
Fields.PASSWORD.getPreferredName(), "",
@ -479,7 +479,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
DeleteRequest request = client
.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username()))
.prepareDelete(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username()))
.request();
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
@ -526,7 +526,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
client.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.request(),
new ActionListener<GetResponse>() {
@Override
@ -571,7 +571,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SECURITY_INDEX_NAME)
client.prepareSearch(SECURITY_MAIN_ALIAS)
.setTrackTotalHits(true)
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE))
.setFetchSource(true).request(),

View File

@ -35,6 +35,7 @@ import org.elasticsearch.xpack.core.security.action.rolemapping.PutRoleMappingRe
import org.elasticsearch.xpack.core.security.authc.support.mapper.ExpressionRoleMapping;
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExpressionModel;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.security.authc.support.CachingRealm;
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
@ -60,13 +61,13 @@ import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isIndexDeleted;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isMoveFromRedToNonRed;
/**
* This store reads + writes {@link ExpressionRoleMapping role mappings} in an Elasticsearch
* {@link SecurityIndexManager#SECURITY_INDEX_NAME index}.
* {@link RestrictedIndicesNames#SECURITY_MAIN_ALIAS index}.
* <br>
* The store is responsible for all read and write operations as well as
* {@link #resolveRoles(UserData, ActionListener) resolving roles}.
@ -131,7 +132,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
final QueryBuilder query = QueryBuilders.termQuery(DOC_TYPE_FIELD, DOC_TYPE_ROLE_MAPPING);
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(query)
.setSize(1000)
@ -143,7 +144,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
listener.onResponse(mappings.stream().filter(Objects::nonNull).collect(Collectors.toList())),
ex -> {
logger.error(new ParameterizedMessage("failed to load role mappings from index [{}] skipping all mappings.",
SECURITY_INDEX_NAME), ex);
SECURITY_MAIN_ALIAS), ex);
listener.onResponse(Collections.emptyList());
})),
doc -> buildMapping(getNameFromId(doc.getId()), doc.getSourceRef()));
@ -202,7 +203,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForName(mapping.getName()))
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForName(mapping.getName()))
.setSource(xContentBuilder)
.setRefreshPolicy(request.getRefreshPolicy())
.request(),
@ -231,7 +232,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForName(request.getName()))
client.prepareDelete(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForName(request.getName()))
.setRefreshPolicy(request.getRefreshPolicy())
.request(),
new ActionListener<DeleteResponse>() {
@ -286,7 +287,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
logger.info("The security index is not yet available - no role mappings can be loaded");
if (logger.isDebugEnabled()) {
logger.debug("Security Index [{}] [exists: {}] [available: {}] [mapping up to date: {}]",
SECURITY_INDEX_NAME,
SECURITY_MAIN_ALIAS,
securityIndex.indexExists(),
securityIndex.isAvailable(),
securityIndex.isMappingUpToDate()

View File

@ -65,7 +65,7 @@ import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor.DOC_TYPE_VALUE;
import static org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor.Fields.APPLICATION;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
/**
* {@code NativePrivilegeStore} is a store that reads/writes {@link ApplicationPrivilegeDescriptor} objects,
@ -129,7 +129,7 @@ public class NativePrivilegeStore {
}
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(query)
.setSize(1000)
@ -201,7 +201,7 @@ public class NativePrivilegeStore {
} else {
securityIndexManager.checkIndexVersionThenExecute(listener::onFailure,
() -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(application, name))
client.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, toDocId(application, name))
.request(),
new ActionListener<GetResponse>() {
@Override
@ -253,7 +253,7 @@ public class NativePrivilegeStore {
final String name = privilege.getName();
final XContentBuilder xContentBuilder = privilege.toXContent(jsonBuilder(), true);
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(privilege.getApplication(), name))
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, toDocId(privilege.getApplication(), name))
.setSource(xContentBuilder)
.setRefreshPolicy(refreshPolicy)
.request(), listener, client::index);
@ -284,7 +284,7 @@ public class NativePrivilegeStore {
}, listener::onFailure), names.size());
for (String name : names) {
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(application, name))
client.prepareDelete(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, toDocId(application, name))
.setRefreshPolicy(refreshPolicy)
.request(), groupListener, client::delete);
}

View File

@ -70,7 +70,7 @@ import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
import static org.elasticsearch.xpack.core.security.authz.RoleDescriptor.ROLE_TYPE;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
/**
* NativeRolesStore is a {@code RolesStore} that, instead of reading from a
@ -124,7 +124,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
QueryBuilder query = QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE);
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
SearchRequest request = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(query)
.setSize(1000)
@ -142,7 +142,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
final String[] roleIds = names.stream().map(NativeRolesStore::getIdForRole).toArray(String[]::new);
MultiGetRequest multiGetRequest = client.prepareMultiGet().add(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, roleIds).request();
MultiGetRequest multiGetRequest = client.prepareMultiGet().add(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, roleIds).request();
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, multiGetRequest,
ActionListener.<MultiGetResponse>wrap(mGetResponse -> {
final MultiGetItemResponse[] responses = mGetResponse.getResponses();
@ -179,7 +179,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
DeleteRequest request = client
.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(deleteRoleRequest.name())).request();
.prepareDelete(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForRole(deleteRoleRequest.name())).request();
request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<DeleteResponse>() {
@ -219,7 +219,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
listener.onFailure(e);
return;
}
final IndexRequest indexRequest = client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(role.getName()))
final IndexRequest indexRequest = client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForRole(role.getName()))
.setSource(xContentBuilder)
.setRefreshPolicy(request.getRefreshPolicy())
.request();
@ -253,11 +253,11 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareMultiSearch()
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
.setQuery(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
.setTrackTotalHits(true)
.setSize(0))
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
.setQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
.must(QueryBuilders.boolQuery()
@ -268,7 +268,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
.setTrackTotalHits(true)
.setSize(0)
.setTerminateAfter(1))
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
.setQuery(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
.filter(existsQuery("indices.query")))
@ -340,7 +340,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(role)).request(),
client.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, getIdForRole(role)).request(),
listener,
client::get));
}

View File

@ -53,6 +53,7 @@ import org.elasticsearch.xpack.core.template.TemplateUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -77,12 +78,13 @@ import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
*/
public class SecurityIndexManager implements ClusterStateListener {
public static final String INTERNAL_SECURITY_INDEX = RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7;
public static final int INTERNAL_INDEX_FORMAT = 6;
public static final int INTERNAL_MAIN_INDEX_FORMAT = 6;
public static final int INTERNAL_TOKENS_INDEX_FORMAT = 7;
public static final String SECURITY_MAIN_TEMPLATE_7 = "security-index-template-7";
public static final String SECURITY_TOKENS_TEMPLATE_7 = "security-tokens-index-template-7";
public static final String SECURITY_VERSION_STRING = "security-version";
public static final String TEMPLATE_VERSION_PATTERN = Pattern.quote("${security.template.version}");
public static final String SECURITY_TEMPLATE_NAME = "security-index-template";
public static final String SECURITY_INDEX_NAME = ".security";
private static final Logger logger = LogManager.getLogger(SecurityIndexManager.class);
private final String aliasName;
@ -95,19 +97,26 @@ public class SecurityIndexManager implements ClusterStateListener {
private volatile State indexState;
public static SecurityIndexManager buildSecurityIndexManager(Client client, ClusterService clusterService) {
return new SecurityIndexManager(client, SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX, INTERNAL_INDEX_FORMAT,
SecurityIndexManager::readSecurityTemplateAsBytes, clusterService);
public static SecurityIndexManager buildSecurityMainIndexManager(Client client, ClusterService clusterService) {
return new SecurityIndexManager(client, clusterService, RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7, INTERNAL_MAIN_INDEX_FORMAT,
() -> SecurityIndexManager.readTemplateAsBytes(SECURITY_MAIN_TEMPLATE_7));
}
private SecurityIndexManager(Client client, String aliasName, String internalIndexName, int internalIndexFormat,
Supplier<byte[]> mappingSourceSupplier, ClusterService clusterService) {
public static SecurityIndexManager buildSecurityTokensIndexManager(Client client, ClusterService clusterService) {
return new SecurityIndexManager(client, clusterService, RestrictedIndicesNames.SECURITY_TOKENS_ALIAS,
RestrictedIndicesNames.INTERNAL_SECURITY_TOKENS_INDEX_7, INTERNAL_TOKENS_INDEX_FORMAT,
() -> SecurityIndexManager.readTemplateAsBytes(SECURITY_TOKENS_TEMPLATE_7));
}
private SecurityIndexManager(Client client, ClusterService clusterService, String aliasName, String internalIndexName,
int internalIndexFormat, Supplier<byte[]> mappingSourceSupplier) {
this(client, aliasName, internalIndexName, internalIndexFormat, mappingSourceSupplier, State.UNRECOVERED_STATE);
clusterService.addListener(this);
}
private SecurityIndexManager(Client client, String aliasName, String internalIndexName, int internalIndexFormat,
Supplier<byte[]> mappingSourceSupplier, State indexState) {
Supplier<byte[]> mappingSourceSupplier, State indexState) {
this.aliasName = aliasName;
this.internalIndexName = internalIndexName;
this.internalIndexFormat = internalIndexFormat;
@ -126,8 +135,16 @@ public class SecurityIndexManager implements ClusterStateListener {
return currentIndexState.mappingVersion == null || requiredVersion.test(currentIndexState.mappingVersion);
}
public String aliasName() {
return aliasName;
}
public boolean indexExists() {
return this.indexState.indexExists;
return this.indexState.indexExists();
}
public Instant getCreationTime() {
return this.indexState.creationTime;
}
/**
@ -156,7 +173,7 @@ public class SecurityIndexManager implements ClusterStateListener {
throw new IllegalStateException("caller must make sure to use a frozen state and check indexAvailable");
}
if (localState.indexExists) {
if (localState.indexExists()) {
return new UnavailableShardsException(null,
"at least one primary shard for the index [" + localState.concreteIndexName + "] is unavailable");
} else {
@ -183,17 +200,17 @@ public class SecurityIndexManager implements ClusterStateListener {
}
final State previousState = indexState;
final IndexMetaData indexMetaData = resolveConcreteIndex(aliasName, event.state().metaData());
final boolean indexExists = indexMetaData != null;
final boolean isIndexUpToDate = indexExists == false ||
final Instant creationTime = indexMetaData != null ? Instant.ofEpochMilli(indexMetaData.getCreationDate()) : null;
final boolean isIndexUpToDate = indexMetaData == null ||
INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()).intValue() == internalIndexFormat;
final boolean indexAvailable = checkIndexAvailable(event.state());
final boolean mappingIsUpToDate = indexExists == false || checkIndexMappingUpToDate(event.state());
final boolean mappingIsUpToDate = indexMetaData == null || checkIndexMappingUpToDate(event.state());
final Version mappingVersion = oldestIndexMappingVersion(event.state());
final ClusterHealthStatus indexStatus = indexMetaData == null ? null :
new ClusterIndexHealth(indexMetaData, event.state().getRoutingTable().index(indexMetaData.getIndex())).getStatus();
final String concreteIndexName = indexMetaData == null ? internalIndexName : indexMetaData.getIndex().getName();
final State newState = new State(indexExists, isIndexUpToDate, indexAvailable, mappingIsUpToDate, mappingVersion, concreteIndexName,
indexStatus);
final State newState = new State(creationTime, isIndexUpToDate, indexAvailable, mappingIsUpToDate, mappingVersion,
concreteIndexName, indexStatus);
this.indexState = newState;
if (newState.equals(previousState) == false) {
@ -304,7 +321,7 @@ public class SecurityIndexManager implements ClusterStateListener {
*/
public void checkIndexVersionThenExecute(final Consumer<Exception> consumer, final Runnable andThen) {
final State indexState = this.indexState; // use a local copy so all checks execute against the same state!
if (indexState.indexExists && indexState.isIndexUpToDate == false) {
if (indexState.indexExists() && indexState.isIndexUpToDate == false) {
consumer.accept(new IllegalStateException(
"Index [" + indexState.concreteIndexName + "] is not on the current version. Security features relying on the index"
+ " will not be available until the upgrade API is run on the index"));
@ -324,11 +341,11 @@ public class SecurityIndexManager implements ClusterStateListener {
consumer.accept(new ElasticsearchStatusException(
"Cluster state has not been recovered yet, cannot write to the [" + indexState.concreteIndexName + "] index",
RestStatus.SERVICE_UNAVAILABLE));
} else if (indexState.indexExists && indexState.isIndexUpToDate == false) {
} else if (indexState.indexExists() && indexState.isIndexUpToDate == false) {
consumer.accept(new IllegalStateException(
"Index [" + indexState.concreteIndexName + "] is not on the current version."
+ "Security features relying on the index will not be available until the upgrade API is run on the index"));
} else if (indexState.indexExists == false) {
} else if (indexState.indexExists() == false) {
assert indexState.concreteIndexName != null;
logger.info("security index does not exist. Creating [{}] with alias [{}]", indexState.concreteIndexName, this.aliasName);
final byte[] mappingSource = mappingSourceSupplier.get();
@ -396,8 +413,8 @@ public class SecurityIndexManager implements ClusterStateListener {
return previousState.indexStatus != null && currentState.indexStatus == null;
}
private static byte[] readSecurityTemplateAsBytes() {
return TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json", Version.CURRENT.toString(),
private static byte[] readTemplateAsBytes(String templateName) {
return TemplateUtils.loadTemplate("/" + templateName + ".json", Version.CURRENT.toString(),
SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
}
@ -423,8 +440,8 @@ public class SecurityIndexManager implements ClusterStateListener {
* State of the security index.
*/
public static class State {
public static final State UNRECOVERED_STATE = new State(false, false, false, false, null, null, null);
public final boolean indexExists;
public static final State UNRECOVERED_STATE = new State(null, false, false, false, null, null, null);
public final Instant creationTime;
public final boolean isIndexUpToDate;
public final boolean indexAvailable;
public final boolean mappingUpToDate;
@ -432,9 +449,9 @@ public class SecurityIndexManager implements ClusterStateListener {
public final String concreteIndexName;
public final ClusterHealthStatus indexStatus;
public State(boolean indexExists, boolean isIndexUpToDate, boolean indexAvailable,
public State(Instant creationTime, boolean isIndexUpToDate, boolean indexAvailable,
boolean mappingUpToDate, Version mappingVersion, String concreteIndexName, ClusterHealthStatus indexStatus) {
this.indexExists = indexExists;
this.creationTime = creationTime;
this.isIndexUpToDate = isIndexUpToDate;
this.indexAvailable = indexAvailable;
this.mappingUpToDate = mappingUpToDate;
@ -448,7 +465,7 @@ public class SecurityIndexManager implements ClusterStateListener {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
State state = (State) o;
return indexExists == state.indexExists &&
return Objects.equals(creationTime, state.creationTime) &&
isIndexUpToDate == state.isIndexUpToDate &&
indexAvailable == state.indexAvailable &&
mappingUpToDate == state.mappingUpToDate &&
@ -457,9 +474,13 @@ public class SecurityIndexManager implements ClusterStateListener {
indexStatus == state.indexStatus;
}
public boolean indexExists() {
return creationTime != null;
}
@Override
public int hashCode() {
return Objects.hash(indexExists, isIndexUpToDate, indexAvailable, mappingUpToDate, mappingVersion, concreteIndexName,
return Objects.hash(creationTime, isIndexUpToDate, indexAvailable, mappingUpToDate, mappingVersion, concreteIndexName,
indexStatus);
}
}

View File

@ -13,8 +13,8 @@ import org.elasticsearch.xpack.core.security.action.role.GetRolesResponse;
import org.elasticsearch.xpack.core.security.action.role.PutRoleResponse;
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.junit.Before;
import org.junit.BeforeClass;
@ -56,7 +56,7 @@ public class ClearRolesCacheTests extends NativeRealmIntegTestCase {
logger.debug("--> created role [{}]", role);
}
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
final Set<String> rolesSet = new HashSet<>(Arrays.asList(roles));
// warm up the caches on every node

View File

@ -59,7 +59,7 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
@Override
public Set<String> excludeTemplates() {
Set<String> templates = Sets.newHashSet(super.excludeTemplates());
templates.add(SecurityIndexManager.SECURITY_TEMPLATE_NAME); // don't remove the security index template
templates.add(SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7); // don't remove the security index template
return templates;
}

View File

@ -67,7 +67,7 @@ import static org.elasticsearch.test.SecuritySettingsSourceField.TEST_PASSWORD_S
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
@ -491,7 +491,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject();
assertTrue("security index mapping not sufficient to read:\n" +
Strings.toString(clusterState.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject()),
SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger,
SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_MAIN_ALIAS, clusterState, logger,
Version.CURRENT.minimumIndexCompatibilityVersion()::onOrBefore));
Index securityIndex = resolveSecurityIndex(clusterState.metaData());
if (securityIndex != null) {
@ -509,7 +509,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_SUPERUSER,
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
GetIndexRequest getIndexRequest = new GetIndexRequest();
getIndexRequest.indices(SECURITY_INDEX_NAME);
getIndexRequest.indices(SECURITY_MAIN_ALIAS);
getIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
GetIndexResponse getIndexResponse = client.admin().indices().getIndex(getIndexRequest).actionGet();
if (getIndexResponse.getIndices().length > 0) {
@ -520,7 +520,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
}
private static Index resolveSecurityIndex(MetaData metaData) {
final AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(SECURITY_INDEX_NAME);
final AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(SECURITY_MAIN_ALIAS);
if (aliasOrIndex != null) {
return aliasOrIndex.getIndices().get(0).getIndex();
}

View File

@ -68,8 +68,8 @@ import java.util.stream.Collectors;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
import static org.elasticsearch.discovery.DiscoveryModule.ZEN2_DISCOVERY_TYPE;
import static org.elasticsearch.discovery.DiscoveryModule.ZEN_DISCOVERY_TYPE;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
@ -310,8 +310,8 @@ public class SecurityTests extends ESTestCase {
BiConsumer<DiscoveryNode, ClusterState> joinValidator = security.getJoinValidator();
assertNotNull(joinValidator);
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT - 1))
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_MAIN_INDEX_FORMAT - 1))
.numberOfShards(1).numberOfReplicas(0)
.build();
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), Version.V_6_1_0);
@ -330,8 +330,8 @@ public class SecurityTests extends ESTestCase {
BiConsumer<DiscoveryNode, ClusterState> joinValidator = security.getJoinValidator();
assertNotNull(joinValidator);
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
int indexFormat = randomBoolean() ? INTERNAL_INDEX_FORMAT : INTERNAL_INDEX_FORMAT - 1;
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
int indexFormat = randomBoolean() ? INTERNAL_MAIN_INDEX_FORMAT : INTERNAL_MAIN_INDEX_FORMAT - 1;
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), indexFormat))
.numberOfShards(1).numberOfReplicas(0)
.build();
@ -349,8 +349,8 @@ public class SecurityTests extends ESTestCase {
assertNotNull(joinValidator);
Version version = randomBoolean() ? Version.CURRENT : Version.V_6_1_0;
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT))
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_MAIN_INDEX_FORMAT))
.numberOfShards(1).numberOfReplicas(0)
.build();
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), version);

View File

@ -167,7 +167,7 @@ public class TransportOpenIdConnectLogoutActionTests extends OpenIdConnectTestCa
when(securityIndex.isAvailable()).thenReturn(true);
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, clusterService);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, securityIndex, clusterService);
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());

View File

@ -195,10 +195,13 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase {
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
when(securityIndex.isAvailable()).thenReturn(true);
when(securityIndex.indexExists()).thenReturn(true);
when(securityIndex.isIndexUpToDate()).thenReturn(true);
when(securityIndex.getCreationTime()).thenReturn(Clock.systemUTC().instant());
when(securityIndex.aliasName()).thenReturn(".security");
when(securityIndex.freeze()).thenReturn(securityIndex);
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, clusterService);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, securityIndex, clusterService);
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
@ -308,7 +311,8 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase {
assertThat(filter1.get(1), instanceOf(TermQueryBuilder.class));
assertThat(((TermQueryBuilder) filter1.get(1)).fieldName(), equalTo("refresh_token.token"));
assertThat(((TermQueryBuilder) filter1.get(1)).value(), equalTo(tokenToInvalidate1.v2()));
assertThat(((TermQueryBuilder) filter1.get(1)).value(),
equalTo(TokenService.unpackVersionAndPayload(tokenToInvalidate1.v2()).v2()));
assertThat(bulkRequests.size(), equalTo(4)); // 4 updates (refresh-token + access-token)
// Invalidate refresh token 1

View File

@ -203,7 +203,7 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
when(securityIndex.isAvailable()).thenReturn(true);
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, clusterService);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, securityIndex, clusterService);
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());

View File

@ -147,7 +147,8 @@ public class TransportCreateTokenActionTests extends ESTestCase {
}
public void testClientCredentialsCreatesWithoutRefreshToken() throws Exception {
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, securityIndex, clusterService);
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, securityIndex, securityIndex,
clusterService);
Authentication authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
authentication.writeToContext(threadPool.getThreadContext());
@ -171,7 +172,8 @@ public class TransportCreateTokenActionTests extends ESTestCase {
}
public void testPasswordGrantTypeCreatesWithRefreshToken() throws Exception {
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, securityIndex, clusterService);
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, securityIndex, securityIndex,
clusterService);
Authentication authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
authentication.writeToContext(threadPool.getThreadContext());

View File

@ -34,7 +34,6 @@ import org.elasticsearch.xpack.core.security.action.InvalidateApiKeyResponse;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.junit.After;
import org.junit.Before;
@ -53,7 +52,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
@ -336,7 +335,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
Instant dayBefore = created.minus(1L, ChronoUnit.DAYS);
assertTrue(Instant.now().isAfter(dayBefore));
UpdateResponse expirationDateUpdatedResponse = client
.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, createdApiKeys.get(0).getId())
.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, createdApiKeys.get(0).getId())
.setDoc("expiration_time", dayBefore.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
@ -346,7 +345,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
// hack doc to modify the expiration time to the week before
Instant weekBefore = created.minus(8L, ChronoUnit.DAYS);
assertTrue(Instant.now().isAfter(weekBefore));
expirationDateUpdatedResponse = client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, createdApiKeys.get(1).getId())
expirationDateUpdatedResponse = client.prepareUpdate(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, createdApiKeys.get(1).getId())
.setDoc("expiration_time", weekBefore.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
@ -390,8 +389,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
private void refreshSecurityIndex() throws Exception {
assertBusy(() -> {
final RefreshResponse refreshResponse = client().admin().indices().prepareRefresh(SecurityIndexManager.SECURITY_INDEX_NAME)
.get();
final RefreshResponse refreshResponse = client().admin().indices().prepareRefresh(SECURITY_MAIN_ALIAS).get();
assertThat(refreshResponse.getFailedShards(), is(0));
});
}

View File

@ -154,7 +154,7 @@ public class AuthenticationServiceTests extends ESTestCase {
@SuppressForbidden(reason = "Allow accessing localhost")
public void init() throws Exception {
concreteSecurityIndexName = randomFrom(
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
token = mock(AuthenticationToken.class);
when(token.principal()).thenReturn(randomAlphaOfLength(5));
@ -220,7 +220,7 @@ public class AuthenticationServiceTests extends ESTestCase {
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, securityIndex, clusterService, threadPool);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, clusterService);
tokenService = new TokenService(settings, Clock.systemUTC(), client, securityIndex, securityIndex, clusterService);
service = new AuthenticationService(settings, realms, auditTrail, new DefaultAuthenticationFailureHandler(Collections.emptyMap()),
threadPool, new AnonymousUser(settings), tokenService, apiKeyService);
}
@ -1394,6 +1394,6 @@ public class AuthenticationServiceTests extends ESTestCase {
}
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
return new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, indexStatus);
return new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, indexStatus);
}
}

View File

@ -36,7 +36,7 @@ import org.elasticsearch.xpack.core.security.action.user.AuthenticateResponse;
import org.elasticsearch.xpack.core.security.authc.TokenMetaData;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.junit.After;
import org.junit.Before;
@ -55,7 +55,6 @@ import java.util.stream.Collectors;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.hamcrest.Matchers.equalTo;
@TestLogging("org.elasticsearch.xpack.security.authz.store.FileRolesStore:DEBUG")
@ -161,7 +160,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
assertThat(invalidateResponse.getResult().getErrors().size(), equalTo(0));
AtomicReference<String> docId = new AtomicReference<>();
assertBusy(() -> {
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
.setSource(SearchSourceBuilder.searchSource()
.query(QueryBuilders.termQuery("doc_type", "token")))
.setSize(1)
@ -174,7 +173,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
// hack doc to modify the creation time to the day before
Instant yesterday = created.minus(36L, ChronoUnit.HOURS);
assertTrue(Instant.now().isAfter(yesterday));
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, docId.get())
client.prepareUpdate(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS, SINGLE_MAPPING_NAME, docId.get())
.setDoc("creation_time", yesterday.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
@ -192,8 +191,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
assertEquals("token malformed", e.getMessage());
}
}
client.admin().indices().prepareRefresh(SecurityIndexManager.SECURITY_INDEX_NAME).get();
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
client.admin().indices().prepareRefresh(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS).get();
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
.setSource(SearchSourceBuilder.searchSource()
.query(QueryBuilders.termQuery("doc_type", "token")))
.setTerminateAfter(1)
@ -358,10 +357,10 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
// We now have two documents, the original(now refreshed) token doc and the new one with the new access doc
AtomicReference<String> docId = new AtomicReference<>();
assertBusy(() -> {
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
.setSource(SearchSourceBuilder.searchSource()
.query(QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("doc_type", "token"))
.must(QueryBuilders.termQuery("doc_type", TokenService.TOKEN_DOC_TYPE))
.must(QueryBuilders.termQuery("refresh_token.refreshed", "true"))))
.setSize(1)
.setTerminateAfter(1)
@ -374,7 +373,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
Instant refreshed = Instant.now();
Instant aWhileAgo = refreshed.minus(50L, ChronoUnit.SECONDS);
assertTrue(Instant.now().isAfter(aWhileAgo));
UpdateResponse updateResponse = client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, docId.get())
UpdateResponse updateResponse = client.prepareUpdate(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS, SINGLE_MAPPING_NAME, docId.get())
.setDoc("refresh_token", Collections.singletonMap("refresh_time", aWhileAgo.toEpochMilli()))
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.setFetchSource("refresh_token", Strings.EMPTY_STRING)

View File

@ -21,6 +21,9 @@ import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.action.update.UpdateAction;
import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.UUIDs;
@ -51,6 +54,7 @@ import org.elasticsearch.xpack.core.security.authc.support.TokensInvalidationRes
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -74,6 +78,7 @@ import javax.crypto.SecretKey;
import static java.time.Clock.systemUTC;
import static org.elasticsearch.repositories.ESBlobStoreTestCase.randomBytes;
import static org.elasticsearch.test.ClusterServiceUtils.setState;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -92,8 +97,10 @@ public class TokenServiceTests extends ESTestCase {
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
private Client client;
private SecurityIndexManager securityIndex;
private SecurityIndexManager securityMainIndex;
private SecurityIndexManager securityTokensIndex;
private ClusterService clusterService;
private DiscoveryNode oldNode;
private Settings tokenServiceEnabledSettings = Settings.builder()
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
@ -121,20 +128,21 @@ public class TokenServiceTests extends ESTestCase {
}).when(client).execute(eq(IndexAction.INSTANCE), any(IndexRequest.class), any(ActionListener.class));
// setup lifecycle service
securityIndex = mock(SecurityIndexManager.class);
doAnswer(invocationOnMock -> {
Runnable runnable = (Runnable) invocationOnMock.getArguments()[1];
runnable.run();
return null;
}).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class));
doAnswer(invocationOnMock -> {
Runnable runnable = (Runnable) invocationOnMock.getArguments()[1];
runnable.run();
return null;
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
when(securityIndex.indexExists()).thenReturn(true);
when(securityIndex.isAvailable()).thenReturn(true);
this.securityMainIndex = mockSecurityManager();
this.securityTokensIndex = mockSecurityManager();
this.clusterService = ClusterServiceUtils.createClusterService(threadPool);
// version 7.1 was an "inflection" point in the Token Service development (access_tokens as UUIDS, multiple concurrent refreshes,
// tokens docs on a separate index), let's test the TokenService works in a mixed cluster with nodes with versions prior to these
// developments
if (randomBoolean()) {
oldNode = addAnotherDataNodeWithVersion(this.clusterService, randomFrom(Version.V_6_7_0, Version.V_7_0_0));
}
}
@After
public void tearDown() throws Exception {
super.tearDown();
clusterService.close();
}
@BeforeClass
@ -151,7 +159,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testAttachAndGetToken() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -172,8 +181,8 @@ public class TokenServiceTests extends ESTestCase {
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
// verify a second separate token service with its own salt can also verify
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex
, clusterService);
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
anotherService.refreshMetaData(tokenService.getTokenMetaData());
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
anotherService.getAndValidateToken(requestContext, future);
@ -183,7 +192,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testInvalidAuthorizationHeader() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
String token = randomFrom("", " ");
String authScheme = randomFrom("Bearer ", "BEARER ", "bearer ", "Basic ");
@ -198,7 +208,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testRotateKey() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -251,12 +262,14 @@ public class TokenServiceTests extends ESTestCase {
}
public void testKeyExchange() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
int numRotations = randomIntBetween(1, 5);
for (int i = 0; i < numRotations; i++) {
rotateKeys(tokenService);
}
TokenService otherTokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService otherTokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
otherTokenService.refreshMetaData(tokenService.getTokenMetaData());
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
@ -272,7 +285,7 @@ public class TokenServiceTests extends ESTestCase {
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
otherTokenService.getAndValidateToken(requestContext, future);
UserToken serialized = future.get();
assertAuthentication(authentication, serialized.getAuthentication());
assertEquals(authentication, serialized.getAuthentication());
}
rotateKeys(tokenService);
@ -288,7 +301,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testPruneKeys() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -350,7 +364,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testPassphraseWorks() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -371,8 +386,8 @@ public class TokenServiceTests extends ESTestCase {
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
// verify a second separate token service with its own passphrase cannot verify
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex,
clusterService);
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
anotherService.getAndValidateToken(requestContext, future);
assertNull(future.get());
@ -380,7 +395,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testGetTokenWhenKeyCacheHasExpired() throws Exception {
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
@ -393,9 +409,9 @@ public class TokenServiceTests extends ESTestCase {
}
public void testInvalidatedToken() throws Exception {
when(securityIndex.indexExists()).thenReturn(true);
TokenService tokenService =
new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
when(securityMainIndex.indexExists()).thenReturn(true);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -449,7 +465,8 @@ public class TokenServiceTests extends ESTestCase {
public void testTokenExpiry() throws Exception {
ClockMock clock = ClockMock.frozen();
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, clock, client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, clock, client, securityMainIndex, securityTokensIndex,
clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -502,7 +519,7 @@ public class TokenServiceTests extends ESTestCase {
TokenService tokenService = new TokenService(Settings.builder()
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false)
.build(),
Clock.systemUTC(), client, securityIndex, clusterService);
Clock.systemUTC(), client, securityMainIndex, securityTokensIndex, clusterService);
IllegalStateException e = expectThrows(IllegalStateException.class,
() -> tokenService.createOAuth2Tokens(null, null, null, true, null));
assertEquals("tokens are not enabled", e.getMessage());
@ -545,7 +562,8 @@ public class TokenServiceTests extends ESTestCase {
final int numBytes = randomIntBetween(1, TokenService.MINIMUM_BYTES + 32);
final byte[] randomBytes = new byte[numBytes];
random().nextBytes(randomBytes);
TokenService tokenService = new TokenService(Settings.EMPTY, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(Settings.EMPTY, systemUTC(), client, securityMainIndex, securityTokensIndex,
clusterService);
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
requestContext.putHeader("Authorization", "Bearer " + Base64.getEncoder().encodeToString(randomBytes));
@ -558,8 +576,8 @@ public class TokenServiceTests extends ESTestCase {
}
public void testIndexNotAvailable() throws Exception {
TokenService tokenService =
new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
@ -576,34 +594,44 @@ public class TokenServiceTests extends ESTestCase {
return Void.TYPE;
}).when(client).get(any(GetRequest.class), any(ActionListener.class));
final SecurityIndexManager tokensIndex;
if (oldNode != null) {
tokensIndex = securityMainIndex;
when(securityTokensIndex.isAvailable()).thenReturn(false);
when(securityTokensIndex.indexExists()).thenReturn(false);
} else {
tokensIndex = securityTokensIndex;
when(securityMainIndex.isAvailable()).thenReturn(false);
when(securityMainIndex.indexExists()).thenReturn(false);
}
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
tokenService.getAndValidateToken(requestContext, future);
assertNull(future.get());
when(securityIndex.isAvailable()).thenReturn(false);
when(securityIndex.indexExists()).thenReturn(true);
when(tokensIndex.isAvailable()).thenReturn(false);
when(tokensIndex.indexExists()).thenReturn(true);
future = new PlainActionFuture<>();
tokenService.getAndValidateToken(requestContext, future);
assertNull(future.get());
when(securityIndex.indexExists()).thenReturn(false);
when(tokensIndex.indexExists()).thenReturn(false);
future = new PlainActionFuture<>();
tokenService.getAndValidateToken(requestContext, future);
assertNull(future.get());
when(securityIndex.isAvailable()).thenReturn(true);
when(securityIndex.indexExists()).thenReturn(true);
when(tokensIndex.isAvailable()).thenReturn(true);
when(tokensIndex.indexExists()).thenReturn(true);
mockGetTokenFromId(token, false);
future = new PlainActionFuture<>();
tokenService.getAndValidateToken(requestContext, future);
assertEquals(token.getAuthentication(), future.get().getAuthentication());
assertEquals(future.get().getAuthentication(), token.getAuthentication());
}
}
public void testGetAuthenticationWorksWithExpiredUserToken() throws Exception {
TokenService tokenService =
new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, securityIndex, clusterService);
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, securityMainIndex,
securityTokensIndex, clusterService);
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
UserToken expired = new UserToken(authentication, Instant.now().minus(3L, ChronoUnit.DAYS));
mockGetTokenFromId(expired, false);
@ -672,4 +700,33 @@ public class TokenServiceTests extends ESTestCase {
}
}
private SecurityIndexManager mockSecurityManager() {
SecurityIndexManager mockSecurityIndex = mock(SecurityIndexManager.class);
doAnswer(invocationOnMock -> {
Runnable runnable = (Runnable) invocationOnMock.getArguments()[1];
runnable.run();
return null;
}).when(mockSecurityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class));
doAnswer(invocationOnMock -> {
Runnable runnable = (Runnable) invocationOnMock.getArguments()[1];
runnable.run();
return null;
}).when(mockSecurityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
when(mockSecurityIndex.indexExists()).thenReturn(true);
when(mockSecurityIndex.isAvailable()).thenReturn(true);
return mockSecurityIndex;
}
private DiscoveryNode addAnotherDataNodeWithVersion(ClusterService clusterService, Version version) {
final ClusterState currentState = clusterService.state();
final DiscoveryNodes.Builder discoBuilder = DiscoveryNodes.builder(currentState.getNodes());
final DiscoveryNode anotherDataNode = new DiscoveryNode("another_data_node#" + version, buildNewFakeTransportAddress(),
Collections.emptyMap(), Collections.singleton(DiscoveryNode.Role.DATA), version);
discoBuilder.add(anotherDataNode);
final ClusterState.Builder newStateBuilder = ClusterState.builder(currentState);
newStateBuilder.nodes(discoBuilder);
setState(clusterService, newStateBuilder.build());
return anotherDataNode;
}
}

View File

@ -15,7 +15,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.common.CharArrays;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.junit.BeforeClass;
import java.nio.charset.StandardCharsets;
@ -85,7 +85,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
addedUsers.add(uname);
}
logger.error("--> waiting for .security index");
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
MockTerminal t = new MockTerminal();
String username = nodeClientUsername();
@ -136,7 +136,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
addedRoles.add(rname);
}
logger.error("--> waiting for .security index");
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
MockTerminal t = new MockTerminal();
String username = nodeClientUsername();

View File

@ -45,13 +45,13 @@ import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
import org.elasticsearch.xpack.core.security.user.ElasticUser;
import org.elasticsearch.xpack.core.security.user.KibanaUser;
import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.junit.Before;
import org.junit.BeforeClass;
@ -67,8 +67,8 @@ import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDI
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.contains;
@ -146,7 +146,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
logger.error("--> creating user");
c.preparePutUser("joe", "s3kirt".toCharArray(), hasher, "role1", "user").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
@ -201,7 +201,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
.metadata(metadata)
.get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> retrieving role");
GetRolesResponse resp = c.prepareGetRoles().names("test_role").get();
assertTrue("role should exist", resp.hasRoles());
@ -252,7 +252,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
@ -273,7 +273,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, SecuritySettingsSource.TEST_ROLE).get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
@ -309,7 +309,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
c.preparePutUser("joe", "s3krit".toCharArray(), hasher,
SecuritySettingsSource.TEST_ROLE).get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
@ -347,7 +347,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
if (authenticate) {
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
@ -396,7 +396,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
logger.error("--> creating user");
securityClient().preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role", "snapshot_user").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
logger.info("--> creating repository");
assertAcked(client().admin().cluster()
.preparePutRepository("test-repo")
@ -410,10 +410,10 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
.prepareCreateSnapshot("test-repo", "test-snap-1")
.setWaitForCompletion(true)
.setIncludeGlobalState(false)
.setIndices(SECURITY_INDEX_NAME)
.setIndices(SECURITY_MAIN_ALIAS)
.get().getSnapshotInfo();
assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
assertThat(snapshotInfo.indices(), contains(SecurityIndexManager.INTERNAL_SECURITY_INDEX));
assertThat(snapshotInfo.indices(), contains(INTERNAL_SECURITY_MAIN_INDEX_7));
deleteSecurityIndex();
// the realm cache should clear itself but we don't wish to race it
securityClient().prepareClearRealmCache().get();
@ -430,7 +430,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
RestoreSnapshotResponse response = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-1")
.setWaitForCompletion(true).setIncludeAliases(true).get();
assertThat(response.status(), equalTo(RestStatus.OK));
assertThat(response.getRestoreInfo().indices(), contains(SecurityIndexManager.INTERNAL_SECURITY_INDEX));
assertThat(response.getRestoreInfo().indices(), contains(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7));
// the realm cache should clear itself but we don't wish to race it
securityClient().prepareClearRealmCache().get();
// users and roles are retrievable
@ -460,7 +460,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
.get();
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
ensureGreen(SECURITY_MAIN_ALIAS);
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
@ -591,12 +591,12 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
.get();
}
IndicesStatsResponse response = client().admin().indices().prepareStats("foo", SECURITY_INDEX_NAME).get();
IndicesStatsResponse response = client().admin().indices().prepareStats("foo", SECURITY_MAIN_ALIAS).get();
assertThat(response.getFailedShards(), is(0));
assertThat(response.getIndices().size(), is(2));
assertThat(response.getIndices().get(INTERNAL_SECURITY_INDEX), notNullValue());
assertThat(response.getIndices().get(INTERNAL_SECURITY_INDEX).getIndex(),
is(INTERNAL_SECURITY_INDEX));
assertThat(response.getIndices().get(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7), notNullValue());
assertThat(response.getIndices().get(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7).getIndex(),
is(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7));
}
public void testOperationsOnReservedUsers() throws Exception {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;
import static org.mockito.Mockito.mock;
@ -23,10 +24,10 @@ import static org.mockito.Mockito.when;
public class NativeRealmTests extends ESTestCase {
private final String concreteSecurityIndexName = randomFrom(
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
return new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, indexStatus);
return new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, indexStatus);
}
public void testCacheClearOnIndexHealthChange() {

View File

@ -27,6 +27,7 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.core.security.user.APMSystemUser;
import org.elasticsearch.xpack.core.security.user.BeatsSystemUser;
import org.elasticsearch.xpack.core.security.user.ElasticUser;
@ -111,7 +112,7 @@ public class NativeUsersStoreTests extends ESTestCase {
values.put(PASSWORD_FIELD, BLANK_PASSWORD);
final GetResult result = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.RESERVED_USER_TYPE, randomAlphaOfLength(12)),
0, 1, 1L,
@ -180,7 +181,7 @@ public class NativeUsersStoreTests extends ESTestCase {
nativeUsersStore.verifyPassword(username, password, future);
final GetResult getResult = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
UNASSIGNED_SEQ_NO, 0, 1L,
@ -222,7 +223,7 @@ public class NativeUsersStoreTests extends ESTestCase {
values.put(User.Fields.TYPE.getPreferredName(), NativeUsersStore.USER_DOC_TYPE);
final BytesReference source = BytesReference.bytes(jsonBuilder().map(values));
final GetResult getResult = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
0, 1, 1L,
@ -230,7 +231,6 @@ public class NativeUsersStoreTests extends ESTestCase {
source,
Collections.emptyMap());
actionRespond(GetRequest.class, new GetResponse(getResult));
}

View File

@ -37,6 +37,7 @@ import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.hamcrest.Matchers;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -53,7 +54,7 @@ import static org.mockito.Mockito.when;
public class NativeRoleMappingStoreTests extends ESTestCase {
private final String concreteSecurityIndexName = randomFrom(
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
public void testResolveRoles() throws Exception {
// Does match DN
@ -137,7 +138,7 @@ public class NativeRoleMappingStoreTests extends ESTestCase {
}
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
return new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, indexStatus);
return new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, indexStatus);
}
public void testCacheClearOnIndexHealthChange() {
@ -182,13 +183,13 @@ public class NativeRoleMappingStoreTests extends ESTestCase {
final NativeRoleMappingStore store = buildRoleMappingStoreForInvalidationTesting(numInvalidation);
store.onSecurityIndexStateChange(
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null));
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null));
assertEquals(1, numInvalidation.get());
store.onSecurityIndexStateChange(
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null));
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null));
assertEquals(2, numInvalidation.get());
}

View File

@ -156,8 +156,8 @@ import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationExce
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationException;
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationExceptionRunAs;
import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
@ -864,8 +864,8 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1)
.numberOfReplicas(0)
@ -874,31 +874,33 @@ public class AuthorizationServiceTests extends ESTestCase {
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
requests.add(
new Tuple<>(BulkAction.NAME + "[s]", new DeleteRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
requests.add(new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
requests.add(
new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(TermVectorsAction.NAME,
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "type", "id")));
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest()
.addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_INDEX))));
.addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(UpdateSettingsAction.NAME,
new UpdateSettingsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new UpdateSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
// cannot execute monitor operations
requests.add(new Tuple<>(IndicesStatsAction.NAME,
new IndicesStatsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
requests.add(
new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new IndicesStatsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(RecoveryAction.NAME,
new RecoveryRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(IndicesSegmentsAction.NAME,
new IndicesSegmentsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new IndicesSegmentsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(GetSettingsAction.NAME,
new GetSettingsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new GetSettingsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(IndicesShardStoresAction.NAME,
new IndicesShardStoresRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new IndicesShardStoresRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(UpgradeStatusAction.NAME,
new UpgradeStatusRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new UpgradeStatusRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
for (Tuple<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
@ -912,13 +914,13 @@ public class AuthorizationServiceTests extends ESTestCase {
}
// we should allow waiting for the health of the index or any index if the user has this permission
ClusterHealthRequest request = new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX));
ClusterHealthRequest request = new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7));
authorize(authentication, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
authzInfoRoles(new String[]{role.getName()}));
// multiple indices
request = new ClusterHealthRequest(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX, "foo", "bar");
request = new ClusterHealthRequest(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7, "foo", "bar");
authorize(authentication, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
authzInfoRoles(new String[]{role.getName()}));
@ -940,8 +942,8 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1)
.numberOfReplicas(0)
@ -949,12 +951,12 @@ public class AuthorizationServiceTests extends ESTestCase {
.build());
List<Tuple<String, ? extends TransportRequest>> requests = new ArrayList<>();
requests.add(new Tuple<>(IndicesStatsAction.NAME, new IndicesStatsRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(IndicesSegmentsAction.NAME, new IndicesSegmentsRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(GetSettingsAction.NAME, new GetSettingsRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(IndicesShardStoresAction.NAME, new IndicesShardStoresRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(UpgradeStatusAction.NAME, new UpgradeStatusRequest().indices(SECURITY_INDEX_NAME)));
requests.add(new Tuple<>(IndicesStatsAction.NAME, new IndicesStatsRequest().indices(SECURITY_MAIN_ALIAS)));
requests.add(new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(SECURITY_MAIN_ALIAS)));
requests.add(new Tuple<>(IndicesSegmentsAction.NAME, new IndicesSegmentsRequest().indices(SECURITY_MAIN_ALIAS)));
requests.add(new Tuple<>(GetSettingsAction.NAME, new GetSettingsRequest().indices(SECURITY_MAIN_ALIAS)));
requests.add(new Tuple<>(IndicesShardStoresAction.NAME, new IndicesShardStoresRequest().indices(SECURITY_MAIN_ALIAS)));
requests.add(new Tuple<>(UpgradeStatusAction.NAME, new UpgradeStatusRequest().indices(SECURITY_MAIN_ALIAS)));
for (final Tuple<String, ? extends TransportRequest> requestTuple : requests) {
final String action = requestTuple.v1();
@ -984,8 +986,8 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1)
.numberOfReplicas(0)
@ -994,25 +996,28 @@ public class AuthorizationServiceTests extends ESTestCase {
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
requests.add(new Tuple<>(DeleteAction.NAME, new DeleteRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
createBulkShardRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), DeleteRequest::new)));
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
createBulkShardRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), IndexRequest::new)));
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
requests.add(new Tuple<>(TermVectorsAction.NAME,
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
requests.add(new Tuple<>(TermVectorsAction.NAME,
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
requests.add(new Tuple<>(IndicesAliasesAction.NAME,
new IndicesAliasesRequest().addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_INDEX))));
requests.add(
new Tuple<>(ClusterHealthAction.NAME, new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
new Tuple<>(DeleteAction.NAME, new DeleteRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), DeleteRequest::new)));
requests.add(
new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
requests.add(new Tuple<>(IndexAction.NAME, new IndexRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(BulkAction.NAME + "[s]",
createBulkShardRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), IndexRequest::new)));
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(TermVectorsAction.NAME,
new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "type", "id")));
requests.add(
new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "type", "id")));
requests.add(new Tuple<>(TermVectorsAction.NAME,
new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "type", "id")));
requests.add(new Tuple<>(IndicesAliasesAction.NAME, new IndicesAliasesRequest()
.addAliasAction(AliasActions.add().alias("security_alias").index(INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(ClusterHealthAction.NAME,
new ClusterHealthRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "foo", "bar")));
new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
requests.add(new Tuple<>(ClusterHealthAction.NAME,
new ClusterHealthRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "foo", "bar")));
for (final Tuple<String, TransportRequest> requestTuple : requests) {
final String action = requestTuple.v1();
@ -1033,8 +1038,8 @@ public class AuthorizationServiceTests extends ESTestCase {
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1)
.numberOfReplicas(0)
@ -1046,7 +1051,7 @@ public class AuthorizationServiceTests extends ESTestCase {
SearchRequest request = new SearchRequest("_all");
authorize(authentication, action, request);
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(superuser.roles()));
assertThat(request.indices(), arrayContainingInAnyOrder(INTERNAL_SECURITY_INDEX, SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContainingInAnyOrder(INTERNAL_SECURITY_MAIN_INDEX_7, SECURITY_MAIN_ALIAS));
}
public void testCompositeActionsAreImmediatelyRejected() {

View File

@ -24,7 +24,6 @@ import org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import java.util.List;
import java.util.Set;
@ -47,8 +46,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
RoleDescriptor bRole = new RoleDescriptor("b", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("READ").build() }, null);
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
MetaData metaData = MetaData.builder()
.put(new IndexMetaData.Builder("a1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
.put(new IndexMetaData.Builder("a2").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
@ -65,7 +64,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
final PlainActionFuture<Role> future = new PlainActionFuture<>();
@ -78,7 +77,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
assertFalse(list.contains("bbbbb"));
assertFalse(list.contains("ba"));
assertThat(list, not(contains(internalSecurityIndex)));
assertThat(list, not(contains(RestrictedIndicesNames.SECURITY_INDEX_NAME)));
assertThat(list, not(contains(RestrictedIndicesNames.SECURITY_MAIN_ALIAS)));
}
public void testAuthorizedIndicesUserWithSomeRolesEmptyMetaData() {
@ -101,8 +100,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
.cluster(ClusterPrivilege.ALL)
.build();
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
MetaData metaData = MetaData.builder()
.put(new IndexMetaData.Builder("an-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
.put(new IndexMetaData.Builder("another-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
@ -111,7 +110,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
@ -119,7 +118,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
assertThat(authorizedIndices, containsInAnyOrder("an-index", "another-index"));
assertThat(authorizedIndices, not(contains(internalSecurityIndex)));
assertThat(authorizedIndices, not(contains(RestrictedIndicesNames.SECURITY_INDEX_NAME)));
assertThat(authorizedIndices, not(contains(RestrictedIndicesNames.SECURITY_MAIN_ALIAS)));
}
public void testSecurityIndicesAreNotRemovedFromUnrestrictedRole() {
@ -128,8 +127,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
.cluster(ClusterPrivilege.ALL)
.build();
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
MetaData metaData = MetaData.builder()
.put(new IndexMetaData.Builder("an-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
.put(new IndexMetaData.Builder("another-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
@ -137,18 +136,18 @@ public class AuthorizedIndicesTests extends ESTestCase {
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
List<String> authorizedIndices =
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
assertThat(authorizedIndices, containsInAnyOrder(
"an-index", "another-index", SecurityIndexManager.SECURITY_INDEX_NAME, internalSecurityIndex));
"an-index", "another-index", RestrictedIndicesNames.SECURITY_MAIN_ALIAS, internalSecurityIndex));
List<String> authorizedIndicesSuperUser =
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
assertThat(authorizedIndicesSuperUser, containsInAnyOrder(
"an-index", "another-index", SecurityIndexManager.SECURITY_INDEX_NAME, internalSecurityIndex));
"an-index", "another-index", RestrictedIndicesNames.SECURITY_MAIN_ALIAS, internalSecurityIndex));
}
}

View File

@ -64,7 +64,6 @@ import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.security.user.XPackSecurityUser;
import org.elasticsearch.xpack.core.security.user.XPackUser;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -79,7 +78,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.contains;
@ -119,7 +118,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
indexNameExpressionResolver = new IndexNameExpressionResolver();
final boolean withAlias = randomBoolean();
final String securityIndexName = SECURITY_INDEX_NAME + (withAlias ? "-" + randomAlphaOfLength(5) : "");
final String securityIndexName = SECURITY_MAIN_ALIAS + (withAlias ? "-" + randomAlphaOfLength(5) : "");
MetaData metaData = MetaData.builder()
.put(indexBuilder("foo").putAlias(AliasMetaData.builder("foofoobar"))
.putAlias(AliasMetaData.builder("foounauthorized")).settings(settings))
@ -1222,14 +1221,14 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
{
final List<String> authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, SearchAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
assertThat(indices, hasItem(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(indices, hasItem(SECURITY_MAIN_ALIAS));
}
{
IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest();
aliasesRequest.addAliasAction(AliasActions.add().alias("security_alias").index(SECURITY_INDEX_NAME));
aliasesRequest.addAliasAction(AliasActions.add().alias("security_alias").index(SECURITY_MAIN_ALIAS));
final List<String> authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, IndicesAliasesAction.NAME);
List<String> indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal();
assertThat(indices, hasItem(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(indices, hasItem(SECURITY_MAIN_ALIAS));
}
}
@ -1237,7 +1236,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
SearchRequest request = new SearchRequest();
final List<String> authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, SearchAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
assertThat(indices, not(hasItem(SecurityIndexManager.SECURITY_INDEX_NAME)));
assertThat(indices, not(hasItem(SECURITY_MAIN_ALIAS)));
}
public void testNonXPackUserAccessingSecurityIndex() {
@ -1249,7 +1248,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
SearchRequest request = new SearchRequest();
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, SearchAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
assertThat(indices, not(hasItem(SecurityIndexManager.SECURITY_INDEX_NAME)));
assertThat(indices, not(hasItem(SECURITY_MAIN_ALIAS)));
}
{
@ -1257,7 +1256,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
aliasesRequest.addAliasAction(AliasActions.add().alias("security_alias1").index("*"));
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, IndicesAliasesAction.NAME);
List<String> indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal();
assertThat(indices, not(hasItem(SecurityIndexManager.SECURITY_INDEX_NAME)));
assertThat(indices, not(hasItem(SECURITY_MAIN_ALIAS)));
}
}

View File

@ -22,8 +22,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
@ -56,7 +56,7 @@ public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
final String snapshotUserToken = basicAuthHeaderValue(user, new SecureString(password));
client = client().filterWithHeader(Collections.singletonMap("Authorization", snapshotUserToken));
securityClient().preparePutUser(user, password, Hasher.BCRYPT, "snapshot_user").get();
ensureGreen(INTERNAL_SECURITY_INDEX_7);
ensureGreen(INTERNAL_SECURITY_MAIN_INDEX_7);
}
public void testSnapshotUserRoleCanSnapshotAndSeeAllIndices() {
@ -67,17 +67,17 @@ public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
assertThat(getRepositoriesResponse.repositories().get(0).name(), is("repo"));
// view all indices, including restricted ones
final GetIndexResponse getIndexResponse = client.admin().indices().prepareGetIndex().setIndices(randomFrom("_all", "*")).get();
assertThat(Arrays.asList(getIndexResponse.indices()), containsInAnyOrder(INTERNAL_SECURITY_INDEX_7, ordinaryIndex));
assertThat(Arrays.asList(getIndexResponse.indices()), containsInAnyOrder(INTERNAL_SECURITY_MAIN_INDEX_7, ordinaryIndex));
// create snapshot that includes restricted indices
final CreateSnapshotResponse snapshotResponse = client.admin().cluster().prepareCreateSnapshot("repo", "snap")
.setIndices(randomFrom("_all", "*")).setWaitForCompletion(true).get();
assertThat(snapshotResponse.getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
assertThat(snapshotResponse.getSnapshotInfo().indices(), containsInAnyOrder(INTERNAL_SECURITY_INDEX_7, ordinaryIndex));
assertThat(snapshotResponse.getSnapshotInfo().indices(), containsInAnyOrder(INTERNAL_SECURITY_MAIN_INDEX_7, ordinaryIndex));
// view snapshots for repo
final GetSnapshotsResponse getSnapshotResponse = client.admin().cluster().prepareGetSnapshots("repo").get();
assertThat(getSnapshotResponse.getSnapshots().size(), is(1));
assertThat(getSnapshotResponse.getSnapshots().get(0).snapshotId().getName(), is("snap"));
assertThat(getSnapshotResponse.getSnapshots().get(0).indices(), containsInAnyOrder(INTERNAL_SECURITY_INDEX_7, ordinaryIndex));
assertThat(getSnapshotResponse.getSnapshots().get(0).indices(), containsInAnyOrder(INTERNAL_SECURITY_MAIN_INDEX_7, ordinaryIndex));
}
public void testSnapshotUserRoleIsReserved() {
@ -112,7 +112,7 @@ public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
() -> client.admin().cluster().prepareDeleteSnapshot("repo", randomAlphaOfLength(4).toLowerCase(Locale.ROOT)).get(),
"cluster:admin/snapshot/delete", "snapshot_user");
// try destructive/revealing actions on all indices
for (final String indexToTest : Arrays.asList(INTERNAL_SECURITY_INDEX_7, SECURITY_INDEX_NAME, ordinaryIndex)) {
for (final String indexToTest : Arrays.asList(INTERNAL_SECURITY_MAIN_INDEX_7, SECURITY_MAIN_ALIAS, ordinaryIndex)) {
assertThrowsAuthorizationException(() -> client.prepareSearch(indexToTest).get(), "indices:data/read/search", "snapshot_user");
assertThrowsAuthorizationException(() -> client.prepareGet(indexToTest, "doc", "1").get(), "indices:data/read/get",
"snapshot_user");

View File

@ -293,14 +293,14 @@ public class IndicesPermissionTests extends ESTestCase {
public void testSecurityIndicesPermissions() {
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
final MetaData metaData = new MetaData.Builder()
.put(new IndexMetaData.Builder(internalSecurityIndex)
.settings(indexSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
.build(), true)
.build();
FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
@ -309,18 +309,18 @@ public class IndicesPermissionTests extends ESTestCase {
// allow_restricted_indices: false
IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, false, "*");
Map<String, IndicesAccessControl.IndexAccessControl> authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_INDEX_NAME), lookup,
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS), lookup,
fieldPermissionsCache);
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(false));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(false));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(false));
// allow_restricted_indices: true
group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, true, "*");
authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_INDEX_NAME), lookup,
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS), lookup,
fieldPermissionsCache);
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(true));
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
}
private static FieldPermissionsDefinition fieldPermissionDef(String[] granted, String[] denied) {

View File

@ -57,6 +57,7 @@ import org.elasticsearch.xpack.security.authc.ApiKeyService.ApiKeyRoleDescriptor
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import java.io.IOException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@ -98,7 +99,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
private final FieldPermissionsCache cache = new FieldPermissionsCache(Settings.EMPTY);
private final String concreteSecurityIndexName = randomFrom(
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6, RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
public void testRolesWhenDlsFlsUnlicensed() throws IOException {
XPackLicenseState licenseState = mock(XPackLicenseState.class);
@ -762,7 +763,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
}
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
return new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, indexStatus);
return new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, indexStatus);
}
public void testCacheClearOnIndexHealthChange() {
@ -837,13 +838,13 @@ public class CompositeRolesStoreTests extends ESTestCase {
};
compositeRolesStore.onSecurityIndexStateChange(
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null));
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null));
assertEquals(1, numInvalidation.get());
compositeRolesStore.onSecurityIndexStateChange(
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null));
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null),
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null));
assertEquals(2, numInvalidation.get());
}

View File

@ -39,6 +39,7 @@ import org.elasticsearch.test.client.NoOpClient;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.xpack.core.security.action.role.ClearRolesCacheRequest;
import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.hamcrest.Matchers;
import org.junit.After;
@ -125,7 +126,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(GetRequest.class));
GetRequest request = (GetRequest) requests.get(0);
assertThat(request.index(), equalTo(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.index(), equalTo(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
@ -143,7 +144,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(GetRequest.class));
GetRequest request = (GetRequest) requests.get(0);
assertThat(request.index(), equalTo(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.index(), equalTo(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
@ -166,7 +167,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(SearchRequest.class));
SearchRequest request = (SearchRequest) requests.get(0);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
final String query = Strings.toString(request.source().query());
assertThat(query, containsString("{\"terms\":{\"application\":[\"myapp\",\"yourapp\"]"));
@ -187,7 +188,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(SearchRequest.class));
SearchRequest request = (SearchRequest) requests.get(0);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
final String query = Strings.toString(request.source().query());
assertThat(query, containsString("{\"bool\":{\"filter\":[{\"terms\":{\"application\":[\"yourapp\"]"));
@ -207,7 +208,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(SearchRequest.class));
SearchRequest request = (SearchRequest) requests.get(0);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
final String query = Strings.toString(request.source().query());
assertThat(query, containsString("{\"exists\":{\"field\":\"application\""));
@ -232,7 +233,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests, iterableWithSize(1));
assertThat(requests.get(0), instanceOf(SearchRequest.class));
SearchRequest request = (SearchRequest) requests.get(0);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
final String query = Strings.toString(request.source().query());
assertThat(query, containsString("{\"term\":{\"type\":{\"value\":\"application-privilege\""));
@ -268,7 +269,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
for (int i = 0; i < putPrivileges.size(); i++) {
ApplicationPrivilegeDescriptor privilege = putPrivileges.get(i);
IndexRequest request = indexRequests.get(i);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo(
"application-privilege_" + privilege.getApplication() + ":" + privilege.getName()
@ -277,7 +278,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(request.source(), equalTo(BytesReference.bytes(builder)));
final boolean created = privilege.getName().equals("user") == false;
indexListener.onResponse(new IndexResponse(
new ShardId(SecurityIndexManager.SECURITY_INDEX_NAME, uuid, i),
new ShardId(RestrictedIndicesNames.SECURITY_MAIN_ALIAS, uuid, i),
request.type(), request.id(), 1, 1, 1, created
));
}
@ -313,12 +314,12 @@ public class NativePrivilegeStoreTests extends ESTestCase {
for (int i = 0; i < privilegeNames.size(); i++) {
String name = privilegeNames.get(i);
DeleteRequest request = deletes.get(i);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.indices(), arrayContaining(RestrictedIndicesNames.SECURITY_MAIN_ALIAS));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_app1:" + name));
final boolean found = name.equals("p2") == false;
deleteListener.onResponse(new DeleteResponse(
new ShardId(SecurityIndexManager.SECURITY_INDEX_NAME, uuid, i),
new ShardId(RestrictedIndicesNames.SECURITY_MAIN_ALIAS, uuid, i),
request.type(), request.id(), 1, 1, 1, found
));
}

View File

@ -56,7 +56,7 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
@ -187,7 +187,7 @@ public class NativeRolesStoreTests extends ESTestCase {
final ClusterService clusterService = mock(ClusterService.class);
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
final AtomicBoolean methodCalled = new AtomicBoolean(false);
final SecurityIndexManager securityIndex = SecurityIndexManager.buildSecurityIndexManager(client, clusterService);
final SecurityIndexManager securityIndex = SecurityIndexManager.buildSecurityMainIndexManager(client, clusterService);
final NativeRolesStore rolesStore = new NativeRolesStore(Settings.EMPTY, client, licenseState, securityIndex) {
@Override
void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
@ -247,7 +247,7 @@ public class NativeRolesStoreTests extends ESTestCase {
private ClusterState getClusterStateWithSecurityIndex() {
final boolean withAlias = randomBoolean();
final String securityIndexName = SECURITY_INDEX_NAME + (withAlias ? "-" + randomAlphaOfLength(5) : "");
final String securityIndexName = SECURITY_MAIN_ALIAS + (withAlias ? "-" + randomAlphaOfLength(5) : "");
Settings settings = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
@ -256,7 +256,7 @@ public class NativeRolesStoreTests extends ESTestCase {
.build();
MetaData metaData = MetaData.builder()
.put(IndexMetaData.builder(securityIndexName).settings(settings))
.put(new IndexTemplateMetaData(SecurityIndexManager.SECURITY_TEMPLATE_NAME, 0, 0,
.put(new IndexTemplateMetaData(SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7, 0, 0,
Collections.singletonList(securityIndexName), Settings.EMPTY, ImmutableOpenMap.of(),
ImmutableOpenMap.of()))
.build();

View File

@ -29,6 +29,7 @@ import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
@ -52,12 +53,12 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.core.template.TemplateUtils;
import org.hamcrest.Matchers;
import org.junit.Before;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.TEMPLATE_VERSION_PATTERN;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
@ -71,7 +72,6 @@ public class SecurityIndexManagerTests extends ESTestCase {
private static final ClusterName CLUSTER_NAME = new ClusterName("security-index-manager-tests");
private static final ClusterState EMPTY_CLUSTER_STATE = new ClusterState.Builder(CLUSTER_NAME).build();
private static final String INDEX_NAME = ".security";
private static final String TEMPLATE_NAME = "SecurityIndexManagerTests-template";
private SecurityIndexManager manager;
private Map<Action<?>, Map<ActionRequest, ActionListener<?>>> actions;
@ -96,13 +96,14 @@ public class SecurityIndexManagerTests extends ESTestCase {
actions.put(action, map);
}
};
manager = SecurityIndexManager.buildSecurityIndexManager(client, clusterService);
manager = SecurityIndexManager.buildSecurityMainIndexManager(client, clusterService);
}
public void testIndexWithUpToDateMappingAndTemplate() throws IOException {
assertInitialState();
final ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME);
final ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
@ -114,8 +115,9 @@ public class SecurityIndexManagerTests extends ESTestCase {
public void testIndexWithoutPrimaryShards() throws IOException {
assertInitialState();
final ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME);
Index index = new Index(INDEX_NAME, UUID.randomUUID().toString());
final ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME);
Index index = new Index(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7, UUID.randomUUID().toString());
ShardRouting shardRouting = ShardRouting.newUnassigned(new ShardId(index, 0), true,
RecoverySource.ExistingStoreRecoverySource.INSTANCE, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, ""));
String nodeId = ESTestCase.randomAlphaOfLength(8);
@ -147,7 +149,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
manager.addIndexStateListener(listener);
// index doesn't exist and now exists
final ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME);
final ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
@ -171,7 +174,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
previousState.set(null);
currentState.set(null);
ClusterState previousClusterState = clusterStateBuilder.build();
Index prevIndex = previousClusterState.getRoutingTable().index(INDEX_NAME).getIndex();
Index prevIndex = previousClusterState.getRoutingTable().index(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7).getIndex();
clusterStateBuilder.routingTable(RoutingTable.builder()
.add(IndexRoutingTable.builder(prevIndex)
.addIndexShard(new IndexShardRoutingTable.Builder(new ShardId(prevIndex, 0))
@ -231,8 +234,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
prepareException.set(null);
prepareRunnableCalled.set(false);
// state recovered with index
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
SecurityIndexManager.INTERNAL_INDEX_FORMAT);
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
manager.prepareIndexIfNeededThenExecute(ex -> {
@ -255,8 +258,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
assertThat(manager.isStateRecovered(), is(false));
assertThat(listenerCalled.get(), is(false));
// state recovered with index
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
SecurityIndexManager.INTERNAL_INDEX_FORMAT);
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
assertThat(manager.isStateRecovered(), is(true));
@ -278,8 +281,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
assertTrue(manager.isIndexUpToDate());
// index doesn't exist and now exists with wrong format
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
SecurityIndexManager.INTERNAL_INDEX_FORMAT - 1);
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT - 1);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
assertTrue(listenerCalled.get());
@ -295,7 +298,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
listenerCalled.set(false);
// index doesn't exist and now exists with correct format
clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_INDEX_FORMAT);
clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
markShardsAvailable(clusterStateBuilder);
manager.clusterChanged(event(clusterStateBuilder));
assertTrue(listenerCalled.get());
@ -317,18 +321,19 @@ public class SecurityIndexManagerTests extends ESTestCase {
assertThat(manager.isStateRecovered(), Matchers.equalTo(true));
}
public static ClusterState.Builder createClusterState(String indexName, String templateName) throws IOException {
return createClusterState(indexName, templateName, templateName, SecurityIndexManager.INTERNAL_INDEX_FORMAT);
public static ClusterState.Builder createClusterState(String indexName, String aliasName, String templateName) throws IOException {
return createClusterState(indexName, aliasName, templateName, templateName, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
}
public static ClusterState.Builder createClusterState(String indexName, String templateName, int format) throws IOException {
return createClusterState(indexName, templateName, templateName, format);
}
private static ClusterState.Builder createClusterState(String indexName, String templateName, String buildMappingFrom, int format)
public static ClusterState.Builder createClusterState(String indexName, String aliasName, String templateName, int format)
throws IOException {
return createClusterState(indexName, aliasName, templateName, templateName, format);
}
private static ClusterState.Builder createClusterState(String indexName, String aliasName, String templateName, String buildMappingFrom,
int format) throws IOException {
IndexTemplateMetaData.Builder templateBuilder = getIndexTemplateMetaData(templateName);
IndexMetaData.Builder indexMeta = getIndexMetadata(indexName, buildMappingFrom, format);
IndexMetaData.Builder indexMeta = getIndexMetadata(indexName, aliasName, buildMappingFrom, format);
MetaData.Builder metaDataBuilder = new MetaData.Builder();
metaDataBuilder.put(templateBuilder);
@ -338,7 +343,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
}
private void markShardsAvailable(ClusterState.Builder clusterStateBuilder) {
clusterStateBuilder.routingTable(SecurityTestUtils.buildIndexRoutingTable(INDEX_NAME));
clusterStateBuilder.routingTable(SecurityTestUtils.buildIndexRoutingTable(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7));
}
private static ClusterState state() {
@ -349,7 +354,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
.build();
}
private static IndexMetaData.Builder getIndexMetadata(String indexName, String templateName, int format) throws IOException {
private static IndexMetaData.Builder getIndexMetadata(String indexName, String aliasName, String templateName, int format)
throws IOException {
IndexMetaData.Builder indexMetaData = IndexMetaData.builder(indexName);
indexMetaData.settings(Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
@ -357,7 +363,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.INDEX_FORMAT_SETTING.getKey(), format)
.build());
indexMetaData.putAlias(AliasMetaData.builder(aliasName).build());
final Map<String, String> mappings = getTemplateMappings(templateName);
for (Map.Entry<String, String> entry : mappings.entrySet()) {
indexMetaData.putMapping(entry.getKey(), entry.getValue());
@ -389,7 +395,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
}
public void testMappingVersionMatching() throws IOException {
String templateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
String templateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString);
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
assertTrue(manager.checkMappingVersion(Version.CURRENT.minimumIndexCompatibilityVersion()::before));
@ -397,17 +403,19 @@ public class SecurityIndexManagerTests extends ESTestCase {
}
public void testMissingVersionMappingThrowsError() throws IOException {
String templateString = "/missing-version-" + SECURITY_TEMPLATE_NAME + ".json";
String templateString = "/missing-version-security-index-template.json";
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString);
final ClusterState clusterState = clusterStateBuilder.build();
IllegalStateException exception = expectThrows(IllegalStateException.class,
() -> SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, Version.CURRENT::equals));
assertEquals("Cannot read security-version string in index " + SECURITY_INDEX_NAME, exception.getMessage());
() -> SecurityIndexManager.checkIndexMappingVersionMatches(RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
clusterState, logger, Version.CURRENT::equals));
assertEquals("Cannot read security-version string in index " + RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
exception.getMessage());
}
public void testIndexTemplateIsIdentifiedAsUpToDate() throws IOException {
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(
"/" + SECURITY_TEMPLATE_NAME + ".json"
"/" + SECURITY_MAIN_TEMPLATE_7 + ".json"
);
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
// No upgrade actions run
@ -415,20 +423,20 @@ public class SecurityIndexManagerTests extends ESTestCase {
}
public void testIndexTemplateVersionMatching() throws Exception {
String templateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
String templateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(templateString);
final ClusterState clusterState = clusterStateBuilder.build();
assertTrue(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
SecurityIndexManager.SECURITY_TEMPLATE_NAME, clusterState, logger,
SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7, clusterState, logger,
Version.V_6_0_0::before));
assertFalse(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
SecurityIndexManager.SECURITY_TEMPLATE_NAME, clusterState, logger,
SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7, clusterState, logger,
Version.V_6_0_0::after));
}
public void testUpToDateMappingsAreIdentifiedAsUpToDate() throws IOException {
String securityTemplateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
String securityTemplateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(securityTemplateString);
manager.clusterChanged(new ClusterChangedEvent("test-event",
clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
@ -438,8 +446,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
public void testMissingIndexIsIdentifiedAsUpToDate() throws IOException {
final ClusterName clusterName = new ClusterName("test-cluster");
final ClusterState.Builder clusterStateBuilder = ClusterState.builder(clusterName);
String mappingString = "/" + SECURITY_TEMPLATE_NAME + ".json";
IndexTemplateMetaData.Builder templateMeta = getIndexTemplateMetaData(SECURITY_TEMPLATE_NAME, mappingString);
String mappingString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
IndexTemplateMetaData.Builder templateMeta = getIndexTemplateMetaData(SECURITY_MAIN_TEMPLATE_7, mappingString);
MetaData.Builder builder = new MetaData.Builder(clusterStateBuilder.build().getMetaData());
builder.put(templateMeta);
clusterStateBuilder.metaData(builder);
@ -450,24 +458,24 @@ public class SecurityIndexManagerTests extends ESTestCase {
private ClusterState.Builder createClusterStateWithTemplate(String securityTemplateString) throws IOException {
// add the correct mapping no matter what the template
ClusterState clusterState = createClusterStateWithIndex("/" + SECURITY_TEMPLATE_NAME + ".json").build();
ClusterState clusterState = createClusterStateWithIndex("/" + SECURITY_MAIN_TEMPLATE_7 + ".json").build();
final MetaData.Builder metaDataBuilder = new MetaData.Builder(clusterState.metaData());
metaDataBuilder.put(getIndexTemplateMetaData(SECURITY_TEMPLATE_NAME, securityTemplateString));
metaDataBuilder.put(getIndexTemplateMetaData(SECURITY_MAIN_TEMPLATE_7, securityTemplateString));
return ClusterState.builder(clusterState).metaData(metaDataBuilder);
}
private ClusterState.Builder createClusterStateWithMapping(String securityTemplateString) throws IOException {
final ClusterState clusterState = createClusterStateWithIndex(securityTemplateString).build();
final String indexName = clusterState.metaData().getAliasAndIndexLookup()
.get(SECURITY_INDEX_NAME).getIndices().get(0).getIndex().getName();
.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).getIndices().get(0).getIndex().getName();
return ClusterState.builder(clusterState).routingTable(SecurityTestUtils.buildIndexRoutingTable(indexName));
}
private ClusterState.Builder createClusterStateWithMappingAndTemplate(String securityTemplateString) throws IOException {
ClusterState.Builder clusterStateBuilder = createClusterStateWithMapping(securityTemplateString);
MetaData.Builder metaDataBuilder = new MetaData.Builder(clusterStateBuilder.build().metaData());
String securityMappingString = "/" + SECURITY_TEMPLATE_NAME + ".json";
IndexTemplateMetaData.Builder securityTemplateMeta = getIndexTemplateMetaData(SECURITY_TEMPLATE_NAME, securityMappingString);
String securityMappingString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
IndexTemplateMetaData.Builder securityTemplateMeta = getIndexTemplateMetaData(SECURITY_MAIN_TEMPLATE_7, securityMappingString);
metaDataBuilder.put(securityTemplateMeta);
return clusterStateBuilder.metaData(metaDataBuilder);
}
@ -493,7 +501,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
private ClusterState.Builder createClusterStateWithIndex(String securityTemplate) throws IOException {
final MetaData.Builder metaDataBuilder = new MetaData.Builder();
final boolean withAlias = randomBoolean();
final String securityIndexName = SECURITY_INDEX_NAME + (withAlias ? "-" + randomAlphaOfLength(5) : "");
final String securityIndexName = RestrictedIndicesNames.SECURITY_MAIN_ALIAS
+ (withAlias ? "-" + randomAlphaOfLength(5) : "");
metaDataBuilder.put(createIndexMetadata(securityIndexName, securityTemplate));
ClusterState.Builder clusterStateBuilder = ClusterState.builder(state());

View File

@ -35,7 +35,7 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
public class SecurityTestUtils {
@ -83,7 +83,7 @@ public class SecurityTestUtils {
* Adds the index alias {@code .security} to the underlying concrete index.
*/
public static MetaData addAliasToMetaData(MetaData metaData, String indexName) {
AliasMetaData aliasMetaData = AliasMetaData.newAliasMetaDataBuilder(SECURITY_INDEX_NAME).build();
AliasMetaData aliasMetaData = AliasMetaData.newAliasMetaDataBuilder(SECURITY_MAIN_ALIAS).build();
MetaData.Builder metaDataBuilder = new MetaData.Builder(metaData);
IndexMetaData indexMetaData = metaData.index(indexName);
metaDataBuilder.put(IndexMetaData.builder(indexMetaData).putAlias(aliasMetaData));

View File

@ -14,7 +14,6 @@ import org.elasticsearch.xpack.core.security.index.IndexAuditTrailField;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.core.security.user.XPackUser;
import org.elasticsearch.xpack.security.audit.index.IndexNameResolver;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.hamcrest.Matchers;
import org.joda.time.DateTime;
@ -32,8 +31,6 @@ public class XPackUserTests extends ESTestCase {
public void testXPackUserCannotAccessRestrictedIndices() {
final String action = randomFrom(GetAction.NAME, SearchAction.NAME, IndexAction.NAME);
final Predicate<String> predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action);
assertThat(predicate.test(SecurityIndexManager.SECURITY_INDEX_NAME), Matchers.is(false));
assertThat(predicate.test(SecurityIndexManager.INTERNAL_SECURITY_INDEX), Matchers.is(false));
for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) {
assertThat(predicate.test(index), Matchers.is(false));
}

View File

@ -0,0 +1,161 @@
---
setup:
- skip:
features: headers
- do:
cluster.health:
wait_for_status: yellow
- do:
security.put_role:
name: "all_access"
body: >
{
"cluster": [ "all" ],
"indices": [
{ "names": ["*"], "privileges": ["all"] }
]
}
- do:
security.put_user:
username: "test_user"
body: >
{
"password" : "x-pack-test-password",
"roles" : [ "all_access" ],
"full_name" : "user with all possible privileges (but not superuser)"
}
---
teardown:
- do:
security.delete_user:
username: "test_user"
ignore: 404
- do:
security.delete_role:
name: "all_access"
ignore: 404
---
"Test get security tokens index metadata":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
indices.get:
index: ".security-tokens"
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
indices.get:
index: ".security-tokens"
- do:
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
indices.get:
index: ".secu*rity*tokens"
- length: { $body: 0 }
- do:
headers:
Authorization: Bearer ${token}
indices.get:
index: ".secu*rity*tokens"
- length: { $body: 0 }
---
"Test get security document":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
get:
index: ".security-tokens"
id: token_${token}
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
get:
index: ".security-tokens"
id: token_${token}
---
"Test search security tokens index":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
search:
rest_total_hits_as_int: true
index: ".security-tokens"
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: ".security-tokens"
- do:
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
search:
rest_total_hits_as_int: true
index: ".secu*rity*tokens"
- match: { hits.total: 0 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: ".secu*rity*tokens"
- match: { hits.total: 0 }

View File

@ -0,0 +1,161 @@
---
setup:
- skip:
features: headers
- do:
cluster.health:
wait_for_status: yellow
- do:
security.put_role:
name: "all_access"
body: >
{
"cluster": [ "all" ],
"indices": [
{ "names": ["*"], "privileges": ["all"] }
]
}
- do:
security.put_user:
username: "test_user"
body: >
{
"password" : "x-pack-test-password",
"roles" : [ "all_access" ],
"full_name" : "user with all possible privileges (but not superuser)"
}
---
teardown:
- do:
security.delete_user:
username: "test_user"
ignore: 404
- do:
security.delete_role:
name: "all_access"
ignore: 404
---
"Test get security tokens index metadata":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
indices.get:
index: ".security-tokens-7"
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
indices.get:
index: ".security-tokens-7"
- do:
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
indices.get:
index: ".secu*rity*tokens-7"
- length: { $body: 0 }
- do:
headers:
Authorization: Bearer ${token}
indices.get:
index: ".secu*rity*tokens-7"
- length: { $body: 0 }
---
"Test get security document":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
get:
index: ".security-tokens-7"
id: token_${token}
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
get:
index: ".security-tokens-7"
id: token_${token}
---
"Test search security tokens index":
- do:
security.get_token:
body:
grant_type: "password"
username: "test_user"
password: "x-pack-test-password"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_false: scope
- do:
catch: forbidden
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
search:
rest_total_hits_as_int: true
index: ".security-tokens-7"
- do:
catch: forbidden
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: ".security-tokens-7"
- do:
headers: { Authorization: "Basic dGVzdF91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" } # test_user
search:
rest_total_hits_as_int: true
index: ".secu*rity*tokens-7"
- match: { hits.total: 0 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: ".secu*rity*tokens-7"
- match: { hits.total: 0 }

View File

@ -119,6 +119,8 @@ for (Version version : bwcVersions.wireCompatible) {
setting 'xpack.security.enabled', 'true'
setting 'xpack.security.transport.ssl.enabled', 'true'
setting 'xpack.security.authc.token.enabled', 'true'
setting 'xpack.security.authc.token.timeout', '60m'
setting 'logger.org.elasticsearch.xpack.security.authc.TokenService', 'trace'
setting 'xpack.security.audit.enabled', 'true'
if (project.inFipsJvm) {
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
@ -184,6 +186,8 @@ for (Version version : bwcVersions.wireCompatible) {
setting 'xpack.license.self_generated.type', 'trial'
setting 'xpack.security.enabled', 'true'
setting 'xpack.security.transport.ssl.enabled', 'true'
setting 'xpack.security.authc.token.timeout', '60m'
setting 'logger.org.elasticsearch.xpack.security.authc.TokenService', 'trace'
if (project.inFipsJvm) {
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
setting 'xpack.security.transport.ssl.certificate', 'testnode.crt'

View File

@ -16,9 +16,14 @@ import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.test.rest.yaml.ObjectPath;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -27,7 +32,33 @@ import static org.hamcrest.Matchers.equalTo;
public class TokenBackwardsCompatibilityIT extends AbstractUpgradeTestCase {
public void testGeneratingTokenInOldCluster() throws Exception {
private Collection<RestClient> twoClients = null;
@Before
private void collectClientsByVersion() throws IOException {
Map<Version, RestClient> clientsByVersion = getRestClientByVersion();
if (clientsByVersion.size() == 2) {
// usual case, clients have different versions
twoClients = clientsByVersion.values();
} else {
assert clientsByVersion.size() == 1 : "A rolling upgrade has a maximum of two distinct node versions, found: "
+ clientsByVersion.keySet();
// tests assumes exactly two clients to simplify some logic
twoClients = new ArrayList<>();
twoClients.add(clientsByVersion.values().iterator().next());
twoClients.add(clientsByVersion.values().iterator().next());
}
}
@After
private void closeClientsByVersion() throws IOException {
for (RestClient client : twoClients) {
client.close();
}
twoClients = null;
}
public void testGeneratingTokensInOldCluster() throws Exception {
assumeTrue("this test should only run against the old cluster", CLUSTER_TYPE == ClusterType.OLD);
{
Version minimumIndexCompatibilityVersion = Version.CURRENT.minimumIndexCompatibilityVersion();
@ -48,188 +79,363 @@ public class TokenBackwardsCompatibilityIT extends AbstractUpgradeTestCase {
client().performRequest(createTemplate);
}
}
// Creates two access and refresh tokens and stores them in the token_backwards_compatibility_it index to be used for tests in the
// mixed/upgraded clusters
Map<String, Object> responseMap = createTokens(client(), "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
// Create a couple of tokens and store them in the token_backwards_compatibility_it index to be used for tests in the mixed/upgraded
// clusters
Request createTokenRequest = new Request("POST", "/_security/oauth2/token");
createTokenRequest.setJsonEntity(
"{\n" +
" \"username\": \"test_user\",\n" +
" \"password\": \"x-pack-test-password\",\n" +
" \"grant_type\": \"password\"\n" +
"}");
Response response = client().performRequest(createTokenRequest);
assertOK(response);
Map<String, Object> responseMap = entityAsMap(response);
String token = (String) responseMap.get("access_token");
assertNotNull(token);
assertTokenWorks(token);
storeTokens(client(), 1, accessToken, refreshToken);
// In this test either all or none tests or on a specific version:
Request indexRequest1 = new Request("PUT", "token_backwards_compatibility_it/_doc/old_cluster_token1");
indexRequest1.setJsonEntity(
"{\n" +
" \"token\": \"" + token + "\"\n" +
"}");
Response indexResponse1 = client().performRequest(indexRequest1);
assertOK(indexResponse1);
Request createSecondTokenRequest = new Request("POST", "/_security/oauth2/token");
createSecondTokenRequest.setEntity(createTokenRequest.getEntity());
response = client().performRequest(createSecondTokenRequest);
responseMap = entityAsMap(response);
token = (String) responseMap.get("access_token");
assertNotNull(token);
assertTokenWorks(token);
Request indexRequest2 = new Request("PUT", "token_backwards_compatibility_it/_doc/old_cluster_token2");
indexRequest2.setJsonEntity(
"{\n" +
" \"token\": \"" + token + "\"\n" +
"}");
Response indexResponse2 = client().performRequest(indexRequest2);
assertOK(indexResponse2);
responseMap = createTokens(client(), "test_user", "x-pack-test-password");
accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
storeTokens(client(), 2, accessToken, refreshToken);
}
public void testTokenWorksInMixedCluster() throws Exception {
public void testRefreshingTokensInOldCluster() throws Exception {
assumeTrue("this test should only run against the old cluster", CLUSTER_TYPE == ClusterType.OLD);
{
Version minimumIndexCompatibilityVersion = Version.CURRENT.minimumIndexCompatibilityVersion();
assertThat("this branch is not needed if we aren't compatible with 6.0",
minimumIndexCompatibilityVersion.onOrBefore(Version.V_6_0_0), equalTo(true));
if (minimumIndexCompatibilityVersion.before(Version.V_7_0_0)) {
XContentBuilder template = jsonBuilder();
template.startObject();
{
template.field("index_patterns", "*");
template.startObject("settings");
template.field("number_of_shards", 5);
template.endObject();
}
template.endObject();
Request createTemplate = new Request("PUT", "/_template/template");
createTemplate.setJsonEntity(Strings.toString(template));
client().performRequest(createTemplate);
}
}
// Creates access and refresh tokens and uses the refresh token. The new resulting tokens are used in different phases
Map<String, Object> responseMap = createTokens(client(), "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
storeTokens(client(), 3, accessToken, refreshToken);
// refresh the token just created. The old token is invalid (tested further) and the new refresh token is tested in the upgraded
// cluster
Map<String, Object> refreshResponseMap = refreshToken(client(), refreshToken);
String refreshedAccessToken = (String) refreshResponseMap.get("access_token");
String refreshedRefreshToken = (String) refreshResponseMap.get("refresh_token");
assertNotNull(refreshedAccessToken);
assertNotNull(refreshedRefreshToken);
assertAccessTokenWorks(refreshedAccessToken);
// assert previous access token still works
assertAccessTokenWorks(accessToken);
storeTokens(client(), 4, refreshedAccessToken, refreshedRefreshToken);
}
public void testInvalidatingTokensInOldCluster() throws Exception {
assumeTrue("this test should only run against the old cluster", CLUSTER_TYPE == ClusterType.OLD);
{
Version minimumIndexCompatibilityVersion = Version.CURRENT.minimumIndexCompatibilityVersion();
assertThat("this branch is not needed if we aren't compatible with 6.0",
minimumIndexCompatibilityVersion.onOrBefore(Version.V_6_0_0), equalTo(true));
if (minimumIndexCompatibilityVersion.before(Version.V_7_0_0)) {
XContentBuilder template = jsonBuilder();
template.startObject();
{
template.field("index_patterns", "*");
template.startObject("settings");
template.field("number_of_shards", 5);
template.endObject();
}
template.endObject();
Request createTemplate = new Request("PUT", "/_template/template");
createTemplate.setJsonEntity(Strings.toString(template));
client().performRequest(createTemplate);
}
}
// Creates access and refresh tokens and tries to use the access tokens several times
Map<String, Object> responseMap = createTokens(client(), "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
storeTokens(client(), 5, accessToken, refreshToken);
// invalidate access token
invalidateAccessToken(client(), accessToken);
assertAccessTokenDoesNotWork(accessToken);
// invalidate refresh token
invalidateRefreshToken(client(), refreshToken);
assertRefreshTokenInvalidated(refreshToken);
}
public void testAccessTokensWorkInMixedCluster() throws Exception {
// Verify that an old token continues to work during all stages of the rolling upgrade
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
Request getRequest = new Request("GET", "token_backwards_compatibility_it/_doc/old_cluster_token1");
Response getResponse = client().performRequest(getRequest);
assertOK(getResponse);
Map<String, Object> source = (Map<String, Object>) entityAsMap(getResponse).get("_source");
assertTokenWorks((String) source.get("token"));
}
public void testInvalidatingTokenInMixedCluster() throws Exception {
// Verify that we can invalidate a token in a mixed cluster
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
Request getRequest = new Request("GET", "token_backwards_compatibility_it/_doc/old_cluster_token2");
Response getResponse = client().performRequest(getRequest);
assertOK(getResponse);
Map<String, Object> source = (Map<String, Object>) entityAsMap(getResponse).get("_source");
String token = (String) source.get("token");
// The token might be already invalidated by running testInvalidatingTokenInMixedCluster in a previous stage
// we don't try to assert it works before invalidating. This case is handled by testTokenWorksInMixedCluster
Request invalidateRequest = new Request("DELETE", "/_security/oauth2/token");
invalidateRequest.setJsonEntity("{\"token\": \"" + token + "\"}");
invalidateRequest.addParameter("error_trace", "true");
client().performRequest(invalidateRequest);
assertTokenDoesNotWork(token);
}
public void testMixedClusterWithUpgradedMaster() throws Exception {
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
assumeTrue("the master must be on the latest version before we can write", isMasterOnLatestVersion());
// create token and refresh on version that supports it
Request createTokenRequest = new Request("POST", "/_security/oauth2/token");
createTokenRequest.setJsonEntity(
"{\n" +
" \"username\": \"test_user\",\n" +
" \"password\": \"x-pack-test-password\",\n" +
" \"grant_type\": \"password\"\n" +
"}");
try (RestClient client = getRestClientForCurrentVersionNodesOnly()) {
Response response = client.performRequest(createTokenRequest);
Map<String, Object> responseMap = entityAsMap(response);
String accessToken = (String) responseMap.get("access_token");
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(accessToken);
assertNotNull(refreshToken);
assertTokenWorks(accessToken);
Request tokenRefreshRequest = new Request("POST", "/_security/oauth2/token");
tokenRefreshRequest.setJsonEntity(
"{\n" +
" \"refresh_token\": \"" + refreshToken + "\",\n" +
" \"grant_type\": \"refresh_token\"\n" +
"}");
response = client.performRequest(tokenRefreshRequest);
responseMap = entityAsMap(response);
String updatedAccessToken = (String) responseMap.get("access_token");
String updatedRefreshToken = (String) responseMap.get("refresh_token");
assertNotNull(updatedAccessToken);
assertNotNull(updatedRefreshToken);
assertTokenWorks(updatedAccessToken);
assertTokenWorks(accessToken);
assertNotEquals(accessToken, updatedAccessToken);
assertNotEquals(refreshToken, updatedRefreshToken);
// Invalidate the new access token and ensure that it no longer works
Request invalidateTokenRequest = new Request("DELETE", "/_security/oauth2/token");
invalidateTokenRequest.setJsonEntity(
"{\n" +
" \"token\": \"" + updatedAccessToken + "\"\n" +
"}");
Response invalidateTokenResponse = client.performRequest(invalidateTokenRequest);
assertOK(invalidateTokenResponse);
assertTokenDoesNotWork(updatedAccessToken);
for (int tokenIdx : Arrays.asList(1, 3, 4)) { // 2 is invalidated in another mixed-cluster test, 5 is invalidated in the old cluster
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
assertAccessTokenWorks((String) source.get("token"));
}
}
public void testUpgradedCluster() throws Exception {
public void testTokensStayInvalidatedInMixedCluster() throws Exception {
// Verify that an old, invalidated token remains invalidated during all stages of the rolling upgrade
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
Map<String, Object> source = retrieveStoredTokens(client(), 5);
assertAccessTokenDoesNotWork((String) source.get("token"));
assertRefreshTokenInvalidated((String) source.get("refresh_token"));
}
public void testGeneratingTokensInMixedCluster() throws Exception {
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
// Creates two access and refresh tokens and stores them in the token_backwards_compatibility_it index to be used for tests in the
// mixed/upgraded clusters
int generatedTokenIdxDuringMixed = 10;
for (RestClient client : twoClients) {
Map<String, Object> responseMap = createTokens(client, "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
storeTokens(client(), generatedTokenIdxDuringMixed++, accessToken, refreshToken);
responseMap = createTokens(client, "test_user", "x-pack-test-password");
accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
storeTokens(client(), generatedTokenIdxDuringMixed++, accessToken, refreshToken);
}
}
public void testRefreshingTokensInMixedCluster() throws Exception {
// verify new nodes can refresh tokens created by old nodes and vice versa
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
for (RestClient client1 : twoClients) {
Map<String, Object> responseMap = createTokens(client1, "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
for (RestClient client2 : twoClients) {
responseMap = refreshToken(client2, refreshToken);
accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
}
}
}
public void testInvalidatingTokensInMixedCluster() throws Exception {
// Verify that we can invalidate an access and refresh token in a mixed cluster
assumeTrue("this test should only run against the mixed cluster", CLUSTER_TYPE == ClusterType.MIXED);
Map<String, Object> source = retrieveStoredTokens(client(), 2);
String accessToken = (String) source.get("token");
String refreshToken = (String) source.get("refresh_token");
// The token might be already invalidated by running testInvalidatingTokenInMixedCluster in a previous stage
// we don't try to assert it works before invalidating. This case is handled by testTokenWorksInMixedCluster
invalidateAccessToken(client(), accessToken);
assertAccessTokenDoesNotWork(accessToken);
// invalidate refresh token
invalidateRefreshToken(client(), refreshToken);
assertRefreshTokenInvalidated(refreshToken);
}
public void testTokensStayInvalidatedInUpgradedCluster() throws Exception {
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
// Use an old token to authenticate, then invalidate it and verify that it can no longer be used
Request getRequest = new Request("GET", "token_backwards_compatibility_it/_doc/old_cluster_token1");
Response getResponse = client().performRequest(getRequest);
assertOK(getResponse);
Map<String, Object> source = (Map<String, Object>) entityAsMap(getResponse).get("_source");
final String token = (String) source.get("token");
Request invalidateRequest = new Request("DELETE", "/_security/oauth2/token");
invalidateRequest.setJsonEntity("{\"token\": \"" + token + "\"}");
invalidateRequest.addParameter("error_trace", "true");
Response invalidationResponse = client().performRequest(invalidateRequest);
assertOK(invalidationResponse);
assertTokenDoesNotWork(token);
for (int tokenIdx : Arrays.asList(2, 5)) {
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
assertAccessTokenDoesNotWork((String) source.get("token"));
assertRefreshTokenInvalidated((String) source.get("refresh_token"));
}
}
private void assertTokenWorks(String token) throws IOException {
Request request = new Request("GET", "/_security/_authenticate");
RequestOptions.Builder options = request.getOptions().toBuilder();
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
request.setOptions(options);
Response authenticateResponse = client().performRequest(request);
assertOK(authenticateResponse);
assertEquals("test_user", entityAsMap(authenticateResponse).get("username"));
public void testAccessTokensWorkInUpgradedCluster() throws Exception {
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
for (int tokenIdx : Arrays.asList(3, 4, 10, 12)) {
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
assertAccessTokenWorks((String) source.get("token"));
}
}
private void assertTokenDoesNotWork(String token) {
Request request = new Request("GET", "/_security/_authenticate");
RequestOptions.Builder options = request.getOptions().toBuilder();
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest(request));
assertEquals(401, e.getResponse().getStatusLine().getStatusCode());
Response response = e.getResponse();
assertEquals("Bearer realm=\"security\", error=\"invalid_token\", error_description=\"The access token expired\"",
response.getHeader("WWW-Authenticate"));
public void testGeneratingTokensInUpgradedCluster() throws Exception {
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
Map<String, Object> responseMap = createTokens(client(), "test_user", "x-pack-test-password");
String accessToken = (String) responseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) responseMap.get("refresh_token");
assertNotNull(refreshToken);
}
private boolean isMasterOnLatestVersion() throws Exception {
Response response = client().performRequest(new Request("GET", "_cluster/state"));
assertOK(response);
final String masterNodeId = ObjectPath.createFromResponse(response).evaluate("master_node");
response = client().performRequest(new Request("GET", "_nodes"));
assertOK(response);
ObjectPath objectPath = ObjectPath.createFromResponse(response);
logger.info("Master node is on version: " + objectPath.evaluate("nodes." + masterNodeId + ".version"));
return Version.CURRENT.equals(Version.fromString(objectPath.evaluate("nodes." + masterNodeId + ".version")));
public void testRefreshingTokensInUpgradedCluster() throws Exception {
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
for (int tokenIdx : Arrays.asList(4, 10, 12)) {
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
Map<String, Object> refreshedResponseMap = refreshToken(client(), (String) source.get("refresh_token"));
String accessToken = (String) refreshedResponseMap.get("access_token");
assertNotNull(accessToken);
assertAccessTokenWorks(accessToken);
String refreshToken = (String) refreshedResponseMap.get("refresh_token");
assertNotNull(refreshToken);
}
}
private RestClient getRestClientForCurrentVersionNodesOnly() throws IOException {
public void testInvalidatingTokensInUpgradedCluster() throws Exception {
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
for (int tokenIdx : Arrays.asList(1, 11, 13)) {
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
String accessToken = (String) source.get("token");
String refreshToken = (String) source.get("refresh_token");
// invalidate access token
invalidateAccessToken(client(), accessToken);
assertAccessTokenDoesNotWork(accessToken);
// invalidate refresh token
invalidateRefreshToken(client(), refreshToken);
assertRefreshTokenInvalidated(refreshToken);
}
}
private void assertAccessTokenWorks(String token) throws IOException {
for (RestClient client : twoClients) {
Request request = new Request("GET", "/_security/_authenticate");
RequestOptions.Builder options = request.getOptions().toBuilder();
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
request.setOptions(options);
Response authenticateResponse = client.performRequest(request);
assertOK(authenticateResponse);
assertEquals("test_user", entityAsMap(authenticateResponse).get("username"));
}
}
private void assertAccessTokenDoesNotWork(String token) throws IOException {
for (RestClient client : twoClients) {
Request request = new Request("GET", "/_security/_authenticate");
RequestOptions.Builder options = request.getOptions().toBuilder();
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> client.performRequest(request));
assertEquals(401, e.getResponse().getStatusLine().getStatusCode());
Response response = e.getResponse();
assertEquals("Bearer realm=\"security\", error=\"invalid_token\", error_description=\"The access token expired\"",
response.getHeader("WWW-Authenticate"));
}
}
private void assertRefreshTokenInvalidated(String refreshToken) throws IOException {
for (RestClient client : twoClients) {
Request refreshTokenRequest = new Request("POST", "/_security/oauth2/token");
refreshTokenRequest.setJsonEntity(
"{\n" +
" \"refresh_token\": \"" + refreshToken + "\",\n" +
" \"grant_type\": \"refresh_token\"\n" +
"}");
ResponseException e = expectThrows(ResponseException.class, () -> client.performRequest(refreshTokenRequest));
assertEquals(400, e.getResponse().getStatusLine().getStatusCode());
Response response = e.getResponse();
Map<String, Object> responseMap = entityAsMap(response);
assertEquals("invalid_grant", responseMap.get("error"));
assertEquals("token has been invalidated", responseMap.get("error_description"));
}
}
private Map<Version, RestClient> getRestClientByVersion() throws IOException {
Response response = client().performRequest(new Request("GET", "_nodes"));
assertOK(response);
ObjectPath objectPath = ObjectPath.createFromResponse(response);
Map<String, Object> nodesAsMap = objectPath.evaluate("nodes");
List<HttpHost> hosts = new ArrayList<>();
Map<Version, List<HttpHost>> hostsByVersion = new HashMap<>();
for (Map.Entry<String, Object> entry : nodesAsMap.entrySet()) {
Map<String, Object> nodeDetails = (Map<String, Object>) entry.getValue();
Version version = Version.fromString((String) nodeDetails.get("version"));
if (Version.CURRENT.equals(version)) {
Map<String, Object> httpInfo = (Map<String, Object>) nodeDetails.get("http");
hosts.add(HttpHost.create((String) httpInfo.get("publish_address")));
}
Map<String, Object> httpInfo = (Map<String, Object>) nodeDetails.get("http");
hostsByVersion.computeIfAbsent(version, k -> new ArrayList<>()).add(HttpHost.create((String) httpInfo.get("publish_address")));
}
Map<Version, RestClient> clientsByVersion = new HashMap<>();
for (Map.Entry<Version, List<HttpHost>> entry : hostsByVersion.entrySet()) {
clientsByVersion.put(entry.getKey(), buildClient(restClientSettings(), entry.getValue().toArray(new HttpHost[0])));
}
return clientsByVersion;
}
return buildClient(restClientSettings(), hosts.toArray(new HttpHost[0]));
private Map<String, Object> createTokens(RestClient client, String username, String password) throws IOException {
final Request createTokenRequest = new Request("POST", "/_security/oauth2/token");
createTokenRequest.setJsonEntity(
"{\n" +
" \"username\": \"" + username + "\",\n" +
" \"password\": \"" + password + "\",\n" +
" \"grant_type\": \"password\"\n" +
"}");
Response response = client().performRequest(createTokenRequest);
assertOK(response);
return entityAsMap(response);
}
private void storeTokens(RestClient client, int idx, String accessToken, String refreshToken) throws IOException {
final Request indexRequest = new Request("PUT", "token_backwards_compatibility_it/_doc/old_cluster_token" + idx);
indexRequest.setJsonEntity(
"{\n" +
" \"token\": \"" + accessToken + "\",\n" +
" \"refresh_token\": \"" + refreshToken + "\"\n" +
"}");
Response indexResponse1 = client.performRequest(indexRequest);
assertOK(indexResponse1);
}
private Map<String, Object> retrieveStoredTokens(RestClient client, int tokenIdx) throws IOException {
Request getRequest = new Request("GET", "token_backwards_compatibility_it/_doc/old_cluster_token" + tokenIdx);
Response getResponse = client().performRequest(getRequest);
assertOK(getResponse);
return (Map<String, Object>) entityAsMap(getResponse).get("_source");
}
private Map<String, Object> refreshToken(RestClient client, String refreshToken) throws IOException {
final Request refreshTokenRequest = new Request("POST", "/_security/oauth2/token");
refreshTokenRequest.setJsonEntity(
"{\n" +
" \"refresh_token\": \"" + refreshToken + "\",\n" +
" \"grant_type\": \"refresh_token\"\n" +
"}");
Response refreshResponse = client.performRequest(refreshTokenRequest);
assertOK(refreshResponse);
return entityAsMap(refreshResponse);
}
private void invalidateAccessToken(RestClient client, String accessToken) throws IOException {
Request invalidateRequest = new Request("DELETE", "/_security/oauth2/token");
invalidateRequest.setJsonEntity("{\"token\": \"" + accessToken + "\"}");
invalidateRequest.addParameter("error_trace", "true");
Response invalidateResponse = client.performRequest(invalidateRequest);
assertOK(invalidateResponse);
}
private void invalidateRefreshToken(RestClient client, String refreshToken) throws IOException {
Request invalidateRequest = new Request("DELETE", "/_security/oauth2/token");
invalidateRequest.setJsonEntity("{\"refresh_token\": \"" + refreshToken + "\"}");
invalidateRequest.addParameter("error_trace", "true");
Response invalidateResponse = client.performRequest(invalidateRequest);
assertOK(invalidateResponse);
}
}

View File

@ -3,14 +3,17 @@
- skip:
features: headers
- do:
cluster.health:
wait_for_status: yellow
- do:
get:
index: token_index
type: doc
id: "6"
- match: { _index: token_index }
- match: { _type: doc }
- match: { _type: _doc }
- match: { _id: "6" }
- is_true: _source.token
- set: { _source.token : token }
@ -24,6 +27,59 @@
- match: { roles.0: "superuser" }
- match: { full_name: "Token User" }
# call three times because the client rotates the nodes
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
---
"Get the indexed refreshed access token and use if to authenticate":
- skip:
features: headers
- do:
get:
index: token_index
id: "7"
- match: { _index: token_index }
- match: { _type: _doc }
- match: { _id: "7" }
- is_true: _source.token
- set: { _source.token : token }
- do:
headers:
Authorization: Bearer ${token}
security.authenticate: {}
- match: { username: "token_user" }
- match: { roles.0: "superuser" }
- match: { full_name: "Token User" }
- do:
headers:
Authorization: Bearer ${token}
@ -31,7 +87,7 @@
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 6 }
- match: { hits.total: 8 }
- do:
headers:
@ -40,7 +96,7 @@
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 6 }
- match: { hits.total: 8 }
- do:
headers:
@ -49,5 +105,79 @@
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 6 }
- match: { hits.total: 8 }
---
"Get the indexed refresh token and use it to get another access token and authenticate":
- skip:
features: headers
- do:
get:
index: token_index
id: "8"
- match: { _index: token_index }
- match: { _type: _doc }
- match: { _id: "8" }
- is_true: _source.token
- set: { _source.token : refresh_token }
- do:
security.get_token:
body:
grant_type: "refresh_token"
refresh_token: "${refresh_token}"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- is_true: refresh_token
- set: { refresh_token: refresh_token }
- match: { expires_in: 3600 }
- is_false: scope
- do:
headers:
Authorization: Bearer ${token}
security.authenticate: {}
- match: { username: "token_user" }
- match: { roles.0: "superuser" }
- match: { full_name: "Token User" }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }
# overwrite the used refresh token with the new one
- do:
headers:
Authorization: Bearer ${token}
index:
index: token_index
id: "8"
body: { "token" : "${refresh_token}"}

View File

@ -27,7 +27,9 @@
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- match: { expires_in: 1200 }
- is_true: refresh_token
- set: { refresh_token: refresh_token }
- match: { expires_in: 3600 }
- is_false: scope
- do:
@ -54,15 +56,15 @@
bulk:
refresh: true
body:
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "1"}}'
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "1"}}'
- '{"f1": "v1_old", "f2": 0}'
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "2"}}'
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "2"}}'
- '{"f1": "v2_old", "f2": 1}'
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "3"}}'
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "3"}}'
- '{"f1": "v3_old", "f2": 2}'
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "4"}}'
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "4"}}'
- '{"f1": "v4_old", "f2": 3}'
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "5"}}'
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "5"}}'
- '{"f1": "v5_old", "f2": 4}'
- do:
@ -81,6 +83,48 @@
Authorization: Bearer ${token}
index:
index: token_index
type: doc
id: "6"
body: { "token" : "${token}"}
# refresh token and store it as well
- do:
security.get_token:
body:
grant_type: "refresh_token"
refresh_token: "${refresh_token}"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: refreshed_access_token }
- is_true: refresh_token
- set: { refresh_token: refreshed_refresh_token }
- match: { expires_in: 3600 }
- is_false: scope
# test refresh token (use it)
- do:
headers:
Authorization: Bearer ${refreshed_access_token}
security.authenticate: {}
- match: { username: "token_user" }
- match: { roles.0: "superuser" }
- match: { full_name: "Token User" }
# store the new refreshed access token
- do:
headers:
Authorization: Bearer ${refreshed_access_token}
index:
index: token_index
id: "7"
body: { "token" : "${refreshed_access_token}"}
# store the refresh token
- do:
headers:
Authorization: Bearer ${refreshed_access_token}
index:
index: token_index
id: "8"
body: { "token" : "${refreshed_refresh_token}"}

View File

@ -2,14 +2,18 @@
"Get the indexed token and use if to authenticate":
- skip:
features: headers
- do:
cluster.health:
wait_for_status: yellow
- do:
get:
index: token_index
type: doc
id: "6"
- match: { _index: token_index }
- match: { _type: doc }
- match: { _type: _doc }
- match: { _id: "6" }
- is_true: _source.token
- set: { _source.token : token }
@ -30,7 +34,7 @@
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 6 }
- match: { hits.total: 8 }
# counter example that we are really checking this
- do:
@ -40,3 +44,51 @@
search:
rest_total_hits_as_int: true
index: token_index
---
"Get the indexed refresh token and use if to get another access token and authenticate":
- skip:
features: headers
- do:
get:
index: token_index
id: "8"
- match: { _index: token_index }
- match: { _type: _doc }
- match: { _id: "8" }
- is_true: _source.token
- set: { _source.token : refresh_token }
- do:
security.get_token:
body:
grant_type: "refresh_token"
refresh_token: "${refresh_token}"
- match: { type: "Bearer" }
- is_true: access_token
- set: { access_token: token }
- is_true: refresh_token
- set: { refresh_token: refresh_token }
- match: { expires_in: 3600 }
- is_false: scope
- do:
headers:
Authorization: Bearer ${token}
security.authenticate: {}
- match: { username: "token_user" }
- match: { roles.0: "superuser" }
- match: { full_name: "Token User" }
- do:
headers:
Authorization: Bearer ${token}
search:
rest_total_hits_as_int: true
index: token_index
- match: { hits.total: 8 }

View File

@ -199,7 +199,7 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
@Override
public Set<String> excludeTemplates() {
Set<String> templates = Sets.newHashSet(super.excludeTemplates());
templates.add(SecurityIndexManager.SECURITY_TEMPLATE_NAME); // don't remove the security index template
templates.add(SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7); // don't remove the security index template
return templates;
}