Types removal security index template (#39705) (#39728)

As we are moving to single type indices,
we need to address this change in security-related indexes.
To address this, we are
- updating index templates to use preferred type name `_doc`
- updating the API calls to use preferred type name `_doc`

Upgrade impact:-
In case of an upgrade from 6.x, the security index has type
`doc` and this will keep working as there is a single type and `_doc`
works as an alias to an existing type. The change is handled in the
`SecurityIndexManager` when we load mappings and settings from
the template. Previously, we used to do a `PutIndexTemplateRequest`
with the mapping source JSON with the type name. This has been
modified to remove the type name from the source.
So in the case of an upgrade, the `doc` type is updated
whereas for fresh installs `_doc` is updated. This happens as
backend handles `_doc` as an alias to the existing type name.

An optional step is to `reindex` security index and update the
type to `_doc`.

Since we do not support the security audit log index,
that template has been deleted.

Relates: #38637
This commit is contained in:
Yogesh Gaikwad 2019-03-06 18:53:59 +11:00 committed by GitHub
parent aaecaf59a4
commit c91dcbd5ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 118 additions and 178 deletions

View File

@ -10,7 +10,6 @@ public final class NativeRoleMappingStoreField {
public static final String DOC_TYPE_FIELD = "doc_type";
public static final String DOC_TYPE_ROLE_MAPPING = "role-mapping";
public static final String ID_PREFIX = DOC_TYPE_ROLE_MAPPING + "_";
public static final String SECURITY_GENERIC_TYPE = "doc";
private NativeRoleMappingStoreField() {}
}

View File

@ -33,7 +33,7 @@
}
},
"mappings" : {
"doc" : {
"_doc" : {
"_meta": {
"security-version": "${security.template.version}"
},

View File

@ -1,90 +0,0 @@
{
"index_patterns": [ ".security_audit_log*" ],
"order": 1000,
"settings": {
"index.format": 6
},
"mappings": {
"doc": {
"_meta": {
"security-version": "${security.template.version}"
},
"dynamic" : "strict",
"properties": {
"@timestamp": {
"type": "date",
"format": "date_time",
"doc_values": true
},
"node_name": {
"type": "keyword"
},
"node_host_name": {
"type": "keyword"
},
"node_host_address": {
"type": "keyword"
},
"layer": {
"type": "keyword"
},
"event_type": {
"type": "keyword"
},
"origin_address": {
"type": "keyword"
},
"origin_type": {
"type": "keyword"
},
"principal": {
"type": "keyword"
},
"roles": {
"type": "keyword"
},
"run_by_principal": {
"type": "keyword"
},
"run_as_principal": {
"type": "keyword"
},
"action": {
"type": "keyword"
},
"indices": {
"type": "keyword"
},
"request": {
"type": "keyword"
},
"request_body": {
"type": "keyword",
"index": false,
"doc_values": false
},
"uri": {
"type": "keyword"
},
"realm": {
"type": "keyword"
},
"run_by_realm": {
"type": "keyword"
},
"run_as_realm": {
"type": "keyword"
},
"transport_profile": {
"type": "keyword"
},
"rule": {
"type": "keyword"
},
"opaque_id": {
"type": "keyword"
}
}
}
}
}

View File

@ -93,15 +93,16 @@ import java.util.stream.Collectors;
import javax.crypto.SecretKeyFactory;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
public class ApiKeyService {
private static final Logger logger = LogManager.getLogger(ApiKeyService.class);
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(logger);
private static final String TYPE = "doc";
static final String API_KEY_ID_KEY = "_security_api_key_id";
static final String API_KEY_ROLE_DESCRIPTORS_KEY = "_security_api_key_role_descriptors";
static final String API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY = "_security_api_key_limited_by_role_descriptors";
@ -248,7 +249,7 @@ public class ApiKeyService {
.endObject()
.endObject();
final IndexRequest indexRequest =
client.prepareIndex(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE)
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME)
.setSource(builder)
.setRefreshPolicy(request.getRefreshPolicy())
.request();
@ -286,8 +287,10 @@ public class ApiKeyService {
}
if (credentials != null) {
final GetRequest getRequest = client.prepareGet(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, credentials.getId())
.setFetchSource(true).request();
final GetRequest getRequest = client
.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, credentials.getId())
.setFetchSource(true)
.request();
executeAsyncWithOrigin(ctx, SECURITY_ORIGIN, getRequest, ActionListener.<GetResponse>wrap(response -> {
if (response.isExists()) {
try (ApiKeyCredentials ignore = credentials) {
@ -693,7 +696,7 @@ public class ApiKeyService {
expiredQuery.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
boolQuery.filter(expiredQuery);
}
final SearchRequest request = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
final SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(boolQuery)
.setVersion(false)
@ -766,9 +769,10 @@ public class ApiKeyService {
} else {
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
for (String apiKeyId : apiKeyIds) {
UpdateRequest request = client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, apiKeyId)
.setDoc(Collections.singletonMap("api_key_invalidated", true))
.request();
UpdateRequest request = client
.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, apiKeyId)
.setDoc(Collections.singletonMap("api_key_invalidated", true))
.request();
bulkRequestBuilder.add(request);
}
bulkRequestBuilder.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL);

View File

@ -129,9 +129,11 @@ import java.util.stream.Collectors;
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
import static org.elasticsearch.gateway.GatewayService.STATE_NOT_RECOVERED_BLOCK;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.threadpool.ThreadPool.Names.GENERIC;
/**
@ -158,7 +160,6 @@ public final class TokenService {
"\", error=\"invalid_token\", error_description=\"The access token expired\"";
private static final String MALFORMED_TOKEN_WWW_AUTH_VALUE = "Bearer realm=\"" + XPackField.SECURITY +
"\", error=\"invalid_token\", error_description=\"The access token is malformed\"";
private static final String TYPE = "doc";
private static final BackoffPolicy DEFAULT_BACKOFF = BackoffPolicy.exponentialBackoff();
public static final String THREAD_POOL_NAME = XPackField.SECURITY + "-token-key";
@ -280,7 +281,7 @@ public final class TokenService {
builder.endObject();
final String documentId = getTokenDocumentId(userToken);
IndexRequest request =
client.prepareIndex(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, documentId)
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, documentId)
.setOpType(OpType.CREATE)
.setSource(builder)
.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL)
@ -377,7 +378,7 @@ public final class TokenService {
securityIndex.checkIndexVersionThenExecute(
ex -> listener.onFailure(traceLog("prepare security index", userTokenId, ex)),
() -> {
final GetRequest getRequest = client.prepareGet(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE,
final GetRequest getRequest = client.prepareGet(SecurityIndexManager.SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME,
getTokenDocumentId(userTokenId)).request();
Consumer<Exception> onFailure = ex -> listener.onFailure(traceLog("decode token", userTokenId, ex));
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, getRequest,
@ -638,10 +639,11 @@ public final class TokenService {
} else {
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
for (String tokenId : tokenIds) {
UpdateRequest request = client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(tokenId))
.setDoc(srcPrefix, Collections.singletonMap("invalidated", true))
.setFetchSource(srcPrefix, null)
.request();
UpdateRequest request = client
.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getTokenDocumentId(tokenId))
.setDoc(srcPrefix, Collections.singletonMap("invalidated", true))
.setFetchSource(srcPrefix, null)
.request();
bulkRequestBuilder.add(request);
}
bulkRequestBuilder.setRefreshPolicy(RefreshPolicy.WAIT_UNTIL);
@ -734,7 +736,7 @@ public final class TokenService {
*/
private void findTokenFromRefreshToken(String refreshToken, ActionListener<SearchResponse> listener,
Iterator<TimeValue> backoff) {
SearchRequest request = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
.setQuery(QueryBuilders.boolQuery()
.filter(QueryBuilders.termQuery("doc_type", TOKEN_DOC_TYPE))
.filter(QueryBuilders.termQuery("refresh_token.token", refreshToken)))
@ -880,7 +882,7 @@ public final class TokenService {
updateMap.put("refresh_time", refreshTime.toEpochMilli());
updateMap.put("superseded_by", getTokenDocumentId(newUserTokenId));
UpdateRequestBuilder updateRequest =
client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, tokenDocId)
client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, tokenDocId)
.setDoc("refresh_token", updateMap)
.setFetchSource(true)
.setRefreshPolicy(RefreshPolicy.IMMEDIATE);
@ -970,7 +972,7 @@ public final class TokenService {
private void getTokenDocAsync(String tokenDocId, ActionListener<GetResponse> listener) {
GetRequest getRequest =
client.prepareGet(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE, tokenDocId).request();
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, tokenDocId).request();
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, getRequest, listener, client::get);
}
@ -1127,7 +1129,7 @@ public final class TokenService {
)
);
final SearchRequest request = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
final SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(boolQuery)
.setVersion(false)
@ -1170,7 +1172,7 @@ public final class TokenService {
)
);
final SearchRequest request = client.prepareSearch(SecurityIndexManager.SECURITY_INDEX_NAME)
final SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setQuery(boolQuery)
.setVersion(false)
@ -1277,8 +1279,8 @@ public final class TokenService {
listener.onResponse(null);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
final GetRequest getRequest = client.prepareGet(SecurityIndexManager.SECURITY_INDEX_NAME, TYPE,
getTokenDocumentId(userToken)).request();
final GetRequest getRequest = client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getTokenDocumentId(userToken))
.request();
Consumer<Exception> onFailure = ex -> listener.onFailure(traceLog("check token state", userToken.getId(), ex));
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, getRequest,
ActionListener.<GetResponse>wrap(response -> {

View File

@ -62,6 +62,7 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
@ -77,7 +78,6 @@ import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECU
*/
public class NativeUsersStore {
public static final String INDEX_TYPE = "doc";
static final String USER_DOC_TYPE = "user";
public static final String RESERVED_USER_TYPE = "reserved-user";
private static final Logger logger = LogManager.getLogger(NativeUsersStore.class);
@ -143,7 +143,7 @@ public class NativeUsersStore {
query = QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE);
} else {
final String[] users = Arrays.stream(userNames).map(s -> getIdForUser(USER_DOC_TYPE, s)).toArray(String[]::new);
query = QueryBuilders.boolQuery().filter(QueryBuilders.idsQuery(INDEX_TYPE).addIds(users));
query = QueryBuilders.boolQuery().filter(QueryBuilders.idsQuery().addIds(users));
}
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN)) {
@ -206,8 +206,7 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, user)).request(),
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, user)).request(),
new ActionListener<GetResponse>() {
@Override
public void onResponse(GetResponse response) {
@ -247,7 +246,7 @@ public class NativeUsersStore {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(docType, username))
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(docType, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(),
String.valueOf(request.passwordHash()))
.setRefreshPolicy(request.getRefreshPolicy()).request(),
@ -285,11 +284,9 @@ public class NativeUsersStore {
private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username))
.setSource(Fields.PASSWORD.getPreferredName(), String.valueOf(passwordHash),
Fields.ENABLED.getPreferredName(), true,
Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.setSource(Fields.PASSWORD.getPreferredName(), String.valueOf(passwordHash), Fields.ENABLED.getPreferredName(),
true, Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)
.setRefreshPolicy(refresh).request(),
new ActionListener<IndexResponse>() {
@Override
@ -327,8 +324,7 @@ public class NativeUsersStore {
// We must have an existing document
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
.setDoc(Requests.INDEX_CONTENT_TYPE,
Fields.USERNAME.getPreferredName(), putUserRequest.username(),
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
@ -372,8 +368,7 @@ public class NativeUsersStore {
assert putUserRequest.passwordHash() != null;
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
.setSource(Fields.USERNAME.getPreferredName(), putUserRequest.username(),
Fields.PASSWORD.getPreferredName(), String.valueOf(putUserRequest.passwordHash()),
Fields.ROLES.getPreferredName(), putUserRequest.roles(),
@ -416,8 +411,7 @@ public class NativeUsersStore {
final ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, username))
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
.setRefreshPolicy(refreshPolicy)
.request(),
@ -451,8 +445,7 @@ public class NativeUsersStore {
boolean clearCache, final ActionListener<Void> listener) {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username))
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.ENABLED.getPreferredName(), enabled)
.setUpsert(XContentType.JSON,
Fields.PASSWORD.getPreferredName(), "",
@ -486,8 +479,9 @@ public class NativeUsersStore {
listener.onFailure(frozenSecurityIndex.getUnavailableReason());
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
DeleteRequest request = client.prepareDelete(SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username())).request();
DeleteRequest request = client
.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username()))
.request();
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<DeleteResponse>() {
@ -533,8 +527,8 @@ public class NativeUsersStore {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username)).request(),
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForUser(RESERVED_USER_TYPE, username))
.request(),
new ActionListener<GetResponse>() {
@Override
public void onResponse(GetResponse getResponse) {

View File

@ -56,6 +56,7 @@ import java.util.stream.Stream;
import static org.elasticsearch.action.DocWriteResponse.Result.CREATED;
import static org.elasticsearch.action.DocWriteResponse.Result.DELETED;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
@ -83,8 +84,6 @@ public class NativeRoleMappingStore implements UserRoleMapper {
private static final String ID_PREFIX = DOC_TYPE_ROLE_MAPPING + "_";
private static final String SECURITY_GENERIC_TYPE = "doc";
private static final ActionListener<Object> NO_OP_ACTION_LISTENER = new ActionListener<Object>() {
@Override
public void onResponse(Object o) {
@ -133,7 +132,6 @@ public class NativeRoleMappingStore implements UserRoleMapper {
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN)) {
SearchRequest request = client.prepareSearch(SECURITY_INDEX_NAME)
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
.setTypes(SECURITY_GENERIC_TYPE)
.setQuery(query)
.setSize(1000)
.setFetchSource(true)
@ -203,7 +201,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, SECURITY_GENERIC_TYPE, getIdForName(mapping.getName()))
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForName(mapping.getName()))
.setSource(xContentBuilder)
.setRefreshPolicy(request.getRefreshPolicy())
.request(),
@ -232,7 +230,7 @@ public class NativeRoleMappingStore implements UserRoleMapper {
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, SECURITY_GENERIC_TYPE, getIdForName(request.getName()))
client.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForName(request.getName()))
.setRefreshPolicy(request.getRefreshPolicy())
.request(),
new ActionListener<DeleteResponse>() {

View File

@ -56,6 +56,7 @@ import java.util.stream.Collector;
import java.util.stream.Collectors;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
@ -118,7 +119,7 @@ public class NativePrivilegeStore {
final String[] docIds = applications.stream()
.flatMap(a -> names.stream().map(n -> toDocId(a, n)))
.toArray(String[]::new);
query = QueryBuilders.boolQuery().filter(typeQuery).filter(QueryBuilders.idsQuery("doc").addIds(docIds));
query = QueryBuilders.boolQuery().filter(typeQuery).filter(QueryBuilders.idsQuery().addIds(docIds));
}
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN)) {
@ -151,7 +152,8 @@ public class NativePrivilegeStore {
} else {
securityIndexManager.checkIndexVersionThenExecute(listener::onFailure,
() -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, "doc", toDocId(application, name)).request(),
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(application, name))
.request(),
new ActionListener<GetResponse>() {
@Override
public void onResponse(GetResponse response) {
@ -202,7 +204,7 @@ public class NativePrivilegeStore {
final String name = privilege.getName();
final XContentBuilder xContentBuilder = privilege.toXContent(jsonBuilder(), true);
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SECURITY_INDEX_NAME, "doc", toDocId(privilege.getApplication(), name))
client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(privilege.getApplication(), name))
.setSource(xContentBuilder)
.setRefreshPolicy(refreshPolicy)
.request(), listener, client::index);
@ -233,7 +235,7 @@ public class NativePrivilegeStore {
}, listener::onFailure), names.size(), Collections.emptyList());
for (String name : names) {
ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, "doc", toDocId(application, name))
client.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, toDocId(application, name))
.setRefreshPolicy(refreshPolicy)
.request(), groupListener, client::delete);
}

View File

@ -63,6 +63,7 @@ import java.util.function.BiConsumer;
import java.util.function.Supplier;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.search.SearchService.DEFAULT_KEEPALIVE_SETTING;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
@ -87,7 +88,6 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
Setting.intSetting(setting("authz.store.roles.index.cache.max_size"), 10000, Property.NodeScope, Property.Deprecated);
private static final Setting<TimeValue> CACHE_TTL_SETTING = Setting.timeSetting(setting("authz.store.roles.index.cache.ttl"),
TimeValue.timeValueMinutes(20), Property.NodeScope, Property.Deprecated);
private static final String ROLE_DOC_TYPE = "doc";
private static final Logger logger = LogManager.getLogger(NativeRolesStore.class);
private final Settings settings;
@ -143,7 +143,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
final String[] roleIds = names.stream().map(NativeRolesStore::getIdForRole).toArray(String[]::new);
MultiGetRequest multiGetRequest = client.prepareMultiGet().add(SECURITY_INDEX_NAME, ROLE_DOC_TYPE, roleIds).request();
MultiGetRequest multiGetRequest = client.prepareMultiGet().add(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, roleIds).request();
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, multiGetRequest,
ActionListener.<MultiGetResponse>wrap(mGetResponse -> {
final MultiGetItemResponse[] responses = mGetResponse.getResponses();
@ -179,8 +179,8 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
listener.onFailure(frozenSecurityIndex.getUnavailableReason());
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
DeleteRequest request = client.prepareDelete(SecurityIndexManager.SECURITY_INDEX_NAME,
ROLE_DOC_TYPE, getIdForRole(deleteRoleRequest.name())).request();
DeleteRequest request = client
.prepareDelete(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(deleteRoleRequest.name())).request();
request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<DeleteResponse>() {
@ -220,7 +220,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
listener.onFailure(e);
return;
}
final IndexRequest indexRequest = client.prepareIndex(SECURITY_INDEX_NAME, ROLE_DOC_TYPE, getIdForRole(role.getName()))
final IndexRequest indexRequest = client.prepareIndex(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(role.getName()))
.setSource(xContentBuilder)
.setRefreshPolicy(request.getRefreshPolicy())
.request();
@ -341,8 +341,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME,
ROLE_DOC_TYPE, getIdForRole(role)).request(),
client.prepareGet(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, getIdForRole(role)).request(),
listener,
client::get));
}

