Merge remote-tracking branch 'upstream/master'

Original commit: elastic/x-pack-elasticsearch@24d927e455
This commit is contained in:
lcawley 2018-01-12 11:59:50 -08:00
commit adde96f54a
26 changed files with 532 additions and 801 deletions

View File

@ -207,7 +207,6 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@ -755,18 +754,12 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus
} }
final boolean indexAuditingEnabled = Security.indexAuditLoggingEnabled(settings); final boolean indexAuditingEnabled = Security.indexAuditLoggingEnabled(settings);
final String auditIndex;
if (indexAuditingEnabled) { if (indexAuditingEnabled) {
auditIndex = "," + IndexAuditTrail.INDEX_NAME_PREFIX + "*"; String auditIndex = IndexAuditTrail.INDEX_NAME_PREFIX + "*";
} else {
auditIndex = "";
}
String securityIndices = SecurityLifecycleService.indexNames().stream()
.collect(Collectors.joining(","));
String errorMessage = LoggerMessageFormat.format( String errorMessage = LoggerMessageFormat.format(
"the [action.auto_create_index] setting value [{}] is too" + "the [action.auto_create_index] setting value [{}] is too" +
" restrictive. disable [action.auto_create_index] or set it to " + " restrictive. disable [action.auto_create_index] or set it to include " +
"[{}{}]", (Object) value, securityIndices, auditIndex); "[{}]", (Object) value, auditIndex);
if (Booleans.isFalse(value)) { if (Booleans.isFalse(value)) {
throw new IllegalArgumentException(errorMessage); throw new IllegalArgumentException(errorMessage);
} }
@ -776,8 +769,7 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus
} }
String[] matches = Strings.commaDelimitedListToStringArray(value); String[] matches = Strings.commaDelimitedListToStringArray(value);
List<String> indices = new ArrayList<>(SecurityLifecycleService.indexNames()); List<String> indices = new ArrayList<>();
if (indexAuditingEnabled) {
DateTime now = new DateTime(DateTimeZone.UTC); DateTime now = new DateTime(DateTimeZone.UTC);
// just use daily rollover // just use daily rollover
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY)); indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY));
@ -788,7 +780,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(4), IndexNameResolver.Rollover.DAILY)); indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(4), IndexNameResolver.Rollover.DAILY));
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(5), IndexNameResolver.Rollover.DAILY)); indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(5), IndexNameResolver.Rollover.DAILY));
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(6), IndexNameResolver.Rollover.DAILY)); indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(6), IndexNameResolver.Rollover.DAILY));
}
for (String index : indices) { for (String index : indices) {
boolean matched = false; boolean matched = false;
@ -815,7 +806,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus
} }
} }
if (indexAuditingEnabled) {
logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. " + logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. " +
" for the next 6 months audit indices are allowed to be created, but please make sure" + " for the next 6 months audit indices are allowed to be created, but please make sure" +
" that any future history indices after 6 months with the pattern " + " that any future history indices after 6 months with the pattern " +
@ -904,17 +894,8 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin, Clus
public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDataUpgrader() { public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDataUpgrader() {
return templates -> { return templates -> {
final byte[] securityTemplate = TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json", templates.remove(SECURITY_TEMPLATE_NAME);
Version.CURRENT.toString(), IndexLifecycleManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);
final XContent xContent = XContentFactory.xContent(XContentType.JSON); final XContent xContent = XContentFactory.xContent(XContentType.JSON);
try (XContentParser parser = xContent.createParser(NamedXContentRegistry.EMPTY, securityTemplate)) {
templates.put(SECURITY_TEMPLATE_NAME, IndexTemplateMetaData.Builder.fromXContent(parser, SECURITY_TEMPLATE_NAME));
} catch (IOException e) {
// TODO: should we handle this with a thrown exception?
logger.error("Error loading template [{}] as part of metadata upgrading", SECURITY_TEMPLATE_NAME);
}
final byte[] auditTemplate = TemplateUtils.loadTemplate("/" + IndexAuditTrail.INDEX_TEMPLATE_NAME + ".json", final byte[] auditTemplate = TemplateUtils.loadTemplate("/" + IndexAuditTrail.INDEX_TEMPLATE_NAME + ".json",
Version.CURRENT.toString(), IndexLifecycleManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); Version.CURRENT.toString(), IndexLifecycleManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8);

View File

@ -7,7 +7,6 @@ package org.elasticsearch.xpack.security;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
@ -28,6 +27,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@ -64,7 +64,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
this.settings = settings; this.settings = settings;
this.threadPool = threadPool; this.threadPool = threadPool;
this.indexAuditTrail = indexAuditTrail; this.indexAuditTrail = indexAuditTrail;
this.securityIndex = new IndexLifecycleManager(settings, client, SECURITY_INDEX_NAME, SECURITY_TEMPLATE_NAME); this.securityIndex = new IndexLifecycleManager(settings, client, SECURITY_INDEX_NAME);
clusterService.addListener(this); clusterService.addListener(this);
clusterService.addLifecycleListener(new LifecycleListener() { clusterService.addLifecycleListener(new LifecycleListener() {
@Override @Override
@ -114,20 +114,34 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
return securityIndex; return securityIndex;
} }
/**
* Returns {@code true} if the security index exists
*/
public boolean isSecurityIndexExisting() { public boolean isSecurityIndexExisting() {
return securityIndex.indexExists(); return securityIndex.indexExists();
} }
/**
* Returns <code>true</code> if the security index does not exist or it exists and has the current
* value for the <code>index.format</code> index setting
*/
public boolean isSecurityIndexUpToDate() { public boolean isSecurityIndexUpToDate() {
return securityIndex.isIndexUpToDate(); return securityIndex.isIndexUpToDate();
} }
/**
* Returns <code>true</code> if the security index exists and all primary shards are active
*/
public boolean isSecurityIndexAvailable() { public boolean isSecurityIndexAvailable() {
return securityIndex.isAvailable(); return securityIndex.isAvailable();
} }
public boolean isSecurityIndexWriteable() { /**
return securityIndex.isWritable(); * Returns <code>true</code> if the security index does not exist or the mappings are up to date
* based on the version in the <code>_meta</code> field
*/
public boolean isSecurityIndexMappingUpToDate() {
return securityIndex().isMappingUpToDate();
} }
/** /**
@ -170,22 +184,16 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
} }
} }
public static boolean securityIndexMappingAndTemplateSufficientToRead(ClusterState clusterState, public static boolean securityIndexMappingSufficientToRead(ClusterState clusterState, Logger logger) {
Logger logger) { return checkMappingVersions(clusterState, logger, MIN_READ_VERSION::onOrBefore);
return checkTemplateAndMappingVersions(clusterState, logger, MIN_READ_VERSION::onOrBefore);
} }
public static boolean securityIndexMappingAndTemplateUpToDate(ClusterState clusterState, static boolean securityIndexMappingUpToDate(ClusterState clusterState, Logger logger) {
Logger logger) { return checkMappingVersions(clusterState, logger, Version.CURRENT::equals);
return checkTemplateAndMappingVersions(clusterState, logger, Version.CURRENT::equals);
} }
private static boolean checkTemplateAndMappingVersions(ClusterState clusterState, Logger logger, private static boolean checkMappingVersions(ClusterState clusterState, Logger logger, Predicate<Version> versionPredicate) {
Predicate<Version> versionPredicate) { return IndexLifecycleManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, versionPredicate);
return IndexLifecycleManager.checkTemplateExistsAndVersionMatches(SECURITY_TEMPLATE_NAME,
clusterState, logger, versionPredicate) &&
IndexLifecycleManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME,
clusterState, logger, versionPredicate);
} }
public static List<String> indexNames() { public static List<String> indexNames() {
@ -193,17 +201,11 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
} }
/** /**
* Creates the security index, if it does not already exist, then runs the given * Prepares the security index by creating it if it doesn't exist or updating the mappings if the mappings are
* action on the security index. * out of date. After any tasks have been executed, the runnable is then executed.
*/ */
public <T> void createIndexIfNeededThenExecute(final ActionListener<T> listener, final Runnable andThen) { public void prepareIndexIfNeededThenExecute(final Consumer<Exception> consumer, final Runnable andThen) {
if (!isSecurityIndexExisting() || isSecurityIndexUpToDate()) { securityIndex.prepareIndexIfNeededThenExecute(consumer, andThen);
securityIndex.createIndexIfNeededThenExecute(listener, andThen);
} else {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
}
} }
/** /**

View File

@ -271,14 +271,7 @@ public final class TokenService extends AbstractComponent {
*/ */
public void invalidateToken(String tokenString, ActionListener<Boolean> listener) { public void invalidateToken(String tokenString, ActionListener<Boolean> listener) {
ensureEnabled(); ensureEnabled();
if (lifecycleService.isSecurityIndexOutOfDate()) { if (Strings.isNullOrEmpty(tokenString)) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (lifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("cannot write to the tokens index"));
} else if (Strings.isNullOrEmpty(tokenString)) {
listener.onFailure(new IllegalArgumentException("token must be provided")); listener.onFailure(new IllegalArgumentException("token must be provided"));
} else { } else {
maybeStartTokenRemover(); maybeStartTokenRemover();
@ -291,7 +284,7 @@ public final class TokenService extends AbstractComponent {
listener.onResponse(false); listener.onResponse(false);
} else { } else {
final String id = getDocumentId(userToken); final String id = getDocumentId(userToken);
lifecycleService.createIndexIfNeededThenExecute(listener, () -> { lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, id) client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, id)
.setOpType(OpType.CREATE) .setOpType(OpType.CREATE)
@ -338,13 +331,11 @@ public final class TokenService extends AbstractComponent {
* have been explicitly cleared. * have been explicitly cleared.
*/ */
private void checkIfTokenIsRevoked(UserToken userToken, ActionListener<UserToken> listener) { private void checkIfTokenIsRevoked(UserToken userToken, ActionListener<UserToken> listener) {
if (lifecycleService.isSecurityIndexAvailable()) { if (lifecycleService.isSecurityIndexExisting() == false) {
if (lifecycleService.isSecurityIndexOutOfDate()) { // index doesn't exist so the token is considered valid.
listener.onFailure(new IllegalStateException( listener.onResponse(userToken);
"Security index is not on the current version - the native realm will not be operational until " + } else {
"the upgrade API is run on the security index")); lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, getDocumentId(userToken)).request(), client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, getDocumentId(userToken)).request(),
new ActionListener<GetResponse>() { new ActionListener<GetResponse>() {
@ -371,14 +362,7 @@ public final class TokenService extends AbstractComponent {
listener.onFailure(e); listener.onFailure(e);
} }
} }
}, client::get); }, client::get));
} else if (lifecycleService.isSecurityIndexExisting()) {
// index exists but the index isn't available, do not trust the token
logger.warn("could not validate token as the security index is not available");
listener.onResponse(null);
} else {
// index doesn't exist so the token is considered valid.
listener.onResponse(userToken);
} }
} }

View File

@ -17,6 +17,7 @@ import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.ContextPreservingActionListener; import org.elasticsearch.action.support.ContextPreservingActionListener;
import org.elasticsearch.action.support.TransportActions;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy; import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
@ -113,19 +114,17 @@ public class NativeUsersStore extends AbstractComponent {
listener.onFailure(t); listener.onFailure(t);
} }
}; };
if (userNames.length == 1) { // optimization for single user lookup
if (securityLifecycleService.isSecurityIndexExisting() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
listener.onResponse(Collections.emptyList());
} else if (userNames.length == 1) { // optimization for single user lookup
final String username = userNames[0]; final String username = userNames[0];
getUserAndPassword(username, ActionListener.wrap( getUserAndPassword(username, ActionListener.wrap(
(uap) -> listener.onResponse(uap == null ? Collections.emptyList() : Collections.singletonList(uap.user())), (uap) -> listener.onResponse(uap == null ? Collections.emptyList() : Collections.singletonList(uap.user())),
handleException::accept)); handleException));
} else { } else {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational " +
"until the upgrade API is run on the security index"));
return;
}
try {
final QueryBuilder query; final QueryBuilder query;
if (userNames == null || userNames.length == 0) { if (userNames == null || userNames.length == 0) {
query = QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE); query = QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE);
@ -148,10 +147,7 @@ public class NativeUsersStore extends AbstractComponent {
return u != null ? u.user() : null; return u != null ? u.user() : null;
}); });
} }
} catch (Exception e) { });
logger.error(new ParameterizedMessage("unable to retrieve users {}", Arrays.toString(userNames)), e);
listener.onFailure(e);
}
} }
} }
@ -159,13 +155,11 @@ public class NativeUsersStore extends AbstractComponent {
* Async method to retrieve a user and their password * Async method to retrieve a user and their password
*/ */
private void getUserAndPassword(final String user, final ActionListener<UserAndPassword> listener) { private void getUserAndPassword(final String user, final ActionListener<UserAndPassword> listener) {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { if (securityLifecycleService.isSecurityIndexExisting() == false) {
listener.onFailure(new IllegalStateException( // TODO remove this short circuiting and fix tests that fail without this!
"Security index is not on the current version - the native realm will not be operational until " + listener.onResponse(null);
"the upgrade API is run on the security index")); } else {
return; securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
}
try {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, user)).request(), INDEX_TYPE, getIdForUser(USER_DOC_TYPE, user)).request(),
@ -188,14 +182,7 @@ public class NativeUsersStore extends AbstractComponent {
// we call the response with a null user // we call the response with a null user
listener.onResponse(null); listener.onResponse(null);
} }
}, client::get); }, client::get));
} catch (IndexNotFoundException infe) {
logger.trace((org.apache.logging.log4j.util.Supplier<?>)
() -> new ParameterizedMessage("could not retrieve user [{}] because security index does not exist", user));
listener.onResponse(null);
} catch (Exception e) {
logger.error(new ParameterizedMessage("unable to retrieve user [{}]", user), e);
listener.onFailure(e);
} }
} }
@ -208,18 +195,7 @@ public class NativeUsersStore extends AbstractComponent {
assert SystemUser.NAME.equals(username) == false && XPackUser.NAME.equals(username) == false : username + "is internal!"; assert SystemUser.NAME.equals(username) == false && XPackUser.NAME.equals(username) == false : username + "is internal!";
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node")); listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node"));
return; } else {
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("password cannot be changed as user service cannot write until template and " +
"mappings are up to date"));
return;
}
final String docType; final String docType;
if (ClientReservedRealm.isReserved(username, settings)) { if (ClientReservedRealm.isReserved(username, settings)) {
docType = RESERVED_USER_TYPE; docType = RESERVED_USER_TYPE;
@ -227,10 +203,11 @@ public class NativeUsersStore extends AbstractComponent {
docType = USER_DOC_TYPE; docType = USER_DOC_TYPE;
} }
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(docType, username)) client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(docType, username))
.setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(), String.valueOf(request.passwordHash())) .setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(),
String.valueOf(request.passwordHash()))
.setRefreshPolicy(request.getRefreshPolicy()).request(), .setRefreshPolicy(request.getRefreshPolicy()).request(),
new ActionListener<UpdateResponse>() { new ActionListener<UpdateResponse>() {
@Override @Override
@ -258,19 +235,14 @@ public class NativeUsersStore extends AbstractComponent {
}, client::update); }, client::update);
}); });
} }
}
/** /**
* Asynchronous method to create a reserved user with the given password hash. The cache for the user will be cleared after the document * Asynchronous method to create a reserved user with the given password hash. The cache for the user will be cleared after the document
* has been indexed * has been indexed
*/ */
private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) { private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener<Void> listener) {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username)) getIdForUser(RESERVED_USER_TYPE, username))
@ -301,28 +273,11 @@ public class NativeUsersStore extends AbstractComponent {
public void putUser(final PutUserRequest request, final ActionListener<Boolean> listener) { public void putUser(final PutUserRequest request, final ActionListener<Boolean> listener) {
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node")); listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node"));
return; } else if (request.passwordHash() == null) {
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("user cannot be created or changed as the user service cannot write until " +
"template and mappings are up to date"));
return;
}
try {
if (request.passwordHash() == null) {
updateUserWithoutPassword(request, listener); updateUserWithoutPassword(request, listener);
} else { } else {
indexUser(request, listener); indexUser(request, listener);
} }
} catch (Exception e) {
logger.error(new ParameterizedMessage("unable to put user [{}]", request.username()), e);
listener.onFailure(e);
}
} }
/** /**
@ -330,9 +285,8 @@ public class NativeUsersStore extends AbstractComponent {
*/ */
private void updateUserWithoutPassword(final PutUserRequest putUserRequest, final ActionListener<Boolean> listener) { private void updateUserWithoutPassword(final PutUserRequest putUserRequest, final ActionListener<Boolean> listener) {
assert putUserRequest.passwordHash() == null; assert putUserRequest.passwordHash() == null;
assert !securityLifecycleService.isSecurityIndexOutOfDate() : "security index should be up to date";
// We must have an existing document // We must have an existing document
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, putUserRequest.username())) getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
@ -375,8 +329,7 @@ public class NativeUsersStore extends AbstractComponent {
private void indexUser(final PutUserRequest putUserRequest, final ActionListener<Boolean> listener) { private void indexUser(final PutUserRequest putUserRequest, final ActionListener<Boolean> listener) {
assert putUserRequest.passwordHash() != null; assert putUserRequest.passwordHash() != null;
assert !securityLifecycleService.isSecurityIndexOutOfDate() : "security index should be up to date"; securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, client.prepareIndex(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, putUserRequest.username())) getIdForUser(USER_DOC_TYPE, putUserRequest.username()))
@ -413,19 +366,7 @@ public class NativeUsersStore extends AbstractComponent {
final ActionListener<Void> listener) { final ActionListener<Void> listener) {
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node")); listener.onFailure(new UnsupportedOperationException("users may not be created or modified using a tribe node"));
return; } else if (ClientReservedRealm.isReserved(username, settings)) {
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("enabled status cannot be changed as user service cannot write until template " +
"and mappings are up to date"));
return;
}
if (ClientReservedRealm.isReserved(username, settings)) {
setReservedUserEnabled(username, enabled, refreshPolicy, true, listener); setReservedUserEnabled(username, enabled, refreshPolicy, true, listener);
} else { } else {
setRegularUserEnabled(username, enabled, refreshPolicy, listener); setRegularUserEnabled(username, enabled, refreshPolicy, listener);
@ -434,9 +375,7 @@ public class NativeUsersStore extends AbstractComponent {
private void setRegularUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy, private void setRegularUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy,
final ActionListener<Void> listener) { final ActionListener<Void> listener) {
assert !securityLifecycleService.isSecurityIndexOutOfDate() : "security index should be up to date"; securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
try {
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(USER_DOC_TYPE, username)) getIdForUser(USER_DOC_TYPE, username))
@ -467,16 +406,11 @@ public class NativeUsersStore extends AbstractComponent {
} }
}, client::update); }, client::update);
}); });
} catch (Exception e) {
listener.onFailure(e);
}
} }
private void setReservedUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy, private void setReservedUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy,
boolean clearCache, final ActionListener<Void> listener) { boolean clearCache, final ActionListener<Void> listener) {
assert !securityLifecycleService.isSecurityIndexOutOfDate() : "security index should be up to date"; securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
try {
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, client.prepareUpdate(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username)) getIdForUser(RESERVED_USER_TYPE, username))
@ -503,32 +437,18 @@ public class NativeUsersStore extends AbstractComponent {
} }
}, client::update); }, client::update);
}); });
} catch (Exception e) {
listener.onFailure(e);
}
} }
public void deleteUser(final DeleteUserRequest deleteUserRequest, final ActionListener<Boolean> listener) { public void deleteUser(final DeleteUserRequest deleteUserRequest, final ActionListener<Boolean> listener) {
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("users may not be deleted using a tribe node")); listener.onFailure(new UnsupportedOperationException("users may not be deleted using a tribe node"));
return; } else {
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("user cannot be deleted as user service cannot write until template and " +
"mappings are up to date"));
return;
}
try {
DeleteRequest request = client.prepareDelete(SecurityLifecycleService.SECURITY_INDEX_NAME, DeleteRequest request = client.prepareDelete(SecurityLifecycleService.SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username())).request(); INDEX_TYPE, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username())).request();
request.indicesOptions().ignoreUnavailable();
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy()); request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request, new ActionListener<DeleteResponse>() { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<DeleteResponse>() {
@Override @Override
public void onResponse(DeleteResponse deleteResponse) { public void onResponse(DeleteResponse deleteResponse) {
clearRealmCache(deleteUserRequest.username(), listener, clearRealmCache(deleteUserRequest.username(), listener,
@ -540,9 +460,7 @@ public class NativeUsersStore extends AbstractComponent {
listener.onFailure(e); listener.onFailure(e);
} }
}, client::delete); }, client::delete);
} catch (Exception e) { });
logger.error("unable to remove user", e);
listener.onFailure(e);
} }
} }
@ -565,18 +483,14 @@ public class NativeUsersStore extends AbstractComponent {
} }
void getReservedUserInfo(String username, ActionListener<ReservedUserInfo> listener) { void getReservedUserInfo(String username, ActionListener<ReservedUserInfo> listener) {
if (!securityLifecycleService.isSecurityIndexExisting()) { if (securityLifecycleService.isSecurityIndexExisting() == false) {
listener.onFailure(new IllegalStateException("Attempt to get reserved user info but the security index does not exist")); // TODO remove this short circuiting and fix tests that fail without this!
return; listener.onResponse(null);
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) { } else {
listener.onFailure(new IllegalStateException( securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
"Security index is not on the current version - the native realm not be operational until " +
"the upgrade API is run on the security index"));
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(RESERVED_USER_TYPE, username)) client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, INDEX_TYPE,
.request(), getIdForUser(RESERVED_USER_TYPE, username)).request(),
new ActionListener<GetResponse>() { new ActionListener<GetResponse>() {
@Override @Override
public void onResponse(GetResponse getResponse) { public void onResponse(GetResponse getResponse) {
@ -601,25 +515,19 @@ public class NativeUsersStore extends AbstractComponent {
@Override @Override
public void onFailure(Exception e) { public void onFailure(Exception e) {
if (e instanceof IndexNotFoundException) { if (TransportActions.isShardNotAvailableException(e)) {
logger.trace((org.apache.logging.log4j.util.Supplier<?>) () -> new ParameterizedMessage( logger.trace((org.apache.logging.log4j.util.Supplier<?>) () -> new ParameterizedMessage(
"could not retrieve built in user [{}] info since security index does not exist", username), e); "could not retrieve built in user [{}] info since security index unavailable", username),
listener.onResponse(null); e);
} else {
logger.error(new ParameterizedMessage("failed to retrieve built in user [{}] info", username), e);
listener.onFailure(null);
} }
listener.onFailure(e);
}
}, client::get));
} }
}, client::get);
} }
void getAllReservedUserInfo(ActionListener<Map<String, ReservedUserInfo>> listener) { void getAllReservedUserInfo(ActionListener<Map<String, ReservedUserInfo>> listener) {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SecurityLifecycleService.SECURITY_INDEX_NAME) client.prepareSearch(SecurityLifecycleService.SECURITY_INDEX_NAME)
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)) .setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE))
@ -661,7 +569,7 @@ public class NativeUsersStore extends AbstractComponent {
listener.onFailure(e); listener.onFailure(e);
} }
} }
}, client::search); }, client::search));
} }
private <Response> void clearRealmCache(String username, ActionListener<Response> listener, Response response) { private <Response> void clearRealmCache(String username, ActionListener<Response> listener, Response response) {

View File

@ -167,8 +167,6 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol
listener.onFailure(new IllegalStateException( listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " + "Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index")); "the upgrade API is run on the security index"));
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("role-mappings cannot be modified until template and mappings are up to date"));
} else { } else {
try { try {
inner.accept(request, ActionListener.wrap(r -> refreshRealms(listener, r), listener::onFailure)); inner.accept(request, ActionListener.wrap(r -> refreshRealms(listener, r), listener::onFailure));
@ -181,7 +179,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol
private void innerPutMapping(PutRoleMappingRequest request, ActionListener<Boolean> listener) { private void innerPutMapping(PutRoleMappingRequest request, ActionListener<Boolean> listener) {
final ExpressionRoleMapping mapping = request.getMapping(); final ExpressionRoleMapping mapping = request.getMapping();
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
final XContentBuilder xContentBuilder; final XContentBuilder xContentBuilder;
try { try {
xContentBuilder = mapping.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true); xContentBuilder = mapping.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true);
@ -270,11 +268,11 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol
} else { } else {
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: {}] [writable: {}]", logger.debug("Security Index [{}] [exists: {}] [available: {}] [mapping up to date: {}]",
SECURITY_INDEX_NAME, SECURITY_INDEX_NAME,
securityLifecycleService.isSecurityIndexExisting(), securityLifecycleService.isSecurityIndexExisting(),
securityLifecycleService.isSecurityIndexAvailable(), securityLifecycleService.isSecurityIndexAvailable(),
securityLifecycleService.isSecurityIndexWriteable() securityLifecycleService.isSecurityIndexMappingUpToDate()
); );
} }
listener.onResponse(Collections.emptyList()); listener.onResponse(Collections.emptyList());

View File

@ -31,8 +31,6 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.LicenseUtils;
@ -105,16 +103,15 @@ public class NativeRolesStore extends AbstractComponent {
* Retrieve a list of roles, if rolesToGet is null or empty, fetch all roles * Retrieve a list of roles, if rolesToGet is null or empty, fetch all roles
*/ */
public void getRoleDescriptors(String[] names, final ActionListener<Collection<RoleDescriptor>> listener) { public void getRoleDescriptors(String[] names, final ActionListener<Collection<RoleDescriptor>> listener) {
if (names != null && names.length == 1) { if (securityLifecycleService.isSecurityIndexExisting() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
listener.onResponse(Collections.emptyList());
} else if (names != null && names.length == 1) {
getRoleDescriptor(Objects.requireNonNull(names[0]), ActionListener.wrap(roleDescriptor -> getRoleDescriptor(Objects.requireNonNull(names[0]), ActionListener.wrap(roleDescriptor ->
listener.onResponse(roleDescriptor == null ? Collections.emptyList() : Collections.singletonList(roleDescriptor)), listener.onResponse(roleDescriptor == null ? Collections.emptyList() : Collections.singletonList(roleDescriptor)),
listener::onFailure)); listener::onFailure));
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
} else { } else {
try { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
QueryBuilder query; QueryBuilder query;
if (names == null || names.length == 0) { if (names == null || names.length == 0) {
query = QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE); query = QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE);
@ -134,29 +131,15 @@ public class NativeRolesStore extends AbstractComponent {
ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener), ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener),
(hit) -> transformRole(hit.getId(), hit.getSourceRef(), logger, licenseState)); (hit) -> transformRole(hit.getId(), hit.getSourceRef(), logger, licenseState));
} }
} catch (Exception e) { });
logger.error(new ParameterizedMessage("unable to retrieve roles {}", Arrays.toString(names)), e);
listener.onFailure(e);
}
} }
} }
public void deleteRole(final DeleteRoleRequest deleteRoleRequest, final ActionListener<Boolean> listener) { public void deleteRole(final DeleteRoleRequest deleteRoleRequest, final ActionListener<Boolean> listener) {
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("roles may not be deleted using a tribe node")); listener.onFailure(new UnsupportedOperationException("roles may not be deleted using a tribe node"));
return; } else {
} else if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("role cannot be deleted as service cannot write until template and " +
"mappings are up to date"));
return;
}
try {
DeleteRequest request = client.prepareDelete(SecurityLifecycleService.SECURITY_INDEX_NAME, DeleteRequest request = client.prepareDelete(SecurityLifecycleService.SECURITY_INDEX_NAME,
ROLE_DOC_TYPE, getIdForUser(deleteRoleRequest.name())).request(); ROLE_DOC_TYPE, getIdForUser(deleteRoleRequest.name())).request();
request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy()); request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy());
@ -174,21 +157,13 @@ public class NativeRolesStore extends AbstractComponent {
listener.onFailure(e); listener.onFailure(e);
} }
}, client::delete); }, client::delete);
} catch (IndexNotFoundException e) { });
logger.trace("security index does not exist", e);
listener.onResponse(false);
} catch (Exception e) {
logger.error("unable to remove role", e);
listener.onFailure(e);
} }
} }
public void putRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) { public void putRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
if (isTribeNode) { if (isTribeNode) {
listener.onFailure(new UnsupportedOperationException("roles may not be created or modified using a tribe node")); listener.onFailure(new UnsupportedOperationException("roles may not be created or modified using a tribe node"));
} else if (securityLifecycleService.isSecurityIndexWriteable() == false) {
listener.onFailure(new IllegalStateException("role cannot be created or modified as service cannot write until template and " +
"mappings are up to date"));
} else if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) { } else if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
innerPutRole(request, role, listener); innerPutRole(request, role, listener);
} else if (role.isUsingDocumentOrFieldLevelSecurity()) { } else if (role.isUsingDocumentOrFieldLevelSecurity()) {
@ -200,14 +175,7 @@ public class NativeRolesStore extends AbstractComponent {
// pkg-private for testing // pkg-private for testing
void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) { void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
try {
securityLifecycleService.createIndexIfNeededThenExecute(listener, () -> {
final XContentBuilder xContentBuilder; final XContentBuilder xContentBuilder;
try { try {
xContentBuilder = role.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true); xContentBuilder = role.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true);
@ -234,10 +202,6 @@ public class NativeRolesStore extends AbstractComponent {
} }
}, client::index); }, client::index);
}); });
} catch (Exception e) {
logger.error(new ParameterizedMessage("unable to put role [{}]", request.name()), e);
listener.onFailure(e);
}
} }
public void usageStats(ActionListener<Map<String, Object>> listener) { public void usageStats(ActionListener<Map<String, Object>> listener) {
@ -248,12 +212,7 @@ public class NativeRolesStore extends AbstractComponent {
usageStats.put("dls", false); usageStats.put("dls", false);
listener.onResponse(usageStats); listener.onResponse(usageStats);
} else { } else {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareMultiSearch() client.prepareMultiSearch()
.add(client.prepareSearch(SecurityLifecycleService.SECURITY_INDEX_NAME) .add(client.prepareSearch(SecurityLifecycleService.SECURITY_INDEX_NAME)
@ -304,14 +263,16 @@ public class NativeRolesStore extends AbstractComponent {
public void onFailure(Exception e) { public void onFailure(Exception e) {
listener.onFailure(e); listener.onFailure(e);
} }
}, client::multiSearch); }, client::multiSearch));
} }
} }
private void getRoleDescriptor(final String roleId, ActionListener<RoleDescriptor> roleActionListener) { private void getRoleDescriptor(final String roleId, ActionListener<RoleDescriptor> roleActionListener) {
if (securityLifecycleService.isSecurityIndexExisting() == false) { if (securityLifecycleService.isSecurityIndexExisting() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
roleActionListener.onResponse(null); roleActionListener.onResponse(null);
} else { } else {
securityLifecycleService.prepareIndexIfNeededThenExecute(roleActionListener::onFailure, () ->
executeGetRoleRequest(roleId, new ActionListener<GetResponse>() { executeGetRoleRequest(roleId, new ActionListener<GetResponse>() {
@Override @Override
public void onResponse(GetResponse response) { public void onResponse(GetResponse response) {
@ -331,35 +292,17 @@ public class NativeRolesStore extends AbstractComponent {
roleActionListener.onFailure(e); roleActionListener.onFailure(e);
} }
} }
}); }));
} }
} }
private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) { private void executeGetRoleRequest(String role, ActionListener<GetResponse> listener) {
if (securityLifecycleService.isSecurityIndexOutOfDate()) { securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
try {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME,
ROLE_DOC_TYPE, getIdForUser(role)).request(), ROLE_DOC_TYPE, getIdForUser(role)).request(),
listener, listener,
client::get); client::get));
} catch (IndexNotFoundException e) {
logger.trace(
(org.apache.logging.log4j.util.Supplier<?>) () -> new ParameterizedMessage(
"unable to retrieve role [{}] since security index does not exist", role), e);
listener.onResponse(new GetResponse(
new GetResult(SecurityLifecycleService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE,
getIdForUser(role), -1, false, null, null)));
} catch (Exception e) {
logger.error("unable to retrieve role", e);
listener.onFailure(e);
}
} }
private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) { private <Response> void clearRoleCache(final String role, ActionListener<Response> listener, Response response) {

View File

@ -16,6 +16,10 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
@ -25,18 +29,22 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.xpack.template.TemplateUtils; import org.elasticsearch.xpack.template.TemplateUtils;
import org.elasticsearch.xpack.upgrade.IndexUpgradeCheck; import org.elasticsearch.xpack.upgrade.IndexUpgradeCheck;
import java.nio.charset.StandardCharsets;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -45,6 +53,7 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETT
import static org.elasticsearch.xpack.ClientHelper.SECURITY_ORIGIN; import static org.elasticsearch.xpack.ClientHelper.SECURITY_ORIGIN;
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin; import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_TEMPLATE_NAME;
/** /**
* Manages the lifecycle of a single index, its template, mapping and and data upgrades/migrations. * Manages the lifecycle of a single index, its template, mapping and and data upgrades/migrations.
@ -58,7 +67,6 @@ public class IndexLifecycleManager extends AbstractComponent {
Pattern.quote("${security.template.version}"); Pattern.quote("${security.template.version}");
private final String indexName; private final String indexName;
private final String templateName;
private final Client client; private final Client client;
private final List<BiConsumer<ClusterIndexHealth, ClusterIndexHealth>> indexHealthChangeListeners = new CopyOnWriteArrayList<>(); private final List<BiConsumer<ClusterIndexHealth, ClusterIndexHealth>> indexHealthChangeListeners = new CopyOnWriteArrayList<>();
@ -66,11 +74,10 @@ public class IndexLifecycleManager extends AbstractComponent {
private volatile State indexState = new State(false, false, false, false, null); private volatile State indexState = new State(false, false, false, false, null);
public IndexLifecycleManager(Settings settings, Client client, String indexName, String templateName) { public IndexLifecycleManager(Settings settings, Client client, String indexName) {
super(settings); super(settings);
this.client = client; this.client = client;
this.indexName = indexName; this.indexName = indexName;
this.templateName = templateName;
} }
public boolean checkMappingVersion(Predicate<Version> requiredVersion) { public boolean checkMappingVersion(Predicate<Version> requiredVersion) {
@ -95,8 +102,8 @@ public class IndexLifecycleManager extends AbstractComponent {
return this.indexState.indexAvailable; return this.indexState.indexAvailable;
} }
public boolean isWritable() { public boolean isMappingUpToDate() {
return this.indexState.canWriteToIndex; return this.indexState.mappingUpToDate;
} }
/** /**
@ -133,12 +140,9 @@ public class IndexLifecycleManager extends AbstractComponent {
final boolean isIndexUpToDate = indexExists == false || final boolean isIndexUpToDate = indexExists == false ||
INDEX_FORMAT_SETTING.get(securityIndex.getSettings()).intValue() == INTERNAL_INDEX_FORMAT; INDEX_FORMAT_SETTING.get(securityIndex.getSettings()).intValue() == INTERNAL_INDEX_FORMAT;
final boolean indexAvailable = checkIndexAvailable(clusterState); final boolean indexAvailable = checkIndexAvailable(clusterState);
final boolean templateIsUpToDate = TemplateUtils.checkTemplateExistsAndIsUpToDate(templateName, final boolean mappingIsUpToDate = indexExists == false || checkIndexMappingUpToDate(clusterState);
SECURITY_VERSION_STRING, clusterState, logger);
final boolean mappingIsUpToDate = checkIndexMappingUpToDate(clusterState);
final boolean canWriteToIndex = templateIsUpToDate && (mappingIsUpToDate || isIndexUpToDate);
final Version mappingVersion = oldestIndexMappingVersion(clusterState); final Version mappingVersion = oldestIndexMappingVersion(clusterState);
this.indexState = new State(indexExists, isIndexUpToDate, indexAvailable, canWriteToIndex, mappingVersion); this.indexState = new State(indexExists, isIndexUpToDate, indexAvailable, mappingIsUpToDate, mappingVersion);
} }
private void checkIndexHealthChange(ClusterChangedEvent event) { private void checkIndexHealthChange(ClusterChangedEvent event) {
@ -284,15 +288,23 @@ public class IndexLifecycleManager extends AbstractComponent {
} }
/** /**
* Creates the security index, if it does not already exist, then runs the given * Prepares the index by creating it if it doesn't exist or updating the mappings if the mappings are
* action on the security index. * out of date. After any tasks have been executed, the runnable is then executed.
*/ */
public <T> void createIndexIfNeededThenExecute(final ActionListener<T> listener, final Runnable andThen) { public void prepareIndexIfNeededThenExecute(final Consumer<Exception> consumer, final Runnable andThen) {
if (this.indexState.indexExists) { final State indexState = this.indexState; // use a local copy so all checks execute against the same state!
andThen.run(); // TODO we should improve this so we don't fire off a bunch of requests to do the same thing (create or update mappings)
} else { if (indexState.indexExists && indexState.isIndexUpToDate == false) {
CreateIndexRequest request = new CreateIndexRequest(INTERNAL_SECURITY_INDEX); consumer.accept(new IllegalStateException(
request.alias(new Alias(SECURITY_INDEX_NAME)); "Security index is not on the current version. Security features relying on the index will not be available until " +
"the upgrade API is run on the security index"));
} else if (indexState.indexExists == false) {
Tuple<String, Settings> mappingAndSettings = loadMappingAndSettingsSourceFromTemplate();
CreateIndexRequest request = new CreateIndexRequest(INTERNAL_SECURITY_INDEX)
.alias(new Alias(SECURITY_INDEX_NAME))
.mapping("doc", mappingAndSettings.v1(), XContentType.JSON)
.waitForActiveShards(ActiveShardCount.ALL)
.settings(mappingAndSettings.v2());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request, executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<CreateIndexResponse>() { new ActionListener<CreateIndexResponse>() {
@Override @Override
@ -300,7 +312,7 @@ public class IndexLifecycleManager extends AbstractComponent {
if (createIndexResponse.isAcknowledged()) { if (createIndexResponse.isAcknowledged()) {
andThen.run(); andThen.run();
} else { } else {
listener.onFailure(new ElasticsearchException("Failed to create security index")); consumer.accept(new ElasticsearchException("Failed to create security index"));
} }
} }
@ -312,13 +324,33 @@ public class IndexLifecycleManager extends AbstractComponent {
// node hasn't yet received the cluster state update with the index // node hasn't yet received the cluster state update with the index
andThen.run(); andThen.run();
} else { } else {
listener.onFailure(e); consumer.accept(e);
} }
} }
}, client.admin().indices()::create); }, client.admin().indices()::create);
} else if (indexState.mappingUpToDate == false) {
PutMappingRequest request = new PutMappingRequest(INTERNAL_SECURITY_INDEX)
.source(loadMappingAndSettingsSourceFromTemplate().v1(), XContentType.JSON)
.type("doc");
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
ActionListener.<PutMappingResponse>wrap(putMappingResponse -> {
if (putMappingResponse.isAcknowledged()) {
andThen.run();
} else {
consumer.accept(new IllegalStateException("put mapping request was not acknowledged"));
}
}, consumer), client.admin().indices()::putMapping);
} else {
andThen.run();
} }
} }
private Tuple<String, Settings> loadMappingAndSettingsSourceFromTemplate() {
final byte[] template = TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json",
Version.CURRENT.toString(), IndexLifecycleManager.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());
}
/** /**
* Holder class so we can update all values at once * Holder class so we can update all values at once
*/ */
@ -326,15 +358,15 @@ public class IndexLifecycleManager extends AbstractComponent {
private final boolean indexExists; private final boolean indexExists;
private final boolean isIndexUpToDate; private final boolean isIndexUpToDate;
private final boolean indexAvailable; private final boolean indexAvailable;
private final boolean canWriteToIndex; private final boolean mappingUpToDate;
private final Version mappingVersion; private final Version mappingVersion;
private State(boolean indexExists, boolean isIndexUpToDate, boolean indexAvailable, private State(boolean indexExists, boolean isIndexUpToDate, boolean indexAvailable,
boolean canWriteToIndex, Version mappingVersion) { boolean mappingUpToDate, Version mappingVersion) {
this.indexExists = indexExists; this.indexExists = indexExists;
this.isIndexUpToDate = isIndexUpToDate; this.isIndexUpToDate = isIndexUpToDate;
this.indexAvailable = indexAvailable; this.indexAvailable = indexAvailable;
this.canWriteToIndex = canWriteToIndex; this.mappingUpToDate = mappingUpToDate;
this.mappingVersion = mappingVersion; this.mappingVersion = mappingVersion;
} }
} }

