Skip to content

Commit 1157224

Browse files
committed
Merge remote-tracking branch 'es/7.x' into enrich-7.x
2 parents b170b76 + 154d1dd commit 1157224

File tree

353 files changed

+12127
-2832
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

353 files changed

+12127
-2832
lines changed

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import static org.elasticsearch.gradle.tool.Boilerplate.maybeConfigure
3333

3434
plugins {
3535
id 'com.gradle.build-scan' version '2.4'
36-
id 'base'
36+
id 'lifecycle-base'
3737
id 'elasticsearch.global-build-info'
3838
}
3939

@@ -179,8 +179,8 @@ task verifyVersions {
179179
* after the backport of the backcompat code is complete.
180180
*/
181181

182-
boolean bwc_tests_enabled = true
183-
final String bwc_tests_disabled_issue = "" /* place a PR link here when committing bwc changes */
182+
boolean bwc_tests_enabled = false
183+
final String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/45767"
184184
if (bwc_tests_enabled == false) {
185185
if (bwc_tests_disabled_issue.isEmpty()) {
186186
throw new GradleException("bwc_tests_disabled_issue must be set when bwc_tests_enabled == false")

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919
package org.elasticsearch.gradle
2020

21-
2221
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
2322
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
2423
import groovy.transform.CompileDynamic
@@ -48,7 +47,6 @@ import org.gradle.api.artifacts.ModuleVersionIdentifier
4847
import org.gradle.api.artifacts.ProjectDependency
4948
import org.gradle.api.artifacts.ResolvedArtifact
5049
import org.gradle.api.artifacts.dsl.RepositoryHandler
51-
import org.gradle.api.artifacts.repositories.ArtifactRepository
5250
import org.gradle.api.artifacts.repositories.IvyArtifactRepository
5351
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout
5452
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
@@ -408,11 +406,11 @@ class BuildPlugin implements Plugin<Project> {
408406
project.getRepositories().all { repository ->
409407
if (repository instanceof MavenArtifactRepository) {
410408
final MavenArtifactRepository maven = (MavenArtifactRepository) repository
411-
assertRepositoryURIUsesHttps(maven, project, maven.getUrl())
412-
repository.getArtifactUrls().each { uri -> assertRepositoryURIUsesHttps(maven, project, uri) }
409+
assertRepositoryURIIsSecure(maven.name, project.path, maven.getUrl())
410+
repository.getArtifactUrls().each { uri -> assertRepositoryURIIsSecure(maven.name, project.path, uri) }
413411
} else if (repository instanceof IvyArtifactRepository) {
414412
final IvyArtifactRepository ivy = (IvyArtifactRepository) repository
415-
assertRepositoryURIUsesHttps(ivy, project, ivy.getUrl())
413+
assertRepositoryURIIsSecure(ivy.name, project.path, ivy.getUrl())
416414
}
417415
}
418416
RepositoryHandler repos = project.repositories
@@ -452,9 +450,15 @@ class BuildPlugin implements Plugin<Project> {
452450
}
453451
}
454452

455-
private static void assertRepositoryURIUsesHttps(final ArtifactRepository repository, final Project project, final URI uri) {
456-
if (uri != null && uri.toURL().getProtocol().equals("http")) {
457-
throw new GradleException("repository [${repository.name}] on project with path [${project.path}] is using http for artifacts on [${uri.toURL()}]")
453+
static void assertRepositoryURIIsSecure(final String repositoryName, final String projectPath, final URI uri) {
454+
if (uri != null && ["file", "https", "s3"].contains(uri.getScheme()) == false) {
455+
final String message = String.format(
456+
Locale.ROOT,
457+
"repository [%s] on project with path [%s] is not using a secure protocol for artifacts on [%s]",
458+
repositoryName,
459+
projectPath,
460+
uri.toURL())
461+
throw new GradleException(message)
458462
}
459463
}
460464

buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/SnippetsTask.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public class SnippetsTask extends DefaultTask {
123123
}
124124
}
125125
if (snippet.testResponse
126-
&& 'js' == snippet.language
126+
&& ('js' == snippet.language || 'console-result' == snippet.language)
127127
&& null == snippet.skip) {
128128
String quoted = snippet.contents
129129
// quote values starting with $
@@ -162,7 +162,7 @@ public class SnippetsTask extends DefaultTask {
162162
}
163163
return
164164
}
165-
matcher = line =~ /\["?source"?,\s*"?(\w+)"?(,.*)?].*/
165+
matcher = line =~ /\["?source"?,\s*"?([-\w]+)"?(,.*)?].*/
166166
if (matcher.matches()) {
167167
lastLanguage = matcher.group(1)
168168
lastLanguageLine = lineNumber

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ class ClusterFormationTasks {
387387
Map esConfig = [
388388
'cluster.name' : node.clusterName,
389389
'node.name' : "node-" + node.nodeNum,
390-
'pidfile' : node.pidFile,
390+
(node.nodeVersion.onOrAfter('7.4.0') ? 'node.pidfile' : 'pidfile') : node.pidFile,
391391
'path.repo' : "${node.sharedDir}/repo",
392392
'path.shared_data' : "${node.sharedDir}/",
393393
// Define a node attribute so we can test that it exists

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ public class ElasticsearchNode implements TestClusterConfiguration {
105105
"is a pre-release version of Elasticsearch",
106106
"max virtual memory areas vm.max_map_count"
107107
);
108+
private static final String HOSTNAME_OVERRIDE = "LinuxDarwinHostname";
109+
private static final String COMPUTERNAME_OVERRIDE = "WindowsComputername";
108110

109111
private final String path;
110112
private final String name;
@@ -604,6 +606,10 @@ private Map<String, String> getESEnvironment() {
604606
// Windows requires this as it defaults to `c:\windows` despite ES_TMPDIR
605607
defaultEnv.put("TMP", tmpDir.toString());
606608

609+
// Override the system hostname variables for testing
610+
defaultEnv.put("HOSTNAME", HOSTNAME_OVERRIDE);
611+
defaultEnv.put("COMPUTERNAME", COMPUTERNAME_OVERRIDE);
612+
607613
Set<String> commonKeys = new HashSet<>(environment.keySet());
608614
commonKeys.retainAll(defaultEnv.keySet());
609615
if (commonKeys.isEmpty() == false) {

buildSrc/src/test/groovy/org/elasticsearch/gradle/BuildPluginTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
import org.gradle.api.GradleException;
2323
import org.junit.Test;
2424

25+
import java.net.URI;
26+
import java.net.URISyntaxException;
27+
2528

2629
public class BuildPluginTests extends GradleUnitTestCase {
2730

@@ -36,4 +39,25 @@ public void testFailingDockerVersions() {
3639
BuildPlugin.checkDockerVersionRecent("Docker version 17.04.0, build e68fc7a");
3740
}
3841

42+
@Test(expected = GradleException.class)
43+
public void testRepositoryURIThatUsesHttpScheme() throws URISyntaxException {
44+
final URI uri = new URI("http://s3.amazonaws.com/artifacts.elastic.co/maven");
45+
BuildPlugin.assertRepositoryURIIsSecure("test", "test", uri);
46+
}
47+
48+
public void testRepositoryThatUsesFileScheme() throws URISyntaxException {
49+
final URI uri = new URI("file:/tmp/maven");
50+
BuildPlugin.assertRepositoryURIIsSecure("test", "test", uri);
51+
}
52+
53+
public void testRepositoryURIThatUsesHttpsScheme() throws URISyntaxException {
54+
final URI uri = new URI("https://s3.amazonaws.com/artifacts.elastic.co/maven");
55+
BuildPlugin.assertRepositoryURIIsSecure("test", "test", uri);
56+
}
57+
58+
public void testRepositoryURIThatUsesS3Scheme() throws URISyntaxException {
59+
final URI uri = new URI("s3://artifacts.elastic.co/maven");
60+
BuildPlugin.assertRepositoryURIIsSecure("test", "test", uri);
61+
}
62+
3963
}

buildSrc/src/test/java/org/elasticsearch/gradle/BuildPluginIT.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,29 @@
1818
*/
1919
package org.elasticsearch.gradle;
2020

21+
import org.apache.commons.io.FileUtils;
2122
import org.apache.commons.io.IOUtils;
2223
import org.elasticsearch.gradle.test.GradleIntegrationTestCase;
2324
import org.gradle.testkit.runner.BuildResult;
25+
import org.gradle.testkit.runner.GradleRunner;
26+
import org.junit.Rule;
27+
import org.junit.rules.TemporaryFolder;
2428

2529
import java.io.File;
2630
import java.io.IOException;
2731
import java.io.InputStream;
2832
import java.nio.charset.StandardCharsets;
33+
import java.nio.file.Files;
34+
import java.util.Arrays;
35+
import java.util.List;
2936
import java.util.zip.ZipEntry;
3037
import java.util.zip.ZipFile;
3138

3239
public class BuildPluginIT extends GradleIntegrationTestCase {
3340

41+
@Rule
42+
public TemporaryFolder tmpDir = new TemporaryFolder();
43+
3444
public void testPluginCanBeApplied() {
3545
BuildResult result = getGradleRunner("elasticsearch.build")
3646
.withArguments("hello", "-s")
@@ -46,6 +56,51 @@ public void testCheckTask() {
4656
assertTaskSuccessful(result, ":check");
4757
}
4858

59+
public void testInsecureMavenRepository() throws IOException {
60+
final String name = "elastic-maven";
61+
final String url = "http://s3.amazonaws.com/artifacts.elastic.co/maven";
62+
// add an insecure maven repository to the build.gradle
63+
final List<String> lines = Arrays.asList(
64+
"repositories {",
65+
" maven {",
66+
" name \"elastic-maven\"",
67+
" url \"" + url + "\"\n",
68+
" }",
69+
"}");
70+
runInsecureArtifactRepositoryTest(name, url, lines);
71+
}
72+
73+
public void testInsecureIvyRepository() throws IOException {
74+
final String name = "elastic-ivy";
75+
final String url = "http://s3.amazonaws.com/artifacts.elastic.co/ivy";
76+
// add an insecure ivy repository to the build.gradle
77+
final List<String> lines = Arrays.asList(
78+
"repositories {",
79+
" ivy {",
80+
" name \"elastic-ivy\"",
81+
" url \"" + url + "\"\n",
82+
" }",
83+
"}");
84+
runInsecureArtifactRepositoryTest(name, url, lines);
85+
}
86+
87+
private void runInsecureArtifactRepositoryTest(final String name, final String url, final List<String> lines) throws IOException {
88+
final File projectDir = getProjectDir("elasticsearch.build");
89+
FileUtils.copyDirectory(projectDir, tmpDir.getRoot(), pathname -> pathname.getPath().contains("/build/") == false);
90+
final List<String> buildGradleLines =
91+
Files.readAllLines(tmpDir.getRoot().toPath().resolve("build.gradle"), StandardCharsets.UTF_8);
92+
buildGradleLines.addAll(lines);
93+
Files.write(tmpDir.getRoot().toPath().resolve("build.gradle"), buildGradleLines, StandardCharsets.UTF_8);
94+
final BuildResult result = GradleRunner.create()
95+
.withProjectDir(tmpDir.getRoot())
96+
.withArguments("clean", "hello", "-s", "-i", "--warning-mode=all", "--scan")
97+
.withPluginClasspath()
98+
.buildAndFail();
99+
assertOutputContains(
100+
result.getOutput(),
101+
"repository [" + name + "] on project with path [:] is not using a secure protocol for artifacts on [" + url + "]");
102+
}
103+
49104
public void testLicenseAndNotice() throws IOException {
50105
BuildResult result = getGradleRunner("elasticsearch.build")
51106
.withArguments("clean", "assemble", "-s", "-Dlocal.repo.path=" + getLocalTestRepoPath())

buildSrc/version.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ slf4j = 1.6.2
2121
jna = 4.5.1
2222

2323
netty = 4.1.38.Final
24-
joda = 2.10.2
24+
joda = 2.10.3
2525

2626
# when updating this version, you need to ensure compatibility with:
2727
# - plugins/ingest-attachment (transitive dependency, check the upstream POM)

client/rest-high-level/build.gradle

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ processTestResources {
7878
from({ zipTree(configurations.restSpec.singleFile) }) {
7979
include 'rest-api-spec/api/**'
8080
}
81+
from(project(':client:rest-high-level').file('src/test/resources'))
8182
}
8283

8384
dependencyLicenses {
@@ -96,6 +97,7 @@ forbiddenApisMain {
9697
}
9798
File nodeCert = file("./testnode.crt")
9899
File nodeTrustStore = file("./testnode.jks")
100+
File pkiTrustCert = file("./src/test/resources/org/elasticsearch/client/security/delegate_pki/testRootCA.crt")
99101

100102
integTest.runner {
101103
systemProperty 'tests.rest.cluster.username', System.getProperty('tests.rest.cluster.username', 'test_user')
@@ -113,11 +115,18 @@ testClusters.integTest {
113115
// Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API
114116
setting 'xpack.security.http.ssl.certificate_authorities', 'testnode.crt'
115117
setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks'
118+
setting 'xpack.security.authc.realms.file.default_file.order', '0'
119+
setting 'xpack.security.authc.realms.native.default_native.order', '1'
120+
setting 'xpack.security.authc.realms.pki.pki1.order', '2'
121+
setting 'xpack.security.authc.realms.pki.pki1.certificate_authorities', '[ "testRootCA.crt" ]'
122+
setting 'xpack.security.authc.realms.pki.pki1.delegation.enabled', 'true'
123+
116124
setting 'indices.lifecycle.poll_interval', '1000ms'
117125
keystore 'xpack.security.transport.ssl.truststore.secure_password', 'testnode'
118126
user username: System.getProperty('tests.rest.cluster.username', 'test_user'),
119127
password: System.getProperty('tests.rest.cluster.password', 'test-password')
120128

121129
extraConfigFile nodeCert.name, nodeCert
122130
extraConfigFile nodeTrustStore.name, nodeTrustStore
131+
extraConfigFile pkiTrustCert.name, pkiTrustCert
123132
}

client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.elasticsearch.client.security.CreateApiKeyResponse;
3232
import org.elasticsearch.client.security.CreateTokenRequest;
3333
import org.elasticsearch.client.security.CreateTokenResponse;
34+
import org.elasticsearch.client.security.DelegatePkiAuthenticationRequest;
35+
import org.elasticsearch.client.security.DelegatePkiAuthenticationResponse;
3436
import org.elasticsearch.client.security.DeletePrivilegesRequest;
3537
import org.elasticsearch.client.security.DeletePrivilegesResponse;
3638
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
@@ -969,4 +971,38 @@ public void invalidateApiKeyAsync(final InvalidateApiKeyRequest request, final R
969971
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::invalidateApiKey, options,
970972
InvalidateApiKeyResponse::fromXContent, listener, emptySet());
971973
}
974+
975+
/**
976+
* Get an Elasticsearch access token from an {@code X509Certificate} chain. The certificate chain is that of the client from a mutually
977+
* authenticated TLS session, and it is validated by the PKI realms with {@code delegation.enabled} toggled to {@code true}.<br>
978+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delegate-pki-authentication.html"> the
979+
* docs</a> for more details.
980+
*
981+
* @param request the request containing the certificate chain
982+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
983+
* @return the response from the delegate-pki-authentication API key call
984+
* @throws IOException in case there is a problem sending the request or parsing back the response
985+
*/
986+
public DelegatePkiAuthenticationResponse delegatePkiAuthentication(DelegatePkiAuthenticationRequest request, RequestOptions options)
987+
throws IOException {
988+
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::delegatePkiAuthentication, options,
989+
DelegatePkiAuthenticationResponse::fromXContent, emptySet());
990+
}
991+
992+
/**
993+
* Asynchronously get an Elasticsearch access token from an {@code X509Certificate} chain. The certificate chain is that of the client
994+
* from a mutually authenticated TLS session, and it is validated by the PKI realms with {@code delegation.enabled} toggled to
995+
* {@code true}.<br>
996+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delegate-pki-authentication.html"> the
997+
* docs</a> for more details.
998+
*
999+
* @param request the request containing the certificate chain
1000+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
1001+
* @param listener the listener to be notified upon request completion
1002+
*/
1003+
public void delegatePkiAuthenticationAsync(DelegatePkiAuthenticationRequest request, RequestOptions options,
1004+
ActionListener<DelegatePkiAuthenticationResponse> listener) {
1005+
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::delegatePkiAuthentication, options,
1006+
DelegatePkiAuthenticationResponse::fromXContent, listener, emptySet());
1007+
}
9721008
}

0 commit comments

Comments
 (0)