View File

@ -35,9 +35,15 @@ import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.mapper.MapperService;
@ -45,6 +51,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.core.security.index.RestrictedIndicesNames;
import org.elasticsearch.xpack.core.template.TemplateUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
@ -59,6 +66,8 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureFieldName;
import static org.elasticsearch.xpack.core.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
@ -315,7 +324,7 @@ public class SecurityIndexManager implements ClusterStateListener {
Tuple<String, Settings> mappingAndSettings = loadMappingAndSettingsSourceFromTemplate();
CreateIndexRequest request = new CreateIndexRequest(INTERNAL_SECURITY_INDEX)
.alias(new Alias(SECURITY_INDEX_NAME))
.mapping("doc", mappingAndSettings.v1(), XContentType.JSON)
.mapping(MapperService.SINGLE_MAPPING_NAME, mappingAndSettings.v1(), XContentType.JSON)
.waitForActiveShards(ActiveShardCount.ALL)
.settings(mappingAndSettings.v2());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
@ -344,9 +353,10 @@ public class SecurityIndexManager implements ClusterStateListener {
} else if (indexState.mappingUpToDate == false) {
LOGGER.info(
"security index [{}] (alias [{}]) is not up to date. Updating mapping", indexState.concreteIndexName, SECURITY_INDEX_NAME);
PutMappingRequest request = new PutMappingRequest(indexState.concreteIndexName)
.source(loadMappingAndSettingsSourceFromTemplate().v1(), XContentType.JSON)
.type("doc");
.type(MapperService.SINGLE_MAPPING_NAME);
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
ActionListener.<AcknowledgedResponse>wrap(putMappingResponse -> {
if (putMappingResponse.isAcknowledged()) {
@ -361,10 +371,24 @@ public class SecurityIndexManager implements ClusterStateListener {
}
private Tuple<String, Settings> loadMappingAndSettingsSourceFromTemplate() {
final byte[] template = TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json",
Version.CURRENT.toString(), SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
PutIndexTemplateRequest request = new PutIndexTemplateRequest(SECURITY_TEMPLATE_NAME).source(template, XContentType.JSON);
return new Tuple<>(request.mappings().get("doc"), request.settings());
final byte[] template = TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json", Version.CURRENT.toString(),
SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
final PutIndexTemplateRequest request = new PutIndexTemplateRequest(SECURITY_TEMPLATE_NAME).source(template, XContentType.JSON);
final String mappingSource = request.mappings().get(MapperService.SINGLE_MAPPING_NAME);
try (XContentParser parser = XContentType.JSON.xContent().createParser(NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, mappingSource)) {
// remove the type wrapping to get the mapping
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); // {
ensureFieldName(parser, parser.nextToken(), MapperService.SINGLE_MAPPING_NAME); // _doc
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); // {
XContentBuilder builder = JsonXContent.contentBuilder();
builder.generator().copyCurrentStructure(parser);
return new Tuple<>(Strings.toString(builder), request.settings());
} catch (IOException e) {
throw ExceptionsHelper.convertToRuntime(e);
}
}
/**

View File

@ -52,6 +52,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
@ -334,17 +336,20 @@ public class ApiKeyIntegTests extends SecurityIntegTestCase {
Instant dayBefore = created.minus(1L, ChronoUnit.DAYS);
assertTrue(Instant.now().isAfter(dayBefore));
UpdateResponse expirationDateUpdatedResponse = client
.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, "doc", createdApiKeys.get(0).getId())
.setDoc("expiration_time", dayBefore.toEpochMilli()).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, createdApiKeys.get(0).getId())
.setDoc("expiration_time", dayBefore.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
assertThat(expirationDateUpdatedResponse.getResult(), is(DocWriteResponse.Result.UPDATED));
// Expire the 2nd key such that it cannot be deleted by the remover
// hack doc to modify the expiration time to the week before
Instant weekBefore = created.minus(8L, ChronoUnit.DAYS);
assertTrue(Instant.now().isAfter(weekBefore));
expirationDateUpdatedResponse = client
.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, "doc", createdApiKeys.get(1).getId())
.setDoc("expiration_time", weekBefore.toEpochMilli()).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
expirationDateUpdatedResponse = client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, createdApiKeys.get(1).getId())
.setDoc("expiration_time", weekBefore.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
assertThat(expirationDateUpdatedResponse.getResult(), is(DocWriteResponse.Result.UPDATED));
// Invalidate to trigger the remover

View File

@ -190,9 +190,9 @@ public class AuthenticationServiceTests extends ESTestCase {
when(client.threadPool()).thenReturn(threadPool);
when(client.settings()).thenReturn(settings);
when(client.prepareIndex(any(String.class), any(String.class), any(String.class)))
.thenReturn(new IndexRequestBuilder(client, IndexAction.INSTANCE));
.thenReturn(new IndexRequestBuilder(client, IndexAction.INSTANCE));
when(client.prepareUpdate(any(String.class), any(String.class), any(String.class)))
.thenReturn(new UpdateRequestBuilder(client, UpdateAction.INSTANCE));
.thenReturn(new UpdateRequestBuilder(client, UpdateAction.INSTANCE));
doAnswer(invocationOnMock -> {
ActionListener<IndexResponse> responseActionListener = (ActionListener<IndexResponse>) invocationOnMock.getArguments()[2];
responseActionListener.onResponse(new IndexResponse());

View File

@ -53,7 +53,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.hamcrest.Matchers.equalTo;
@TestLogging("org.elasticsearch.xpack.security.authz.store.FileRolesStore:DEBUG")
@ -172,10 +174,10 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
// hack doc to modify the creation time to the day before
Instant yesterday = created.minus(36L, ChronoUnit.HOURS);
assertTrue(Instant.now().isAfter(yesterday));
client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, "doc", docId.get())
client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, docId.get())
.setDoc("creation_time", yesterday.toEpochMilli())
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.get();
AtomicBoolean deleteTriggered = new AtomicBoolean(false);
assertBusy(() -> {
@ -372,7 +374,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
Instant refreshed = Instant.now();
Instant aWhileAgo = refreshed.minus(50L, ChronoUnit.SECONDS);
assertTrue(Instant.now().isAfter(aWhileAgo));
UpdateResponse updateResponse = client.prepareUpdate(SecurityIndexManager.SECURITY_INDEX_NAME, "doc", docId.get())
UpdateResponse updateResponse = client.prepareUpdate(SECURITY_INDEX_NAME, SINGLE_MAPPING_NAME, docId.get())
.setDoc("refresh_token", Collections.singletonMap("refresh_time", aWhileAgo.toEpochMilli()))
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.setFetchSource("refresh_token", Strings.EMPTY_STRING)

View File

@ -22,6 +22,7 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
@ -111,7 +112,7 @@ public class NativeUsersStoreTests extends ESTestCase {
final GetResult result = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.RESERVED_USER_TYPE, randomAlphaOfLength(12)),
0, 1, 1L,
true,
@ -180,7 +181,7 @@ public class NativeUsersStoreTests extends ESTestCase {
final GetResult getResult = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
UNASSIGNED_SEQ_NO, 0, 1L,
false,
@ -222,7 +223,7 @@ public class NativeUsersStoreTests extends ESTestCase {
final BytesReference source = BytesReference.bytes(jsonBuilder().map(values));
final GetResult getResult = new GetResult(
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
MapperService.SINGLE_MAPPING_NAME,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
0, 1, 1L,
true,

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
@ -125,7 +126,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests.get(0), instanceOf(GetRequest.class));
GetRequest request = (GetRequest) requests.get(0);
assertThat(request.index(), equalTo(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.type(), equalTo("doc"));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
final String docSource = Strings.toString(sourcePrivilege);
@ -143,7 +144,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(requests.get(0), instanceOf(GetRequest.class));
GetRequest request = (GetRequest) requests.get(0);
assertThat(request.index(), equalTo(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.type(), equalTo("doc"));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
listener.get().onResponse(new GetResponse(
@ -229,7 +230,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
ApplicationPrivilegeDescriptor privilege = putPrivileges.get(i);
IndexRequest request = indexRequests.get(i);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.type(), equalTo("doc"));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo(
"application-privilege_" + privilege.getApplication() + ":" + privilege.getName()
));
@ -274,7 +275,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
String name = privilegeNames.get(i);
DeleteRequest request = deletes.get(i);
assertThat(request.indices(), arrayContaining(SecurityIndexManager.SECURITY_INDEX_NAME));
assertThat(request.type(), equalTo("doc"));
assertThat(request.type(), equalTo(MapperService.SINGLE_MAPPING_NAME));
assertThat(request.id(), equalTo("application-privilege_app1:" + name));
final boolean found = name.equals("p2") == false;
deleteListener.onResponse(new DeleteResponse(

View File

@ -1,7 +1,7 @@
{
"index_patterns": ".security",
"mappings": {
"doc": {
"_doc": {
"_meta": {
"security-version": "${security.template.version}"
},

View File

@ -124,7 +124,6 @@ teardown:
- do:
get:
index: .security
type: doc
id: user-bob
- set: { _source.password: "hash" }