View File

@ -37,6 +37,7 @@ import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.action.user.GetUsersResponse; import org.elasticsearch.xpack.security.action.user.GetUsersResponse;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.client.SecurityClient;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.util.ArrayList; import java.util.ArrayList;
@ -119,6 +120,11 @@ public class LicensingTests extends SecurityIntegTestCase {
enableLicensing(); enableLicensing();
} }
@After
public void cleanupSecurityIndex() {
deleteSecurityIndex();
}
public void testEnableDisableBehaviour() throws Exception { public void testEnableDisableBehaviour() throws Exception {
IndexResponse indexResponse = index("test", "type", jsonBuilder() IndexResponse indexResponse = index("test", "type", jsonBuilder()
.startObject() .startObject()

View File

@ -58,8 +58,7 @@ import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE
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.security.SecurityLifecycleService.SECURITY_INDEX_NAME; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.securityIndexMappingAndTemplateSufficientToRead; import static org.elasticsearch.xpack.security.SecurityLifecycleService.securityIndexMappingSufficientToRead;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.securityIndexMappingAndTemplateUpToDate;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
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;
@ -450,33 +449,9 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
ClusterState clusterState = client.admin().cluster().prepareState().setLocal(true).get().getState(); ClusterState clusterState = client.admin().cluster().prepareState().setLocal(true).get().getState();
assertFalse(clusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)); assertFalse(clusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK));
XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject(); XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject();
assertTrue("security index mapping and template not sufficient to read:\n" + assertTrue("security index mapping not sufficient to read:\n" +
clusterState.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject().string(), clusterState.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject().string(),
securityIndexMappingAndTemplateSufficientToRead(clusterState, logger)); securityIndexMappingSufficientToRead(clusterState, logger));
Index securityIndex = resolveSecurityIndex(clusterState.metaData());
if (securityIndex != null) {
IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(securityIndex);
if (indexRoutingTable != null) {
assertTrue(indexRoutingTable.allPrimaryShardsActive());
}
}
}, 30L, TimeUnit.SECONDS);
}
}
public void assertSecurityIndexWriteable() throws Exception {
assertSecurityIndexWriteable(cluster());
}
public void assertSecurityIndexWriteable(TestCluster testCluster) throws Exception {
for (Client client : testCluster.getClients()) {
assertBusy(() -> {
ClusterState clusterState = client.admin().cluster().prepareState().setLocal(true).get().getState();
assertFalse(clusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK));
XContentBuilder builder = JsonXContent.contentBuilder().prettyPrint().startObject();
assertTrue("security index mapping and template not up to date:\n" +
clusterState.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject().string(),
securityIndexMappingAndTemplateUpToDate(clusterState, logger));
Index securityIndex = resolveSecurityIndex(clusterState.metaData()); Index securityIndex = resolveSecurityIndex(clusterState.metaData());
if (securityIndex != null) { if (securityIndex != null) {
IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(securityIndex); IndexRoutingTable indexRoutingTable = clusterState.routingTable().index(securityIndex);

View File

@ -1,84 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.Version;
import org.elasticsearch.client.Response;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.ObjectPath;
import org.junit.Before;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_TEMPLATE_NAME;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
/**
* A base {@link ESClientYamlSuiteTestCase} test class for the security module,
* which depends on security template and mappings being up to date before any writes
* to the {@code .security} index can take place.
*/
public abstract class SecurityClusterClientYamlTestCase extends ESClientYamlSuiteTestCase {
public SecurityClusterClientYamlTestCase(ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@Before
public void waitForSecuritySetup() throws Exception {
waitForSecurity();
}
public static void waitForSecurity() throws Exception {
String masterNode = null;
HttpEntity entity = client().performRequest("GET", "/_cat/nodes?h=id,master").getEntity();
String catNodesResponse = EntityUtils.toString(entity, StandardCharsets.UTF_8);
for (String line : catNodesResponse.split("\n")) {
int indexOfStar = line.indexOf('*'); // * in the node's output denotes it is master
if (indexOfStar != -1) {
masterNode = line.substring(0, indexOfStar).trim();
break;
}
}
assertNotNull(masterNode);
final String masterNodeId = masterNode;
assertBusy(() -> {
try {
Response nodesResponse = client().performRequest("GET", "/_nodes");
ObjectPath nodesPath = ObjectPath.createFromResponse(nodesResponse);
Map<String, Object> nodes = nodesPath.evaluate("nodes");
Version masterVersion = null;
for (String nodeId : nodes.keySet()) {
// get the ES version number master is on
if (nodeId.startsWith(masterNodeId)) {
masterVersion = Version.fromString(nodesPath.evaluate("nodes." + nodeId + ".version"));
break;
}
}
assertNotNull(masterVersion);
Response response = client().performRequest("GET", "/_cluster/state/metadata");
ObjectPath objectPath = ObjectPath.createFromResponse(response);
String mappingsPath = "metadata.templates." + SECURITY_TEMPLATE_NAME + ".mappings";
Map<String, Object> mappings = objectPath.evaluate(mappingsPath);
assertNotNull(mappings);
assertThat(mappings.size(), greaterThanOrEqualTo(1));
for (String key : mappings.keySet()) {
String templatePath = mappingsPath + "." + key + "._meta.security-version";
Version templateVersion = Version.fromString(objectPath.evaluate(templatePath));
assertEquals(masterVersion, templateVersion);
}
} catch (Exception e) {
throw new AssertionError("failed to get cluster state", e);
}
});
}
}

View File

@ -44,7 +44,7 @@ import org.junit.Before;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_TEMPLATE_NAME; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_TEMPLATE_NAME;
import static org.elasticsearch.xpack.security.SecurityLifecycleService.securityIndexMappingAndTemplateUpToDate; import static org.elasticsearch.xpack.security.SecurityLifecycleService.securityIndexMappingUpToDate;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -135,7 +135,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase {
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,
() -> securityIndexMappingAndTemplateUpToDate(clusterState, logger)); () -> securityIndexMappingUpToDate(clusterState, logger));
assertEquals("Cannot read security-version string in index " + SECURITY_INDEX_NAME, assertEquals("Cannot read security-version string in index " + SECURITY_INDEX_NAME,
exception.getMessage()); exception.getMessage());
} }

View File

@ -141,34 +141,13 @@ public class SecuritySettingsTests extends ESTestCase {
public void testValidAutoCreateIndex() { public void testValidAutoCreateIndex() {
Security.validateAutoCreateIndex(Settings.EMPTY); Security.validateAutoCreateIndex(Settings.EMPTY);
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", true).build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", true).build());
try {
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(SecurityLifecycleService.SECURITY_INDEX_NAME));
assertThat(e.getMessage(), not(containsString(IndexAuditTrail.INDEX_NAME_PREFIX)));
}
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security,.security-6").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security,.security-6").build());
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security*").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security*").build());
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "*s*").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "*s*").build());
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".s*").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".s*").build());
try {
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "foo").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "foo").build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(SecurityLifecycleService.SECURITY_INDEX_NAME));
assertThat(e.getMessage(), not(containsString(IndexAuditTrail.INDEX_NAME_PREFIX)));
}
try {
Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security_audit_log*").build()); Security.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security_audit_log*").build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(SecurityLifecycleService.SECURITY_INDEX_NAME));
}
Security.validateAutoCreateIndex(Settings.builder() Security.validateAutoCreateIndex(Settings.builder()
.put("action.auto_create_index", ".security,.security-6") .put("action.auto_create_index", ".security,.security-6")
@ -183,7 +162,6 @@ public class SecuritySettingsTests extends ESTestCase {
.build()); .build());
fail("IllegalArgumentException expected"); fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(SecurityLifecycleService.SECURITY_INDEX_NAME));
assertThat(e.getMessage(), containsString(IndexAuditTrail.INDEX_NAME_PREFIX)); assertThat(e.getMessage(), containsString(IndexAuditTrail.INDEX_NAME_PREFIX));
} }

View File

@ -62,6 +62,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException; import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError; import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
@ -865,7 +866,7 @@ public class AuthenticationServiceTests extends ESTestCase {
User user = new User("_username", "r1"); User user = new User("_username", "r1");
final Authentication expected = new Authentication(user, new RealmRef("realm", "custom", "node"), null); final Authentication expected = new Authentication(user, new RealmRef("realm", "custom", "node"), null);
String token = tokenService.getUserTokenString(tokenService.createUserToken(expected)); String token = tokenService.getUserTokenString(tokenService.createUserToken(expected));
when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); when(lifecycleService.isSecurityIndexExisting()).thenReturn(true);
GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class); GetRequestBuilder getRequestBuilder = mock(GetRequestBuilder.class);
when(client.prepareGet(eq(SecurityLifecycleService.SECURITY_INDEX_NAME), eq("doc"), any(String.class))) when(client.prepareGet(eq(SecurityLifecycleService.SECURITY_INDEX_NAME), eq("doc"), any(String.class)))
.thenReturn(getRequestBuilder); .thenReturn(getRequestBuilder);
@ -877,6 +878,11 @@ public class AuthenticationServiceTests 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));
doAnswer(invocationOnMock -> {
((Runnable) invocationOnMock.getArguments()[1]).run();
return null;
}).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class));
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
threadContext.putHeader("Authorization", "Bearer " + token); threadContext.putHeader("Authorization", "Bearer " + token);
ElasticsearchSecurityException e = ElasticsearchSecurityException e =

View File

@ -204,7 +204,7 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
@Before @Before
public void waitForSecurityIndexWritable() throws Exception { public void waitForSecurityIndexWritable() throws Exception {
assertSecurityIndexWriteable(); assertSecurityIndexActive();
} }
@After @After

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.security.authc;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.NoShardAvailableActionException;
import org.elasticsearch.action.get.GetAction; import org.elasticsearch.action.get.GetAction;
import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetRequestBuilder; import org.elasticsearch.action.get.GetRequestBuilder;
@ -18,6 +19,8 @@ import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils; import org.elasticsearch.test.EqualsHashCodeTestUtils;
@ -38,10 +41,12 @@ import java.security.GeneralSecurityException;
import java.time.Clock; import java.time.Clock;
import java.util.Base64; import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import java.util.function.Consumer;
import static org.elasticsearch.repositories.ESBlobStoreTestCase.randomBytes; import static org.elasticsearch.repositories.ESBlobStoreTestCase.randomBytes;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -60,19 +65,22 @@ public class TokenServiceTests extends ESTestCase {
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
@Before @Before
public void setupClient() throws GeneralSecurityException { public void setupClient() {
client = mock(Client.class); client = mock(Client.class);
when(client.threadPool()).thenReturn(threadPool); when(client.threadPool()).thenReturn(threadPool);
when(client.settings()).thenReturn(settings); when(client.settings()).thenReturn(settings);
lifecycleService = mock(SecurityLifecycleService.class); lifecycleService = mock(SecurityLifecycleService.class);
when(lifecycleService.isSecurityIndexWriteable()).thenReturn(true);
doAnswer(invocationOnMock -> { doAnswer(invocationOnMock -> {
ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocationOnMock.getArguments()[2]; ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocationOnMock.getArguments()[2];
GetResponse response = mock(GetResponse.class); GetResponse response = mock(GetResponse.class);
when(response.isExists()).thenReturn(false); when(response.isExists()).thenReturn(false);
listener.onResponse(response); listener.onResponse(response);
return Void.TYPE; return Void.TYPE;
}).when(client).execute(eq(GetAction.INSTANCE), any(GetRequest.class), any(ActionListener.class)); }).when(client).get(any(GetRequest.class), any(ActionListener.class));
doAnswer(invocationOnMock -> {
((Runnable) invocationOnMock.getArguments()[1]).run();
return null;
}).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class));
when(client.threadPool()).thenReturn(threadPool); when(client.threadPool()).thenReturn(threadPool);
this.clusterService = new ClusterService(settings, new ClusterSettings(settings, ClusterSettings this.clusterService = new ClusterService(settings, new ClusterSettings(settings, ClusterSettings
.BUILT_IN_CLUSTER_SETTINGS), threadPool, Collections.emptyMap()); .BUILT_IN_CLUSTER_SETTINGS), threadPool, Collections.emptyMap());
@ -286,7 +294,7 @@ public class TokenServiceTests extends ESTestCase {
} }
public void testInvalidatedToken() throws Exception { public void testInvalidatedToken() throws Exception {
when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); when(lifecycleService.isSecurityIndexExisting()).thenReturn(true);
TokenService tokenService = TokenService tokenService =
new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, lifecycleService, clusterService); new TokenService(tokenServiceEnabledSettings, Clock.systemUTC(), client, lifecycleService, 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);
@ -438,6 +446,13 @@ public class TokenServiceTests extends ESTestCase {
ThreadContext requestContext = new ThreadContext(Settings.EMPTY); ThreadContext requestContext = new ThreadContext(Settings.EMPTY);
requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token)); requestContext.putHeader("Authorization", "Bearer " + tokenService.getUserTokenString(token));
doAnswer(invocationOnMock -> {
ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocationOnMock.getArguments()[1];
listener.onFailure(new NoShardAvailableActionException(new ShardId(new Index("foo", "uuid"), 0), "shard oh shard"));
return Void.TYPE;
}).when(client).get(any(GetRequest.class), any(ActionListener.class));
when(client.prepareGet(anyString(), anyString(), anyString())).thenReturn(new GetRequestBuilder(client, GetAction.INSTANCE));
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);

View File

@ -11,6 +11,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import org.elasticsearch.action.Action; import org.elasticsearch.action.Action;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
@ -231,20 +232,19 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(getResult)); actionRespond(GetRequest.class, new GetResponse(getResult));
} }
private NativeUsersStore startNativeUsersStore() { private NativeUsersStore startNativeUsersStore() {
SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class);
when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true);
when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true);
when(securityLifecycleService.isSecurityIndexWriteable()).thenReturn(true); when(securityLifecycleService.isSecurityIndexMappingUpToDate()).thenReturn(true);
when(securityLifecycleService.isSecurityIndexOutOfDate()).thenReturn(false); when(securityLifecycleService.isSecurityIndexOutOfDate()).thenReturn(false);
when(securityLifecycleService.isSecurityIndexUpToDate()).thenReturn(true); when(securityLifecycleService.isSecurityIndexUpToDate()).thenReturn(true);
doAnswer((i) -> { doAnswer((i) -> {
Runnable action = (Runnable) i.getArguments()[1]; Runnable action = (Runnable) i.getArguments()[1];
action.run(); action.run();
ActionListener listener = (ActionListener) i.getArguments()[0];
listener.onResponse(null);
return null; return null;
}).when(securityLifecycleService).createIndexIfNeededThenExecute(any(ActionListener.class), any(Runnable.class)); }).when(securityLifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class));
return new NativeUsersStore(Settings.EMPTY, client, securityLifecycleService); return new NativeUsersStore(Settings.EMPTY, client, securityLifecycleService);
} }

View File

@ -28,7 +28,7 @@ import static org.hamcrest.Matchers.instanceOf;
public class SecurityScrollTests extends SecurityIntegTestCase { public class SecurityScrollTests extends SecurityIntegTestCase {
public void testScrollIsPerUser() throws Exception { public void testScrollIsPerUser() throws Exception {
assertSecurityIndexWriteable(); assertSecurityIndexActive();
securityClient().preparePutRole("scrollable") securityClient().preparePutRole("scrollable")
.addIndices(new String[] { randomAlphaOfLengthBetween(4, 12) }, new String[] { "read" }, null, null, null) .addIndices(new String[] { randomAlphaOfLengthBetween(4, 12) }, new String[] { "read" }, null, null, null)
.get(); .get();

View File

@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class IndexLifecycleManagerIntegTests extends SecurityIntegTestCase { public class IndexLifecycleManagerIntegTests extends SecurityIntegTestCase {
public void testConcurrentOperationsTryingToCreateSecurityIndexAndAlias() throws Exception { public void testConcurrentOperationsTryingToCreateSecurityIndexAndAlias() throws Exception {
assertSecurityIndexWriteable(); assertSecurityIndexActive();
final int processors = Runtime.getRuntime().availableProcessors(); final int processors = Runtime.getRuntime().availableProcessors();
final int numThreads = scaledRandomIntBetween((processors + 1) / 2, 4 * processors); final int numThreads = scaledRandomIntBetween((processors + 1) / 2, 4 * processors);
final int maxNumRequests = 100 / numThreads; // bound to a maximum of 100 requests final int maxNumRequests = 100 / numThreads; // bound to a maximum of 100 requests

View File

@ -86,7 +86,7 @@ public class IndexLifecycleManagerTests extends ESTestCase {
actions.put(action, map); actions.put(action, map);
} }
}; };
manager = new IndexLifecycleManager(Settings.EMPTY, client, INDEX_NAME, TEMPLATE_NAME); manager = new IndexLifecycleManager(Settings.EMPTY, client, INDEX_NAME);
} }
public void testIndexWithUpToDateMappingAndTemplate() throws IOException { public void testIndexWithUpToDateMappingAndTemplate() throws IOException {
@ -98,7 +98,7 @@ public class IndexLifecycleManagerTests extends ESTestCase {
assertThat(manager.indexExists(), Matchers.equalTo(true)); assertThat(manager.indexExists(), Matchers.equalTo(true));
assertThat(manager.isAvailable(), Matchers.equalTo(true)); assertThat(manager.isAvailable(), Matchers.equalTo(true));
assertThat(manager.isWritable(), Matchers.equalTo(true)); assertThat(manager.isMappingUpToDate(), Matchers.equalTo(true));
} }
public void testIndexWithoutPrimaryShards() throws IOException { public void testIndexWithoutPrimaryShards() throws IOException {
@ -245,13 +245,13 @@ public class IndexLifecycleManagerTests extends ESTestCase {
private void assertInitialState() { private void assertInitialState() {
assertThat(manager.indexExists(), Matchers.equalTo(false)); assertThat(manager.indexExists(), Matchers.equalTo(false));
assertThat(manager.isAvailable(), Matchers.equalTo(false)); assertThat(manager.isAvailable(), Matchers.equalTo(false));
assertThat(manager.isWritable(), Matchers.equalTo(false)); assertThat(manager.isMappingUpToDate(), Matchers.equalTo(false));
} }
private void assertIndexUpToDateButNotAvailable() { private void assertIndexUpToDateButNotAvailable() {
assertThat(manager.indexExists(), Matchers.equalTo(true)); assertThat(manager.indexExists(), Matchers.equalTo(true));
assertThat(manager.isAvailable(), Matchers.equalTo(false)); assertThat(manager.isAvailable(), Matchers.equalTo(false));
assertThat(manager.isWritable(), Matchers.equalTo(true)); assertThat(manager.isMappingUpToDate(), Matchers.equalTo(true));
} }
public static ClusterState.Builder createClusterState(String indexName, String templateName) throws IOException { public static ClusterState.Builder createClusterState(String indexName, String templateName) throws IOException {

View File

@ -21,7 +21,6 @@ import org.elasticsearch.xpack.ml.MlMetaIndex;
import org.elasticsearch.xpack.ml.integration.MlRestTestStateCleaner; import org.elasticsearch.xpack.ml.integration.MlRestTestStateCleaner;
import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex; import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex;
import org.elasticsearch.xpack.ml.notifications.Auditor; import org.elasticsearch.xpack.ml.notifications.Auditor;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry; import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -81,7 +80,6 @@ public class XPackRestIT extends ESClientYamlSuiteTestCase {
private void waitForTemplates() throws Exception { private void waitForTemplates() throws Exception {
if (installTemplates()) { if (installTemplates()) {
List<String> templates = new ArrayList<>(); List<String> templates = new ArrayList<>();
templates.add(SecurityLifecycleService.SECURITY_TEMPLATE_NAME);
templates.addAll(Arrays.asList(Auditor.NOTIFICATIONS_INDEX, MlMetaIndex.INDEX_NAME, AnomalyDetectorsIndex.jobStateIndexName(), templates.addAll(Arrays.asList(Auditor.NOTIFICATIONS_INDEX, MlMetaIndex.INDEX_NAME, AnomalyDetectorsIndex.jobStateIndexName(),
AnomalyDetectorsIndex.jobResultsIndexPrefix())); AnomalyDetectorsIndex.jobResultsIndexPrefix()));
templates.addAll(Arrays.asList(WatcherIndexTemplateRegistry.TEMPLATE_NAMES)); templates.addAll(Arrays.asList(WatcherIndexTemplateRegistry.TEMPLATE_NAMES));

View File

@ -21,7 +21,6 @@ import org.elasticsearch.test.StreamsUtils;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate; import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils; import org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils;
import org.elasticsearch.xpack.security.SecurityClusterClientYamlTestCase;
import org.elasticsearch.xpack.security.support.IndexLifecycleManager; import org.elasticsearch.xpack.security.support.IndexLifecycleManager;
import org.elasticsearch.xpack.test.rest.XPackRestTestHelper; import org.elasticsearch.xpack.test.rest.XPackRestTestHelper;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction; import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction;
@ -61,11 +60,6 @@ public class FullClusterRestartIT extends ESRestTestCase {
private final boolean runningAgainstOldCluster = Booleans.parseBoolean(System.getProperty("tests.is_old_cluster")); private final boolean runningAgainstOldCluster = Booleans.parseBoolean(System.getProperty("tests.is_old_cluster"));
private final Version oldClusterVersion = Version.fromString(System.getProperty("tests.old_cluster_version")); private final Version oldClusterVersion = Version.fromString(System.getProperty("tests.old_cluster_version"));
@Before
public void waitForSecuritySetup() throws Exception {
SecurityClusterClientYamlTestCase.waitForSecurity();
}
@Before @Before
public void waitForMlTemplates() throws Exception { public void waitForMlTemplates() throws Exception {
XPackRestTestHelper.waitForMlTemplates(client()); XPackRestTestHelper.waitForMlTemplates(client());

View File

@ -16,7 +16,7 @@ import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class MultiClusterSearchWithSecurityYamlTestSuiteIT extends SecurityClusterClientYamlTestCase { public class MultiClusterSearchWithSecurityYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER = "test_user"; private static final String USER = "test_user";
private static final String PASS = "x-pack-test-password"; private static final String PASS = "x-pack-test-password";

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse; import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.xpack.security.SecurityClusterClientYamlTestCase; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.xpack.test.rest.XPackRestTestHelper; import org.elasticsearch.xpack.test.rest.XPackRestTestHelper;
import org.junit.Before; import org.junit.Before;
@ -29,7 +29,7 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@TimeoutSuite(millis = 5 * TimeUnits.MINUTE) // to account for slow as hell VMs @TimeoutSuite(millis = 5 * TimeUnits.MINUTE) // to account for slow as hell VMs
public class UpgradeClusterClientYamlTestSuiteIT extends SecurityClusterClientYamlTestCase { public class UpgradeClusterClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
/** /**
* Waits for the Machine Learning templates to be created by {@link org.elasticsearch.plugins.MetaDataUpgrader} * Waits for the Machine Learning templates to be created by {@link org.elasticsearch.plugins.MetaDataUpgrader}

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.security.authc.esnative.tool; package org.elasticsearch.xpack.security.authc.esnative.tool;
import org.apache.http.HttpHost;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.elasticsearch.cli.MockTerminal; import org.elasticsearch.cli.MockTerminal;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
@ -18,7 +17,6 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.security.SecurityClusterClientYamlTestCase;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
@ -49,8 +47,6 @@ public class SetupPasswordToolIT extends ESRestTestCase {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void testSetupPasswordToolAutoSetup() throws Exception { public void testSetupPasswordToolAutoSetup() throws Exception {
SecurityClusterClientYamlTestCase.waitForSecurity();
final String testConfigDir = System.getProperty("tests.config.dir"); final String testConfigDir = System.getProperty("tests.config.dir");
logger.info("--> CONF: {}", testConfigDir); logger.info("--> CONF: {}", testConfigDir);
final Path configPath = PathUtils.get(testConfigDir); final Path configPath = PathUtils.get(testConfigDir);

View File

@ -13,11 +13,10 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.xpack.security.SecurityClusterClientYamlTestCase;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class SmokeTestSecurityWithMustacheClientYamlTestSuiteIT extends SecurityClusterClientYamlTestCase { public class SmokeTestSecurityWithMustacheClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("test_admin", private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("test_admin",
new SecureString("x-pack-test-password".toCharArray())); new SecureString("x-pack-test-password".toCharArray()));

View File

@ -113,7 +113,7 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
} }
public void testThatTribeCanAuthenticateElasticUserWithChangedPassword() throws Exception { public void testThatTribeCanAuthenticateElasticUserWithChangedPassword() throws Exception {
assertSecurityIndexWriteable(); assertSecurityIndexActive();
securityClient(client()).prepareChangePassword("elastic", "password".toCharArray()).get(); securityClient(client()).prepareChangePassword("elastic", "password".toCharArray()).get();
assertTribeNodeHasAllIndices(); assertTribeNodeHasAllIndices();
@ -124,8 +124,8 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
} }
public void testThatTribeClustersHaveDifferentPasswords() throws Exception { public void testThatTribeClustersHaveDifferentPasswords() throws Exception {
assertSecurityIndexWriteable(); assertSecurityIndexActive();
assertSecurityIndexWriteable(cluster2); assertSecurityIndexActive(cluster2);
securityClient().prepareChangePassword("elastic", "password".toCharArray()).get(); securityClient().prepareChangePassword("elastic", "password".toCharArray()).get();
securityClient(cluster2.client()).prepareChangePassword("elastic", "password2".toCharArray()).get(); securityClient(cluster2.client()).prepareChangePassword("elastic", "password2".toCharArray()).get();
@ -155,7 +155,7 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
final int randomRoles = scaledRandomIntBetween(3, 8); final int randomRoles = scaledRandomIntBetween(3, 8);
List<String> shouldBeSuccessfulRoles = new ArrayList<>(); List<String> shouldBeSuccessfulRoles = new ArrayList<>();
assertSecurityIndexWriteable(); assertSecurityIndexActive();
for (int i = 0; i < randomRoles; i++) { for (int i = 0; i < randomRoles; i++) {
final String rolename = "preferredClusterRole" + i; final String rolename = "preferredClusterRole" + i;
PutRoleResponse response = securityClient(client()).preparePutRole(rolename).cluster("monitor").get(); PutRoleResponse response = securityClient(client()).preparePutRole(rolename).cluster("monitor").get();