diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy index 18f264690fa..88ded22fb4d 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy @@ -497,10 +497,15 @@ class BuildPlugin implements Plugin { project.afterEvaluate { project.tasks.withType(JavaCompile) { final JavaVersion targetCompatibilityVersion = JavaVersion.toVersion(it.targetCompatibility) - // we fork because compiling lots of different classes in a shared jvm can eventually trigger GC overhead limitations - options.fork = true - options.forkOptions.javaHome = new File(project.compilerJavaHome) - options.forkOptions.memoryMaximumSize = "512m" + final compilerJavaHomeFile = new File(project.compilerJavaHome) + // we only fork if the Gradle JDK is not the same as the compiler JDK + if (compilerJavaHomeFile.canonicalPath == Jvm.current().javaHome.canonicalPath) { + options.fork = false + } else { + options.fork = true + options.forkOptions.javaHome = compilerJavaHomeFile + options.forkOptions.memoryMaximumSize = "512m" + } if (targetCompatibilityVersion == JavaVersion.VERSION_1_8) { // compile with compact 3 profile by default // NOTE: this is just a compile time check: does not replace testing with a compact3 JRE diff --git a/client/rest/src/main/java/org/elasticsearch/client/RestClient.java b/client/rest/src/main/java/org/elasticsearch/client/RestClient.java index 1d4036c2103..05fa4d536b3 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/RestClient.java +++ b/client/rest/src/main/java/org/elasticsearch/client/RestClient.java @@ -210,7 +210,9 @@ public class RestClient implements Closeable { * @throws IOException in case of a problem or the connection was aborted * @throws ClientProtocolException in case of an http protocol error * @throws ResponseException in case Elasticsearch responded with a status code that indicated an error + * @deprecated prefer {@link #performRequest(Request)} */ + @Deprecated public Response performRequest(String method, String endpoint, Header... headers) throws IOException { Request request = new Request(method, endpoint); request.setHeaders(headers); @@ -229,7 +231,9 @@ public class RestClient implements Closeable { * @throws IOException in case of a problem or the connection was aborted * @throws ClientProtocolException in case of an http protocol error * @throws ResponseException in case Elasticsearch responded with a status code that indicated an error + * @deprecated prefer {@link #performRequest(Request)} */ + @Deprecated public Response performRequest(String method, String endpoint, Map params, Header... headers) throws IOException { Request request = new Request(method, endpoint); addParameters(request, params); @@ -252,7 +256,9 @@ public class RestClient implements Closeable { * @throws IOException in case of a problem or the connection was aborted * @throws ClientProtocolException in case of an http protocol error * @throws ResponseException in case Elasticsearch responded with a status code that indicated an error + * @deprecated prefer {@link #performRequest(Request)} */ + @Deprecated public Response performRequest(String method, String endpoint, Map params, HttpEntity entity, Header... headers) throws IOException { Request request = new Request(method, endpoint); @@ -289,7 +295,9 @@ public class RestClient implements Closeable { * @throws IOException in case of a problem or the connection was aborted * @throws ClientProtocolException in case of an http protocol error * @throws ResponseException in case Elasticsearch responded with a status code that indicated an error + * @deprecated prefer {@link #performRequest(Request)} */ + @Deprecated public Response performRequest(String method, String endpoint, Map params, HttpEntity entity, HttpAsyncResponseConsumerFactory httpAsyncResponseConsumerFactory, Header... headers) throws IOException { @@ -310,7 +318,9 @@ public class RestClient implements Closeable { * @param endpoint the path of the request (without host and port) * @param responseListener the {@link ResponseListener} to notify when the request is completed or fails * @param headers the optional request headers + * @deprecated prefer {@link #performRequestAsync(Request, ResponseListener)} */ + @Deprecated public void performRequestAsync(String method, String endpoint, ResponseListener responseListener, Header... headers) { Request request; try { @@ -333,7 +343,9 @@ public class RestClient implements Closeable { * @param params the query_string parameters * @param responseListener the {@link ResponseListener} to notify when the request is completed or fails * @param headers the optional request headers + * @deprecated prefer {@link #performRequestAsync(Request, ResponseListener)} */ + @Deprecated public void performRequestAsync(String method, String endpoint, Map params, ResponseListener responseListener, Header... headers) { Request request; @@ -361,7 +373,9 @@ public class RestClient implements Closeable { * @param entity the body of the request, null if not applicable * @param responseListener the {@link ResponseListener} to notify when the request is completed or fails * @param headers the optional request headers + * @deprecated prefer {@link #performRequestAsync(Request, ResponseListener)} */ + @Deprecated public void performRequestAsync(String method, String endpoint, Map params, HttpEntity entity, ResponseListener responseListener, Header... headers) { Request request; @@ -394,7 +408,9 @@ public class RestClient implements Closeable { * connection on the client side. * @param responseListener the {@link ResponseListener} to notify when the request is completed or fails * @param headers the optional request headers + * @deprecated prefer {@link #performRequestAsync(Request, ResponseListener)} */ + @Deprecated public void performRequestAsync(String method, String endpoint, Map params, HttpEntity entity, HttpAsyncResponseConsumerFactory httpAsyncResponseConsumerFactory, ResponseListener responseListener, Header... headers) { diff --git a/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java b/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java index 286ed7dd539..8768c071619 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java +++ b/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java @@ -43,7 +43,6 @@ public final class RestClientBuilder { public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 1000; public static final int DEFAULT_SOCKET_TIMEOUT_MILLIS = 30000; public static final int DEFAULT_MAX_RETRY_TIMEOUT_MILLIS = DEFAULT_SOCKET_TIMEOUT_MILLIS; - public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT_MILLIS = 500; public static final int DEFAULT_MAX_CONN_PER_ROUTE = 10; public static final int DEFAULT_MAX_CONN_TOTAL = 30; @@ -196,8 +195,7 @@ public final class RestClientBuilder { //default timeouts are all infinite RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS) - .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT_MILLIS) - .setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT_MILLIS); + .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT_MILLIS); if (requestConfigCallback != null) { requestConfigBuilder = requestConfigCallback.customizeRequestConfig(requestConfigBuilder); } diff --git a/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java index c9243d3aaf6..9657e782bda 100644 --- a/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java +++ b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java @@ -177,4 +177,24 @@ public class RestClientBuilderTests extends RestClientTestCase { } } + /** + * This test verifies that we don't change the default value for the connection request timeout as that causes problems. + * See https://github.com/elastic/elasticsearch/issues/24069 + */ + public void testDefaultConnectionRequestTimeout() throws IOException { + RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", 9200)); + builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() { + @Override + public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { + RequestConfig requestConfig = requestConfigBuilder.build(); + assertEquals(RequestConfig.DEFAULT.getConnectionRequestTimeout(), requestConfig.getConnectionRequestTimeout()); + //this way we get notified if the default ever changes + assertEquals(-1, requestConfig.getConnectionRequestTimeout()); + return requestConfigBuilder; + } + }); + try (RestClient restClient = builder.build()) { + assertNotNull(restClient); + } + } } diff --git a/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostIntegTests.java b/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostIntegTests.java index dd23dbe454f..3f57e8c3912 100644 --- a/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostIntegTests.java +++ b/client/rest/src/test/java/org/elasticsearch/client/RestClientSingleHostIntegTests.java @@ -32,6 +32,7 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.nio.entity.NStringEntity; import org.apache.http.util.EntityUtils; import org.elasticsearch.mocksocket.MockHttpServer; import org.junit.AfterClass; @@ -48,6 +49,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static org.elasticsearch.client.RestClientTestUtil.getAllStatusCodes; import static org.elasticsearch.client.RestClientTestUtil.getHttpMethods; @@ -159,6 +163,42 @@ public class RestClientSingleHostIntegTests extends RestClientTestCase { httpServer = null; } + /** + * Tests sending a bunch of async requests works well (e.g. no TimeoutException from the leased pool) + * See https://github.com/elastic/elasticsearch/issues/24069 + */ + public void testManyAsyncRequests() throws Exception { + int iters = randomIntBetween(500, 1000); + final CountDownLatch latch = new CountDownLatch(iters); + final List exceptions = new CopyOnWriteArrayList<>(); + for (int i = 0; i < iters; i++) { + Request request = new Request("PUT", "/200"); + request.setEntity(new NStringEntity("{}", ContentType.APPLICATION_JSON)); + restClient.performRequestAsync(request, new ResponseListener() { + @Override + public void onSuccess(Response response) { + latch.countDown(); + } + + @Override + public void onFailure(Exception exception) { + exceptions.add(exception); + latch.countDown(); + } + }); + } + + assertTrue("timeout waiting for requests to be sent", latch.await(10, TimeUnit.SECONDS)); + if (exceptions.isEmpty() == false) { + AssertionError error = new AssertionError("expected no failures but got some. see suppressed for first 10 of [" + + exceptions.size() + "] failures"); + for (Exception exception : exceptions.subList(0, Math.min(10, exceptions.size()))) { + error.addSuppressed(exception); + } + throw error; + } + } + /** * End to end test for headers. We test it explicitly against a real http client as there are different ways * to set/add headers to the {@link org.apache.http.client.HttpClient}. diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 346290c9f76..a105951203a 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -3,7 +3,7 @@ [partintro] -- -// To add a release, copy and paste the template text +// To add a release, copy and paste the template text // and add a link to the new section. Note that release subheads must // be floated and sections cannot be empty. @@ -104,6 +104,8 @@ ones that the user is authorized to access in case field level security is enabl [float] === Bug Fixes +Use date format in `date_range` mapping before fallback to default ({pull}29310[#29310]) + Fix NPE in 'more_like_this' when field has zero tokens ({pull}30365[#30365]) Fixed prerelease version of elasticsearch in the `deb` package to sort before GA versions @@ -139,8 +141,11 @@ coming[6.4.0] //[float] //=== Breaking Java Changes -//[float] -//=== Deprecations +[float] +=== Deprecations + +Deprecated multi-argument versions of the request methods in the RestClient. +Prefer the "Request" object flavored methods. ({pull}30315[#30315]) [float] === New Features @@ -157,8 +162,11 @@ analysis module. ({pull}30397[#30397]) {ref-64}/breaking_64_api_changes.html#copy-source-settings-on-resize[Allow copying source settings on index resize operations] ({pull}30255[#30255]) -Added new "Request" object flavored request methods. Prefer these instead of the -multi-argument versions. ({pull}29623[#29623]) +Added new "Request" object flavored request methods in the RestClient. Prefer +these instead of the multi-argument versions. ({pull}29623[#29623]) + +Watcher HTTP client used in watches now allows more parallel connections to the +same endpoint and evicts long running connections. ({pull}30130[#30130]) The cluster state listener to decide if watcher should be stopped/started/paused now runs far less code in an executor but is more @@ -171,6 +179,8 @@ Added put index template API to the high level rest client ({pull}30400[#30400]) [float] === Bug Fixes +Use date format in `date_range` mapping before fallback to default ({pull}29310[#29310]) + Fix NPE in 'more_like_this' when field has zero tokens ({pull}30365[#30365]) Do not ignore request analysis/similarity settings on index resize operations when the source index already contains such settings ({pull}30216[#30216]) diff --git a/docs/reference/cluster/tasks.asciidoc b/docs/reference/cluster/tasks.asciidoc index b3457953f46..2e59da42224 100644 --- a/docs/reference/cluster/tasks.asciidoc +++ b/docs/reference/cluster/tasks.asciidoc @@ -64,9 +64,10 @@ It is also possible to retrieve information for a particular task: [source,js] -------------------------------------------------- -GET _tasks/task_id:1 <1> +GET _tasks/task_id <1> -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] // TEST[catch:missing] <1> This will return a 404 if the task isn't found. @@ -75,9 +76,10 @@ Or to retrieve all children of a particular task: [source,js] -------------------------------------------------- -GET _tasks?parent_task_id=parentTaskId:1 <1> +GET _tasks?parent_task_id=parent_task_id <1> -------------------------------------------------- // CONSOLE +// TEST[s/=parent_task_id/=node_id:1/] <1> This won't return a 404 if the parent isn't found. diff --git a/docs/reference/docs/delete-by-query.asciidoc b/docs/reference/docs/delete-by-query.asciidoc index f9919483e5a..6edc453903d 100644 --- a/docs/reference/docs/delete-by-query.asciidoc +++ b/docs/reference/docs/delete-by-query.asciidoc @@ -357,9 +357,10 @@ With the task id you can look up the task directly: [source,js] -------------------------------------------------- -GET /_tasks/taskId:1 +GET /_tasks/task_id -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] // TEST[catch:missing] The advantage of this API is that it integrates with `wait_for_completion=false` @@ -378,8 +379,9 @@ Any Delete By Query can be canceled using the <>: [source,js] -------------------------------------------------- -POST _tasks/task_id:1/_cancel +POST _tasks/task_id/_cancel -------------------------------------------------- +// TEST[s/task_id/node_id:1/] // CONSOLE The `task_id` can be found using the tasks API above. @@ -397,8 +399,9 @@ using the `_rethrottle` API: [source,js] -------------------------------------------------- -POST _delete_by_query/task_id:1/_rethrottle?requests_per_second=-1 +POST _delete_by_query/task_id/_rethrottle?requests_per_second=-1 -------------------------------------------------- +// TEST[s/task_id/node_id:1/] // CONSOLE The `task_id` can be found using the tasks API above. diff --git a/docs/reference/docs/reindex.asciidoc b/docs/reference/docs/reindex.asciidoc index e8283abfc2e..b4205311dfe 100644 --- a/docs/reference/docs/reindex.asciidoc +++ b/docs/reference/docs/reindex.asciidoc @@ -740,9 +740,10 @@ With the task id you can look up the task directly: [source,js] -------------------------------------------------- -GET /_tasks/taskId:1 +GET /_tasks/task_id -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] // TEST[catch:missing] The advantage of this API is that it integrates with `wait_for_completion=false` @@ -761,9 +762,10 @@ Any Reindex can be canceled using the <>: [source,js] -------------------------------------------------- -POST _tasks/task_id:1/_cancel +POST _tasks/task_id/_cancel -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] The `task_id` can be found using the Tasks API. @@ -780,9 +782,10 @@ the `_rethrottle` API: [source,js] -------------------------------------------------- -POST _reindex/task_id:1/_rethrottle?requests_per_second=-1 +POST _reindex/task_id/_rethrottle?requests_per_second=-1 -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] The `task_id` can be found using the Tasks API above. diff --git a/docs/reference/docs/update-by-query.asciidoc b/docs/reference/docs/update-by-query.asciidoc index 1d81e4a44ff..6e7cfbd2b79 100644 --- a/docs/reference/docs/update-by-query.asciidoc +++ b/docs/reference/docs/update-by-query.asciidoc @@ -415,9 +415,10 @@ With the task id you can look up the task directly: [source,js] -------------------------------------------------- -GET /_tasks/taskId:1 +GET /_tasks/task_id -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] // TEST[catch:missing] The advantage of this API is that it integrates with `wait_for_completion=false` @@ -436,9 +437,10 @@ Any Update By Query can be canceled using the <>: [source,js] -------------------------------------------------- -POST _tasks/task_id:1/_cancel +POST _tasks/task_id/_cancel -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] The `task_id` can be found using the tasks API above. @@ -455,9 +457,10 @@ using the `_rethrottle` API: [source,js] -------------------------------------------------- -POST _update_by_query/task_id:1/_rethrottle?requests_per_second=-1 +POST _update_by_query/task_id/_rethrottle?requests_per_second=-1 -------------------------------------------------- // CONSOLE +// TEST[s/task_id/node_id:1/] The `task_id` can be found using the tasks API above. diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index 0a92d0d1884..e1ebfd58cd2 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -287,6 +287,9 @@ public class RangeFieldMapper extends FieldMapper { public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, ShapeRelation relation, DateTimeZone timeZone, DateMathParser parser, QueryShardContext context) { failIfNotIndexed(); + if (parser == null) { + parser = dateMathParser(); + } return rangeType.rangeQuery(name(), hasDocValues(), lowerTerm, upperTerm, includeLower, includeUpper, relation, timeZone, parser, context); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index 0c20153675a..803ec60153d 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -19,7 +19,6 @@ package org.elasticsearch.index.mapper; -import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.document.DoubleRange; import org.apache.lucene.document.FloatRange; import org.apache.lucene.document.InetAddressPoint; @@ -31,13 +30,16 @@ import org.apache.lucene.queries.BinaryDocValuesRangeQuery; import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.geo.ShapeRelation; +import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.mapper.RangeFieldMapper.RangeFieldType; import org.elasticsearch.index.mapper.RangeFieldMapper.RangeType; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.test.IndexSettingsModule; @@ -55,42 +57,38 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { @Before public void setupProperties() { - type = RandomPicks.randomFrom(random(), RangeType.values()); + type = randomFrom(RangeType.values()); nowInMillis = randomNonNegativeLong(); if (type == RangeType.DATE) { addModifier(new Modifier("format", true) { @Override public void modify(MappedFieldType ft) { - ((RangeFieldMapper.RangeFieldType) ft).setDateTimeFormatter(Joda.forPattern("basic_week_date", Locale.ROOT)); + ((RangeFieldType) ft).setDateTimeFormatter(Joda.forPattern("basic_week_date", Locale.ROOT)); } }); addModifier(new Modifier("locale", true) { @Override public void modify(MappedFieldType ft) { - ((RangeFieldMapper.RangeFieldType) ft).setDateTimeFormatter(Joda.forPattern("date_optional_time", Locale.CANADA)); + ((RangeFieldType) ft).setDateTimeFormatter(Joda.forPattern("date_optional_time", Locale.CANADA)); } }); } } @Override - protected RangeFieldMapper.RangeFieldType createDefaultFieldType() { - return new RangeFieldMapper.RangeFieldType(type, Version.CURRENT); + protected RangeFieldType createDefaultFieldType() { + return new RangeFieldType(type, Version.CURRENT); } public void testRangeQuery() throws Exception { - Settings indexSettings = Settings.builder() - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); - IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(randomAlphaOfLengthBetween(1, 10), indexSettings); - QueryShardContext context = new QueryShardContext(0, idxSettings, null, null, null, null, null, xContentRegistry(), - writableRegistry(), null, null, () -> nowInMillis, null); - RangeFieldMapper.RangeFieldType ft = new RangeFieldMapper.RangeFieldType(type, Version.CURRENT); + QueryShardContext context = createContext(); + RangeFieldType ft = new RangeFieldType(type, Version.CURRENT); ft.setName(FIELDNAME); ft.setIndexOptions(IndexOptions.DOCS); - ShapeRelation relation = RandomPicks.randomFrom(random(), ShapeRelation.values()); - boolean includeLower = random().nextBoolean(); - boolean includeUpper = random().nextBoolean(); + ShapeRelation relation = randomFrom(ShapeRelation.values()); + boolean includeLower = randomBoolean(); + boolean includeUpper = randomBoolean(); Object from = nextFrom(); Object to = nextTo(from); @@ -98,6 +96,41 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { ft.rangeQuery(from, to, includeLower, includeUpper, relation, null, null, context)); } + private QueryShardContext createContext() { + Settings indexSettings = Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); + IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(randomAlphaOfLengthBetween(1, 10), indexSettings); + return new QueryShardContext(0, idxSettings, null, null, null, null, null, xContentRegistry(), + writableRegistry(), null, null, () -> nowInMillis, null); + } + + public void testDateRangeQueryUsingMappingFormat() { + QueryShardContext context = createContext(); + RangeFieldType fieldType = new RangeFieldType(RangeType.DATE, Version.CURRENT); + fieldType.setName(FIELDNAME); + fieldType.setIndexOptions(IndexOptions.DOCS); + fieldType.setHasDocValues(false); + ShapeRelation relation = randomFrom(ShapeRelation.values()); + + // dates will break the default format + final String from = "2016-15-06T15:29:50+08:00"; + final String to = "2016-16-06T15:29:50+08:00"; + + ElasticsearchParseException ex = expectThrows(ElasticsearchParseException.class, + () -> fieldType.rangeQuery(from, to, true, true, relation, null, null, context)); + assertEquals("failed to parse date field [2016-15-06T15:29:50+08:00] with format [strict_date_optional_time||epoch_millis]", + ex.getMessage()); + + // setting mapping format which is compatible with those dates + final FormatDateTimeFormatter formatter = Joda.forPattern("yyyy-dd-MM'T'HH:mm:ssZZ"); + assertEquals(1465975790000L, formatter.parser().parseMillis(from)); + assertEquals(1466062190000L, formatter.parser().parseMillis(to)); + + fieldType.setDateTimeFormatter(formatter); + final Query query = fieldType.rangeQuery(from, to, true, true, relation, null, null, context); + assertEquals("field:", query.toString()); + } + private Query getExpectedRangeQuery(ShapeRelation relation, Object from, Object to, boolean includeLower, boolean includeUpper) { switch (type) { case DATE: @@ -277,14 +310,10 @@ public class RangeFieldTypeTests extends FieldTypeTestCase { assertEquals(InetAddresses.forString("::1"), RangeFieldMapper.RangeType.IP.parse(new BytesRef("::1"), randomBoolean())); } - public void testTermQuery() throws Exception, IllegalArgumentException { + public void testTermQuery() throws Exception { // See https://github.com/elastic/elasticsearch/issues/25950 - Settings indexSettings = Settings.builder() - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); - IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(randomAlphaOfLengthBetween(1, 10), indexSettings); - QueryShardContext context = new QueryShardContext(0, idxSettings, null, null, null, null, null, xContentRegistry(), - writableRegistry(), null, null, () -> nowInMillis, null); - RangeFieldMapper.RangeFieldType ft = new RangeFieldMapper.RangeFieldType(type, Version.CURRENT); + QueryShardContext context = createContext(); + RangeFieldType ft = new RangeFieldType(type, Version.CURRENT); ft.setName(FIELDNAME); ft.setIndexOptions(IndexOptions.DOCS); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/LocalStateCompositeXPackPlugin.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/LocalStateCompositeXPackPlugin.java index 0becdffb7ea..44fd61e1693 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/LocalStateCompositeXPackPlugin.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/LocalStateCompositeXPackPlugin.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.PageCacheRecycler; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.http.HttpServerTransport; @@ -38,6 +39,7 @@ import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.ingest.Processor; import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.persistent.PersistentTasksExecutor; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.AnalysisPlugin; import org.elasticsearch.plugins.ClusterPlugin; @@ -57,9 +59,9 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportInterceptor; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.persistent.PersistentTasksExecutor; import org.elasticsearch.xpack.core.ssl.SSLService; +import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; @@ -391,6 +393,11 @@ public class LocalStateCompositeXPackPlugin extends XPackPlugin implements Scrip .collect(toList()); } + @Override + public void close() throws IOException { + IOUtils.close(plugins); + } + private List filterPlugins(Class type) { return plugins.stream().filter(x -> type.isAssignableFrom(x.getClass())).map(p -> ((T)p)) .collect(Collectors.toList()); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index 4e9c6d1e5d7..a448cd9c65c 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -197,7 +197,7 @@ import org.elasticsearch.xpack.security.rest.action.user.RestGetUsersAction; import org.elasticsearch.xpack.security.rest.action.user.RestHasPrivilegesAction; import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction; import org.elasticsearch.xpack.security.rest.action.user.RestSetEnabledAction; -import org.elasticsearch.xpack.security.support.IndexLifecycleManager; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.security.transport.SecurityServerTransportInterceptor; import org.elasticsearch.xpack.security.transport.filter.IPFilter; import org.elasticsearch.xpack.security.transport.netty4.SecurityNetty4HttpServerTransport; @@ -233,7 +233,7 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETT import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED; import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField.SECURITY_TEMPLATE_NAME; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME; -import static org.elasticsearch.xpack.security.support.IndexLifecycleManager.INTERNAL_INDEX_FORMAT; +import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT; public class Security extends Plugin implements ActionPlugin, IngestPlugin, NetworkPlugin, ClusterPlugin, DiscoveryPlugin, MapperPlugin, ExtensiblePlugin { @@ -424,8 +424,8 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw components.add(realms); components.add(reservedRealm); - securityLifecycleService.addSecurityIndexHealthChangeListener(nativeRoleMappingStore::onSecurityIndexHealthChange); - securityLifecycleService.addSecurityIndexOutOfDateListener(nativeRoleMappingStore::onSecurityIndexOutOfDateChange); + securityLifecycleService.securityIndex().addIndexHealthChangeListener(nativeRoleMappingStore::onSecurityIndexHealthChange); + securityLifecycleService.securityIndex().addIndexOutOfDateListener(nativeRoleMappingStore::onSecurityIndexOutOfDateChange); AuthenticationFailureHandler failureHandler = null; String extensionName = null; @@ -458,8 +458,8 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw } final CompositeRolesStore allRolesStore = new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore, reservedRolesStore, rolesProviders, threadPool.getThreadContext(), getLicenseState()); - securityLifecycleService.addSecurityIndexHealthChangeListener(allRolesStore::onSecurityIndexHealthChange); - securityLifecycleService.addSecurityIndexOutOfDateListener(allRolesStore::onSecurityIndexOutOfDateChange); + securityLifecycleService.securityIndex().addIndexHealthChangeListener(allRolesStore::onSecurityIndexHealthChange); + securityLifecycleService.securityIndex().addIndexOutOfDateListener(allRolesStore::onSecurityIndexOutOfDateChange); // to keep things simple, just invalidate all cached entries on license change. this happens so rarely that the impact should be // minimal getLicenseState().addListener(allRolesStore::invalidateAll); @@ -886,7 +886,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw templates.remove(SECURITY_TEMPLATE_NAME); final XContent xContent = XContentFactory.xContent(XContentType.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(), SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); try (XContentParser parser = xContent .createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, auditTemplate)) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java index fd9bf875b34..099c9cc625b 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java @@ -22,7 +22,7 @@ import org.elasticsearch.common.util.concurrent.AbstractRunnable; import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; -import org.elasticsearch.xpack.security.support.IndexLifecycleManager; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import java.util.Arrays; import java.util.Collections; @@ -46,7 +46,7 @@ import java.util.function.Predicate; */ public class SecurityLifecycleService extends AbstractComponent implements ClusterStateListener { - public static final String INTERNAL_SECURITY_INDEX = IndexLifecycleManager.INTERNAL_SECURITY_INDEX; + public static final String INTERNAL_SECURITY_INDEX = SecurityIndexManager.INTERNAL_SECURITY_INDEX; public static final String SECURITY_INDEX_NAME = ".security"; private static final Version MIN_READ_VERSION = Version.V_5_0_0; @@ -55,7 +55,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust private final ThreadPool threadPool; private final IndexAuditTrail indexAuditTrail; - private final IndexLifecycleManager securityIndex; + private final SecurityIndexManager securityIndex; public SecurityLifecycleService(Settings settings, ClusterService clusterService, ThreadPool threadPool, Client client, @@ -64,7 +64,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust this.settings = settings; this.threadPool = threadPool; this.indexAuditTrail = indexAuditTrail; - this.securityIndex = new IndexLifecycleManager(settings, client, SECURITY_INDEX_NAME); + this.securityIndex = new SecurityIndexManager(settings, client, SECURITY_INDEX_NAME); clusterService.addListener(this); clusterService.addLifecycleListener(new LifecycleListener() { @Override @@ -110,69 +110,10 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust } } - IndexLifecycleManager securityIndex() { + public SecurityIndexManager securityIndex() { return securityIndex; } - /** - * Returns {@code true} if the security index exists - */ - public boolean isSecurityIndexExisting() { - return securityIndex.indexExists(); - } - - /** - * Returns true if the security index does not exist or it exists and has the current - * value for the index.format index setting - */ - public boolean isSecurityIndexUpToDate() { - return securityIndex.isIndexUpToDate(); - } - - /** - * Returns true if the security index exists and all primary shards are active - */ - public boolean isSecurityIndexAvailable() { - return securityIndex.isAvailable(); - } - - /** - * Returns true if the security index does not exist or the mappings are up to date - * based on the version in the _meta field - */ - public boolean isSecurityIndexMappingUpToDate() { - return securityIndex().isMappingUpToDate(); - } - - /** - * Test whether the effective (active) version of the security mapping meets the - * requiredVersion. - * - * @return true if the effective version passes the predicate, or the security - * mapping does not exist (null version). Otherwise, false. - */ - public boolean checkSecurityMappingVersion(Predicate requiredVersion) { - return securityIndex.checkMappingVersion(requiredVersion); - } - - /** - * Adds a listener which will be notified when the security index health changes. The previous and - * current health will be provided to the listener so that the listener can determine if any action - * needs to be taken. - */ - public void addSecurityIndexHealthChangeListener(BiConsumer listener) { - securityIndex.addIndexHealthChangeListener(listener); - } - - /** - * Adds a listener which will be notified when the security index out of date value changes. The previous and - * current value will be provided to the listener so that the listener can determine if any action - * needs to be taken. - */ - void addSecurityIndexOutOfDateListener(BiConsumer listener) { - securityIndex.addIndexOutOfDateListener(listener); - } - // this is called in a lifecycle listener beforeStop on the cluster service private void close() { if (indexAuditTrail != null) { @@ -193,29 +134,13 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust } private static boolean checkMappingVersions(ClusterState clusterState, Logger logger, Predicate versionPredicate) { - return IndexLifecycleManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, versionPredicate); + return SecurityIndexManager.checkIndexMappingVersionMatches(SECURITY_INDEX_NAME, clusterState, logger, versionPredicate); } public static List indexNames() { return Collections.unmodifiableList(Arrays.asList(SECURITY_INDEX_NAME, INTERNAL_SECURITY_INDEX)); } - /** - * Prepares the security index by creating it if it doesn't exist or updating the mappings if the mappings are - * out of date. After any tasks have been executed, the runnable is then executed. - */ - public void prepareIndexIfNeededThenExecute(final Consumer consumer, final Runnable andThen) { - securityIndex.prepareIndexIfNeededThenExecute(consumer, andThen); - } - - /** - * Checks if the security index is out of date with the current version. If the index does not exist - * we treat the index as up to date as we expect it to be created with the current format. - */ - public boolean isSecurityIndexOutOfDate() { - return securityIndex.isIndexUpToDate() == false; - } - /** * Is the move from {@code previousHealth} to {@code currentHealth} a move from an unhealthy ("RED") index state to a healthy * ("non-RED") state. diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java index e16a09c8a2a..590c2bc5ecd 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java @@ -57,7 +57,7 @@ import org.elasticsearch.xpack.core.template.TemplateUtils; import org.elasticsearch.xpack.security.audit.AuditLevel; import org.elasticsearch.xpack.security.audit.AuditTrail; import org.elasticsearch.xpack.security.rest.RemoteHostHeader; -import org.elasticsearch.xpack.security.support.IndexLifecycleManager; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -105,7 +105,7 @@ import static org.elasticsearch.xpack.security.audit.AuditLevel.parse; import static org.elasticsearch.xpack.security.audit.AuditUtil.indices; import static org.elasticsearch.xpack.security.audit.AuditUtil.restRequestContent; import static org.elasticsearch.xpack.security.audit.index.IndexNameResolver.resolve; -import static org.elasticsearch.xpack.security.support.IndexLifecycleManager.SECURITY_VERSION_STRING; +import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_VERSION_STRING; /** * Audit trail implementation that writes events into an index. @@ -1001,7 +1001,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail { private PutIndexTemplateRequest getPutIndexTemplateRequest(Settings customSettings) { final byte[] template = TemplateUtils.loadTemplate("/" + INDEX_TEMPLATE_NAME + ".json", - Version.CURRENT.toString(), IndexLifecycleManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); + Version.CURRENT.toString(), SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); final PutIndexTemplateRequest request = new PutIndexTemplateRequest(INDEX_TEMPLATE_NAME).source(template, XContentType.JSON); if (customSettings != null && customSettings.names().size() > 0) { Settings updatedSettings = Settings.builder() diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java index 017f4a6e049..6e97071cea9 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalRealms.java @@ -96,7 +96,7 @@ public final class InternalRealms { map.put(FileRealmSettings.TYPE, config -> new FileRealm(config, resourceWatcherService)); map.put(NativeRealmSettings.TYPE, config -> { final NativeRealm nativeRealm = new NativeRealm(config, nativeUsersStore); - securityLifecycleService.addSecurityIndexHealthChangeListener(nativeRealm::onSecurityIndexHealthChange); + securityLifecycleService.securityIndex().addIndexHealthChangeListener(nativeRealm::onSecurityIndexHealthChange); return nativeRealm; }); map.put(LdapRealmSettings.AD_TYPE, config -> new LdapRealm(LdapRealmSettings.AD_TYPE, config, sslService, diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java index 305c6caeba6..28098faa50e 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/TokenService.java @@ -250,7 +250,7 @@ public final class TokenService extends AbstractComponent { .setSource(builder) .setRefreshPolicy(RefreshPolicy.WAIT_UNTIL) .request(); - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client, SECURITY_ORIGIN, IndexAction.INSTANCE, request, ActionListener.wrap(indexResponse -> listener.onResponse(new Tuple<>(userToken, refreshToken)), listener::onFailure)) @@ -354,7 +354,7 @@ public final class TokenService extends AbstractComponent { if (version.onOrAfter(Version.V_6_2_0)) { // we only have the id and need to get the token from the doc! decryptTokenId(in, cipher, version, ActionListener.wrap(tokenId -> - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { final GetRequest getRequest = client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(tokenId)).request(); @@ -524,7 +524,7 @@ public final class TokenService extends AbstractComponent { .request(); final String tokenDocId = getTokenDocumentId(userToken); final Version version = userToken.getVersion(); - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, indexRequest, ActionListener.wrap(indexResponse -> { ActionListener wrappedListener = @@ -566,7 +566,7 @@ public final class TokenService extends AbstractComponent { .setVersion(documentVersion) .setRefreshPolicy(RefreshPolicy.WAIT_UNTIL) .request(); - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request, ActionListener.wrap(updateResponse -> { if (updateResponse.getGetResult() != null @@ -665,7 +665,7 @@ public final class TokenService extends AbstractComponent { .setVersion(true) .request(); - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request, ActionListener.wrap(searchResponse -> { if (searchResponse.isTimedOut()) { @@ -847,7 +847,7 @@ public final class TokenService extends AbstractComponent { .request(); final Supplier supplier = client.threadPool().getThreadContext().newRestorableContext(false); - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener), this::parseHit)); } @@ -914,11 +914,11 @@ public final class TokenService extends AbstractComponent { * have been explicitly cleared. */ private void checkIfTokenIsRevoked(UserToken userToken, ActionListener listener) { - if (lifecycleService.isSecurityIndexExisting() == false) { + if (lifecycleService.securityIndex().indexExists() == false) { // index doesn't exist so the token is considered valid. listener.onResponse(userToken); } else { - lifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + lifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { MultiGetRequest mGetRequest = client.prepareMultiGet() .add(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, getInvalidatedTokenDocumentId(userToken)) .add(SecurityLifecycleService.SECURITY_INDEX_NAME, TYPE, getTokenDocumentId(userToken)) @@ -989,7 +989,7 @@ public final class TokenService extends AbstractComponent { } private void maybeStartTokenRemover() { - if (lifecycleService.isSecurityIndexAvailable()) { + if (lifecycleService.securityIndex().isAvailable()) { if (client.threadPool().relativeTimeInMillis() - lastExpirationRunMs > deleteInterval.getMillis()) { expiredTokenRemover.submit(client.threadPool()); lastExpirationRunMs = client.threadPool().relativeTimeInMillis(); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java index d4d71523fea..381053d9633 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStore.java @@ -114,7 +114,7 @@ public class NativeUsersStore extends AbstractComponent { } }; - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == 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 @@ -123,7 +123,7 @@ public class NativeUsersStore extends AbstractComponent { (uap) -> listener.onResponse(uap == null ? Collections.emptyList() : Collections.singletonList(uap.user())), handleException)); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { final QueryBuilder query; if (userNames == null || userNames.length == 0) { query = QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE); @@ -154,11 +154,11 @@ public class NativeUsersStore extends AbstractComponent { * Async method to retrieve a user and their password */ private void getUserAndPassword(final String user, final ActionListener listener) { - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { // TODO remove this short circuiting and fix tests that fail without this! listener.onResponse(null); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareGet(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(USER_DOC_TYPE, user)).request(), @@ -199,7 +199,7 @@ public class NativeUsersStore extends AbstractComponent { docType = USER_DOC_TYPE; } - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(docType, username)) .setDoc(Requests.INDEX_CONTENT_TYPE, Fields.PASSWORD.getPreferredName(), @@ -237,7 +237,7 @@ public class NativeUsersStore extends AbstractComponent { * has been indexed */ private void createReservedUser(String username, char[] passwordHash, RefreshPolicy refresh, ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareIndex(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(RESERVED_USER_TYPE, username)) @@ -279,7 +279,7 @@ public class NativeUsersStore extends AbstractComponent { private void updateUserWithoutPassword(final PutUserRequest putUserRequest, final ActionListener listener) { assert putUserRequest.passwordHash() == null; // We must have an existing document - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(USER_DOC_TYPE, putUserRequest.username())) @@ -322,7 +322,7 @@ public class NativeUsersStore extends AbstractComponent { private void indexUser(final PutUserRequest putUserRequest, final ActionListener listener) { assert putUserRequest.passwordHash() != null; - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareIndex(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(USER_DOC_TYPE, putUserRequest.username())) @@ -366,7 +366,7 @@ public class NativeUsersStore extends AbstractComponent { private void setRegularUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy, final ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(USER_DOC_TYPE, username)) @@ -401,7 +401,7 @@ public class NativeUsersStore extends AbstractComponent { private void setReservedUserEnabled(final String username, final boolean enabled, final RefreshPolicy refreshPolicy, boolean clearCache, final ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareUpdate(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(RESERVED_USER_TYPE, username)) @@ -431,7 +431,7 @@ public class NativeUsersStore extends AbstractComponent { } public void deleteUser(final DeleteUserRequest deleteUserRequest, final ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { DeleteRequest request = client.prepareDelete(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username())).request(); request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy()); @@ -470,11 +470,11 @@ public class NativeUsersStore extends AbstractComponent { } void getReservedUserInfo(String username, ActionListener listener) { - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { // TODO remove this short circuiting and fix tests that fail without this! listener.onResponse(null); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareGet(SECURITY_INDEX_NAME, INDEX_TYPE, getIdForUser(RESERVED_USER_TYPE, username)).request(), @@ -514,7 +514,7 @@ public class NativeUsersStore extends AbstractComponent { } void getAllReservedUserInfo(ActionListener> listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareSearch(SECURITY_INDEX_NAME) .setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE)) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java index 601942b694a..199a1c19684 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java @@ -191,7 +191,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm { if (userIsDefinedForCurrentSecurityMapping(username) == false) { logger.debug("Marking user [{}] as disabled because the security mapping is not at the required version", username); listener.onResponse(DISABLED_DEFAULT_USER_INFO.deepClone()); - } else if (securityLifecycleService.isSecurityIndexExisting() == false) { + } else if (securityLifecycleService.securityIndex().indexExists() == false) { listener.onResponse(getDefaultUserInfo(username)); } else { nativeUsersStore.getReservedUserInfo(username, ActionListener.wrap((userInfo) -> { @@ -218,7 +218,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm { private boolean userIsDefinedForCurrentSecurityMapping(String username) { final Version requiredVersion = getDefinedVersion(username); - return securityLifecycleService.checkSecurityMappingVersion(requiredVersion::onOrBefore); + return securityLifecycleService.securityIndex().checkMappingVersion(requiredVersion::onOrBefore); } private Version getDefinedVersion(String username) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java index 0fcaf297c0f..bd26d778c0d 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStore.java @@ -120,7 +120,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol * package private for unit testing */ void loadMappings(ActionListener> listener) { - if (securityLifecycleService.isSecurityIndexOutOfDate()) { + if (securityLifecycleService.securityIndex().isIndexUpToDate() == false) { 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")); @@ -176,7 +176,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol private void modifyMapping(String name, CheckedBiConsumer, Exception> inner, Request request, ActionListener listener) { - if (securityLifecycleService.isSecurityIndexOutOfDate()) { + if (securityLifecycleService.securityIndex().isIndexUpToDate() == false) { 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")); @@ -192,7 +192,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol private void innerPutMapping(PutRoleMappingRequest request, ActionListener listener) { final ExpressionRoleMapping mapping = request.getMapping(); - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { final XContentBuilder xContentBuilder; try { xContentBuilder = mapping.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true); @@ -222,7 +222,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol } private void innerDeleteMapping(DeleteRoleMappingRequest request, ActionListener listener) throws IOException { - if (securityLifecycleService.isSecurityIndexOutOfDate()) { + if (securityLifecycleService.securityIndex().isIndexUpToDate() == false) { 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")); @@ -276,16 +276,16 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol } private void getMappings(ActionListener> listener) { - if (securityLifecycleService.isSecurityIndexAvailable()) { + if (securityLifecycleService.securityIndex().isAvailable()) { loadMappings(listener); } else { logger.info("The security index is not yet available - no role mappings can be loaded"); if (logger.isDebugEnabled()) { logger.debug("Security Index [{}] [exists: {}] [available: {}] [mapping up to date: {}]", SECURITY_INDEX_NAME, - securityLifecycleService.isSecurityIndexExisting(), - securityLifecycleService.isSecurityIndexAvailable(), - securityLifecycleService.isSecurityIndexMappingUpToDate() + securityLifecycleService.securityIndex().indexExists(), + securityLifecycleService.securityIndex().isAvailable(), + securityLifecycleService.securityIndex().isMappingUpToDate() ); } listener.onResponse(Collections.emptyList()); @@ -302,7 +302,7 @@ public class NativeRoleMappingStore extends AbstractComponent implements UserRol * */ public void usageStats(ActionListener> listener) { - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { reportStats(listener, Collections.emptyList()); } else { getMappings(ActionListener.wrap(mappings -> reportStats(listener, mappings), listener::onFailure)); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java index 4f0bb5b2e3c..834a70b9e03 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java @@ -100,7 +100,7 @@ public class NativeRolesStore extends AbstractComponent { * Retrieve a list of roles, if rolesToGet is null or empty, fetch all roles */ public void getRoleDescriptors(String[] names, final ActionListener> listener) { - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { // TODO remove this short circuiting and fix tests that fail without this! listener.onResponse(Collections.emptyList()); } else if (names != null && names.length == 1) { @@ -108,7 +108,7 @@ public class NativeRolesStore extends AbstractComponent { listener.onResponse(roleDescriptor == null ? Collections.emptyList() : Collections.singletonList(roleDescriptor)), listener::onFailure)); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { QueryBuilder query; if (names == null || names.length == 0) { query = QueryBuilders.termQuery(RoleDescriptor.Fields.TYPE.getPreferredName(), ROLE_TYPE); @@ -133,7 +133,7 @@ public class NativeRolesStore extends AbstractComponent { } public void deleteRole(final DeleteRoleRequest deleteRoleRequest, final ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { DeleteRequest request = client.prepareDelete(SecurityLifecycleService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE, getIdForUser(deleteRoleRequest.name())).request(); request.setRefreshPolicy(deleteRoleRequest.getRefreshPolicy()); @@ -166,7 +166,7 @@ public class NativeRolesStore extends AbstractComponent { // pkg-private for testing void innerPutRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> { + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> { final XContentBuilder xContentBuilder; try { xContentBuilder = role.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS, true); @@ -197,13 +197,13 @@ public class NativeRolesStore extends AbstractComponent { public void usageStats(ActionListener> listener) { Map usageStats = new HashMap<>(); - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { usageStats.put("size", 0L); usageStats.put("fls", false); usageStats.put("dls", false); listener.onResponse(usageStats); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareMultiSearch() .add(client.prepareSearch(SecurityLifecycleService.SECURITY_INDEX_NAME) @@ -259,11 +259,11 @@ public class NativeRolesStore extends AbstractComponent { } private void getRoleDescriptor(final String roleId, ActionListener roleActionListener) { - if (securityLifecycleService.isSecurityIndexExisting() == false) { + if (securityLifecycleService.securityIndex().indexExists() == false) { // TODO remove this short circuiting and fix tests that fail without this! roleActionListener.onResponse(null); } else { - securityLifecycleService.prepareIndexIfNeededThenExecute(roleActionListener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(roleActionListener::onFailure, () -> executeGetRoleRequest(roleId, new ActionListener() { @Override public void onResponse(GetResponse response) { @@ -288,7 +288,7 @@ public class NativeRolesStore extends AbstractComponent { } private void executeGetRoleRequest(String role, ActionListener listener) { - securityLifecycleService.prepareIndexIfNeededThenExecute(listener::onFailure, () -> + securityLifecycleService.securityIndex().prepareIndexIfNeededThenExecute(listener::onFailure, () -> executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, client.prepareGet(SecurityLifecycleService.SECURITY_INDEX_NAME, ROLE_DOC_TYPE, getIdForUser(role)).request(), diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/SecurityIndexManager.java similarity index 98% rename from x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java rename to x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/SecurityIndexManager.java index e2e278c7082..bfa02ed17c2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/IndexLifecycleManager.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/support/SecurityIndexManager.java @@ -58,7 +58,7 @@ import static org.elasticsearch.xpack.core.security.SecurityLifecycleServiceFiel /** * Manages the lifecycle of a single index, its template, mapping and and data upgrades/migrations. */ -public class IndexLifecycleManager extends AbstractComponent { +public class SecurityIndexManager extends AbstractComponent { public static final String INTERNAL_SECURITY_INDEX = ".security-" + IndexUpgradeCheckVersion.UPRADE_VERSION; public static final int INTERNAL_INDEX_FORMAT = 6; @@ -74,7 +74,7 @@ public class IndexLifecycleManager extends AbstractComponent { private volatile State indexState = new State(false, false, false, false, null); - public IndexLifecycleManager(Settings settings, Client client, String indexName) { + public SecurityIndexManager(Settings settings, Client client, String indexName) { super(settings); this.client = client; this.indexName = indexName; @@ -347,7 +347,7 @@ public class IndexLifecycleManager extends AbstractComponent { private Tuple loadMappingAndSettingsSourceFromTemplate() { final byte[] template = TemplateUtils.loadTemplate("/" + SECURITY_TEMPLATE_NAME + ".json", - Version.CURRENT.toString(), IndexLifecycleManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); + Version.CURRENT.toString(), SecurityIndexManager.TEMPLATE_VERSION_PATTERN).getBytes(StandardCharsets.UTF_8); PutIndexTemplateRequest request = new PutIndexTemplateRequest(SECURITY_TEMPLATE_NAME).source(template, XContentType.JSON); return new Tuple<>(request.mappings().get("doc"), request.settings()); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java index af00d4ac616..02d99fe0edc 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityLifecycleServiceTests.java @@ -37,7 +37,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.MockTransportClient; import org.elasticsearch.xpack.core.security.SecurityLifecycleServiceField; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; -import org.elasticsearch.xpack.security.support.IndexLifecycleManager; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.security.test.SecurityTestUtils; import org.elasticsearch.xpack.core.template.TemplateUtils; import org.junit.After; @@ -105,10 +105,10 @@ public class SecurityLifecycleServiceTests extends ESTestCase { ClusterState.Builder clusterStateBuilder = createClusterStateWithTemplate(templateString); final ClusterState clusterState = clusterStateBuilder.build(); - assertTrue(IndexLifecycleManager.checkTemplateExistsAndVersionMatches( + assertTrue(SecurityIndexManager.checkTemplateExistsAndVersionMatches( SecurityLifecycleServiceField.SECURITY_TEMPLATE_NAME, clusterState, logger, Version.V_5_0_0::before)); - assertFalse(IndexLifecycleManager.checkTemplateExistsAndVersionMatches( + assertFalse(SecurityIndexManager.checkTemplateExistsAndVersionMatches( SecurityLifecycleServiceField.SECURITY_TEMPLATE_NAME, clusterState, logger, Version.V_5_0_0::after)); } @@ -126,7 +126,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase { ClusterState.Builder clusterStateBuilder = createClusterStateWithMappingAndTemplate(templateString); securityLifecycleService.clusterChanged(new ClusterChangedEvent("test-event", clusterStateBuilder.build(), EMPTY_CLUSTER_STATE)); - final IndexLifecycleManager securityIndex = securityLifecycleService.securityIndex(); + final SecurityIndexManager securityIndex = securityLifecycleService.securityIndex(); assertTrue(securityIndex.checkMappingVersion(Version.V_5_0_0::before)); assertFalse(securityIndex.checkMappingVersion(Version.V_5_0_0::after)); } @@ -172,7 +172,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase { private static IndexMetaData.Builder createIndexMetadata(String indexName, String templateString) throws IOException { String template = TemplateUtils.loadTemplate(templateString, Version.CURRENT.toString(), - IndexLifecycleManager.TEMPLATE_VERSION_PATTERN); + SecurityIndexManager.TEMPLATE_VERSION_PATTERN); PutIndexTemplateRequest request = new PutIndexTemplateRequest(); request.source(template, XContentType.JSON); IndexMetaData.Builder indexMetaData = IndexMetaData.builder(indexName); @@ -219,7 +219,7 @@ public class SecurityLifecycleServiceTests extends ESTestCase { String templateName, String templateString) throws IOException { String template = TemplateUtils.loadTemplate(templateString, Version.CURRENT.toString(), - IndexLifecycleManager.TEMPLATE_VERSION_PATTERN); + SecurityIndexManager.TEMPLATE_VERSION_PATTERN); PutIndexTemplateRequest request = new PutIndexTemplateRequest(); request.source(template, XContentType.JSON); IndexTemplateMetaData.Builder templateBuilder = IndexTemplateMetaData.builder(templateName) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index 7d751a80246..988f60fe57e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -63,7 +63,7 @@ import java.util.function.Predicate; import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_FORMAT_SETTING; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME; -import static org.elasticsearch.xpack.security.support.IndexLifecycleManager.INTERNAL_INDEX_FORMAT; +import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_INDEX_FORMAT; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java index a0755f9cd06..52a2e537d8d 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java @@ -67,6 +67,7 @@ import org.elasticsearch.xpack.security.authc.saml.SamlRealm; import org.elasticsearch.xpack.security.authc.saml.SamlRealmTestHelper; import org.elasticsearch.xpack.security.authc.saml.SamlRealmTests; import org.elasticsearch.xpack.security.authc.saml.SamlTestCase; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.After; import org.junit.Before; import org.opensaml.saml.saml2.core.NameID; @@ -161,10 +162,12 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase { }; final SecurityLifecycleService lifecycleService = mock(SecurityLifecycleService.class); + final SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); doAnswer(inv -> { ((Runnable) inv.getArguments()[1]).run(); return null; - }).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool); tokenService = new TokenService(settings, Clock.systemUTC(), client, lifecycleService, clusterService); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java index 50a7a35b7a6..93e6ebf2861 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlLogoutActionTests.java @@ -56,6 +56,7 @@ import org.elasticsearch.xpack.security.authc.saml.SamlRealm; import org.elasticsearch.xpack.security.authc.saml.SamlRealmTests; import org.elasticsearch.xpack.security.authc.saml.SamlTestCase; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.After; import org.junit.Before; import org.opensaml.saml.saml2.core.NameID; @@ -173,10 +174,12 @@ public class TransportSamlLogoutActionTests extends SamlTestCase { }).when(client).execute(eq(IndexAction.INSTANCE), any(IndexRequest.class), any(ActionListener.class)); final SecurityLifecycleService lifecycleService = mock(SecurityLifecycleService.class); + final SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); doAnswer(inv -> { ((Runnable) inv.getArguments()[1]).run(); return null; - }).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool); tokenService = new TokenService(settings, Clock.systemUTC(), client, lifecycleService, clusterService); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportGetUsersActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportGetUsersActionTests.java index b23fccec018..02af431f897 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportGetUsersActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportGetUsersActionTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealmTests; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.Before; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -76,7 +77,9 @@ public class TransportGetUsersActionTests extends ESTestCase { public void testAnonymousUser() { NativeUsersStore usersStore = mock(NativeUsersStore.class); SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); AnonymousUser anonymousUser = new AnonymousUser(settings); ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, anonymousUser, securityLifecycleService, new ThreadContext(Settings.EMPTY)); @@ -146,8 +149,10 @@ public class TransportGetUsersActionTests extends ESTestCase { public void testReservedUsersOnly() { NativeUsersStore usersStore = mock(NativeUsersStore.class); SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); - when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); + when(securityIndex.checkMappingVersion(any())).thenReturn(true); ReservedRealmTests.mockGetAllReservedUserInfo(usersStore, Collections.emptyMap()); ReservedRealm reservedRealm = @@ -194,7 +199,9 @@ public class TransportGetUsersActionTests extends ESTestCase { Arrays.asList(new User("jane"), new User("fred")), randomUsers()); NativeUsersStore usersStore = mock(NativeUsersStore.class); SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); ReservedRealmTests.mockGetAllReservedUserInfo(usersStore, Collections.emptyMap()); ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(settings), securityLifecycleService, new ThreadContext(Settings.EMPTY)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportPutUserActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportPutUserActionTests.java index bab047951e5..7b26e605207 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportPutUserActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/user/TransportPutUserActionTests.java @@ -29,6 +29,7 @@ import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealmTests; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -118,7 +119,9 @@ public class TransportPutUserActionTests extends ESTestCase { public void testReservedUser() { NativeUsersStore usersStore = mock(NativeUsersStore.class); SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); ReservedRealmTests.mockGetAllReservedUserInfo(usersStore, Collections.emptyMap()); Settings settings = Settings.builder().put("path.home", createTempDir()).build(); ReservedRealm reservedRealm = new ReservedRealm(TestEnvironment.newEnvironment(settings), settings, usersStore, diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index 0c75e36fa6c..41b765cb333 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -68,6 +68,7 @@ import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.audit.AuditTrailService; import org.elasticsearch.xpack.security.authc.AuthenticationService.Authenticator; import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.After; import org.junit.Before; @@ -125,6 +126,7 @@ public class AuthenticationServiceTests extends ESTestCase { private ThreadContext threadContext; private TokenService tokenService; private SecurityLifecycleService lifecycleService; + private SecurityIndexManager securityIndex; private Client client; private InetSocketAddress remoteAddress; @@ -181,11 +183,13 @@ public class AuthenticationServiceTests extends ESTestCase { return builder; }).when(client).prepareGet(anyString(), anyString(), anyString()); lifecycleService = mock(SecurityLifecycleService.class); + securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); doAnswer(invocationOnMock -> { Runnable runnable = (Runnable) invocationOnMock.getArguments()[1]; runnable.run(); return null; - }).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool); tokenService = new TokenService(settings, Clock.systemUTC(), client, lifecycleService, clusterService); service = new AuthenticationService(settings, realms, auditTrail, @@ -924,8 +928,8 @@ public class AuthenticationServiceTests extends ESTestCase { } public void testExpiredToken() throws Exception { - when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); - when(lifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.isAvailable()).thenReturn(true); + when(lifecycleService.securityIndex().indexExists()).thenReturn(true); User user = new User("_username", "r1"); final Authentication expected = new Authentication(user, new RealmRef("realm", "custom", "node"), null); PlainActionFuture> tokenFuture = new PlainActionFuture<>(); @@ -963,7 +967,7 @@ public class AuthenticationServiceTests extends ESTestCase { doAnswer(invocationOnMock -> { ((Runnable) invocationOnMock.getArguments()[1]).run(); return null; - }).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader("Authorization", "Bearer " + token); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java index 91e8111b54c..f0af7a2539e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalRealmsTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import java.util.Map; import java.util.function.BiConsumer; @@ -30,11 +31,14 @@ import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class InternalRealmsTests extends ESTestCase { public void testNativeRealmRegistersIndexHealthChangeListener() throws Exception { SecurityLifecycleService lifecycleService = mock(SecurityLifecycleService.class); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); Map factories = InternalRealms.getFactories(mock(ThreadPool.class), mock(ResourceWatcherService.class), mock(SSLService.class), mock(NativeUsersStore.class), mock(NativeRoleMappingStore.class), lifecycleService); assertThat(factories, hasEntry(is(NativeRealmSettings.TYPE), any(Realm.Factory.class))); @@ -43,10 +47,10 @@ public class InternalRealmsTests extends ESTestCase { Settings settings = Settings.builder().put("path.home", createTempDir()).build(); factories.get(NativeRealmSettings.TYPE).create(new RealmConfig("test", Settings.EMPTY, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings))); - verify(lifecycleService).addSecurityIndexHealthChangeListener(isA(BiConsumer.class)); + verify(securityIndex).addIndexHealthChangeListener(isA(BiConsumer.class)); factories.get(NativeRealmSettings.TYPE).create(new RealmConfig("test", Settings.EMPTY, settings, TestEnvironment.newEnvironment(settings), new ThreadContext(settings))); - verify(lifecycleService, times(2)).addSecurityIndexHealthChangeListener(isA(BiConsumer.class)); + verify(securityIndex, times(2)).addIndexHealthChangeListener(isA(BiConsumer.class)); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java index 9b401873941..79a26479975 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/TokenServiceTests.java @@ -51,6 +51,7 @@ import org.elasticsearch.xpack.core.security.authc.TokenMetaData; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.watcher.watch.ClockMock; import org.elasticsearch.xpack.security.SecurityLifecycleService; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -86,6 +87,7 @@ public class TokenServiceTests extends ESTestCase { private Client client; private SecurityLifecycleService lifecycleService; + private SecurityIndexManager securityIndex; private ClusterService clusterService; private Settings tokenServiceEnabledSettings = Settings.builder() .put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build(); @@ -131,11 +133,13 @@ public class TokenServiceTests extends ESTestCase { // setup lifecycle service lifecycleService = mock(SecurityLifecycleService.class); + securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); doAnswer(invocationOnMock -> { Runnable runnable = (Runnable) invocationOnMock.getArguments()[1]; runnable.run(); return null; - }).when(lifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); this.clusterService = ClusterServiceUtils.createClusterService(threadPool); } @@ -376,7 +380,7 @@ public class TokenServiceTests extends ESTestCase { } public void testInvalidatedToken() throws Exception { - when(lifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); TokenService tokenService = new TokenService(tokenServiceEnabledSettings, systemUTC(), client, lifecycleService, clusterService); Authentication authentication = new Authentication(new User("joe", "admin"), new RealmRef("native_realm", "native", "node1"), null); @@ -563,8 +567,8 @@ public class TokenServiceTests extends ESTestCase { UserToken serialized = future.get(); assertEquals(authentication, serialized.getAuthentication()); - when(lifecycleService.isSecurityIndexAvailable()).thenReturn(false); - when(lifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.isAvailable()).thenReturn(false); + when(securityIndex.indexExists()).thenReturn(true); future = new PlainActionFuture<>(); tokenService.getAndValidateToken(requestContext, future); assertNull(future.get()); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java index 36a49653645..2c11411955a 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeRealmIntegTests.java @@ -55,7 +55,7 @@ import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDI import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.SecurityLifecycleService.SECURITY_INDEX_NAME; -import static org.elasticsearch.xpack.security.support.IndexLifecycleManager.INTERNAL_SECURITY_INDEX; +import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java index 51314c64375..091f6f2ed45 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/NativeUsersStoreTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.xpack.core.security.user.KibanaUser; import org.elasticsearch.xpack.core.security.user.LogstashSystemUser; import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.SecurityLifecycleService; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.Before; import java.io.IOException; @@ -236,16 +237,17 @@ public class NativeUsersStoreTests extends ESTestCase { private NativeUsersStore startNativeUsersStore() { SecurityLifecycleService securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); - when(securityLifecycleService.isSecurityIndexMappingUpToDate()).thenReturn(true); - when(securityLifecycleService.isSecurityIndexOutOfDate()).thenReturn(false); - when(securityLifecycleService.isSecurityIndexUpToDate()).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); + when(securityIndex.isMappingUpToDate()).thenReturn(true); + when(securityIndex.isIndexUpToDate()).thenReturn(true); doAnswer((i) -> { Runnable action = (Runnable) i.getArguments()[1]; action.run(); return null; - }).when(securityLifecycleService).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); + }).when(securityIndex).prepareIndexIfNeededThenExecute(any(Consumer.class), any(Runnable.class)); return new NativeUsersStore(Settings.EMPTY, client, securityLifecycleService); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealmTests.java index 272af679d13..024f8f603c9 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealmTests.java @@ -29,6 +29,7 @@ import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.security.user.UsernamesField; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -63,13 +64,16 @@ public class ReservedRealmTests extends ESTestCase { private static final SecureString EMPTY_PASSWORD = new SecureString("".toCharArray()); private NativeUsersStore usersStore; private SecurityLifecycleService securityLifecycleService; + private SecurityIndexManager securityIndex; @Before public void setupMocks() throws Exception { usersStore = mock(NativeUsersStore.class); securityLifecycleService = mock(SecurityLifecycleService.class); - when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); - when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true); + securityIndex = mock(SecurityIndexManager.class); + when(securityLifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); + when(securityIndex.checkMappingVersion(any())).thenReturn(true); mockGetAllReservedUserInfo(usersStore, Collections.emptyMap()); } @@ -90,7 +94,7 @@ public class ReservedRealmTests extends ESTestCase { Settings settings = Settings.builder().put(XPackSettings.RESERVED_REALM_ENABLED_SETTING.getKey(), false).build(); final boolean securityIndexExists = randomBoolean(); if (securityIndexExists) { - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); } final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, @@ -120,7 +124,7 @@ public class ReservedRealmTests extends ESTestCase { final User expectedUser = randomReservedUser(enabled); final String principal = expectedUser.principal(); final SecureString newPassword = new SecureString("foobar".toCharArray()); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); doAnswer((i) -> { ActionListener callback = (ActionListener) i.getArguments()[1]; callback.onResponse(new ReservedUserInfo(Hasher.BCRYPT.hash(newPassword), enabled, false)); @@ -146,10 +150,10 @@ public class ReservedRealmTests extends ESTestCase { assertEquals(expectedUser, authenticated); assertThat(expectedUser.enabled(), is(enabled)); - verify(securityLifecycleService, times(2)).isSecurityIndexExisting(); + verify(securityIndex, times(2)).indexExists(); verify(usersStore, times(2)).getReservedUserInfo(eq(principal), any(ActionListener.class)); final ArgumentCaptor predicateCaptor = ArgumentCaptor.forClass(Predicate.class); - verify(securityLifecycleService, times(2)).checkSecurityMappingVersion(predicateCaptor.capture()); + verify(securityIndex, times(2)).checkMappingVersion(predicateCaptor.capture()); verifyVersionPredicate(principal, predicateCaptor.getValue()); verifyNoMoreInteractions(usersStore); } @@ -165,10 +169,10 @@ public class ReservedRealmTests extends ESTestCase { reservedRealm.doLookupUser(principal, listener); final User user = listener.actionGet(); assertEquals(expectedUser, user); - verify(securityLifecycleService).isSecurityIndexExisting(); + verify(securityIndex).indexExists(); final ArgumentCaptor predicateCaptor = ArgumentCaptor.forClass(Predicate.class); - verify(securityLifecycleService).checkSecurityMappingVersion(predicateCaptor.capture()); + verify(securityIndex).checkMappingVersion(predicateCaptor.capture()); verifyVersionPredicate(principal, predicateCaptor.getValue()); PlainActionFuture future = new PlainActionFuture<>(); @@ -199,7 +203,7 @@ public class ReservedRealmTests extends ESTestCase { new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); final User expectedUser = randomReservedUser(true); final String principal = expectedUser.principal(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); final RuntimeException e = new RuntimeException("store threw"); doAnswer((i) -> { ActionListener callback = (ActionListener) i.getArguments()[1]; @@ -212,11 +216,11 @@ public class ReservedRealmTests extends ESTestCase { ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class, future::actionGet); assertThat(securityException.getMessage(), containsString("failed to lookup")); - verify(securityLifecycleService).isSecurityIndexExisting(); + verify(securityIndex).indexExists(); verify(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class)); final ArgumentCaptor predicateCaptor = ArgumentCaptor.forClass(Predicate.class); - verify(securityLifecycleService).checkSecurityMappingVersion(predicateCaptor.capture()); + verify(securityIndex).checkMappingVersion(predicateCaptor.capture()); verifyVersionPredicate(principal, predicateCaptor.getValue()); verifyNoMoreInteractions(usersStore); @@ -269,7 +273,7 @@ public class ReservedRealmTests extends ESTestCase { } public void testFailedAuthentication() throws Exception { - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); SecureString password = new SecureString("password".toCharArray()); char[] hash = Hasher.BCRYPT.hash(password); ReservedUserInfo userInfo = new ReservedUserInfo(hash, true, false); @@ -302,7 +306,7 @@ public class ReservedRealmTests extends ESTestCase { MockSecureSettings mockSecureSettings = new MockSecureSettings(); mockSecureSettings.setString("bootstrap.password", "foobar"); Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); @@ -324,7 +328,7 @@ public class ReservedRealmTests extends ESTestCase { MockSecureSettings mockSecureSettings = new MockSecureSettings(); mockSecureSettings.setString("bootstrap.password", "foobar"); Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); @@ -351,7 +355,7 @@ public class ReservedRealmTests extends ESTestCase { MockSecureSettings mockSecureSettings = new MockSecureSettings(); mockSecureSettings.setString("bootstrap.password", "foobar"); Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(false); + when(securityIndex.indexExists()).thenReturn(false); final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); @@ -369,7 +373,7 @@ public class ReservedRealmTests extends ESTestCase { final String password = randomAlphaOfLengthBetween(8, 24); mockSecureSettings.setString("bootstrap.password", password); Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true); + when(securityIndex.indexExists()).thenReturn(true); final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); @@ -391,7 +395,7 @@ public class ReservedRealmTests extends ESTestCase { final String password = randomAlphaOfLengthBetween(8, 24); mockSecureSettings.setString("bootstrap.password", password); Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build(); - when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(false); + when(securityIndex.indexExists()).thenReturn(false); final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), settings, usersStore, new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java index 41fe340d05f..3a67ab9447e 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java @@ -30,6 +30,7 @@ import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.security.SecurityLifecycleService; import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.hamcrest.Matchers; import java.util.Arrays; @@ -75,7 +76,9 @@ public class NativeRoleMappingStoreTests extends ESTestCase { final Client client = mock(Client.class); final SecurityLifecycleService lifecycleService = mock(SecurityLifecycleService.class); - when(lifecycleService.isSecurityIndexAvailable()).thenReturn(true); + SecurityIndexManager securityIndex = mock(SecurityIndexManager.class); + when(lifecycleService.securityIndex()).thenReturn(securityIndex); + when(securityIndex.isAvailable()).thenReturn(true); final NativeRoleMappingStore store = new NativeRoleMappingStore(Settings.EMPTY, client, lifecycleService) { @Override diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerIntegTests.java similarity index 97% rename from x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerIntegTests.java rename to x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerIntegTests.java index 4934bcd9303..677be9a94e7 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerIntegTests.java @@ -21,7 +21,7 @@ import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -public class IndexLifecycleManagerIntegTests extends SecurityIntegTestCase { +public class SecurityIndexManagerIntegTests extends SecurityIntegTestCase { public void testConcurrentOperationsTryingToCreateSecurityIndexAndAlias() throws Exception { assertSecurityIndexActive(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerTests.java similarity index 96% rename from x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java rename to x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerTests.java index 9411042e363..e85c8629f2c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/IndexLifecycleManagerTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/support/SecurityIndexManagerTests.java @@ -52,17 +52,17 @@ import org.hamcrest.Matchers; import org.junit.Before; import static org.elasticsearch.cluster.routing.RecoverySource.StoreRecoverySource.EXISTING_STORE_INSTANCE; -import static org.elasticsearch.xpack.security.support.IndexLifecycleManager.TEMPLATE_VERSION_PATTERN; +import static org.elasticsearch.xpack.security.support.SecurityIndexManager.TEMPLATE_VERSION_PATTERN; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class IndexLifecycleManagerTests extends ESTestCase { +public class SecurityIndexManagerTests extends ESTestCase { private static final ClusterName CLUSTER_NAME = new ClusterName("index-lifecycle-manager-tests"); private static final ClusterState EMPTY_CLUSTER_STATE = new ClusterState.Builder(CLUSTER_NAME).build(); - public static final String INDEX_NAME = "IndexLifecycleManagerTests"; - private static final String TEMPLATE_NAME = "IndexLifecycleManagerTests-template"; - private IndexLifecycleManager manager; + public static final String INDEX_NAME = "SecurityIndexManagerTests"; + private static final String TEMPLATE_NAME = "SecurityIndexManagerTests-template"; + private SecurityIndexManager manager; private Map, Map>> actions; @Before @@ -86,7 +86,7 @@ public class IndexLifecycleManagerTests extends ESTestCase { actions.put(action, map); } }; - manager = new IndexLifecycleManager(Settings.EMPTY, client, INDEX_NAME); + manager = new SecurityIndexManager(Settings.EMPTY, client, INDEX_NAME); } public void testIndexWithUpToDateMappingAndTemplate() throws IOException { @@ -221,7 +221,7 @@ public class IndexLifecycleManagerTests extends ESTestCase { // index doesn't exist and now exists with wrong format ClusterState.Builder clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME, - IndexLifecycleManager.INTERNAL_INDEX_FORMAT - 1); + SecurityIndexManager.INTERNAL_INDEX_FORMAT - 1); markShardsAvailable(clusterStateBuilder); manager.clusterChanged(event(clusterStateBuilder)); assertTrue(listenerCalled.get()); @@ -235,7 +235,7 @@ public class IndexLifecycleManagerTests extends ESTestCase { listenerCalled.set(false); // index doesn't exist and now exists with correct format - clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME, IndexLifecycleManager.INTERNAL_INDEX_FORMAT); + clusterStateBuilder = createClusterState(INDEX_NAME, TEMPLATE_NAME, SecurityIndexManager.INTERNAL_INDEX_FORMAT); markShardsAvailable(clusterStateBuilder); manager.clusterChanged(event(clusterStateBuilder)); assertFalse(listenerCalled.get()); @@ -255,7 +255,7 @@ public class IndexLifecycleManagerTests extends ESTestCase { } public static ClusterState.Builder createClusterState(String indexName, String templateName) throws IOException { - return createClusterState(indexName, templateName, templateName, IndexLifecycleManager.INTERNAL_INDEX_FORMAT); + return createClusterState(indexName, templateName, templateName, SecurityIndexManager.INTERNAL_INDEX_FORMAT); } public static ClusterState.Builder createClusterState(String indexName, String templateName, int format) throws IOException { diff --git a/x-pack/plugin/security/src/test/resources/IndexLifecycleManagerTests-template.json b/x-pack/plugin/security/src/test/resources/SecurityIndexManagerTests-template.json similarity index 100% rename from x-pack/plugin/security/src/test/resources/IndexLifecycleManagerTests-template.json rename to x-pack/plugin/security/src/test/resources/SecurityIndexManagerTests-template.json diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java index 6c4ac1994ff..1bd1aa59f70 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java @@ -30,6 +30,7 @@ import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.core.internal.io.IOUtils; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.index.IndexModule; @@ -216,6 +217,7 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin { private static final Logger logger = Loggers.getLogger(Watcher.class); private WatcherIndexingListener listener; + private HttpClient httpClient; protected final Settings settings; protected final boolean transportClient; @@ -266,7 +268,7 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin { // TODO: add more auth types, or remove this indirection HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories); HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry); - final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, getSslService()); + httpClient = new HttpClient(settings, httpAuthRegistry, getSslService()); // notification EmailService emailService = new EmailService(settings, cryptoService, clusterService.getClusterSettings()); @@ -608,4 +610,9 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin { public List getContexts() { return Arrays.asList(Watcher.SCRIPT_SEARCH_CONTEXT, Watcher.SCRIPT_EXECUTABLE_CONTEXT, Watcher.SCRIPT_TEMPLATE_CONTEXT); } + + @Override + public void close() throws IOException { + IOUtils.closeWhileHandlingException(httpClient); + } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/common/http/HttpClient.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/common/http/HttpClient.java index 729696ffa35..80d12f5fbce 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/common/http/HttpClient.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/common/http/HttpClient.java @@ -46,6 +46,7 @@ import org.elasticsearch.xpack.watcher.common.http.auth.HttpAuthRegistry; import javax.net.ssl.HostnameVerifier; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -56,9 +57,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class HttpClient extends AbstractComponent { +public class HttpClient extends AbstractComponent implements Closeable { private static final String SETTINGS_SSL_PREFIX = "xpack.http.ssl."; + // picking a reasonable high value here to allow for setups with lots of watch executions or many http inputs/actions + // this is also used as the value per route, if you are connecting to the same endpoint a lot, which is likely, when + // you are querying a remote Elasticsearch cluster + private static final int MAX_CONNECTIONS = 500; private final HttpAuthRegistry httpAuthRegistry; private final CloseableHttpClient client; @@ -84,6 +89,10 @@ public class HttpClient extends AbstractComponent { SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslService.sslSocketFactory(sslSettings), verifier); clientBuilder.setSSLSocketFactory(factory); + clientBuilder.evictExpiredConnections(); + clientBuilder.setMaxConnPerRoute(MAX_CONNECTIONS); + clientBuilder.setMaxConnTotal(MAX_CONNECTIONS); + client = clientBuilder.build(); } @@ -251,6 +260,11 @@ public class HttpClient extends AbstractComponent { } } + @Override + public void close() throws IOException { + client.close(); + } + /** * Helper class to have all HTTP methods except HEAD allow for an body, including GET */ diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java index f57f65f1d62..09ca57c1708 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookActionTests.java @@ -44,7 +44,6 @@ import org.joda.time.DateTime; import org.junit.Before; import javax.mail.internet.AddressException; - import java.io.IOException; import java.util.Map; @@ -219,10 +218,9 @@ public class WebhookActionTests extends ESTestCase { public void testThatSelectingProxyWorks() throws Exception { Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, - new SSLService(environment.settings(), environment)); - try (MockWebServer proxyServer = new MockWebServer()) { + try (HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, + new SSLService(environment.settings(), environment)); MockWebServer proxyServer = new MockWebServer()) { proxyServer.start(); proxyServer.enqueue(new MockResponse().setResponseCode(200).setBody("fullProxiedContent")); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java index 2a02c5300bd..10618b36e8a 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java @@ -77,6 +77,7 @@ public class HttpClientTests extends ESTestCase { @After public void shutdown() throws Exception { webServer.close(); + httpClient.close(); } public void testBasics() throws Exception { @@ -184,17 +185,18 @@ public class HttpClientTests extends ESTestCase { .setSecureSettings(secureSettings) .build(); } - httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); - secureSettings = new MockSecureSettings(); - // We can't use the client created above for the server since it is only a truststore - secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); - Settings settings2 = Settings.builder() - .put("xpack.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks")) - .setSecureSettings(secureSettings) - .build(); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(settings, environment))) { + secureSettings = new MockSecureSettings(); + // We can't use the client created above for the server since it is only a truststore + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode"); + Settings settings2 = Settings.builder() + .put("xpack.ssl.keystore.path", getDataPath("/org/elasticsearch/xpack/security/keystore/testnode.jks")) + .setSecureSettings(secureSettings) + .build(); - TestsSSLService sslService = new TestsSSLService(settings2, environment); - testSslMockWebserver(sslService.sslContext(), false); + TestsSSLService sslService = new TestsSSLService(settings2, environment); + testSslMockWebserver(client, sslService.sslContext(), false); + } } public void testHttpsDisableHostnameVerification() throws Exception { @@ -217,18 +219,19 @@ public class HttpClientTests extends ESTestCase { .setSecureSettings(secureSettings) .build(); } - httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); - MockSecureSettings secureSettings = new MockSecureSettings(); - // We can't use the client created above for the server since it only defines a truststore - secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode-no-subjaltname"); - Settings settings2 = Settings.builder() - .put("xpack.ssl.keystore.path", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-no-subjaltname.jks")) - .setSecureSettings(secureSettings) - .build(); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(settings, environment))) { + MockSecureSettings secureSettings = new MockSecureSettings(); + // We can't use the client created above for the server since it only defines a truststore + secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode-no-subjaltname"); + Settings settings2 = Settings.builder() + .put("xpack.ssl.keystore.path", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode-no-subjaltname.jks")) + .setSecureSettings(secureSettings) + .build(); - TestsSSLService sslService = new TestsSSLService(settings2, environment); - testSslMockWebserver(sslService.sslContext(), false); + TestsSSLService sslService = new TestsSSLService(settings2, environment); + testSslMockWebserver(client, sslService.sslContext(), false); + } } public void testHttpsClientAuth() throws Exception { @@ -241,11 +244,12 @@ public class HttpClientTests extends ESTestCase { .build(); TestsSSLService sslService = new TestsSSLService(settings, environment); - httpClient = new HttpClient(settings, authRegistry, sslService); - testSslMockWebserver(sslService.sslContext(), true); + try (HttpClient client = new HttpClient(settings, authRegistry, sslService)) { + testSslMockWebserver(client, sslService.sslContext(), true); + } } - private void testSslMockWebserver(SSLContext sslContext, boolean needClientAuth) throws IOException { + private void testSslMockWebserver(HttpClient client, SSLContext sslContext, boolean needClientAuth) throws IOException { try (MockWebServer mockWebServer = new MockWebServer(sslContext, needClientAuth)) { mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody("body")); mockWebServer.start(); @@ -253,7 +257,7 @@ public class HttpClientTests extends ESTestCase { HttpRequest.Builder request = HttpRequest.builder("localhost", mockWebServer.getPort()) .scheme(Scheme.HTTPS) .path("/test"); - HttpResponse response = httpClient.execute(request.build()); + HttpResponse response = client.execute(request.build()); assertThat(response.status(), equalTo(200)); assertThat(response.body().utf8ToString(), equalTo("body")); @@ -288,14 +292,14 @@ public class HttpClientTests extends ESTestCase { @Network public void testHttpsWithoutTruststore() throws Exception { - HttpClient httpClient = new HttpClient(Settings.EMPTY, authRegistry, new SSLService(Settings.EMPTY, environment)); - - // Known server with a valid cert from a commercial CA - HttpRequest.Builder request = HttpRequest.builder("www.elastic.co", 443).scheme(Scheme.HTTPS); - HttpResponse response = httpClient.execute(request.build()); - assertThat(response.status(), equalTo(200)); - assertThat(response.hasContent(), is(true)); - assertThat(response.body(), notNullValue()); + try (HttpClient client = new HttpClient(Settings.EMPTY, authRegistry, new SSLService(Settings.EMPTY, environment))) { + // Known server with a valid cert from a commercial CA + HttpRequest.Builder request = HttpRequest.builder("www.elastic.co", 443).scheme(Scheme.HTTPS); + HttpResponse response = client.execute(request.build()); + assertThat(response.status(), equalTo(200)); + assertThat(response.hasContent(), is(true)); + assertThat(response.body(), notNullValue()); + } } public void testThatProxyCanBeConfigured() throws Exception { @@ -307,15 +311,16 @@ public class HttpClientTests extends ESTestCase { .put(HttpSettings.PROXY_HOST.getKey(), "localhost") .put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort()) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort()) .method(HttpMethod.GET) .path("/"); - HttpResponse response = httpClient.execute(requestBuilder.build()); - assertThat(response.status(), equalTo(200)); - assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(settings, environment))) { + HttpResponse response = client.execute(requestBuilder.build()); + assertThat(response.status(), equalTo(200)); + assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + } // ensure we hit the proxyServer and not the webserver assertThat(webServer.requests(), hasSize(0)); @@ -386,16 +391,16 @@ public class HttpClientTests extends ESTestCase { .setSecureSettings(secureSettings) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); - HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort()) .method(HttpMethod.GET) .scheme(Scheme.HTTP) .path("/"); - HttpResponse response = httpClient.execute(requestBuilder.build()); - assertThat(response.status(), equalTo(200)); - assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(settings, environment))) { + HttpResponse response = client.execute(requestBuilder.build()); + assertThat(response.status(), equalTo(200)); + assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + } // ensure we hit the proxyServer and not the webserver assertThat(webServer.requests(), hasSize(0)); @@ -413,16 +418,17 @@ public class HttpClientTests extends ESTestCase { .put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort() + 1) .put(HttpSettings.PROXY_HOST.getKey(), "https") .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, new SSLService(settings, environment)); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort()) .method(HttpMethod.GET) .proxy(new HttpProxy("localhost", proxyServer.getPort(), Scheme.HTTP)) .path("/"); - HttpResponse response = httpClient.execute(requestBuilder.build()); - assertThat(response.status(), equalTo(200)); - assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(settings, environment))) { + HttpResponse response = client.execute(requestBuilder.build()); + assertThat(response.status(), equalTo(200)); + assertThat(response.body().utf8ToString(), equalTo("fullProxiedContent")); + } // ensure we hit the proxyServer and not the webserver assertThat(webServer.requests(), hasSize(0)); @@ -535,12 +541,13 @@ public class HttpClientTests extends ESTestCase { Settings settings = Settings.builder() .put(HttpSettings.MAX_HTTP_RESPONSE_SIZE.getKey(), new ByteSizeValue(randomBytesLength - 1, ByteSizeUnit.BYTES)) .build(); - HttpClient httpClient = new HttpClient(settings, authRegistry, new SSLService(environment.settings(), environment)); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort()).method(HttpMethod.GET).path("/"); - IOException e = expectThrows(IOException.class, () -> httpClient.execute(requestBuilder.build())); - assertThat(e.getMessage(), startsWith("Maximum limit of")); + try (HttpClient client = new HttpClient(settings, authRegistry, new SSLService(environment.settings(), environment))) { + IOException e = expectThrows(IOException.class, () -> client.execute(requestBuilder.build())); + assertThat(e.getMessage(), startsWith("Maximum limit of")); + } } public void testThatGetRedirectIsFollowed() throws Exception { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpReadTimeoutTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpReadTimeoutTests.java index 2d134681e8b..fa5a53f4e1d 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpReadTimeoutTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpReadTimeoutTests.java @@ -40,66 +40,69 @@ public class HttpReadTimeoutTests extends ESTestCase { public void testDefaultTimeout() throws Exception { Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), - new SSLService(environment.settings(), environment)); - HttpRequest request = HttpRequest.builder("localhost", webServer.getPort()) .method(HttpMethod.POST) .path("/") .build(); - long start = System.nanoTime(); - expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); - TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); - logger.info("http connection timed out after {}", timeout); + try (HttpClient httpClient = new HttpClient(Settings.EMPTY, mock(HttpAuthRegistry.class), + new SSLService(environment.settings(), environment))) { + long start = System.nanoTime(); - // it's supposed to be 10, but we'll give it an error margin of 2 seconds - assertThat(timeout.seconds(), greaterThan(8L)); - assertThat(timeout.seconds(), lessThan(12L)); + expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); + TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); + logger.info("http connection timed out after {}", timeout); + + // it's supposed to be 10, but we'll give it an error margin of 2 seconds + assertThat(timeout.seconds(), greaterThan(8L)); + assertThat(timeout.seconds(), lessThan(12L)); + } } public void testDefaultTimeoutCustom() throws Exception { Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.builder() - .put("xpack.http.default_read_timeout", "3s").build() - , mock(HttpAuthRegistry.class), new SSLService(environment.settings(), environment)); - HttpRequest request = HttpRequest.builder("localhost", webServer.getPort()) .method(HttpMethod.POST) .path("/") .build(); - long start = System.nanoTime(); - expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); - TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); - logger.info("http connection timed out after {}", timeout); + try (HttpClient httpClient = new HttpClient(Settings.builder() + .put("xpack.http.default_read_timeout", "3s").build() + , mock(HttpAuthRegistry.class), new SSLService(environment.settings(), environment))) { - // it's supposed to be 3, but we'll give it an error margin of 2 seconds - assertThat(timeout.seconds(), greaterThan(1L)); - assertThat(timeout.seconds(), lessThan(5L)); + long start = System.nanoTime(); + expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); + TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); + logger.info("http connection timed out after {}", timeout); + + // it's supposed to be 3, but we'll give it an error margin of 2 seconds + assertThat(timeout.seconds(), greaterThan(1L)); + assertThat(timeout.seconds(), lessThan(5L)); + } } public void testTimeoutCustomPerRequest() throws Exception { Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()); - HttpClient httpClient = new HttpClient(Settings.builder() - .put("xpack.http.default_read_timeout", "10s").build() - , mock(HttpAuthRegistry.class), new SSLService(environment.settings(), environment)); - HttpRequest request = HttpRequest.builder("localhost", webServer.getPort()) .readTimeout(TimeValue.timeValueSeconds(3)) .method(HttpMethod.POST) .path("/") .build(); - long start = System.nanoTime(); - expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); - TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); - logger.info("http connection timed out after {}", timeout); + try (HttpClient httpClient = new HttpClient(Settings.builder() + .put("xpack.http.default_read_timeout", "10s").build() + , mock(HttpAuthRegistry.class), new SSLService(environment.settings(), environment))) { - // it's supposed to be 3, but we'll give it an error margin of 2 seconds - assertThat(timeout.seconds(), greaterThan(1L)); - assertThat(timeout.seconds(), lessThan(5L)); + long start = System.nanoTime(); + expectThrows(SocketTimeoutException.class, () -> httpClient.execute(request)); + TimeValue timeout = TimeValue.timeValueNanos(System.nanoTime() - start); + logger.info("http connection timed out after {}", timeout); + + // it's supposed to be 3, but we'll give it an error margin of 2 seconds + assertThat(timeout.seconds(), greaterThan(1L)); + assertThat(timeout.seconds(), lessThan(5L)); + } } } diff --git a/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java b/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java index 48a8ba7e228..4808700604d 100644 --- a/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java +++ b/x-pack/qa/full-cluster-restart/src/test/java/org/elasticsearch/xpack/restart/FullClusterRestartIT.java @@ -23,7 +23,7 @@ import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.xpack.core.monitoring.exporter.MonitoringTemplateUtils; import org.elasticsearch.xpack.core.watcher.client.WatchSourceBuilder; import org.elasticsearch.xpack.core.watcher.support.xcontent.ObjectPath; -import org.elasticsearch.xpack.security.support.IndexLifecycleManager; +import org.elasticsearch.xpack.security.support.SecurityIndexManager; import org.elasticsearch.xpack.test.rest.XPackRestTestHelper; import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction; import org.elasticsearch.xpack.watcher.common.text.TextTemplate; @@ -138,7 +138,7 @@ public class FullClusterRestartIT extends ESRestTestCase { logger.info("settings map {}", settingsMap); if (settingsMap.containsKey("index")) { int format = Integer.parseInt(String.valueOf(((Map)settingsMap.get("index")).get("format"))); - needsUpgrade = format == IndexLifecycleManager.INTERNAL_INDEX_FORMAT ? false : true; + needsUpgrade = format == SecurityIndexManager.INTERNAL_INDEX_FORMAT ? false : true; } else { needsUpgrade = true; } diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/UpgradeClusterClientYamlTestSuiteIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/UpgradeClusterClientYamlTestSuiteIT.java index c9ad4b3053c..6040de8f50c 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/UpgradeClusterClientYamlTestSuiteIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/UpgradeClusterClientYamlTestSuiteIT.java @@ -8,6 +8,7 @@ package org.elasticsearch.upgrades; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite; +import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TimeUnits; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; @@ -29,6 +30,7 @@ import static java.util.Collections.singletonMap; import static org.hamcrest.Matchers.is; @TimeoutSuite(millis = 5 * TimeUnits.MINUTE) // to account for slow as hell VMs +@LuceneTestCase.AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/30456") public class UpgradeClusterClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase { /**