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:
parent
bc333a5cbf
commit
990be1f806
|
@ -14,12 +14,15 @@ import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public final class RestrictedIndicesNames {
|
public final class RestrictedIndicesNames {
|
||||||
public static final String INTERNAL_SECURITY_INDEX_6 = ".security-6";
|
public static final String INTERNAL_SECURITY_MAIN_INDEX_6 = ".security-6";
|
||||||
public static final String INTERNAL_SECURITY_INDEX_7 = ".security-7";
|
public static final String INTERNAL_SECURITY_MAIN_INDEX_7 = ".security-7";
|
||||||
public static final String SECURITY_INDEX_NAME = ".security";
|
public static final String SECURITY_MAIN_ALIAS = ".security";
|
||||||
|
|
||||||
public static final Set<String> RESTRICTED_NAMES = Collections.unmodifiableSet(
|
public static final String INTERNAL_SECURITY_TOKENS_INDEX_7 = ".security-tokens-7";
|
||||||
Sets.newHashSet(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX_6, INTERNAL_SECURITY_INDEX_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);
|
public static final Automaton NAMES_AUTOMATON = Automatons.patterns(RESTRICTED_NAMES);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"index_patterns" : [ ".security-*" ],
|
"index_patterns" : [ ".security-7" ],
|
||||||
"order" : 1000,
|
"order" : 1000,
|
||||||
"settings" : {
|
"settings" : {
|
||||||
"number_of_shards" : 1,
|
"number_of_shards" : 1,
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -601,14 +601,14 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
||||||
|
|
||||||
private void assertMonitoringOnRestrictedIndices(Role role) {
|
private void assertMonitoringOnRestrictedIndices(Role role) {
|
||||||
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
final MetaData metaData = new MetaData.Builder()
|
final MetaData metaData = new MetaData.Builder()
|
||||||
.put(new IndexMetaData.Builder(internalSecurityIndex)
|
.put(new IndexMetaData.Builder(internalSecurityIndex)
|
||||||
.settings(indexSettings)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
||||||
|
@ -616,10 +616,10 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
||||||
GetSettingsAction.NAME, IndicesShardStoresAction.NAME, UpgradeStatusAction.NAME, RecoveryAction.NAME);
|
GetSettingsAction.NAME, IndicesShardStoresAction.NAME, UpgradeStatusAction.NAME, RecoveryAction.NAME);
|
||||||
for (final String indexMonitoringActionName : indexMonitoringActionNamesList) {
|
for (final String indexMonitoringActionName : indexMonitoringActionNamesList) {
|
||||||
final Map<String, IndexAccessControl> authzMap = role.indices().authorize(indexMonitoringActionName,
|
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);
|
metaData.getAliasAndIndexLookup(), fieldPermissionsCache);
|
||||||
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
|
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));
|
assertThat(superuserRole.cluster().check("internal:admin/foo", request), is(false));
|
||||||
|
|
||||||
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
final MetaData metaData = new MetaData.Builder()
|
final MetaData metaData = new MetaData.Builder()
|
||||||
.put(new IndexMetaData.Builder("a1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
.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)
|
.put(new IndexMetaData.Builder("a2").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||||
|
@ -731,7 +731,7 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
||||||
.settings(indexSettings)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -753,8 +753,8 @@ public class ReservedRolesStoreTests extends ESTestCase {
|
||||||
assertThat(authzMap.get("aaaaaa").isGranted(), is(true));
|
assertThat(authzMap.get("aaaaaa").isGranted(), is(true));
|
||||||
assertThat(authzMap.get("b").isGranted(), is(true));
|
assertThat(authzMap.get("b").isGranted(), is(true));
|
||||||
authzMap = superuserRole.indices().authorize(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME),
|
authzMap = superuserRole.indices().authorize(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME),
|
||||||
Sets.newHashSet(RestrictedIndicesNames.SECURITY_INDEX_NAME), lookup, fieldPermissionsCache);
|
Sets.newHashSet(RestrictedIndicesNames.SECURITY_MAIN_ALIAS), lookup, fieldPermissionsCache);
|
||||||
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_INDEX_NAME).isGranted(), is(true));
|
assertThat(authzMap.get(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).isGranted(), is(true));
|
||||||
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
|
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
|
||||||
assertTrue(superuserRole.indices().check(SearchAction.NAME));
|
assertTrue(superuserRole.indices().check(SearchAction.NAME));
|
||||||
assertFalse(superuserRole.indices().check("unknown"));
|
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.runAs().check(randomAlphaOfLengthBetween(1, 30)), is(true));
|
||||||
|
|
||||||
assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME))
|
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))
|
assertThat(superuserRole.indices().allowedIndicesMatcher(randomFrom(IndexAction.NAME, DeleteIndexAction.NAME, SearchAction.NAME))
|
||||||
.test(internalSecurityIndex), is(true));
|
.test(internalSecurityIndex), is(true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,9 +258,9 @@ import static java.util.Collections.singletonList;
|
||||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
|
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.API_KEY_SERVICE_ENABLED_SETTING;
|
||||||
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
|
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.INTERNAL_MAIN_INDEX_FORMAT;
|
||||||
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.SECURITY_TEMPLATE_NAME;
|
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7;
|
||||||
|
|
||||||
public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin,
|
public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin,
|
||||||
DiscoveryPlugin, MapperPlugin, ExtensiblePlugin {
|
DiscoveryPlugin, MapperPlugin, ExtensiblePlugin {
|
||||||
|
@ -406,9 +406,10 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
components.add(auditTrailService);
|
components.add(auditTrailService);
|
||||||
this.auditTrailService.set(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);
|
this.tokenService.set(tokenService);
|
||||||
components.add(tokenService);
|
components.add(tokenService);
|
||||||
|
|
||||||
|
@ -948,7 +949,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDataUpgrader() {
|
public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDataUpgrader() {
|
||||||
return templates -> {
|
return templates -> {
|
||||||
// .security index is not managed by using templates anymore
|
// .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");
|
templates.remove("security_audit_log");
|
||||||
return templates;
|
return templates;
|
||||||
};
|
};
|
||||||
|
@ -1015,9 +1016,9 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
@Override
|
@Override
|
||||||
public void accept(DiscoveryNode node, ClusterState state) {
|
public void accept(DiscoveryNode node, ClusterState state) {
|
||||||
if (state.getNodes().getMinNodeVersion().before(Version.V_7_0_0)) {
|
if (state.getNodes().getMinNodeVersion().before(Version.V_7_0_0)) {
|
||||||
IndexMetaData indexMetaData = state.getMetaData().getIndices().get(SECURITY_INDEX_NAME);
|
IndexMetaData indexMetaData = state.getMetaData().getIndices().get(SECURITY_MAIN_ALIAS);
|
||||||
if (indexMetaData != null && INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()) < INTERNAL_INDEX_FORMAT) {
|
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_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");
|
"The Upgrade API must be run for 7.x nodes to join the cluster");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
|
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 {
|
public class ApiKeyService {
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ public class ApiKeyService {
|
||||||
.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
|
.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
|
||||||
boolQuery.filter(expiredQuery);
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(boolQuery)
|
.setQuery(boolQuery)
|
||||||
.setVersion(false)
|
.setVersion(false)
|
||||||
|
@ -286,7 +286,7 @@ public class ApiKeyService {
|
||||||
.endObject()
|
.endObject()
|
||||||
.endObject();
|
.endObject();
|
||||||
final IndexRequest indexRequest =
|
final IndexRequest indexRequest =
|
||||||
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME)
|
client.prepareIndex(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME)
|
||||||
.setSource(builder)
|
.setSource(builder)
|
||||||
.setRefreshPolicy(request.getRefreshPolicy())
|
.setRefreshPolicy(request.getRefreshPolicy())
|
||||||
.request();
|
.request();
|
||||||
|
@ -319,7 +319,7 @@ public class ApiKeyService {
|
||||||
|
|
||||||
if (credentials != null) {
|
if (credentials != null) {
|
||||||
final GetRequest getRequest = client
|
final GetRequest getRequest = client
|
||||||
.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, credentials.getId())
|
.prepareGet(SECURITY_MAIN_ALIAS, SINGLE_MAPPING_NAME, credentials.getId())
|
||||||
.setFetchSource(true)
|
.setFetchSource(true)
|
||||||
.request();
|
.request();
|
||||||
executeAsyncWithOrigin(ctx, SECURITY_ORIGIN, getRequest, ActionListener.<GetResponse>wrap(response -> {
|
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")));
|
expiredQuery.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
|
||||||
boolQuery.filter(expiredQuery);
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(boolQuery)
|
.setQuery(boolQuery)
|
||||||
.setVersion(false)
|
.setVersion(false)
|
||||||
|
@ -801,7 +801,7 @@ public class ApiKeyService {
|
||||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
||||||
for (String apiKeyId : apiKeyIds) {
|
for (String apiKeyId : apiKeyIds) {
|
||||||
UpdateRequest request = client
|
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))
|
.setDoc(Collections.singletonMap("api_key_invalidated", true))
|
||||||
.request();
|
.request();
|
||||||
bulkRequestBuilder.add(request);
|
bulkRequestBuilder.add(request);
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||||
import org.elasticsearch.index.reindex.ScrollableHitSource;
|
import org.elasticsearch.index.reindex.ScrollableHitSource;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.threadpool.ThreadPool.Names;
|
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.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
@ -51,7 +51,7 @@ public final class ExpiredApiKeysRemover extends AbstractRunnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doRun() {
|
public void doRun() {
|
||||||
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(SecurityIndexManager.SECURITY_INDEX_NAME);
|
DeleteByQueryRequest expiredDbq = new DeleteByQueryRequest(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
|
||||||
if (timeout != TimeValue.MINUS_ONE) {
|
if (timeout != TimeValue.MINUS_ONE) {
|
||||||
expiredDbq.setTimeout(timeout);
|
expiredDbq.setTimeout(timeout);
|
||||||
expiredDbq.getSearchRequest().source().timeout(timeout);
|
expiredDbq.getSearchRequest().source().timeout(timeout);
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
|
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;
|
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for cleaning the invalidated and expired tokens from the security index.
|
* Responsible for cleaning the invalidated and expired tokens from the security indices (`main` and `tokens`).
|
||||||
* The document gets deleted if it was created more than 24 hours which is the maximum
|
* The document is deleted if it was created more than {@code #MAXIMUM_TOKEN_LIFETIME_HOURS} hours in the past.
|
||||||
* lifetime of a refresh token
|
|
||||||
*/
|
*/
|
||||||
final class ExpiredTokenRemover extends AbstractRunnable {
|
final class ExpiredTokenRemover extends AbstractRunnable {
|
||||||
private static final Logger logger = LogManager.getLogger(ExpiredTokenRemover.class);
|
private static final Logger logger = LogManager.getLogger(ExpiredTokenRemover.class);
|
||||||
|
|
||||||
private final Client client;
|
public static final long MAXIMUM_TOKEN_LIFETIME_HOURS = 24L;
|
||||||
private final AtomicBoolean inProgress = new AtomicBoolean(false);
|
|
||||||
private final TimeValue timeout;
|
|
||||||
|
|
||||||
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.client = client;
|
||||||
|
this.securityMainIndex = securityMainIndex;
|
||||||
|
this.securityTokensIndex = securityTokensIndex;
|
||||||
|
this.inProgress = new AtomicBoolean(false);
|
||||||
this.timeout = TokenService.DELETE_TIMEOUT.get(settings);
|
this.timeout = TokenService.DELETE_TIMEOUT.get(settings);
|
||||||
|
this.checkMainIndexForExpiredTokens = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doRun() {
|
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) {
|
if (timeout != TimeValue.MINUS_ONE) {
|
||||||
expiredDbq.setTimeout(timeout);
|
expiredDbq.setTimeout(timeout);
|
||||||
expiredDbq.getSearchRequest().source().timeout(timeout);
|
expiredDbq.getSearchRequest().source().timeout(timeout);
|
||||||
|
@ -59,12 +80,20 @@ final class ExpiredTokenRemover extends AbstractRunnable {
|
||||||
final Instant now = Instant.now();
|
final Instant now = Instant.now();
|
||||||
expiredDbq
|
expiredDbq
|
||||||
.setQuery(QueryBuilders.boolQuery()
|
.setQuery(QueryBuilders.boolQuery()
|
||||||
.filter(QueryBuilders.termsQuery("doc_type", "token"))
|
.filter(QueryBuilders.termsQuery("doc_type", TokenService.TOKEN_DOC_TYPE))
|
||||||
.filter(QueryBuilders.rangeQuery("creation_time").lte(now.minus(24L, ChronoUnit.HOURS).toEpochMilli())));
|
.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)));
|
logger.trace(() -> new ParameterizedMessage("Removing old tokens: [{}]", Strings.toString(expiredDbq)));
|
||||||
executeAsyncWithOrigin(client, SECURITY_ORIGIN, DeleteByQueryAction.INSTANCE, expiredDbq,
|
executeAsyncWithOrigin(client, SECURITY_ORIGIN, DeleteByQueryAction.INSTANCE, expiredDbq,
|
||||||
ActionListener.wrap(r -> {
|
ActionListener.wrap(bulkResponse -> {
|
||||||
debugDbqResponse(r);
|
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();
|
markComplete();
|
||||||
}, this::onFailure));
|
}, this::onFailure));
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
|
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
|
* 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);
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(query)
|
.setQuery(query)
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
|
@ -171,7 +171,7 @@ public class NativeUsersStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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))
|
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE))
|
||||||
.setSize(0)
|
.setSize(0)
|
||||||
.setTrackTotalHits(true)
|
.setTrackTotalHits(true)
|
||||||
|
@ -205,7 +205,7 @@ public class NativeUsersStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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>() {
|
new ActionListener<GetResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(GetResponse response) {
|
public void onResponse(GetResponse response) {
|
||||||
|
@ -245,7 +245,7 @@ public class NativeUsersStore {
|
||||||
|
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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(),
|
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(),
|
||||||
String.valueOf(request.passwordHash()))
|
String.valueOf(request.passwordHash()))
|
||||||
.setRefreshPolicy(request.getRefreshPolicy()).request(),
|
.setRefreshPolicy(request.getRefreshPolicy()).request(),
|
||||||
|
@ -283,7 +283,7 @@ public class NativeUsersStore {
|
||||||
private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) {
|
private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) {
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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(),
|
.setSource(Fields.PASSWORD.getPreferredName(), String.valueOf(passwordHash), Fields.ENABLED.getPreferredName(),
|
||||||
true, Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)
|
true, Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)
|
||||||
.setRefreshPolicy(refresh).request(),
|
.setRefreshPolicy(refresh).request(),
|
||||||
|
@ -323,7 +323,7 @@ public class NativeUsersStore {
|
||||||
// We must have an existing document
|
// We must have an existing document
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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,
|
.setDoc(Requests.INDEX_CONTENT_TYPE,
|
||||||
Fields.USERNAME.getPreferredName(), putUserRequest.username(),
|
Fields.USERNAME.getPreferredName(), putUserRequest.username(),
|
||||||
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
|
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
|
||||||
|
@ -367,7 +367,7 @@ public class NativeUsersStore {
|
||||||
assert putUserRequest.passwordHash() != null;
|
assert putUserRequest.passwordHash() != null;
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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(),
|
.setSource(Fields.USERNAME.getPreferredName(), putUserRequest.username(),
|
||||||
Fields.PASSWORD.getPreferredName(), String.valueOf(putUserRequest.passwordHash()),
|
Fields.PASSWORD.getPreferredName(), String.valueOf(putUserRequest.passwordHash()),
|
||||||
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
|
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
|
||||||
|
@ -410,7 +410,7 @@ public class NativeUsersStore {
|
||||||
final ActionListener<Void> listener) {
|
final ActionListener<Void> listener) {
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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)
|
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
|
||||||
.setRefreshPolicy(refreshPolicy)
|
.setRefreshPolicy(refreshPolicy)
|
||||||
.request(),
|
.request(),
|
||||||
|
@ -444,7 +444,7 @@ public class NativeUsersStore {
|
||||||
boolean clearCache, final ActionListener<Void> listener) {
|
boolean clearCache, final ActionListener<Void> listener) {
|
||||||
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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)
|
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
|
||||||
.setUpsert(XContentType.JSON,
|
.setUpsert(XContentType.JSON,
|
||||||
Fields.PASSWORD.getPreferredName(), "",
|
Fields.PASSWORD.getPreferredName(), "",
|
||||||
|
@ -479,7 +479,7 @@ public class NativeUsersStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
||||||
DeleteRequest request = client
|
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();
|
||||||
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
|
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
|
||||||
|
@ -526,7 +526,7 @@ public class NativeUsersStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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(),
|
.request(),
|
||||||
new ActionListener<GetResponse>() {
|
new ActionListener<GetResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -571,7 +571,7 @@ public class NativeUsersStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
||||||
client.prepareSearch(SECURITY_INDEX_NAME)
|
client.prepareSearch(SECURITY_MAIN_ALIAS)
|
||||||
.setTrackTotalHits(true)
|
.setTrackTotalHits(true)
|
||||||
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE))
|
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE))
|
||||||
.setFetchSource(true).request(),
|
.setFetchSource(true).request(),
|
||||||
|
|
|
@ -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.ExpressionRoleMapping;
|
||||||
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExpressionModel;
|
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.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.CachingRealm;
|
||||||
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
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.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
|
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.isIndexDeleted;
|
||||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isMoveFromRedToNonRed;
|
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.isMoveFromRedToNonRed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This store reads + writes {@link ExpressionRoleMapping role mappings} in an Elasticsearch
|
* This store reads + writes {@link ExpressionRoleMapping role mappings} in an Elasticsearch
|
||||||
* {@link SecurityIndexManager#SECURITY_INDEX_NAME index}.
|
* {@link RestrictedIndicesNames#SECURITY_MAIN_ALIAS index}.
|
||||||
* <br>
|
* <br>
|
||||||
* The store is responsible for all read and write operations as well as
|
* The store is responsible for all read and write operations as well as
|
||||||
* {@link #resolveRoles(UserData, ActionListener) resolving roles}.
|
* {@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 QueryBuilder query = QueryBuilders.termQuery(DOC_TYPE_FIELD, DOC_TYPE_ROLE_MAPPING);
|
||||||
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(query)
|
.setQuery(query)
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
|
@ -143,7 +144,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
|
||||||
listener.onResponse(mappings.stream().filter(Objects::nonNull).collect(Collectors.toList())),
|
listener.onResponse(mappings.stream().filter(Objects::nonNull).collect(Collectors.toList())),
|
||||||
ex -> {
|
ex -> {
|
||||||
logger.error(new ParameterizedMessage("failed to load role mappings from index [{}] skipping all mappings.",
|
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());
|
listener.onResponse(Collections.emptyList());
|
||||||
})),
|
})),
|
||||||
doc -> buildMapping(getNameFromId(doc.getId()), doc.getSourceRef()));
|
doc -> buildMapping(getNameFromId(doc.getId()), doc.getSourceRef()));
|
||||||
|
@ -202,7 +203,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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)
|
.setSource(xContentBuilder)
|
||||||
.setRefreshPolicy(request.getRefreshPolicy())
|
.setRefreshPolicy(request.getRefreshPolicy())
|
||||||
.request(),
|
.request(),
|
||||||
|
@ -231,7 +232,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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())
|
.setRefreshPolicy(request.getRefreshPolicy())
|
||||||
.request(),
|
.request(),
|
||||||
new ActionListener<DeleteResponse>() {
|
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");
|
logger.info("The security index is not yet available - no role mappings can be loaded");
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Security Index [{}] [exists: {}] [available: {}] [mapping up to date: {}]",
|
logger.debug("Security Index [{}] [exists: {}] [available: {}] [mapping up to date: {}]",
|
||||||
SECURITY_INDEX_NAME,
|
SECURITY_MAIN_ALIAS,
|
||||||
securityIndex.indexExists(),
|
securityIndex.indexExists(),
|
||||||
securityIndex.isAvailable(),
|
securityIndex.isAvailable(),
|
||||||
securityIndex.isMappingUpToDate()
|
securityIndex.isMappingUpToDate()
|
||||||
|
|
|
@ -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.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.DOC_TYPE_VALUE;
|
||||||
import static org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor.Fields.APPLICATION;
|
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,
|
* {@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);
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(query)
|
.setQuery(query)
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
|
@ -201,7 +201,7 @@ public class NativePrivilegeStore {
|
||||||
} else {
|
} else {
|
||||||
securityIndexManager.checkIndexVersionThenExecute(listener::onFailure,
|
securityIndexManager.checkIndexVersionThenExecute(listener::onFailure,
|
||||||
() -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
() -> 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(),
|
.request(),
|
||||||
new ActionListener<GetResponse>() {
|
new ActionListener<GetResponse>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -253,7 +253,7 @@ public class NativePrivilegeStore {
|
||||||
final String name = privilege.getName();
|
final String name = privilege.getName();
|
||||||
final XContentBuilder xContentBuilder = privilege.toXContent(jsonBuilder(), true);
|
final XContentBuilder xContentBuilder = privilege.toXContent(jsonBuilder(), true);
|
||||||
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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)
|
.setSource(xContentBuilder)
|
||||||
.setRefreshPolicy(refreshPolicy)
|
.setRefreshPolicy(refreshPolicy)
|
||||||
.request(), listener, client::index);
|
.request(), listener, client::index);
|
||||||
|
@ -284,7 +284,7 @@ public class NativePrivilegeStore {
|
||||||
}, listener::onFailure), names.size());
|
}, listener::onFailure), names.size());
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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)
|
.setRefreshPolicy(refreshPolicy)
|
||||||
.request(), groupListener, client::delete);
|
.request(), groupListener, client::delete);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.ClientHelper.executeAsyncWithOrigin;
|
||||||
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
|
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.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
|
* 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);
|
QueryBuilder query = QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE);
|
||||||
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
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))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(query)
|
.setQuery(query)
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
|
@ -142,7 +142,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
||||||
final String[] roleIds = names.stream().map(NativeRolesStore::getIdForRole).toArray(String[]::new);
|
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,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, multiGetRequest,
|
||||||
ActionListener.<MultiGetResponse>wrap(mGetResponse -> {
|
ActionListener.<MultiGetResponse>wrap(mGetResponse -> {
|
||||||
final MultiGetItemResponse[] responses = mGetResponse.getResponses();
|
final MultiGetItemResponse[] responses = mGetResponse.getResponses();
|
||||||
|
@ -179,7 +179,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
} else {
|
} else {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
|
||||||
DeleteRequest request = client
|
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());
|
request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy());
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
|
||||||
new ActionListener<DeleteResponse>() {
|
new ActionListener<DeleteResponse>() {
|
||||||
|
@ -219,7 +219,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
listener.onFailure(e);
|
listener.onFailure(e);
|
||||||
return;
|
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)
|
.setSource(xContentBuilder)
|
||||||
.setRefreshPolicy(request.getRefreshPolicy())
|
.setRefreshPolicy(request.getRefreshPolicy())
|
||||||
.request();
|
.request();
|
||||||
|
@ -253,11 +253,11 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
||||||
client.prepareMultiSearch()
|
client.prepareMultiSearch()
|
||||||
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
|
||||||
.setQuery(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
.setQuery(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
||||||
.setTrackTotalHits(true)
|
.setTrackTotalHits(true)
|
||||||
.setSize(0))
|
.setSize(0))
|
||||||
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
|
||||||
.setQuery(QueryBuilders.boolQuery()
|
.setQuery(QueryBuilders.boolQuery()
|
||||||
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
||||||
.must(QueryBuilders.boolQuery()
|
.must(QueryBuilders.boolQuery()
|
||||||
|
@ -268,7 +268,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
.setTrackTotalHits(true)
|
.setTrackTotalHits(true)
|
||||||
.setSize(0)
|
.setSize(0)
|
||||||
.setTerminateAfter(1))
|
.setTerminateAfter(1))
|
||||||
.add(client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
.add(client.prepareSearch(SECURITY_MAIN_ALIAS)
|
||||||
.setQuery(QueryBuilders.boolQuery()
|
.setQuery(QueryBuilders.boolQuery()
|
||||||
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
.must(QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE))
|
||||||
.filter(existsQuery("indices.query")))
|
.filter(existsQuery("indices.query")))
|
||||||
|
@ -340,7 +340,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
|
||||||
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
|
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
|
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,
|
listener,
|
||||||
client::get));
|
client::get));
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.elasticsearch.xpack.core.template.TemplateUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -77,12 +78,13 @@ import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
|
||||||
*/
|
*/
|
||||||
public class SecurityIndexManager implements ClusterStateListener {
|
public class SecurityIndexManager implements ClusterStateListener {
|
||||||
|
|
||||||
public static final String INTERNAL_SECURITY_INDEX = RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7;
|
public static final int INTERNAL_MAIN_INDEX_FORMAT = 6;
|
||||||
public static final int INTERNAL_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 SECURITY_VERSION_STRING = "security-version";
|
||||||
public static final String TEMPLATE_VERSION_PATTERN = Pattern.quote("${security.template.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 static final Logger logger = LogManager.getLogger(SecurityIndexManager.class);
|
||||||
|
|
||||||
private final String aliasName;
|
private final String aliasName;
|
||||||
|
@ -95,19 +97,26 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
|
|
||||||
private volatile State indexState;
|
private volatile State indexState;
|
||||||
|
|
||||||
public static SecurityIndexManager buildSecurityIndexManager(Client client, ClusterService clusterService) {
|
public static SecurityIndexManager buildSecurityMainIndexManager(Client client, ClusterService clusterService) {
|
||||||
return new SecurityIndexManager(client, SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX, INTERNAL_INDEX_FORMAT,
|
return new SecurityIndexManager(client, clusterService, RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
SecurityIndexManager::readSecurityTemplateAsBytes, clusterService);
|
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,
|
public static SecurityIndexManager buildSecurityTokensIndexManager(Client client, ClusterService clusterService) {
|
||||||
Supplier<byte[]> mappingSourceSupplier, 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);
|
this(client, aliasName, internalIndexName, internalIndexFormat, mappingSourceSupplier, State.UNRECOVERED_STATE);
|
||||||
clusterService.addListener(this);
|
clusterService.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecurityIndexManager(Client client, String aliasName, String internalIndexName, int internalIndexFormat,
|
private SecurityIndexManager(Client client, String aliasName, String internalIndexName, int internalIndexFormat,
|
||||||
Supplier<byte[]> mappingSourceSupplier, State indexState) {
|
Supplier<byte[]> mappingSourceSupplier, State indexState) {
|
||||||
this.aliasName = aliasName;
|
this.aliasName = aliasName;
|
||||||
this.internalIndexName = internalIndexName;
|
this.internalIndexName = internalIndexName;
|
||||||
this.internalIndexFormat = internalIndexFormat;
|
this.internalIndexFormat = internalIndexFormat;
|
||||||
|
@ -126,8 +135,16 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
return currentIndexState.mappingVersion == null || requiredVersion.test(currentIndexState.mappingVersion);
|
return currentIndexState.mappingVersion == null || requiredVersion.test(currentIndexState.mappingVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String aliasName() {
|
||||||
|
return aliasName;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean indexExists() {
|
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");
|
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,
|
return new UnavailableShardsException(null,
|
||||||
"at least one primary shard for the index [" + localState.concreteIndexName + "] is unavailable");
|
"at least one primary shard for the index [" + localState.concreteIndexName + "] is unavailable");
|
||||||
} else {
|
} else {
|
||||||
|
@ -183,17 +200,17 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
}
|
}
|
||||||
final State previousState = indexState;
|
final State previousState = indexState;
|
||||||
final IndexMetaData indexMetaData = resolveConcreteIndex(aliasName, event.state().metaData());
|
final IndexMetaData indexMetaData = resolveConcreteIndex(aliasName, event.state().metaData());
|
||||||
final boolean indexExists = indexMetaData != null;
|
final Instant creationTime = indexMetaData != null ? Instant.ofEpochMilli(indexMetaData.getCreationDate()) : null;
|
||||||
final boolean isIndexUpToDate = indexExists == false ||
|
final boolean isIndexUpToDate = indexMetaData == null ||
|
||||||
INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()).intValue() == internalIndexFormat;
|
INDEX_FORMAT_SETTING.get(indexMetaData.getSettings()).intValue() == internalIndexFormat;
|
||||||
final boolean indexAvailable = checkIndexAvailable(event.state());
|
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 Version mappingVersion = oldestIndexMappingVersion(event.state());
|
||||||
final ClusterHealthStatus indexStatus = indexMetaData == null ? null :
|
final ClusterHealthStatus indexStatus = indexMetaData == null ? null :
|
||||||
new ClusterIndexHealth(indexMetaData, event.state().getRoutingTable().index(indexMetaData.getIndex())).getStatus();
|
new ClusterIndexHealth(indexMetaData, event.state().getRoutingTable().index(indexMetaData.getIndex())).getStatus();
|
||||||
final String concreteIndexName = indexMetaData == null ? internalIndexName : indexMetaData.getIndex().getName();
|
final String concreteIndexName = indexMetaData == null ? internalIndexName : indexMetaData.getIndex().getName();
|
||||||
final State newState = new State(indexExists, isIndexUpToDate, indexAvailable, mappingIsUpToDate, mappingVersion, concreteIndexName,
|
final State newState = new State(creationTime, isIndexUpToDate, indexAvailable, mappingIsUpToDate, mappingVersion,
|
||||||
indexStatus);
|
concreteIndexName, indexStatus);
|
||||||
this.indexState = newState;
|
this.indexState = newState;
|
||||||
|
|
||||||
if (newState.equals(previousState) == false) {
|
if (newState.equals(previousState) == false) {
|
||||||
|
@ -304,7 +321,7 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
*/
|
*/
|
||||||
public void checkIndexVersionThenExecute(final Consumer<Exception> consumer, final Runnable andThen) {
|
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!
|
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(
|
consumer.accept(new IllegalStateException(
|
||||||
"Index [" + indexState.concreteIndexName + "] is not on the current version. Security features relying on the index"
|
"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"));
|
+ " 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(
|
consumer.accept(new ElasticsearchStatusException(
|
||||||
"Cluster state has not been recovered yet, cannot write to the [" + indexState.concreteIndexName + "] index",
|
"Cluster state has not been recovered yet, cannot write to the [" + indexState.concreteIndexName + "] index",
|
||||||
RestStatus.SERVICE_UNAVAILABLE));
|
RestStatus.SERVICE_UNAVAILABLE));
|
||||||
} else if (indexState.indexExists && indexState.isIndexUpToDate == false) {
|
} else if (indexState.indexExists() && indexState.isIndexUpToDate == false) {
|
||||||
consumer.accept(new IllegalStateException(
|
consumer.accept(new IllegalStateException(
|
||||||
"Index [" + indexState.concreteIndexName + "] is not on the current version."
|
"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"));
|
+ "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;
|
assert indexState.concreteIndexName != null;
|
||||||
logger.info("security index does not exist. Creating [{}] with alias [{}]", indexState.concreteIndexName, this.aliasName);
|
logger.info("security index does not exist. Creating [{}] with alias [{}]", indexState.concreteIndexName, this.aliasName);
|
||||||
final byte[] mappingSource = mappingSourceSupplier.get();
|
final byte[] mappingSource = mappingSourceSupplier.get();
|
||||||
|
@ -396,8 +413,8 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
return previousState.indexStatus != null && currentState.indexStatus == null;
|
return previousState.indexStatus != null && currentState.indexStatus == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] readSecurityTemplateAsBytes() {
|
private static byte[] readTemplateAsBytes(String templateName) {
|
||||||
return TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json", Version.CURRENT.toString(),
|
return TemplateUtils.loadTemplate("/" + templateName + ".json", Version.CURRENT.toString(),
|
||||||
SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
|
SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,8 +440,8 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
* State of the security index.
|
* State of the security index.
|
||||||
*/
|
*/
|
||||||
public static class State {
|
public static class State {
|
||||||
public static final State UNRECOVERED_STATE = new State(false, false, false, false, null, null, null);
|
public static final State UNRECOVERED_STATE = new State(null, false, false, false, null, null, null);
|
||||||
public final boolean indexExists;
|
public final Instant creationTime;
|
||||||
public final boolean isIndexUpToDate;
|
public final boolean isIndexUpToDate;
|
||||||
public final boolean indexAvailable;
|
public final boolean indexAvailable;
|
||||||
public final boolean mappingUpToDate;
|
public final boolean mappingUpToDate;
|
||||||
|
@ -432,9 +449,9 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
public final String concreteIndexName;
|
public final String concreteIndexName;
|
||||||
public final ClusterHealthStatus indexStatus;
|
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) {
|
boolean mappingUpToDate, Version mappingVersion, String concreteIndexName, ClusterHealthStatus indexStatus) {
|
||||||
this.indexExists = indexExists;
|
this.creationTime = creationTime;
|
||||||
this.isIndexUpToDate = isIndexUpToDate;
|
this.isIndexUpToDate = isIndexUpToDate;
|
||||||
this.indexAvailable = indexAvailable;
|
this.indexAvailable = indexAvailable;
|
||||||
this.mappingUpToDate = mappingUpToDate;
|
this.mappingUpToDate = mappingUpToDate;
|
||||||
|
@ -448,7 +465,7 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
State state = (State) o;
|
State state = (State) o;
|
||||||
return indexExists == state.indexExists &&
|
return Objects.equals(creationTime, state.creationTime) &&
|
||||||
isIndexUpToDate == state.isIndexUpToDate &&
|
isIndexUpToDate == state.isIndexUpToDate &&
|
||||||
indexAvailable == state.indexAvailable &&
|
indexAvailable == state.indexAvailable &&
|
||||||
mappingUpToDate == state.mappingUpToDate &&
|
mappingUpToDate == state.mappingUpToDate &&
|
||||||
|
@ -457,9 +474,13 @@ public class SecurityIndexManager implements ClusterStateListener {
|
||||||
indexStatus == state.indexStatus;
|
indexStatus == state.indexStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean indexExists() {
|
||||||
|
return creationTime != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(indexExists, isIndexUpToDate, indexAvailable, mappingUpToDate, mappingVersion, concreteIndexName,
|
return Objects.hash(creationTime, isIndexUpToDate, indexAvailable, mappingUpToDate, mappingVersion, concreteIndexName,
|
||||||
indexStatus);
|
indexStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.action.role.PutRoleResponse;
|
||||||
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
|
import org.elasticsearch.xpack.core.security.authz.store.RoleRetrievalResult;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
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.authz.store.NativeRolesStore;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class ClearRolesCacheTests extends NativeRealmIntegTestCase {
|
||||||
logger.debug("--> created role [{}]", role);
|
logger.debug("--> created role [{}]", role);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
|
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
|
||||||
|
|
||||||
final Set<String> rolesSet = new HashSet<>(Arrays.asList(roles));
|
final Set<String> rolesSet = new HashSet<>(Arrays.asList(roles));
|
||||||
// warm up the caches on every node
|
// warm up the caches on every node
|
||||||
|
|
|
@ -59,7 +59,7 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
|
||||||
@Override
|
@Override
|
||||||
public Set<String> excludeTemplates() {
|
public Set<String> excludeTemplates() {
|
||||||
Set<String> templates = Sets.newHashSet(super.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;
|
return templates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.assertAcked;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
||||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
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.Matchers.is;
|
||||||
import static org.hamcrest.core.IsCollectionContaining.hasItem;
|
import static org.hamcrest.core.IsCollectionContaining.hasItem;
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
||||||
XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject();
|
XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject();
|
||||||
assertTrue("security index mapping not sufficient to read:\n" +
|
assertTrue("security index mapping not sufficient to read:\n" +
|
||||||
Strings.toString(clusterState.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject()),
|
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));
|
Version.CURRENT.minimumIndexCompatibilityVersion()::onOrBefore));
|
||||||
Index securityIndex = resolveSecurityIndex(clusterState.metaData());
|
Index securityIndex = resolveSecurityIndex(clusterState.metaData());
|
||||||
if (securityIndex != null) {
|
if (securityIndex != null) {
|
||||||
|
@ -509,7 +509,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
||||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_SUPERUSER,
|
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_SUPERUSER,
|
||||||
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
|
SecuritySettingsSourceField.TEST_PASSWORD_SECURE_STRING)));
|
||||||
GetIndexRequest getIndexRequest = new GetIndexRequest();
|
GetIndexRequest getIndexRequest = new GetIndexRequest();
|
||||||
getIndexRequest.indices(SECURITY_INDEX_NAME);
|
getIndexRequest.indices(SECURITY_MAIN_ALIAS);
|
||||||
getIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
|
getIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
|
||||||
GetIndexResponse getIndexResponse = client.admin().indices().getIndex(getIndexRequest).actionGet();
|
GetIndexResponse getIndexResponse = client.admin().indices().getIndex(getIndexRequest).actionGet();
|
||||||
if (getIndexResponse.getIndices().length > 0) {
|
if (getIndexResponse.getIndices().length > 0) {
|
||||||
|
@ -520,7 +520,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Index resolveSecurityIndex(MetaData metaData) {
|
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) {
|
if (aliasOrIndex != null) {
|
||||||
return aliasOrIndex.getIndices().get(0).getIndex();
|
return aliasOrIndex.getIndices().get(0).getIndex();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,8 +68,8 @@ import java.util.stream.Collectors;
|
||||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
|
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.ZEN2_DISCOVERY_TYPE;
|
||||||
import static org.elasticsearch.discovery.DiscoveryModule.ZEN_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.INTERNAL_MAIN_INDEX_FORMAT;
|
||||||
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.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -310,8 +310,8 @@ public class SecurityTests extends ESTestCase {
|
||||||
BiConsumer<DiscoveryNode, ClusterState> joinValidator = security.getJoinValidator();
|
BiConsumer<DiscoveryNode, ClusterState> joinValidator = security.getJoinValidator();
|
||||||
assertNotNull(joinValidator);
|
assertNotNull(joinValidator);
|
||||||
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
||||||
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
|
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
|
||||||
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT - 1))
|
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_MAIN_INDEX_FORMAT - 1))
|
||||||
.numberOfShards(1).numberOfReplicas(0)
|
.numberOfShards(1).numberOfReplicas(0)
|
||||||
.build();
|
.build();
|
||||||
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), Version.V_6_1_0);
|
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();
|
BiConsumer<DiscoveryNode, ClusterState> joinValidator = security.getJoinValidator();
|
||||||
assertNotNull(joinValidator);
|
assertNotNull(joinValidator);
|
||||||
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
||||||
int indexFormat = randomBoolean() ? INTERNAL_INDEX_FORMAT : INTERNAL_INDEX_FORMAT - 1;
|
int indexFormat = randomBoolean() ? INTERNAL_MAIN_INDEX_FORMAT : INTERNAL_MAIN_INDEX_FORMAT - 1;
|
||||||
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
|
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
|
||||||
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), indexFormat))
|
.settings(settings(Version.V_6_1_0).put(INDEX_FORMAT_SETTING.getKey(), indexFormat))
|
||||||
.numberOfShards(1).numberOfReplicas(0)
|
.numberOfShards(1).numberOfReplicas(0)
|
||||||
.build();
|
.build();
|
||||||
|
@ -349,8 +349,8 @@ public class SecurityTests extends ESTestCase {
|
||||||
assertNotNull(joinValidator);
|
assertNotNull(joinValidator);
|
||||||
Version version = randomBoolean() ? Version.CURRENT : Version.V_6_1_0;
|
Version version = randomBoolean() ? Version.CURRENT : Version.V_6_1_0;
|
||||||
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
|
||||||
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_INDEX_NAME)
|
IndexMetaData indexMetaData = IndexMetaData.builder(SECURITY_MAIN_ALIAS)
|
||||||
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_INDEX_FORMAT))
|
.settings(settings(version).put(INDEX_FORMAT_SETTING.getKey(), INTERNAL_MAIN_INDEX_FORMAT))
|
||||||
.numberOfShards(1).numberOfReplicas(0)
|
.numberOfShards(1).numberOfReplicas(0)
|
||||||
.build();
|
.build();
|
||||||
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), version);
|
DiscoveryNode existingOtherNode = new DiscoveryNode("bar", buildNewFakeTransportAddress(), version);
|
||||||
|
|
|
@ -167,7 +167,7 @@ public class TransportOpenIdConnectLogoutActionTests extends OpenIdConnectTestCa
|
||||||
when(securityIndex.isAvailable()).thenReturn(true);
|
when(securityIndex.isAvailable()).thenReturn(true);
|
||||||
|
|
||||||
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
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,
|
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||||
|
|
|
@ -195,10 +195,13 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase {
|
||||||
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
||||||
when(securityIndex.isAvailable()).thenReturn(true);
|
when(securityIndex.isAvailable()).thenReturn(true);
|
||||||
when(securityIndex.indexExists()).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);
|
when(securityIndex.freeze()).thenReturn(securityIndex);
|
||||||
|
|
||||||
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
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,
|
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
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(filter1.get(1), instanceOf(TermQueryBuilder.class));
|
||||||
assertThat(((TermQueryBuilder) filter1.get(1)).fieldName(), equalTo("refresh_token.token"));
|
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)
|
assertThat(bulkRequests.size(), equalTo(4)); // 4 updates (refresh-token + access-token)
|
||||||
// Invalidate refresh token 1
|
// Invalidate refresh token 1
|
||||||
|
|
|
@ -203,7 +203,7 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
|
||||||
when(securityIndex.isAvailable()).thenReturn(true);
|
when(securityIndex.isAvailable()).thenReturn(true);
|
||||||
|
|
||||||
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
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,
|
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||||
|
|
|
@ -147,7 +147,8 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testClientCredentialsCreatesWithoutRefreshToken() throws Exception {
|
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 authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
|
||||||
authentication.writeToContext(threadPool.getThreadContext());
|
authentication.writeToContext(threadPool.getThreadContext());
|
||||||
|
|
||||||
|
@ -171,7 +172,8 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPasswordGrantTypeCreatesWithRefreshToken() throws Exception {
|
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 authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
|
||||||
authentication.writeToContext(threadPool.getThreadContext());
|
authentication.writeToContext(threadPool.getThreadContext());
|
||||||
|
|
||||||
|
|
|
@ -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.authc.support.UsernamePasswordToken;
|
||||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
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.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -53,7 +52,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
|
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.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
@ -336,7 +335,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
|
||||||
Instant dayBefore = created.minus(1L, ChronoUnit.DAYS);
|
Instant dayBefore = created.minus(1L, ChronoUnit.DAYS);
|
||||||
assertTrue(Instant.now().isAfter(dayBefore));
|
assertTrue(Instant.now().isAfter(dayBefore));
|
||||||
UpdateResponse expirationDateUpdatedResponse = client
|
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())
|
.setDoc("expiration_time", dayBefore.toEpochMilli())
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||||
.get();
|
.get();
|
||||||
|
@ -346,7 +345,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
|
||||||
// hack doc to modify the expiration time to the week before
|
// hack doc to modify the expiration time to the week before
|
||||||
Instant weekBefore = created.minus(8L, ChronoUnit.DAYS);
|
Instant weekBefore = created.minus(8L, ChronoUnit.DAYS);
|
||||||
assertTrue(Instant.now().isAfter(weekBefore));
|
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())
|
.setDoc("expiration_time", weekBefore.toEpochMilli())
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||||
.get();
|
.get();
|
||||||
|
@ -390,8 +389,7 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
|
||||||
|
|
||||||
private void refreshSecurityIndex() throws Exception {
|
private void refreshSecurityIndex() throws Exception {
|
||||||
assertBusy(() -> {
|
assertBusy(() -> {
|
||||||
final RefreshResponse refreshResponse = client().admin().indices().prepareRefresh(SecurityIndexManager.SECURITY_INDEX_NAME)
|
final RefreshResponse refreshResponse = client().admin().indices().prepareRefresh(SECURITY_MAIN_ALIAS).get();
|
||||||
.get();
|
|
||||||
assertThat(refreshResponse.getFailedShards(), is(0));
|
assertThat(refreshResponse.getFailedShards(), is(0));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
||||||
@SuppressForbidden(reason = "Allow accessing localhost")
|
@SuppressForbidden(reason = "Allow accessing localhost")
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
concreteSecurityIndexName = randomFrom(
|
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);
|
token = mock(AuthenticationToken.class);
|
||||||
when(token.principal()).thenReturn(randomAlphaOfLength(5));
|
when(token.principal()).thenReturn(randomAlphaOfLength(5));
|
||||||
|
@ -220,7 +220,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
||||||
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
||||||
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
||||||
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, securityIndex, clusterService, 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()),
|
service = new AuthenticationService(settings, realms, auditTrail, new DefaultAuthenticationFailureHandler(Collections.emptyMap()),
|
||||||
threadPool, new AnonymousUser(settings), tokenService, apiKeyService);
|
threadPool, new AnonymousUser(settings), tokenService, apiKeyService);
|
||||||
}
|
}
|
||||||
|
@ -1394,6 +1394,6 @@ public class AuthenticationServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.TokenMetaData;
|
||||||
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
|
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
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.After;
|
||||||
import org.junit.Before;
|
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.index.mapper.MapperService.SINGLE_MAPPING_NAME;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
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;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
@TestLogging("org.elasticsearch.xpack.security.authz.store.FileRolesStore:DEBUG")
|
@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));
|
assertThat(invalidateResponse.getResult().getErrors().size(), equalTo(0));
|
||||||
AtomicReference<String> docId = new AtomicReference<>();
|
AtomicReference<String> docId = new AtomicReference<>();
|
||||||
assertBusy(() -> {
|
assertBusy(() -> {
|
||||||
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
|
||||||
.setSource(SearchSourceBuilder.searchSource()
|
.setSource(SearchSourceBuilder.searchSource()
|
||||||
.query(QueryBuilders.termQuery("doc_type", "token")))
|
.query(QueryBuilders.termQuery("doc_type", "token")))
|
||||||
.setSize(1)
|
.setSize(1)
|
||||||
|
@ -174,7 +173,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
||||||
// hack doc to modify the creation time to the day before
|
// hack doc to modify the creation time to the day before
|
||||||
Instant yesterday = created.minus(36L, ChronoUnit.HOURS);
|
Instant yesterday = created.minus(36L, ChronoUnit.HOURS);
|
||||||
assertTrue(Instant.now().isAfter(yesterday));
|
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())
|
.setDoc("creation_time", yesterday.toEpochMilli())
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||||
.get();
|
.get();
|
||||||
|
@ -192,8 +191,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
||||||
assertEquals("token malformed", e.getMessage());
|
assertEquals("token malformed", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.admin().indices().prepareRefresh(SecurityIndexManager.SECURITY_INDEX_NAME).get();
|
client.admin().indices().prepareRefresh(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS).get();
|
||||||
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
|
||||||
.setSource(SearchSourceBuilder.searchSource()
|
.setSource(SearchSourceBuilder.searchSource()
|
||||||
.query(QueryBuilders.termQuery("doc_type", "token")))
|
.query(QueryBuilders.termQuery("doc_type", "token")))
|
||||||
.setTerminateAfter(1)
|
.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
|
// 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<>();
|
AtomicReference<String> docId = new AtomicReference<>();
|
||||||
assertBusy(() -> {
|
assertBusy(() -> {
|
||||||
SearchResponse searchResponse = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
|
SearchResponse searchResponse = client.prepareSearch(RestrictedIndicesNames.SECURITY_TOKENS_ALIAS)
|
||||||
.setSource(SearchSourceBuilder.searchSource()
|
.setSource(SearchSourceBuilder.searchSource()
|
||||||
.query(QueryBuilders.boolQuery()
|
.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"))))
|
.must(QueryBuilders.termQuery("refresh_token.refreshed", "true"))))
|
||||||
.setSize(1)
|
.setSize(1)
|
||||||
.setTerminateAfter(1)
|
.setTerminateAfter(1)
|
||||||
|
@ -374,7 +373,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
||||||
Instant refreshed = Instant.now();
|
Instant refreshed = Instant.now();
|
||||||
Instant aWhileAgo = refreshed.minus(50L, ChronoUnit.SECONDS);
|
Instant aWhileAgo = refreshed.minus(50L, ChronoUnit.SECONDS);
|
||||||
assertTrue(Instant.now().isAfter(aWhileAgo));
|
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()))
|
.setDoc("refresh_token", Collections.singletonMap("refresh_time", aWhileAgo.toEpochMilli()))
|
||||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||||
.setFetchSource("refresh_token", Strings.EMPTY_STRING)
|
.setFetchSource("refresh_token", Strings.EMPTY_STRING)
|
||||||
|
|
|
@ -21,6 +21,9 @@ import org.elasticsearch.action.support.PlainActionFuture;
|
||||||
import org.elasticsearch.action.update.UpdateAction;
|
import org.elasticsearch.action.update.UpdateAction;
|
||||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||||
import org.elasticsearch.client.Client;
|
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.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.UUIDs;
|
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.security.user.User;
|
||||||
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
|
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
@ -74,6 +78,7 @@ import javax.crypto.SecretKey;
|
||||||
|
|
||||||
import static java.time.Clock.systemUTC;
|
import static java.time.Clock.systemUTC;
|
||||||
import static org.elasticsearch.repositories.ESBlobStoreTestCase.randomBytes;
|
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.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -92,8 +97,10 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
|
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
|
||||||
|
|
||||||
private Client client;
|
private Client client;
|
||||||
private SecurityIndexManager securityIndex;
|
private SecurityIndexManager securityMainIndex;
|
||||||
|
private SecurityIndexManager securityTokensIndex;
|
||||||
private ClusterService clusterService;
|
private ClusterService clusterService;
|
||||||
|
private DiscoveryNode oldNode;
|
||||||
private Settings tokenServiceEnabledSettings = Settings.builder()
|
private Settings tokenServiceEnabledSettings = Settings.builder()
|
||||||
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
|
.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));
|
}).when(client).execute(eq(IndexAction.INSTANCE), any(IndexRequest.class), any(ActionListener.class));
|
||||||
|
|
||||||
// setup lifecycle service
|
// setup lifecycle service
|
||||||
securityIndex = mock(SecurityIndexManager.class);
|
this.securityMainIndex = mockSecurityManager();
|
||||||
doAnswer(invocationOnMock -> {
|
this.securityTokensIndex = mockSecurityManager();
|
||||||
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.clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
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
|
@BeforeClass
|
||||||
|
@ -151,7 +159,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAttachAndGetToken() throws Exception {
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -172,8 +181,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
|
|
||||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||||
// verify a second separate token service with its own salt can also verify
|
// verify a second separate token service with its own salt can also verify
|
||||||
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex
|
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
|
||||||
, clusterService);
|
securityTokensIndex, clusterService);
|
||||||
anotherService.refreshMetaData(tokenService.getTokenMetaData());
|
anotherService.refreshMetaData(tokenService.getTokenMetaData());
|
||||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||||
anotherService.getAndValidateToken(requestContext, future);
|
anotherService.getAndValidateToken(requestContext, future);
|
||||||
|
@ -183,7 +192,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInvalidAuthorizationHeader() throws Exception {
|
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);
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||||
String token = randomFrom("", " ");
|
String token = randomFrom("", " ");
|
||||||
String authScheme = randomFrom("Bearer ", "BEARER ", "bearer ", "Basic ");
|
String authScheme = randomFrom("Bearer ", "BEARER ", "bearer ", "Basic ");
|
||||||
|
@ -198,7 +208,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRotateKey() throws Exception {
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -251,12 +262,14 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testKeyExchange() throws Exception {
|
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);
|
int numRotations = randomIntBetween(1, 5);
|
||||||
for (int i = 0; i < numRotations; i++) {
|
for (int i = 0; i < numRotations; i++) {
|
||||||
rotateKeys(tokenService);
|
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());
|
otherTokenService.refreshMetaData(tokenService.getTokenMetaData());
|
||||||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
|
@ -272,7 +285,7 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||||
otherTokenService.getAndValidateToken(requestContext, future);
|
otherTokenService.getAndValidateToken(requestContext, future);
|
||||||
UserToken serialized = future.get();
|
UserToken serialized = future.get();
|
||||||
assertAuthentication(authentication, serialized.getAuthentication());
|
assertEquals(authentication, serialized.getAuthentication());
|
||||||
}
|
}
|
||||||
|
|
||||||
rotateKeys(tokenService);
|
rotateKeys(tokenService);
|
||||||
|
@ -288,7 +301,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPruneKeys() throws Exception {
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -350,7 +364,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPassphraseWorks() throws Exception {
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -371,8 +386,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
|
|
||||||
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||||
// verify a second separate token service with its own passphrase cannot verify
|
// verify a second separate token service with its own passphrase cannot verify
|
||||||
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex,
|
TokenService anotherService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
|
||||||
clusterService);
|
securityTokensIndex, clusterService);
|
||||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||||
anotherService.getAndValidateToken(requestContext, future);
|
anotherService.getAndValidateToken(requestContext, future);
|
||||||
assertNull(future.get());
|
assertNull(future.get());
|
||||||
|
@ -380,7 +395,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetTokenWhenKeyCacheHasExpired() throws Exception {
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
|
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
|
@ -393,9 +409,9 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInvalidatedToken() throws Exception {
|
public void testInvalidatedToken() throws Exception {
|
||||||
when(securityIndex.indexExists()).thenReturn(true);
|
when(securityMainIndex.indexExists()).thenReturn(true);
|
||||||
TokenService tokenService =
|
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
|
||||||
new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
|
securityTokensIndex, clusterService);
|
||||||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -449,7 +465,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
|
|
||||||
public void testTokenExpiry() throws Exception {
|
public void testTokenExpiry() throws Exception {
|
||||||
ClockMock clock = ClockMock.frozen();
|
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);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -502,7 +519,7 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
TokenService tokenService = new TokenService(Settings.builder()
|
TokenService tokenService = new TokenService(Settings.builder()
|
||||||
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false)
|
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false)
|
||||||
.build(),
|
.build(),
|
||||||
Clock.systemUTC(), client, securityIndex, clusterService);
|
Clock.systemUTC(), client, securityMainIndex, securityTokensIndex, clusterService);
|
||||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||||
() -> tokenService.createOAuth2Tokens(null, null, null, true, null));
|
() -> tokenService.createOAuth2Tokens(null, null, null, true, null));
|
||||||
assertEquals("tokens are not enabled", e.getMessage());
|
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 int numBytes = randomIntBetween(1, TokenService.MINIMUM_BYTES + 32);
|
||||||
final byte[] randomBytes = new byte[numBytes];
|
final byte[] randomBytes = new byte[numBytes];
|
||||||
random().nextBytes(randomBytes);
|
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);
|
ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
|
||||||
requestContext.putHeader("Authorization", "Bearer " + Base64.getEncoder().encodeToString(randomBytes));
|
requestContext.putHeader("Authorization", "Bearer " + Base64.getEncoder().encodeToString(randomBytes));
|
||||||
|
@ -558,8 +576,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexNotAvailable() throws Exception {
|
public void testIndexNotAvailable() throws Exception {
|
||||||
TokenService tokenService =
|
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityMainIndex,
|
||||||
new TokenService(tokenServiceEnabledSettings, systemUTC(), client, securityIndex, clusterService);
|
securityTokensIndex, clusterService);
|
||||||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
||||||
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
PlainActionFuture<Tuple<UserToken, String>> tokenFuture = new PlainActionFuture<>();
|
||||||
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
tokenService.createOAuth2Tokens(authentication, authentication, Collections.emptyMap(), true, tokenFuture);
|
||||||
|
@ -576,34 +594,44 @@ public class TokenServiceTests extends ESTestCase {
|
||||||
return Void.TYPE;
|
return Void.TYPE;
|
||||||
}).when(client).get(any(GetRequest.class), any(ActionListener.class));
|
}).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)) {
|
try (ThreadContext.StoredContext ignore = requestContext.newStoredContext(true)) {
|
||||||
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
PlainActionFuture<UserToken> future = new PlainActionFuture<>();
|
||||||
tokenService.getAndValidateToken(requestContext, future);
|
tokenService.getAndValidateToken(requestContext, future);
|
||||||
assertNull(future.get());
|
assertNull(future.get());
|
||||||
|
|
||||||
when(securityIndex.isAvailable()).thenReturn(false);
|
when(tokensIndex.isAvailable()).thenReturn(false);
|
||||||
when(securityIndex.indexExists()).thenReturn(true);
|
when(tokensIndex.indexExists()).thenReturn(true);
|
||||||
future = new PlainActionFuture<>();
|
future = new PlainActionFuture<>();
|
||||||
tokenService.getAndValidateToken(requestContext, future);
|
tokenService.getAndValidateToken(requestContext, future);
|
||||||
assertNull(future.get());
|
assertNull(future.get());
|
||||||
|
|
||||||
when(securityIndex.indexExists()).thenReturn(false);
|
when(tokensIndex.indexExists()).thenReturn(false);
|
||||||
future = new PlainActionFuture<>();
|
future = new PlainActionFuture<>();
|
||||||
tokenService.getAndValidateToken(requestContext, future);
|
tokenService.getAndValidateToken(requestContext, future);
|
||||||
assertNull(future.get());
|
assertNull(future.get());
|
||||||
|
|
||||||
when(securityIndex.isAvailable()).thenReturn(true);
|
when(tokensIndex.isAvailable()).thenReturn(true);
|
||||||
when(securityIndex.indexExists()).thenReturn(true);
|
when(tokensIndex.indexExists()).thenReturn(true);
|
||||||
mockGetTokenFromId(token, false);
|
mockGetTokenFromId(token, false);
|
||||||
future = new PlainActionFuture<>();
|
future = new PlainActionFuture<>();
|
||||||
tokenService.getAndValidateToken(requestContext, future);
|
tokenService.getAndValidateToken(requestContext, future);
|
||||||
assertEquals(token.getAuthentication(), future.get().getAuthentication());
|
assertEquals(future.get().getAuthentication(), token.getAuthentication());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetAuthenticationWorksWithExpiredUserToken() throws Exception {
|
public void testGetAuthenticationWorksWithExpiredUserToken() throws Exception {
|
||||||
TokenService tokenService =
|
TokenService tokenService = new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, securityMainIndex,
|
||||||
new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, securityIndex, clusterService);
|
securityTokensIndex, clusterService);
|
||||||
Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null);
|
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));
|
UserToken expired = new UserToken(authentication, Instant.now().minus(3L, ChronoUnit.DAYS));
|
||||||
mockGetTokenFromId(expired, false);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.test.NativeRealmIntegTestCase;
|
import org.elasticsearch.test.NativeRealmIntegTestCase;
|
||||||
import org.elasticsearch.common.CharArrays;
|
import org.elasticsearch.common.CharArrays;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
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 org.junit.BeforeClass;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -85,7 +85,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
|
||||||
addedUsers.add(uname);
|
addedUsers.add(uname);
|
||||||
}
|
}
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
|
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
|
||||||
|
|
||||||
MockTerminal t = new MockTerminal();
|
MockTerminal t = new MockTerminal();
|
||||||
String username = nodeClientUsername();
|
String username = nodeClientUsername();
|
||||||
|
@ -136,7 +136,7 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
|
||||||
addedRoles.add(rname);
|
addedRoles.add(rname);
|
||||||
}
|
}
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SecurityIndexManager.SECURITY_INDEX_NAME);
|
ensureGreen(RestrictedIndicesNames.SECURITY_MAIN_ALIAS);
|
||||||
|
|
||||||
MockTerminal t = new MockTerminal();
|
MockTerminal t = new MockTerminal();
|
||||||
String username = nodeClientUsername();
|
String username = nodeClientUsername();
|
||||||
|
|
|
@ -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.permission.Role;
|
||||||
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
|
import org.elasticsearch.xpack.core.security.authz.store.ReservedRolesStore;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
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.AnonymousUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.KibanaUser;
|
import org.elasticsearch.xpack.core.security.user.KibanaUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.User;
|
import org.elasticsearch.xpack.core.security.user.User;
|
||||||
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
|
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
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.assertAcked;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
|
||||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
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.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
|
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.arrayContaining;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
@ -146,7 +146,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
logger.error("--> creating user");
|
logger.error("--> creating user");
|
||||||
c.preparePutUser("joe", "s3kirt".toCharArray(), hasher, "role1", "user").get();
|
c.preparePutUser("joe", "s3kirt".toCharArray(), hasher, "role1", "user").get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> retrieving user");
|
logger.info("--> retrieving user");
|
||||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||||
assertTrue("user should exist", resp.hasUsers());
|
assertTrue("user should exist", resp.hasUsers());
|
||||||
|
@ -201,7 +201,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
.metadata(metadata)
|
.metadata(metadata)
|
||||||
.get();
|
.get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> retrieving role");
|
logger.info("--> retrieving role");
|
||||||
GetRolesResponse resp = c.prepareGetRoles().names("test_role").get();
|
GetRolesResponse resp = c.prepareGetRoles().names("test_role").get();
|
||||||
assertTrue("role should exist", resp.hasRoles());
|
assertTrue("role should exist", resp.hasRoles());
|
||||||
|
@ -252,7 +252,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
logger.error("--> creating user");
|
logger.error("--> creating user");
|
||||||
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> retrieving user");
|
logger.info("--> retrieving user");
|
||||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||||
assertTrue("user should exist", resp.hasUsers());
|
assertTrue("user should exist", resp.hasUsers());
|
||||||
|
@ -273,7 +273,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
logger.error("--> creating user");
|
logger.error("--> creating user");
|
||||||
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, SecuritySettingsSource.TEST_ROLE).get();
|
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, SecuritySettingsSource.TEST_ROLE).get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> retrieving user");
|
logger.info("--> retrieving user");
|
||||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||||
assertTrue("user should exist", resp.hasUsers());
|
assertTrue("user should exist", resp.hasUsers());
|
||||||
|
@ -309,7 +309,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
c.preparePutUser("joe", "s3krit".toCharArray(), hasher,
|
c.preparePutUser("joe", "s3krit".toCharArray(), hasher,
|
||||||
SecuritySettingsSource.TEST_ROLE).get();
|
SecuritySettingsSource.TEST_ROLE).get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> retrieving user");
|
logger.info("--> retrieving user");
|
||||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||||
assertTrue("user should exist", resp.hasUsers());
|
assertTrue("user should exist", resp.hasUsers());
|
||||||
|
@ -347,7 +347,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
logger.error("--> creating user");
|
logger.error("--> creating user");
|
||||||
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
|
|
||||||
if (authenticate) {
|
if (authenticate) {
|
||||||
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
||||||
|
@ -396,7 +396,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
logger.error("--> creating user");
|
logger.error("--> creating user");
|
||||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role", "snapshot_user").get();
|
securityClient().preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role", "snapshot_user").get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
logger.info("--> creating repository");
|
logger.info("--> creating repository");
|
||||||
assertAcked(client().admin().cluster()
|
assertAcked(client().admin().cluster()
|
||||||
.preparePutRepository("test-repo")
|
.preparePutRepository("test-repo")
|
||||||
|
@ -410,10 +410,10 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
.prepareCreateSnapshot("test-repo", "test-snap-1")
|
.prepareCreateSnapshot("test-repo", "test-snap-1")
|
||||||
.setWaitForCompletion(true)
|
.setWaitForCompletion(true)
|
||||||
.setIncludeGlobalState(false)
|
.setIncludeGlobalState(false)
|
||||||
.setIndices(SECURITY_INDEX_NAME)
|
.setIndices(SECURITY_MAIN_ALIAS)
|
||||||
.get().getSnapshotInfo();
|
.get().getSnapshotInfo();
|
||||||
assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
|
assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
|
||||||
assertThat(snapshotInfo.indices(), contains(SecurityIndexManager.INTERNAL_SECURITY_INDEX));
|
assertThat(snapshotInfo.indices(), contains(INTERNAL_SECURITY_MAIN_INDEX_7));
|
||||||
deleteSecurityIndex();
|
deleteSecurityIndex();
|
||||||
// the realm cache should clear itself but we don't wish to race it
|
// the realm cache should clear itself but we don't wish to race it
|
||||||
securityClient().prepareClearRealmCache().get();
|
securityClient().prepareClearRealmCache().get();
|
||||||
|
@ -430,7 +430,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
RestoreSnapshotResponse response = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-1")
|
RestoreSnapshotResponse response = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-1")
|
||||||
.setWaitForCompletion(true).setIncludeAliases(true).get();
|
.setWaitForCompletion(true).setIncludeAliases(true).get();
|
||||||
assertThat(response.status(), equalTo(RestStatus.OK));
|
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
|
// the realm cache should clear itself but we don't wish to race it
|
||||||
securityClient().prepareClearRealmCache().get();
|
securityClient().prepareClearRealmCache().get();
|
||||||
// users and roles are retrievable
|
// users and roles are retrievable
|
||||||
|
@ -460,7 +460,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
.get();
|
.get();
|
||||||
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
c.preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role").get();
|
||||||
logger.error("--> waiting for .security index");
|
logger.error("--> waiting for .security index");
|
||||||
ensureGreen(SECURITY_INDEX_NAME);
|
ensureGreen(SECURITY_MAIN_ALIAS);
|
||||||
|
|
||||||
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
||||||
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
|
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
|
||||||
|
@ -591,12 +591,12 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
||||||
.get();
|
.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.getFailedShards(), is(0));
|
||||||
assertThat(response.getIndices().size(), is(2));
|
assertThat(response.getIndices().size(), is(2));
|
||||||
assertThat(response.getIndices().get(INTERNAL_SECURITY_INDEX), notNullValue());
|
assertThat(response.getIndices().get(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7), notNullValue());
|
||||||
assertThat(response.getIndices().get(INTERNAL_SECURITY_INDEX).getIndex(),
|
assertThat(response.getIndices().get(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7).getIndex(),
|
||||||
is(INTERNAL_SECURITY_INDEX));
|
is(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOperationsOnReservedUsers() throws Exception {
|
public void testOperationsOnReservedUsers() throws Exception {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.xpack.core.security.authc.RealmConfig;
|
||||||
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -23,10 +24,10 @@ import static org.mockito.Mockito.when;
|
||||||
public class NativeRealmTests extends ESTestCase {
|
public class NativeRealmTests extends ESTestCase {
|
||||||
|
|
||||||
private final String concreteSecurityIndexName = randomFrom(
|
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) {
|
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() {
|
public void testCacheClearOnIndexHealthChange() {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
|
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
|
||||||
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
|
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.APMSystemUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.BeatsSystemUser;
|
import org.elasticsearch.xpack.core.security.user.BeatsSystemUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
||||||
|
@ -111,7 +112,7 @@ public class NativeUsersStoreTests extends ESTestCase {
|
||||||
values.put(PASSWORD_FIELD, BLANK_PASSWORD);
|
values.put(PASSWORD_FIELD, BLANK_PASSWORD);
|
||||||
|
|
||||||
final GetResult result = new GetResult(
|
final GetResult result = new GetResult(
|
||||||
SecurityIndexManager.SECURITY_INDEX_NAME,
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
MapperService.SINGLE_MAPPING_NAME,
|
MapperService.SINGLE_MAPPING_NAME,
|
||||||
NativeUsersStore.getIdForUser(NativeUsersStore.RESERVED_USER_TYPE, randomAlphaOfLength(12)),
|
NativeUsersStore.getIdForUser(NativeUsersStore.RESERVED_USER_TYPE, randomAlphaOfLength(12)),
|
||||||
0, 1, 1L,
|
0, 1, 1L,
|
||||||
|
@ -180,7 +181,7 @@ public class NativeUsersStoreTests extends ESTestCase {
|
||||||
nativeUsersStore.verifyPassword(username, password, future);
|
nativeUsersStore.verifyPassword(username, password, future);
|
||||||
|
|
||||||
final GetResult getResult = new GetResult(
|
final GetResult getResult = new GetResult(
|
||||||
SecurityIndexManager.SECURITY_INDEX_NAME,
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
MapperService.SINGLE_MAPPING_NAME,
|
MapperService.SINGLE_MAPPING_NAME,
|
||||||
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
|
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
|
||||||
UNASSIGNED_SEQ_NO, 0, 1L,
|
UNASSIGNED_SEQ_NO, 0, 1L,
|
||||||
|
@ -222,7 +223,7 @@ public class NativeUsersStoreTests extends ESTestCase {
|
||||||
values.put(User.Fields.TYPE.getPreferredName(), NativeUsersStore.USER_DOC_TYPE);
|
values.put(User.Fields.TYPE.getPreferredName(), NativeUsersStore.USER_DOC_TYPE);
|
||||||
final BytesReference source = BytesReference.bytes(jsonBuilder().map(values));
|
final BytesReference source = BytesReference.bytes(jsonBuilder().map(values));
|
||||||
final GetResult getResult = new GetResult(
|
final GetResult getResult = new GetResult(
|
||||||
SecurityIndexManager.SECURITY_INDEX_NAME,
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
MapperService.SINGLE_MAPPING_NAME,
|
MapperService.SINGLE_MAPPING_NAME,
|
||||||
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
|
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
|
||||||
0, 1, 1L,
|
0, 1, 1L,
|
||||||
|
@ -230,7 +231,6 @@ public class NativeUsersStoreTests extends ESTestCase {
|
||||||
source,
|
source,
|
||||||
Collections.emptyMap());
|
Collections.emptyMap());
|
||||||
|
|
||||||
|
|
||||||
actionRespond(GetRequest.class, new GetResponse(getResult));
|
actionRespond(GetRequest.class, new GetResponse(getResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -53,7 +54,7 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class NativeRoleMappingStoreTests extends ESTestCase {
|
public class NativeRoleMappingStoreTests extends ESTestCase {
|
||||||
private final String concreteSecurityIndexName = randomFrom(
|
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 {
|
public void testResolveRoles() throws Exception {
|
||||||
// Does match DN
|
// Does match DN
|
||||||
|
@ -137,7 +138,7 @@ public class NativeRoleMappingStoreTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
|
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() {
|
public void testCacheClearOnIndexHealthChange() {
|
||||||
|
@ -182,13 +183,13 @@ public class NativeRoleMappingStoreTests extends ESTestCase {
|
||||||
final NativeRoleMappingStore store = buildRoleMappingStoreForInvalidationTesting(numInvalidation);
|
final NativeRoleMappingStore store = buildRoleMappingStoreForInvalidationTesting(numInvalidation);
|
||||||
|
|
||||||
store.onSecurityIndexStateChange(
|
store.onSecurityIndexStateChange(
|
||||||
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null),
|
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null),
|
||||||
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null));
|
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null));
|
||||||
assertEquals(1, numInvalidation.get());
|
assertEquals(1, numInvalidation.get());
|
||||||
|
|
||||||
store.onSecurityIndexStateChange(
|
store.onSecurityIndexStateChange(
|
||||||
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null),
|
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null),
|
||||||
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null));
|
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null));
|
||||||
assertEquals(2, numInvalidation.get());
|
assertEquals(2, numInvalidation.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,8 +156,8 @@ import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationExce
|
||||||
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationException;
|
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationException;
|
||||||
import static org.elasticsearch.test.SecurityTestsUtils.assertThrowsAuthorizationExceptionRunAs;
|
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.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME;
|
||||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
|
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7;
|
||||||
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.arrayContainingInAnyOrder;
|
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
@ -864,8 +864,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
ClusterState state = mock(ClusterState.class);
|
ClusterState state = mock(ClusterState.class);
|
||||||
when(clusterService.state()).thenReturn(state);
|
when(clusterService.state()).thenReturn(state);
|
||||||
when(state.metaData()).thenReturn(MetaData.builder()
|
when(state.metaData()).thenReturn(MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
|
||||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
|
||||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
|
@ -874,31 +874,33 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||||
|
|
||||||
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
|
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(
|
requests.add(
|
||||||
new Tuple<>(BulkAction.NAME + "[s]", new DeleteRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "id")));
|
||||||
requests.add(new Tuple<>(UpdateAction.NAME, new UpdateRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "id")));
|
requests.add(
|
||||||
requests.add(new Tuple<>(BulkAction.NAME + "[s]", new IndexRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
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_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
requests.add(new Tuple<>(SearchAction.NAME, new SearchRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
|
||||||
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
requests.add(new Tuple<>(TermVectorsAction.NAME,
|
||||||
new TermVectorsRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "type", "id")));
|
new TermVectorsRequest(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7), "type", "id")));
|
||||||
requests.add(new Tuple<>(GetAction.NAME, new GetRequest(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX), "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()
|
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,
|
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
|
// cannot execute monitor operations
|
||||||
requests.add(new Tuple<>(IndicesStatsAction.NAME,
|
requests.add(new Tuple<>(IndicesStatsAction.NAME,
|
||||||
new IndicesStatsRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
new IndicesStatsRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
|
||||||
requests.add(
|
requests.add(new Tuple<>(RecoveryAction.NAME,
|
||||||
new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(randomFrom(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX))));
|
new RecoveryRequest().indices(randomFrom(SECURITY_MAIN_ALIAS, INTERNAL_SECURITY_MAIN_INDEX_7))));
|
||||||
requests.add(new Tuple<>(IndicesSegmentsAction.NAME,
|
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,
|
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,
|
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,
|
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) {
|
for (Tuple<String, TransportRequest> requestTuple : requests) {
|
||||||
String action = requestTuple.v1();
|
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
|
// 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);
|
authorize(authentication, ClusterHealthAction.NAME, request);
|
||||||
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
|
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
|
||||||
authzInfoRoles(new String[]{role.getName()}));
|
authzInfoRoles(new String[]{role.getName()}));
|
||||||
|
|
||||||
// multiple indices
|
// 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);
|
authorize(authentication, ClusterHealthAction.NAME, request);
|
||||||
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
|
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(ClusterHealthAction.NAME), eq(request),
|
||||||
authzInfoRoles(new String[]{role.getName()}));
|
authzInfoRoles(new String[]{role.getName()}));
|
||||||
|
@ -940,8 +942,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
ClusterState state = mock(ClusterState.class);
|
ClusterState state = mock(ClusterState.class);
|
||||||
when(clusterService.state()).thenReturn(state);
|
when(clusterService.state()).thenReturn(state);
|
||||||
when(state.metaData()).thenReturn(MetaData.builder()
|
when(state.metaData()).thenReturn(MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
|
||||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
|
||||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
|
@ -949,12 +951,12 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
List<Tuple<String, ? extends TransportRequest>> requests = new ArrayList<>();
|
List<Tuple<String, ? extends TransportRequest>> requests = new ArrayList<>();
|
||||||
requests.add(new Tuple<>(IndicesStatsAction.NAME, new IndicesStatsRequest().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_INDEX_NAME)));
|
requests.add(new Tuple<>(RecoveryAction.NAME, new RecoveryRequest().indices(SECURITY_MAIN_ALIAS)));
|
||||||
requests.add(new Tuple<>(IndicesSegmentsAction.NAME, new IndicesSegmentsRequest().indices(SECURITY_INDEX_NAME)));
|
requests.add(new Tuple<>(IndicesSegmentsAction.NAME, new IndicesSegmentsRequest().indices(SECURITY_MAIN_ALIAS)));
|
||||||
requests.add(new Tuple<>(GetSettingsAction.NAME, new GetSettingsRequest().indices(SECURITY_INDEX_NAME)));
|
requests.add(new Tuple<>(GetSettingsAction.NAME, new GetSettingsRequest().indices(SECURITY_MAIN_ALIAS)));
|
||||||
requests.add(new Tuple<>(IndicesShardStoresAction.NAME, new IndicesShardStoresRequest().indices(SECURITY_INDEX_NAME)));
|
requests.add(new Tuple<>(IndicesShardStoresAction.NAME, new IndicesShardStoresRequest().indices(SECURITY_MAIN_ALIAS)));
|
||||||
requests.add(new Tuple<>(UpgradeStatusAction.NAME, new UpgradeStatusRequest().indices(SECURITY_INDEX_NAME)));
|
requests.add(new Tuple<>(UpgradeStatusAction.NAME, new UpgradeStatusRequest().indices(SECURITY_MAIN_ALIAS)));
|
||||||
|
|
||||||
for (final Tuple<String, ? extends TransportRequest> requestTuple : requests) {
|
for (final Tuple<String, ? extends TransportRequest> requestTuple : requests) {
|
||||||
final String action = requestTuple.v1();
|
final String action = requestTuple.v1();
|
||||||
|
@ -984,8 +986,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
ClusterState state = mock(ClusterState.class);
|
ClusterState state = mock(ClusterState.class);
|
||||||
when(clusterService.state()).thenReturn(state);
|
when(clusterService.state()).thenReturn(state);
|
||||||
when(state.metaData()).thenReturn(MetaData.builder()
|
when(state.metaData()).thenReturn(MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
|
||||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
|
||||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
|
@ -994,25 +996,28 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
final String requestId = AuditUtil.getOrGenerateRequestId(threadContext);
|
||||||
|
|
||||||
List<Tuple<String, TransportRequest>> requests = new ArrayList<>();
|
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(
|
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,
|
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) {
|
for (final Tuple<String, TransportRequest> requestTuple : requests) {
|
||||||
final String action = requestTuple.v1();
|
final String action = requestTuple.v1();
|
||||||
|
@ -1033,8 +1038,8 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
ClusterState state = mock(ClusterState.class);
|
ClusterState state = mock(ClusterState.class);
|
||||||
when(clusterService.state()).thenReturn(state);
|
when(clusterService.state()).thenReturn(state);
|
||||||
when(state.metaData()).thenReturn(MetaData.builder()
|
when(state.metaData()).thenReturn(MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_INDEX)
|
.put(new IndexMetaData.Builder(INTERNAL_SECURITY_MAIN_INDEX_7)
|
||||||
.putAlias(new AliasMetaData.Builder(SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(SECURITY_MAIN_ALIAS).build())
|
||||||
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
|
@ -1046,7 +1051,7 @@ public class AuthorizationServiceTests extends ESTestCase {
|
||||||
SearchRequest request = new SearchRequest("_all");
|
SearchRequest request = new SearchRequest("_all");
|
||||||
authorize(authentication, action, request);
|
authorize(authentication, action, request);
|
||||||
verify(auditTrail).accessGranted(eq(requestId), eq(authentication), eq(action), eq(request), authzInfoRoles(superuser.roles()));
|
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() {
|
public void testCompositeActionsAreImmediatelyRejected() {
|
||||||
|
|
|
@ -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.authz.store.ReservedRolesStore;
|
||||||
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||||
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -47,8 +46,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
RoleDescriptor bRole = new RoleDescriptor("b", null,
|
RoleDescriptor bRole = new RoleDescriptor("b", null,
|
||||||
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("READ").build() }, null);
|
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("READ").build() }, null);
|
||||||
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
MetaData metaData = MetaData.builder()
|
MetaData metaData = MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder("a1").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
.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)
|
.put(new IndexMetaData.Builder("a2").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
||||||
|
@ -65,7 +64,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
.settings(indexSettings)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
final PlainActionFuture<Role> future = new PlainActionFuture<>();
|
final PlainActionFuture<Role> future = new PlainActionFuture<>();
|
||||||
|
@ -78,7 +77,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
assertFalse(list.contains("bbbbb"));
|
assertFalse(list.contains("bbbbb"));
|
||||||
assertFalse(list.contains("ba"));
|
assertFalse(list.contains("ba"));
|
||||||
assertThat(list, not(contains(internalSecurityIndex)));
|
assertThat(list, not(contains(internalSecurityIndex)));
|
||||||
assertThat(list, not(contains(RestrictedIndicesNames.SECURITY_INDEX_NAME)));
|
assertThat(list, not(contains(RestrictedIndicesNames.SECURITY_MAIN_ALIAS)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAuthorizedIndicesUserWithSomeRolesEmptyMetaData() {
|
public void testAuthorizedIndicesUserWithSomeRolesEmptyMetaData() {
|
||||||
|
@ -101,8 +100,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
.cluster(ClusterPrivilege.ALL)
|
.cluster(ClusterPrivilege.ALL)
|
||||||
.build();
|
.build();
|
||||||
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
MetaData metaData = MetaData.builder()
|
MetaData metaData = MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder("an-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
.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)
|
.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)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -119,7 +118,7 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
||||||
assertThat(authorizedIndices, containsInAnyOrder("an-index", "another-index"));
|
assertThat(authorizedIndices, containsInAnyOrder("an-index", "another-index"));
|
||||||
assertThat(authorizedIndices, not(contains(internalSecurityIndex)));
|
assertThat(authorizedIndices, not(contains(internalSecurityIndex)));
|
||||||
assertThat(authorizedIndices, not(contains(RestrictedIndicesNames.SECURITY_INDEX_NAME)));
|
assertThat(authorizedIndices, not(contains(RestrictedIndicesNames.SECURITY_MAIN_ALIAS)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSecurityIndicesAreNotRemovedFromUnrestrictedRole() {
|
public void testSecurityIndicesAreNotRemovedFromUnrestrictedRole() {
|
||||||
|
@ -128,8 +127,8 @@ public class AuthorizedIndicesTests extends ESTestCase {
|
||||||
.cluster(ClusterPrivilege.ALL)
|
.cluster(ClusterPrivilege.ALL)
|
||||||
.build();
|
.build();
|
||||||
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
MetaData metaData = MetaData.builder()
|
MetaData metaData = MetaData.builder()
|
||||||
.put(new IndexMetaData.Builder("an-index").settings(indexSettings).numberOfShards(1).numberOfReplicas(0).build(), true)
|
.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)
|
.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)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<String> authorizedIndices =
|
List<String> authorizedIndices =
|
||||||
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
||||||
assertThat(authorizedIndices, containsInAnyOrder(
|
assertThat(authorizedIndices, containsInAnyOrder(
|
||||||
"an-index", "another-index", SecurityIndexManager.SECURITY_INDEX_NAME, internalSecurityIndex));
|
"an-index", "another-index", RestrictedIndicesNames.SECURITY_MAIN_ALIAS, internalSecurityIndex));
|
||||||
|
|
||||||
List<String> authorizedIndicesSuperUser =
|
List<String> authorizedIndicesSuperUser =
|
||||||
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
RBACEngine.resolveAuthorizedIndicesFromRole(role, SearchAction.NAME, metaData.getAliasAndIndexLookup());
|
||||||
assertThat(authorizedIndicesSuperUser, containsInAnyOrder(
|
assertThat(authorizedIndicesSuperUser, containsInAnyOrder(
|
||||||
"an-index", "another-index", SecurityIndexManager.SECURITY_INDEX_NAME, internalSecurityIndex));
|
"an-index", "another-index", RestrictedIndicesNames.SECURITY_MAIN_ALIAS, internalSecurityIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.XPackSecurityUser;
|
||||||
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
||||||
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
|
||||||
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
|
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
@ -79,7 +78,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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.arrayContaining;
|
||||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
@ -119,7 +118,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
|
||||||
indexNameExpressionResolver = new IndexNameExpressionResolver();
|
indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||||
|
|
||||||
final boolean withAlias = randomBoolean();
|
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()
|
MetaData metaData = MetaData.builder()
|
||||||
.put(indexBuilder("foo").putAlias(AliasMetaData.builder("foofoobar"))
|
.put(indexBuilder("foo").putAlias(AliasMetaData.builder("foofoobar"))
|
||||||
.putAlias(AliasMetaData.builder("foounauthorized")).settings(settings))
|
.putAlias(AliasMetaData.builder("foounauthorized")).settings(settings))
|
||||||
|
@ -1222,14 +1221,14 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
|
||||||
{
|
{
|
||||||
final List<String> authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, SearchAction.NAME);
|
final List<String> authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, SearchAction.NAME);
|
||||||
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
|
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
|
||||||
assertThat(indices, hasItem(SecurityIndexManager.SECURITY_INDEX_NAME));
|
assertThat(indices, hasItem(SECURITY_MAIN_ALIAS));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest();
|
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);
|
final List<String> authorizedIndices = buildAuthorizedIndices(XPackSecurityUser.INSTANCE, IndicesAliasesAction.NAME);
|
||||||
List<String> indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal();
|
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();
|
SearchRequest request = new SearchRequest();
|
||||||
final List<String> authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, SearchAction.NAME);
|
final List<String> authorizedIndices = buildAuthorizedIndices(XPackUser.INSTANCE, SearchAction.NAME);
|
||||||
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
|
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() {
|
public void testNonXPackUserAccessingSecurityIndex() {
|
||||||
|
@ -1249,7 +1248,7 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
|
||||||
SearchRequest request = new SearchRequest();
|
SearchRequest request = new SearchRequest();
|
||||||
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, SearchAction.NAME);
|
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, SearchAction.NAME);
|
||||||
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
|
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("*"));
|
aliasesRequest.addAliasAction(AliasActions.add().alias("security_alias1").index("*"));
|
||||||
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, IndicesAliasesAction.NAME);
|
final List<String> authorizedIndices = buildAuthorizedIndices(allAccessUser, IndicesAliasesAction.NAME);
|
||||||
List<String> indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal();
|
List<String> indices = resolveIndices(aliasesRequest, authorizedIndices).getLocal();
|
||||||
assertThat(indices, not(hasItem(SecurityIndexManager.SECURITY_INDEX_NAME)));
|
assertThat(indices, not(hasItem(SECURITY_MAIN_ALIAS)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Locale;
|
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.INTERNAL_SECURITY_MAIN_INDEX_7;
|
||||||
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_INDEX_NAME;
|
import static org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames.SECURITY_MAIN_ALIAS;
|
||||||
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
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));
|
final String snapshotUserToken = basicAuthHeaderValue(user, new SecureString(password));
|
||||||
client = client().filterWithHeader(Collections.singletonMap("Authorization", snapshotUserToken));
|
client = client().filterWithHeader(Collections.singletonMap("Authorization", snapshotUserToken));
|
||||||
securityClient().preparePutUser(user, password, Hasher.BCRYPT, "snapshot_user").get();
|
securityClient().preparePutUser(user, password, Hasher.BCRYPT, "snapshot_user").get();
|
||||||
ensureGreen(INTERNAL_SECURITY_INDEX_7);
|
ensureGreen(INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSnapshotUserRoleCanSnapshotAndSeeAllIndices() {
|
public void testSnapshotUserRoleCanSnapshotAndSeeAllIndices() {
|
||||||
|
@ -67,17 +67,17 @@ public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
|
||||||
assertThat(getRepositoriesResponse.repositories().get(0).name(), is("repo"));
|
assertThat(getRepositoriesResponse.repositories().get(0).name(), is("repo"));
|
||||||
// view all indices, including restricted ones
|
// view all indices, including restricted ones
|
||||||
final GetIndexResponse getIndexResponse = client.admin().indices().prepareGetIndex().setIndices(randomFrom("_all", "*")).get();
|
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
|
// create snapshot that includes restricted indices
|
||||||
final CreateSnapshotResponse snapshotResponse = client.admin().cluster().prepareCreateSnapshot("repo", "snap")
|
final CreateSnapshotResponse snapshotResponse = client.admin().cluster().prepareCreateSnapshot("repo", "snap")
|
||||||
.setIndices(randomFrom("_all", "*")).setWaitForCompletion(true).get();
|
.setIndices(randomFrom("_all", "*")).setWaitForCompletion(true).get();
|
||||||
assertThat(snapshotResponse.getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
|
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
|
// view snapshots for repo
|
||||||
final GetSnapshotsResponse getSnapshotResponse = client.admin().cluster().prepareGetSnapshots("repo").get();
|
final GetSnapshotsResponse getSnapshotResponse = client.admin().cluster().prepareGetSnapshots("repo").get();
|
||||||
assertThat(getSnapshotResponse.getSnapshots().size(), is(1));
|
assertThat(getSnapshotResponse.getSnapshots().size(), is(1));
|
||||||
assertThat(getSnapshotResponse.getSnapshots().get(0).snapshotId().getName(), is("snap"));
|
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() {
|
public void testSnapshotUserRoleIsReserved() {
|
||||||
|
@ -112,7 +112,7 @@ public class SnapshotUserRoleIntegTests extends NativeRealmIntegTestCase {
|
||||||
() -> client.admin().cluster().prepareDeleteSnapshot("repo", randomAlphaOfLength(4).toLowerCase(Locale.ROOT)).get(),
|
() -> client.admin().cluster().prepareDeleteSnapshot("repo", randomAlphaOfLength(4).toLowerCase(Locale.ROOT)).get(),
|
||||||
"cluster:admin/snapshot/delete", "snapshot_user");
|
"cluster:admin/snapshot/delete", "snapshot_user");
|
||||||
// try destructive/revealing actions on all indices
|
// 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.prepareSearch(indexToTest).get(), "indices:data/read/search", "snapshot_user");
|
||||||
assertThrowsAuthorizationException(() -> client.prepareGet(indexToTest, "doc", "1").get(), "indices:data/read/get",
|
assertThrowsAuthorizationException(() -> client.prepareGet(indexToTest, "doc", "1").get(), "indices:data/read/get",
|
||||||
"snapshot_user");
|
"snapshot_user");
|
||||||
|
|
|
@ -293,14 +293,14 @@ public class IndicesPermissionTests extends ESTestCase {
|
||||||
|
|
||||||
public void testSecurityIndicesPermissions() {
|
public void testSecurityIndicesPermissions() {
|
||||||
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
final Settings indexSettings = Settings.builder().put("index.version.created", Version.CURRENT).build();
|
||||||
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_6,
|
final String internalSecurityIndex = randomFrom(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_6,
|
||||||
RestrictedIndicesNames.INTERNAL_SECURITY_INDEX_7);
|
RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7);
|
||||||
final MetaData metaData = new MetaData.Builder()
|
final MetaData metaData = new MetaData.Builder()
|
||||||
.put(new IndexMetaData.Builder(internalSecurityIndex)
|
.put(new IndexMetaData.Builder(internalSecurityIndex)
|
||||||
.settings(indexSettings)
|
.settings(indexSettings)
|
||||||
.numberOfShards(1)
|
.numberOfShards(1)
|
||||||
.numberOfReplicas(0)
|
.numberOfReplicas(0)
|
||||||
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_INDEX_NAME).build())
|
.putAlias(new AliasMetaData.Builder(RestrictedIndicesNames.SECURITY_MAIN_ALIAS).build())
|
||||||
.build(), true)
|
.build(), true)
|
||||||
.build();
|
.build();
|
||||||
FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
|
||||||
|
@ -309,18 +309,18 @@ public class IndicesPermissionTests extends ESTestCase {
|
||||||
// allow_restricted_indices: false
|
// allow_restricted_indices: false
|
||||||
IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, false, "*");
|
IndicesPermission.Group group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, false, "*");
|
||||||
Map<String, IndicesAccessControl.IndexAccessControl> authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
|
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);
|
fieldPermissionsCache);
|
||||||
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(false));
|
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
|
// allow_restricted_indices: true
|
||||||
group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, true, "*");
|
group = new IndicesPermission.Group(IndexPrivilege.ALL, new FieldPermissions(), null, true, "*");
|
||||||
authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
|
authzMap = new IndicesPermission(group).authorize(SearchAction.NAME,
|
||||||
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_INDEX_NAME), lookup,
|
Sets.newHashSet(internalSecurityIndex, RestrictedIndicesNames.SECURITY_MAIN_ALIAS), lookup,
|
||||||
fieldPermissionsCache);
|
fieldPermissionsCache);
|
||||||
assertThat(authzMap.get(internalSecurityIndex).isGranted(), is(true));
|
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) {
|
private static FieldPermissionsDefinition fieldPermissionDef(String[] granted, String[] denied) {
|
||||||
|
|
|
@ -57,6 +57,7 @@ import org.elasticsearch.xpack.security.authc.ApiKeyService.ApiKeyRoleDescriptor
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -98,7 +99,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
|
|
||||||
private final FieldPermissionsCache cache = new FieldPermissionsCache(Settings.EMPTY);
|
private final FieldPermissionsCache cache = new FieldPermissionsCache(Settings.EMPTY);
|
||||||
private final String concreteSecurityIndexName = randomFrom(
|
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 {
|
public void testRolesWhenDlsFlsUnlicensed() throws IOException {
|
||||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||||
|
@ -762,7 +763,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecurityIndexManager.State dummyState(ClusterHealthStatus indexStatus) {
|
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() {
|
public void testCacheClearOnIndexHealthChange() {
|
||||||
|
@ -837,13 +838,13 @@ public class CompositeRolesStoreTests extends ESTestCase {
|
||||||
};
|
};
|
||||||
|
|
||||||
compositeRolesStore.onSecurityIndexStateChange(
|
compositeRolesStore.onSecurityIndexStateChange(
|
||||||
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null),
|
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null),
|
||||||
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null));
|
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null));
|
||||||
assertEquals(1, numInvalidation.get());
|
assertEquals(1, numInvalidation.get());
|
||||||
|
|
||||||
compositeRolesStore.onSecurityIndexStateChange(
|
compositeRolesStore.onSecurityIndexStateChange(
|
||||||
new SecurityIndexManager.State(true, true, true, true, null, concreteSecurityIndexName, null),
|
new SecurityIndexManager.State(Instant.now(), true, true, true, null, concreteSecurityIndexName, null),
|
||||||
new SecurityIndexManager.State(true, false, true, true, null, concreteSecurityIndexName, null));
|
new SecurityIndexManager.State(Instant.now(), false, true, true, null, concreteSecurityIndexName, null));
|
||||||
assertEquals(2, numInvalidation.get());
|
assertEquals(2, numInvalidation.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.elasticsearch.test.client.NoOpClient;
|
||||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||||
import org.elasticsearch.xpack.core.security.action.role.ClearRolesCacheRequest;
|
import org.elasticsearch.xpack.core.security.action.role.ClearRolesCacheRequest;
|
||||||
import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor;
|
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.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -125,7 +126,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(GetRequest.class));
|
assertThat(requests.get(0), instanceOf(GetRequest.class));
|
||||||
GetRequest request = (GetRequest) requests.get(0);
|
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.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
|
||||||
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
|
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(GetRequest.class));
|
assertThat(requests.get(0), instanceOf(GetRequest.class));
|
||||||
GetRequest request = (GetRequest) requests.get(0);
|
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.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
|
||||||
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
|
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
|
||||||
|
|
||||||
|
@ -166,7 +167,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
||||||
SearchRequest request = (SearchRequest) requests.get(0);
|
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());
|
final String query = Strings.toString(request.source().query());
|
||||||
assertThat(query, containsString("{\"terms\":{\"application\":[\"myapp\",\"yourapp\"]"));
|
assertThat(query, containsString("{\"terms\":{\"application\":[\"myapp\",\"yourapp\"]"));
|
||||||
|
@ -187,7 +188,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
||||||
SearchRequest request = (SearchRequest) requests.get(0);
|
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());
|
final String query = Strings.toString(request.source().query());
|
||||||
assertThat(query, containsString("{\"bool\":{\"filter\":[{\"terms\":{\"application\":[\"yourapp\"]"));
|
assertThat(query, containsString("{\"bool\":{\"filter\":[{\"terms\":{\"application\":[\"yourapp\"]"));
|
||||||
|
@ -207,7 +208,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
||||||
SearchRequest request = (SearchRequest) requests.get(0);
|
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());
|
final String query = Strings.toString(request.source().query());
|
||||||
assertThat(query, containsString("{\"exists\":{\"field\":\"application\""));
|
assertThat(query, containsString("{\"exists\":{\"field\":\"application\""));
|
||||||
|
@ -232,7 +233,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(requests, iterableWithSize(1));
|
assertThat(requests, iterableWithSize(1));
|
||||||
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
assertThat(requests.get(0), instanceOf(SearchRequest.class));
|
||||||
SearchRequest request = (SearchRequest) requests.get(0);
|
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());
|
final String query = Strings.toString(request.source().query());
|
||||||
assertThat(query, containsString("{\"term\":{\"type\":{\"value\":\"application-privilege\""));
|
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++) {
|
for (int i = 0; i < putPrivileges.size(); i++) {
|
||||||
ApplicationPrivilegeDescriptor privilege = putPrivileges.get(i);
|
ApplicationPrivilegeDescriptor privilege = putPrivileges.get(i);
|
||||||
IndexRequest request = indexRequests.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.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
|
||||||
assertThat(request.id(), equalTo(
|
assertThat(request.id(), equalTo(
|
||||||
"application-privilege_" + privilege.getApplication() + ":" + privilege.getName()
|
"application-privilege_" + privilege.getApplication() + ":" + privilege.getName()
|
||||||
|
@ -277,7 +278,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
|
||||||
assertThat(request.source(), equalTo(BytesReference.bytes(builder)));
|
assertThat(request.source(), equalTo(BytesReference.bytes(builder)));
|
||||||
final boolean created = privilege.getName().equals("user") == false;
|
final boolean created = privilege.getName().equals("user") == false;
|
||||||
indexListener.onResponse(new IndexResponse(
|
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
|
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++) {
|
for (int i = 0; i < privilegeNames.size(); i++) {
|
||||||
String name = privilegeNames.get(i);
|
String name = privilegeNames.get(i);
|
||||||
DeleteRequest request = deletes.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.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
|
||||||
assertThat(request.id(), equalTo("application-privilege_app1:" + name));
|
assertThat(request.id(), equalTo("application-privilege_app1:" + name));
|
||||||
final boolean found = name.equals("p2") == false;
|
final boolean found = name.equals("p2") == false;
|
||||||
deleteListener.onResponse(new DeleteResponse(
|
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
|
request.type(), request.id(), 1, 1, 1, found
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
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.arrayContaining;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
@ -187,7 +187,7 @@ public class NativeRolesStoreTests extends ESTestCase {
|
||||||
final ClusterService clusterService = mock(ClusterService.class);
|
final ClusterService clusterService = mock(ClusterService.class);
|
||||||
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||||
final AtomicBoolean methodCalled = new AtomicBoolean(false);
|
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) {
|
final NativeRolesStore rolesStore = new NativeRolesStore(Settings.EMPTY, client, licenseState, securityIndex) {
|
||||||
@Override
|
@Override
|
||||||
void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
|
void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
|
||||||
|
@ -247,7 +247,7 @@ public class NativeRolesStoreTests extends ESTestCase {
|
||||||
|
|
||||||
private ClusterState getClusterStateWithSecurityIndex() {
|
private ClusterState getClusterStateWithSecurityIndex() {
|
||||||
final boolean withAlias = randomBoolean();
|
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()
|
Settings settings = Settings.builder()
|
||||||
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
@ -256,7 +256,7 @@ public class NativeRolesStoreTests extends ESTestCase {
|
||||||
.build();
|
.build();
|
||||||
MetaData metaData = MetaData.builder()
|
MetaData metaData = MetaData.builder()
|
||||||
.put(IndexMetaData.builder(securityIndexName).settings(settings))
|
.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(),
|
Collections.singletonList(securityIndexName), Settings.EMPTY, ImmutableOpenMap.of(),
|
||||||
ImmutableOpenMap.of()))
|
ImmutableOpenMap.of()))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.cluster.ClusterName;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlocks;
|
import org.elasticsearch.cluster.block.ClusterBlocks;
|
||||||
import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
||||||
|
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.MetaData;
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
@ -52,12 +53,12 @@ import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
|
import org.elasticsearch.xpack.security.test.SecurityTestUtils;
|
||||||
|
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
|
||||||
import org.elasticsearch.xpack.core.template.TemplateUtils;
|
import org.elasticsearch.xpack.core.template.TemplateUtils;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
|
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7;
|
||||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_TEMPLATE_NAME;
|
|
||||||
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.TEMPLATE_VERSION_PATTERN;
|
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.TEMPLATE_VERSION_PATTERN;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
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 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 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 static final String TEMPLATE_NAME = "SecurityIndexManagerTests-template";
|
||||||
private SecurityIndexManager manager;
|
private SecurityIndexManager manager;
|
||||||
private Map<Action<?>, Map<ActionRequest, ActionListener<?>>> actions;
|
private Map<Action<?>, Map<ActionRequest, ActionListener<?>>> actions;
|
||||||
|
@ -96,13 +96,14 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
actions.put(action, map);
|
actions.put(action, map);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
manager = SecurityIndexManager.buildSecurityIndexManager(client, clusterService);
|
manager = SecurityIndexManager.buildSecurityMainIndexManager(client, clusterService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexWithUpToDateMappingAndTemplate() throws IOException {
|
public void testIndexWithUpToDateMappingAndTemplate() throws IOException {
|
||||||
assertInitialState();
|
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);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
|
|
||||||
|
@ -114,8 +115,9 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
public void testIndexWithoutPrimaryShards() throws IOException {
|
public void testIndexWithoutPrimaryShards() throws IOException {
|
||||||
assertInitialState();
|
assertInitialState();
|
||||||
|
|
||||||
final ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME);
|
final ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
|
||||||
Index index = new Index(INDEX_NAME, UUID.randomUUID().toString());
|
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,
|
ShardRouting shardRouting = ShardRouting.newUnassigned(new ShardId(index, 0), true,
|
||||||
RecoverySource.ExistingStoreRecoverySource.INSTANCE, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, ""));
|
RecoverySource.ExistingStoreRecoverySource.INSTANCE, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, ""));
|
||||||
String nodeId = ESTestCase.randomAlphaOfLength(8);
|
String nodeId = ESTestCase.randomAlphaOfLength(8);
|
||||||
|
@ -147,7 +149,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
manager.addIndexStateListener(listener);
|
manager.addIndexStateListener(listener);
|
||||||
|
|
||||||
// index doesn't exist and now exists
|
// 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);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
|
|
||||||
|
@ -171,7 +174,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
previousState.set(null);
|
previousState.set(null);
|
||||||
currentState.set(null);
|
currentState.set(null);
|
||||||
ClusterState previousClusterState = clusterStateBuilder.build();
|
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()
|
clusterStateBuilder.routingTable(RoutingTable.builder()
|
||||||
.add(IndexRoutingTable.builder(prevIndex)
|
.add(IndexRoutingTable.builder(prevIndex)
|
||||||
.addIndexShard(new IndexShardRoutingTable.Builder(new ShardId(prevIndex, 0))
|
.addIndexShard(new IndexShardRoutingTable.Builder(new ShardId(prevIndex, 0))
|
||||||
|
@ -231,8 +234,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
prepareException.set(null);
|
prepareException.set(null);
|
||||||
prepareRunnableCalled.set(false);
|
prepareRunnableCalled.set(false);
|
||||||
// state recovered with index
|
// state recovered with index
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
|
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
|
||||||
SecurityIndexManager.INTERNAL_INDEX_FORMAT);
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
|
||||||
markShardsAvailable(clusterStateBuilder);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
manager.prepareIndexIfNeededThenExecute(ex -> {
|
manager.prepareIndexIfNeededThenExecute(ex -> {
|
||||||
|
@ -255,8 +258,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
assertThat(manager.isStateRecovered(), is(false));
|
assertThat(manager.isStateRecovered(), is(false));
|
||||||
assertThat(listenerCalled.get(), is(false));
|
assertThat(listenerCalled.get(), is(false));
|
||||||
// state recovered with index
|
// state recovered with index
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
|
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
|
||||||
SecurityIndexManager.INTERNAL_INDEX_FORMAT);
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
|
||||||
markShardsAvailable(clusterStateBuilder);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
assertThat(manager.isStateRecovered(), is(true));
|
assertThat(manager.isStateRecovered(), is(true));
|
||||||
|
@ -278,8 +281,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
assertTrue(manager.isIndexUpToDate());
|
assertTrue(manager.isIndexUpToDate());
|
||||||
|
|
||||||
// index doesn't exist and now exists with wrong format
|
// index doesn't exist and now exists with wrong format
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME,
|
ClusterState.Builder clusterStateBuilder = createClusterState(RestrictedIndicesNames.INTERNAL_SECURITY_MAIN_INDEX_7,
|
||||||
SecurityIndexManager.INTERNAL_INDEX_FORMAT - 1);
|
RestrictedIndicesNames.SECURITY_MAIN_ALIAS, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT - 1);
|
||||||
markShardsAvailable(clusterStateBuilder);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
assertTrue(listenerCalled.get());
|
assertTrue(listenerCalled.get());
|
||||||
|
@ -295,7 +298,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
|
|
||||||
listenerCalled.set(false);
|
listenerCalled.set(false);
|
||||||
// index doesn't exist and now exists with correct format
|
// 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);
|
markShardsAvailable(clusterStateBuilder);
|
||||||
manager.clusterChanged(event(clusterStateBuilder));
|
manager.clusterChanged(event(clusterStateBuilder));
|
||||||
assertTrue(listenerCalled.get());
|
assertTrue(listenerCalled.get());
|
||||||
|
@ -317,18 +321,19 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
assertThat(manager.isStateRecovered(), Matchers.equalTo(true));
|
assertThat(manager.isStateRecovered(), Matchers.equalTo(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClusterState.Builder createClusterState(String indexName, String templateName) throws IOException {
|
public static ClusterState.Builder createClusterState(String indexName, String aliasName, String templateName) throws IOException {
|
||||||
return createClusterState(indexName, templateName, templateName, SecurityIndexManager.INTERNAL_INDEX_FORMAT);
|
return createClusterState(indexName, aliasName, templateName, templateName, SecurityIndexManager.INTERNAL_MAIN_INDEX_FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClusterState.Builder createClusterState(String indexName, String templateName, int format) throws IOException {
|
public static ClusterState.Builder createClusterState(String indexName, String aliasName, String templateName, int format)
|
||||||
return createClusterState(indexName, templateName, templateName, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ClusterState.Builder createClusterState(String indexName, String templateName, String buildMappingFrom, int format)
|
|
||||||
throws IOException {
|
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);
|
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();
|
MetaData.Builder metaDataBuilder = new MetaData.Builder();
|
||||||
metaDataBuilder.put(templateBuilder);
|
metaDataBuilder.put(templateBuilder);
|
||||||
|
@ -338,7 +343,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markShardsAvailable(ClusterState.Builder clusterStateBuilder) {
|
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() {
|
private static ClusterState state() {
|
||||||
|
@ -349,7 +354,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
.build();
|
.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.Builder indexMetaData = IndexMetaData.builder(indexName);
|
||||||
indexMetaData.settings(Settings.builder()
|
indexMetaData.settings(Settings.builder()
|
||||||
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
.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.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
.put(IndexMetaData.INDEX_FORMAT_SETTING.getKey(), format)
|
.put(IndexMetaData.INDEX_FORMAT_SETTING.getKey(), format)
|
||||||
.build());
|
.build());
|
||||||
|
indexMetaData.putAlias(AliasMetaData.builder(aliasName).build());
|
||||||
final Map<String, String> mappings = getTemplateMappings(templateName);
|
final Map<String, String> mappings = getTemplateMappings(templateName);
|
||||||
for (Map.Entry<String, String> entry : mappings.entrySet()) {
|
for (Map.Entry<String, String> entry : mappings.entrySet()) {
|
||||||
indexMetaData.putMapping(entry.getKey(), entry.getValue());
|
indexMetaData.putMapping(entry.getKey(), entry.getValue());
|
||||||
|
@ -389,7 +395,7 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMappingVersionMatching() throws IOException {
|
public void testMappingVersionMatching() throws IOException {
|
||||||
String templateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
|
String templateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString);
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString);
|
||||||
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
||||||
assertTrue(manager.checkMappingVersion(Version.CURRENT.minimumIndexCompatibilityVersion()::before));
|
assertTrue(manager.checkMappingVersion(Version.CURRENT.minimumIndexCompatibilityVersion()::before));
|
||||||
|
@ -397,17 +403,19 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMissingVersionMappingThrowsError() throws IOException {
|
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);
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString);
|
||||||
final ClusterState clusterState = clusterStateBuilder.build();
|
final ClusterState clusterState = clusterStateBuilder.build();
|
||||||
IllegalStateException exception = expectThrows(IllegalStateException.class,
|
IllegalStateException exception = expectThrows(IllegalStateException.class,
|
||||||
() -> SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, Version.CURRENT::equals));
|
() -> SecurityIndexManager.checkIndexMappingVersionMatches(RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
assertEquals("Cannot read security-version string in index " + SECURITY_INDEX_NAME, exception.getMessage());
|
clusterState, logger, Version.CURRENT::equals));
|
||||||
|
assertEquals("Cannot read security-version string in index " + RestrictedIndicesNames.SECURITY_MAIN_ALIAS,
|
||||||
|
exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexTemplateIsIdentifiedAsUpToDate() throws IOException {
|
public void testIndexTemplateIsIdentifiedAsUpToDate() throws IOException {
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(
|
||||||
"/" + SECURITY_TEMPLATE_NAME + ".json"
|
"/" + SECURITY_MAIN_TEMPLATE_7 + ".json"
|
||||||
);
|
);
|
||||||
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
manager.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
||||||
// No upgrade actions run
|
// No upgrade actions run
|
||||||
|
@ -415,20 +423,20 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIndexTemplateVersionMatching() throws Exception {
|
public void testIndexTemplateVersionMatching() throws Exception {
|
||||||
String templateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
|
String templateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(templateString);
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(templateString);
|
||||||
final ClusterState clusterState = clusterStateBuilder.build();
|
final ClusterState clusterState = clusterStateBuilder.build();
|
||||||
|
|
||||||
assertTrue(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
|
assertTrue(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
|
||||||
SecurityIndexManager.SECURITY_TEMPLATE_NAME, clusterState, logger,
|
SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7, clusterState, logger,
|
||||||
Version.V_6_0_0::before));
|
Version.V_6_0_0::before));
|
||||||
assertFalse(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
|
assertFalse(SecurityIndexManager.checkTemplateExistsAndVersionMatches(
|
||||||
SecurityIndexManager.SECURITY_TEMPLATE_NAME, clusterState, logger,
|
SecurityIndexManager.SECURITY_MAIN_TEMPLATE_7, clusterState, logger,
|
||||||
Version.V_6_0_0::after));
|
Version.V_6_0_0::after));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUpToDateMappingsAreIdentifiedAsUpToDate() throws IOException {
|
public void testUpToDateMappingsAreIdentifiedAsUpToDate() throws IOException {
|
||||||
String securityTemplateString = "/" + SECURITY_TEMPLATE_NAME + ".json";
|
String securityTemplateString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(securityTemplateString);
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(securityTemplateString);
|
||||||
manager.clusterChanged(new ClusterChangedEvent("test-event",
|
manager.clusterChanged(new ClusterChangedEvent("test-event",
|
||||||
clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
clusterStateBuilder.build(), EMPTY_CLUSTER_STATE));
|
||||||
|
@ -438,8 +446,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
public void testMissingIndexIsIdentifiedAsUpToDate() throws IOException {
|
public void testMissingIndexIsIdentifiedAsUpToDate() throws IOException {
|
||||||
final ClusterName clusterName = new ClusterName("test-cluster");
|
final ClusterName clusterName = new ClusterName("test-cluster");
|
||||||
final ClusterState.Builder clusterStateBuilder = ClusterState.builder(clusterName);
|
final ClusterState.Builder clusterStateBuilder = ClusterState.builder(clusterName);
|
||||||
String mappingString = "/" + SECURITY_TEMPLATE_NAME + ".json";
|
String mappingString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
|
||||||
IndexTemplateMetaData.Builder templateMeta = getIndexTemplateMetaData(SECURITY_TEMPLATE_NAME, mappingString);
|
IndexTemplateMetaData.Builder templateMeta = getIndexTemplateMetaData(SECURITY_MAIN_TEMPLATE_7, mappingString);
|
||||||
MetaData.Builder builder = new MetaData.Builder(clusterStateBuilder.build().getMetaData());
|
MetaData.Builder builder = new MetaData.Builder(clusterStateBuilder.build().getMetaData());
|
||||||
builder.put(templateMeta);
|
builder.put(templateMeta);
|
||||||
clusterStateBuilder.metaData(builder);
|
clusterStateBuilder.metaData(builder);
|
||||||
|
@ -450,24 +458,24 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
|
|
||||||
private ClusterState.Builder createClusterStateWithTemplate(String securityTemplateString) throws IOException {
|
private ClusterState.Builder createClusterStateWithTemplate(String securityTemplateString) throws IOException {
|
||||||
// add the correct mapping no matter what the template
|
// 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());
|
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);
|
return ClusterState.builder(clusterState).metaData(metaDataBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClusterState.Builder createClusterStateWithMapping(String securityTemplateString) throws IOException {
|
private ClusterState.Builder createClusterStateWithMapping(String securityTemplateString) throws IOException {
|
||||||
final ClusterState clusterState = createClusterStateWithIndex(securityTemplateString).build();
|
final ClusterState clusterState = createClusterStateWithIndex(securityTemplateString).build();
|
||||||
final String indexName = clusterState.metaData().getAliasAndIndexLookup()
|
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));
|
return ClusterState.builder(clusterState).routingTable(SecurityTestUtils.buildIndexRoutingTable(indexName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClusterState.Builder createClusterStateWithMappingAndTemplate(String securityTemplateString) throws IOException {
|
private ClusterState.Builder createClusterStateWithMappingAndTemplate(String securityTemplateString) throws IOException {
|
||||||
ClusterState.Builder clusterStateBuilder = createClusterStateWithMapping(securityTemplateString);
|
ClusterState.Builder clusterStateBuilder = createClusterStateWithMapping(securityTemplateString);
|
||||||
MetaData.Builder metaDataBuilder = new MetaData.Builder(clusterStateBuilder.build().metaData());
|
MetaData.Builder metaDataBuilder = new MetaData.Builder(clusterStateBuilder.build().metaData());
|
||||||
String securityMappingString = "/" + SECURITY_TEMPLATE_NAME + ".json";
|
String securityMappingString = "/" + SECURITY_MAIN_TEMPLATE_7 + ".json";
|
||||||
IndexTemplateMetaData.Builder securityTemplateMeta = getIndexTemplateMetaData(SECURITY_TEMPLATE_NAME, securityMappingString);
|
IndexTemplateMetaData.Builder securityTemplateMeta = getIndexTemplateMetaData(SECURITY_MAIN_TEMPLATE_7, securityMappingString);
|
||||||
metaDataBuilder.put(securityTemplateMeta);
|
metaDataBuilder.put(securityTemplateMeta);
|
||||||
return clusterStateBuilder.metaData(metaDataBuilder);
|
return clusterStateBuilder.metaData(metaDataBuilder);
|
||||||
}
|
}
|
||||||
|
@ -493,7 +501,8 @@ public class SecurityIndexManagerTests extends ESTestCase {
|
||||||
private ClusterState.Builder createClusterStateWithIndex(String securityTemplate) throws IOException {
|
private ClusterState.Builder createClusterStateWithIndex(String securityTemplate) throws IOException {
|
||||||
final MetaData.Builder metaDataBuilder = new MetaData.Builder();
|
final MetaData.Builder metaDataBuilder = new MetaData.Builder();
|
||||||
final boolean withAlias = randomBoolean();
|
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));
|
metaDataBuilder.put(createIndexMetadata(securityIndexName, securityTemplate));
|
||||||
|
|
||||||
ClusterState.Builder clusterStateBuilder = ClusterState.builder(state());
|
ClusterState.Builder clusterStateBuilder = ClusterState.builder(state());
|
||||||
|
|
|
@ -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.CREATE;
|
||||||
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
|
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
|
||||||
import static java.nio.file.StandardOpenOption.WRITE;
|
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 {
|
public class SecurityTestUtils {
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ public class SecurityTestUtils {
|
||||||
* Adds the index alias {@code .security} to the underlying concrete index.
|
* Adds the index alias {@code .security} to the underlying concrete index.
|
||||||
*/
|
*/
|
||||||
public static MetaData addAliasToMetaData(MetaData metaData, String indexName) {
|
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);
|
MetaData.Builder metaDataBuilder = new MetaData.Builder(metaData);
|
||||||
IndexMetaData indexMetaData = metaData.index(indexName);
|
IndexMetaData indexMetaData = metaData.index(indexName);
|
||||||
metaDataBuilder.put(IndexMetaData.builder(indexMetaData).putAlias(aliasMetaData));
|
metaDataBuilder.put(IndexMetaData.builder(indexMetaData).putAlias(aliasMetaData));
|
||||||
|
|
|
@ -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.index.RestrictedIndicesNames;
|
||||||
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
||||||
import org.elasticsearch.xpack.security.audit.index.IndexNameResolver;
|
import org.elasticsearch.xpack.security.audit.index.IndexNameResolver;
|
||||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
@ -32,8 +31,6 @@ public class XPackUserTests extends ESTestCase {
|
||||||
public void testXPackUserCannotAccessRestrictedIndices() {
|
public void testXPackUserCannotAccessRestrictedIndices() {
|
||||||
final String action = randomFrom(GetAction.NAME, SearchAction.NAME, IndexAction.NAME);
|
final String action = randomFrom(GetAction.NAME, SearchAction.NAME, IndexAction.NAME);
|
||||||
final Predicate<String> predicate = XPackUser.ROLE.indices().allowedIndicesMatcher(action);
|
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) {
|
for (String index : RestrictedIndicesNames.RESTRICTED_NAMES) {
|
||||||
assertThat(predicate.test(index), Matchers.is(false));
|
assertThat(predicate.test(index), Matchers.is(false));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -119,6 +119,8 @@ for (Version version : bwcVersions.wireCompatible) {
|
||||||
setting 'xpack.security.enabled', 'true'
|
setting 'xpack.security.enabled', 'true'
|
||||||
setting 'xpack.security.transport.ssl.enabled', 'true'
|
setting 'xpack.security.transport.ssl.enabled', 'true'
|
||||||
setting 'xpack.security.authc.token.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'
|
setting 'xpack.security.audit.enabled', 'true'
|
||||||
if (project.inFipsJvm) {
|
if (project.inFipsJvm) {
|
||||||
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
|
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.license.self_generated.type', 'trial'
|
||||||
setting 'xpack.security.enabled', 'true'
|
setting 'xpack.security.enabled', 'true'
|
||||||
setting 'xpack.security.transport.ssl.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) {
|
if (project.inFipsJvm) {
|
||||||
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
|
setting 'xpack.security.transport.ssl.key', 'testnode.pem'
|
||||||
setting 'xpack.security.transport.ssl.certificate', 'testnode.crt'
|
setting 'xpack.security.transport.ssl.certificate', 'testnode.crt'
|
||||||
|
|
|
@ -16,9 +16,14 @@ import org.elasticsearch.client.RestClient;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.test.rest.yaml.ObjectPath;
|
import org.elasticsearch.test.rest.yaml.ObjectPath;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -27,7 +32,33 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class TokenBackwardsCompatibilityIT extends AbstractUpgradeTestCase {
|
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);
|
assumeTrue("this test should only run against the old cluster", CLUSTER_TYPE == ClusterType.OLD);
|
||||||
{
|
{
|
||||||
Version minimumIndexCompatibilityVersion = Version.CURRENT.minimumIndexCompatibilityVersion();
|
Version minimumIndexCompatibilityVersion = Version.CURRENT.minimumIndexCompatibilityVersion();
|
||||||
|
@ -48,188 +79,363 @@ public class TokenBackwardsCompatibilityIT extends AbstractUpgradeTestCase {
|
||||||
client().performRequest(createTemplate);
|
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
|
storeTokens(client(), 1, accessToken, refreshToken);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// In this test either all or none tests or on a specific version:
|
responseMap = createTokens(client(), "test_user", "x-pack-test-password");
|
||||||
Request indexRequest1 = new Request("PUT", "token_backwards_compatibility_it/_doc/old_cluster_token1");
|
accessToken = (String) responseMap.get("access_token");
|
||||||
indexRequest1.setJsonEntity(
|
assertNotNull(accessToken);
|
||||||
"{\n" +
|
assertAccessTokenWorks(accessToken);
|
||||||
" \"token\": \"" + token + "\"\n" +
|
refreshToken = (String) responseMap.get("refresh_token");
|
||||||
"}");
|
assertNotNull(refreshToken);
|
||||||
Response indexResponse1 = client().performRequest(indexRequest1);
|
|
||||||
assertOK(indexResponse1);
|
storeTokens(client(), 2, accessToken, refreshToken);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// 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);
|
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");
|
for (int tokenIdx : Arrays.asList(1, 3, 4)) { // 2 is invalidated in another mixed-cluster test, 5 is invalidated in the old cluster
|
||||||
Response getResponse = client().performRequest(getRequest);
|
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
|
||||||
assertOK(getResponse);
|
assertAccessTokenWorks((String) source.get("token"));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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
|
for (int tokenIdx : Arrays.asList(2, 5)) {
|
||||||
Request getRequest = new Request("GET", "token_backwards_compatibility_it/_doc/old_cluster_token1");
|
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
|
||||||
Response getResponse = client().performRequest(getRequest);
|
assertAccessTokenDoesNotWork((String) source.get("token"));
|
||||||
assertOK(getResponse);
|
assertRefreshTokenInvalidated((String) source.get("refresh_token"));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTokenWorks(String token) throws IOException {
|
public void testAccessTokensWorkInUpgradedCluster() throws Exception {
|
||||||
Request request = new Request("GET", "/_security/_authenticate");
|
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
|
||||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
for (int tokenIdx : Arrays.asList(3, 4, 10, 12)) {
|
||||||
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
|
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
|
||||||
request.setOptions(options);
|
assertAccessTokenWorks((String) source.get("token"));
|
||||||
Response authenticateResponse = client().performRequest(request);
|
}
|
||||||
assertOK(authenticateResponse);
|
|
||||||
assertEquals("test_user", entityAsMap(authenticateResponse).get("username"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTokenDoesNotWork(String token) {
|
public void testGeneratingTokensInUpgradedCluster() throws Exception {
|
||||||
Request request = new Request("GET", "/_security/_authenticate");
|
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
|
||||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
Map<String, Object> responseMap = createTokens(client(), "test_user", "x-pack-test-password");
|
||||||
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + token);
|
String accessToken = (String) responseMap.get("access_token");
|
||||||
request.setOptions(options);
|
assertNotNull(accessToken);
|
||||||
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest(request));
|
assertAccessTokenWorks(accessToken);
|
||||||
assertEquals(401, e.getResponse().getStatusLine().getStatusCode());
|
String refreshToken = (String) responseMap.get("refresh_token");
|
||||||
Response response = e.getResponse();
|
assertNotNull(refreshToken);
|
||||||
assertEquals("Bearer realm=\"security\", error=\"invalid_token\", error_description=\"The access token expired\"",
|
|
||||||
response.getHeader("WWW-Authenticate"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isMasterOnLatestVersion() throws Exception {
|
public void testRefreshingTokensInUpgradedCluster() throws Exception {
|
||||||
Response response = client().performRequest(new Request("GET", "_cluster/state"));
|
assumeTrue("this test should only run against the upgraded cluster", CLUSTER_TYPE == ClusterType.UPGRADED);
|
||||||
assertOK(response);
|
for (int tokenIdx : Arrays.asList(4, 10, 12)) {
|
||||||
final String masterNodeId = ObjectPath.createFromResponse(response).evaluate("master_node");
|
Map<String, Object> source = retrieveStoredTokens(client(), tokenIdx);
|
||||||
response = client().performRequest(new Request("GET", "_nodes"));
|
Map<String, Object> refreshedResponseMap = refreshToken(client(), (String) source.get("refresh_token"));
|
||||||
assertOK(response);
|
String accessToken = (String) refreshedResponseMap.get("access_token");
|
||||||
ObjectPath objectPath = ObjectPath.createFromResponse(response);
|
assertNotNull(accessToken);
|
||||||
logger.info("Master node is on version: " + objectPath.evaluate("nodes." + masterNodeId + ".version"));
|
assertAccessTokenWorks(accessToken);
|
||||||
return Version.CURRENT.equals(Version.fromString(objectPath.evaluate("nodes." + masterNodeId + ".version")));
|
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"));
|
Response response = client().performRequest(new Request("GET", "_nodes"));
|
||||||
assertOK(response);
|
assertOK(response);
|
||||||
ObjectPath objectPath = ObjectPath.createFromResponse(response);
|
ObjectPath objectPath = ObjectPath.createFromResponse(response);
|
||||||
Map<String, Object> nodesAsMap = objectPath.evaluate("nodes");
|
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()) {
|
for (Map.Entry<String, Object> entry : nodesAsMap.entrySet()) {
|
||||||
Map<String, Object> nodeDetails = (Map<String, Object>) entry.getValue();
|
Map<String, Object> nodeDetails = (Map<String, Object>) entry.getValue();
|
||||||
Version version = Version.fromString((String) nodeDetails.get("version"));
|
Version version = Version.fromString((String) nodeDetails.get("version"));
|
||||||
if (Version.CURRENT.equals(version)) {
|
Map<String, Object> httpInfo = (Map<String, Object>) nodeDetails.get("http");
|
||||||
Map<String, Object> httpInfo = (Map<String, Object>) nodeDetails.get("http");
|
hostsByVersion.computeIfAbsent(version, k -> new ArrayList<>()).add(HttpHost.create((String) httpInfo.get("publish_address")));
|
||||||
hosts.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,17 @@
|
||||||
- skip:
|
- skip:
|
||||||
features: headers
|
features: headers
|
||||||
|
|
||||||
|
- do:
|
||||||
|
cluster.health:
|
||||||
|
wait_for_status: yellow
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
get:
|
get:
|
||||||
index: token_index
|
index: token_index
|
||||||
type: doc
|
|
||||||
id: "6"
|
id: "6"
|
||||||
|
|
||||||
- match: { _index: token_index }
|
- match: { _index: token_index }
|
||||||
- match: { _type: doc }
|
- match: { _type: _doc }
|
||||||
- match: { _id: "6" }
|
- match: { _id: "6" }
|
||||||
- is_true: _source.token
|
- is_true: _source.token
|
||||||
- set: { _source.token : token }
|
- set: { _source.token : token }
|
||||||
|
@ -24,6 +27,59 @@
|
||||||
- match: { roles.0: "superuser" }
|
- match: { roles.0: "superuser" }
|
||||||
- match: { full_name: "Token User" }
|
- 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:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: Bearer ${token}
|
Authorization: Bearer ${token}
|
||||||
|
@ -31,7 +87,7 @@
|
||||||
rest_total_hits_as_int: true
|
rest_total_hits_as_int: true
|
||||||
index: token_index
|
index: token_index
|
||||||
|
|
||||||
- match: { hits.total: 6 }
|
- match: { hits.total: 8 }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
|
@ -40,7 +96,7 @@
|
||||||
rest_total_hits_as_int: true
|
rest_total_hits_as_int: true
|
||||||
index: token_index
|
index: token_index
|
||||||
|
|
||||||
- match: { hits.total: 6 }
|
- match: { hits.total: 8 }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
|
@ -49,5 +105,79 @@
|
||||||
rest_total_hits_as_int: true
|
rest_total_hits_as_int: true
|
||||||
index: token_index
|
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}"}
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
- match: { type: "Bearer" }
|
- match: { type: "Bearer" }
|
||||||
- is_true: access_token
|
- is_true: access_token
|
||||||
- set: { access_token: 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
|
- is_false: scope
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
@ -54,15 +56,15 @@
|
||||||
bulk:
|
bulk:
|
||||||
refresh: true
|
refresh: true
|
||||||
body:
|
body:
|
||||||
- '{"index": {"_index": "token_index", "_type": "doc", "_id" : "1"}}'
|
- '{"index": {"_index": "token_index", "_type": "_doc", "_id" : "1"}}'
|
||||||
- '{"f1": "v1_old", "f2": 0}'
|
- '{"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}'
|
- '{"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}'
|
- '{"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}'
|
- '{"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}'
|
- '{"f1": "v5_old", "f2": 4}'
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
@ -81,6 +83,48 @@
|
||||||
Authorization: Bearer ${token}
|
Authorization: Bearer ${token}
|
||||||
index:
|
index:
|
||||||
index: token_index
|
index: token_index
|
||||||
type: doc
|
|
||||||
id: "6"
|
id: "6"
|
||||||
body: { "token" : "${token}"}
|
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}"}
|
||||||
|
|
|
@ -2,14 +2,18 @@
|
||||||
"Get the indexed token and use if to authenticate":
|
"Get the indexed token and use if to authenticate":
|
||||||
- skip:
|
- skip:
|
||||||
features: headers
|
features: headers
|
||||||
|
|
||||||
|
- do:
|
||||||
|
cluster.health:
|
||||||
|
wait_for_status: yellow
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
get:
|
get:
|
||||||
index: token_index
|
index: token_index
|
||||||
type: doc
|
|
||||||
id: "6"
|
id: "6"
|
||||||
|
|
||||||
- match: { _index: token_index }
|
- match: { _index: token_index }
|
||||||
- match: { _type: doc }
|
- match: { _type: _doc }
|
||||||
- match: { _id: "6" }
|
- match: { _id: "6" }
|
||||||
- is_true: _source.token
|
- is_true: _source.token
|
||||||
- set: { _source.token : token }
|
- set: { _source.token : token }
|
||||||
|
@ -30,7 +34,7 @@
|
||||||
rest_total_hits_as_int: true
|
rest_total_hits_as_int: true
|
||||||
index: token_index
|
index: token_index
|
||||||
|
|
||||||
- match: { hits.total: 6 }
|
- match: { hits.total: 8 }
|
||||||
|
|
||||||
# counter example that we are really checking this
|
# counter example that we are really checking this
|
||||||
- do:
|
- do:
|
||||||
|
@ -40,3 +44,51 @@
|
||||||
search:
|
search:
|
||||||
rest_total_hits_as_int: true
|
rest_total_hits_as_int: true
|
||||||
index: token_index
|
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 }
|
||||||
|
|
|
@ -199,7 +199,7 @@ public abstract class AbstractAdLdapRealmTestCase extends SecurityIntegTestCase
|
||||||
@Override
|
@Override
|
||||||
public Set<String> excludeTemplates() {
|
public Set<String> excludeTemplates() {
|
||||||
Set<String> templates = Sets.newHashSet(super.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;
|
return templates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue