From 55eaf7a3ff83d032fd4f2263e144113909d1b2bd Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Mon, 15 Oct 2018 17:20:34 +0100 Subject: [PATCH] HLRC: Get SSL Certificates API (#34135) This change adds support for the get SSL certificate API to the high level rest client. --- client/rest-high-level/build.gradle | 8 ++ .../elasticsearch/client/SecurityClient.java | 29 ++++ .../security/GetSslCertificatesRequest.java | 49 +++++++ .../security/GetSslCertificatesResponse.java | 68 +++++++++ .../security/support/CertificateInfo.java | 133 ++++++++++++++++++ .../client/RestHighLevelClientTests.java | 16 ++- .../SecurityDocumentationIT.java | 86 +++++++++++ client/rest-high-level/testnode.crt | 23 +++ client/rest-high-level/testnode.jks | Bin 0 -> 9360 bytes .../security/get-certificates.asciidoc | 53 +++++++ .../high-level/supported-apis.asciidoc | 2 + 11 files changed, 462 insertions(+), 5 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesResponse.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/CertificateInfo.java create mode 100644 client/rest-high-level/testnode.crt create mode 100644 client/rest-high-level/testnode.jks create mode 100644 docs/java-rest/high-level/security/get-certificates.asciidoc diff --git a/client/rest-high-level/build.gradle b/client/rest-high-level/build.gradle index c608d7c91f16e..bfe7c3d956cd2 100644 --- a/client/rest-high-level/build.gradle +++ b/client/rest-high-level/build.gradle @@ -76,6 +76,8 @@ forbiddenApisMain { addSignatureFiles 'http-signatures' signaturesFiles += files('src/main/resources/forbidden/rest-high-level-signatures.txt') } +File nodeCert = file("./testnode.crt") +File nodeTrustStore = file("./testnode.jks") integTestRunner { systemProperty 'tests.rest.cluster.username', System.getProperty('tests.rest.cluster.username', 'test_user') @@ -85,11 +87,17 @@ integTestRunner { integTestCluster { setting 'xpack.license.self_generated.type', 'trial' setting 'xpack.security.enabled', 'true' + // Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API + setting 'xpack.ssl.certificate_authorities', 'testnode.crt' + setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks' + setting 'xpack.security.transport.ssl.truststore.password', 'testnode' setupCommand 'setupDummyUser', 'bin/elasticsearch-users', 'useradd', System.getProperty('tests.rest.cluster.username', 'test_user'), '-p', System.getProperty('tests.rest.cluster.password', 'test-password'), '-r', 'superuser' + extraConfigFile nodeCert.name, nodeCert + extraConfigFile nodeTrustStore.name, nodeTrustStore waitCondition = { node, ant -> File tmpFile = new File(node.cwd, 'wait.success') ant.get(src: "http://${node.httpUri()}/_cluster/health?wait_for_nodes=>=${numNodes}&wait_for_status=yellow", diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java index 7192d82f474a8..8afaa3551ad88 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java @@ -22,6 +22,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.client.security.DisableUserRequest; import org.elasticsearch.client.security.EnableUserRequest; +import org.elasticsearch.client.security.GetSslCertificatesRequest; +import org.elasticsearch.client.security.GetSslCertificatesResponse; import org.elasticsearch.client.security.PutUserRequest; import org.elasticsearch.client.security.PutUserResponse; import org.elasticsearch.client.security.EmptyResponse; @@ -133,6 +135,33 @@ public void disableUserAsync(DisableUserRequest request, RequestOptions options, EmptyResponse::fromXContent, listener, emptySet()); } + /** + * Synchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster. + * See + * the docs for more. + * + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response from the get certificates call + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public GetSslCertificatesResponse getSslCertificates(RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(GetSslCertificatesRequest.INSTANCE, GetSslCertificatesRequest::getRequest, + options, GetSslCertificatesResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster. + * See + * the docs for more. + * + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + */ + public void getSslCertificatesAsync(RequestOptions options, ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(GetSslCertificatesRequest.INSTANCE, GetSslCertificatesRequest::getRequest, + options, GetSslCertificatesResponse::fromXContent, listener, emptySet()); + } + /** * Change the password of a user of a native realm or built-in user synchronously. * See diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesRequest.java new file mode 100644 index 0000000000000..c4dbef4e422b6 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesRequest.java @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.security; + +import org.apache.http.client.methods.HttpGet; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Validatable; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; + +/** + * Request object to retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster. + */ +public final class GetSslCertificatesRequest implements Validatable, ToXContentObject { + + public static final GetSslCertificatesRequest INSTANCE = new GetSslCertificatesRequest(); + private final Request request; + + private GetSslCertificatesRequest() { + request = new Request(HttpGet.METHOD_NAME, "/_xpack/ssl/certificates"); + } + + public Request getRequest() { + return request; + } + + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject().endObject(); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesResponse.java new file mode 100644 index 0000000000000..80f016b3ae1bf --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/GetSslCertificatesResponse.java @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.security; + +import org.elasticsearch.client.security.support.CertificateInfo; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Response object when retrieving the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster. + * Returns a list of {@link CertificateInfo} objects describing each of the certificates. + */ +public final class GetSslCertificatesResponse { + + private final List certificates; + + public GetSslCertificatesResponse(List certificates) { + this.certificates = certificates; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final GetSslCertificatesResponse that = (GetSslCertificatesResponse) o; + return Objects.equals(this.certificates, that.certificates); + } + + @Override + public int hashCode() { + return Objects.hash(certificates); + } + + public static GetSslCertificatesResponse fromXContent(XContentParser parser) throws IOException { + List certificates = new ArrayList<>(); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser::getTokenLocation); + while (parser.nextToken() != XContentParser.Token.END_ARRAY) { + certificates.add(CertificateInfo.PARSER.parse(parser, null)); + } + return new GetSslCertificatesResponse(certificates); + } + + public List getCertificates() { + return certificates; + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/CertificateInfo.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/CertificateInfo.java new file mode 100644 index 0000000000000..28fd1c61c0d5c --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/security/support/CertificateInfo.java @@ -0,0 +1,133 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.security.support; + +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.Objects; + +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + +/** + * Simple model of an X.509 certificate + */ +public final class CertificateInfo { + public static final ParseField PATH = new ParseField("path"); + public static final ParseField FORMAT = new ParseField("format"); + public static final ParseField ALIAS = new ParseField("alias"); + public static final ParseField SUBJECT_DN = new ParseField("subject_dn"); + public static final ParseField SERIAL_NUMBER = new ParseField("serial_number"); + public static final ParseField HAS_PRIVATE_KEY = new ParseField("has_private_key"); + public static final ParseField EXPIRY = new ParseField("expiry"); + + private final String path; + private final String format; + private final String alias; + private final String subjectDn; + private final String serialNumber; + private final boolean hasPrivateKey; + private final String expiry; + + public CertificateInfo(String path, String format, @Nullable String alias, String subjectDn, String serialNumber, boolean hasPrivateKey, + String expiry) { + this.path = path; + this.format = format; + this.alias = alias; + this.subjectDn = subjectDn; + this.serialNumber = serialNumber; + this.hasPrivateKey = hasPrivateKey; + this.expiry = expiry; + } + + public String getPath() { + return path; + } + + public String getFormat() { + return format; + } + + public String getAlias() { + return alias; + } + + public String getSubjectDn() { + return subjectDn; + } + + public String getSerialNumber() { + return serialNumber; + } + + public boolean isHasPrivateKey() { + return hasPrivateKey; + } + + public String getExpiry() { + return expiry; + } + + @SuppressWarnings("unchecked") + public static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("certificate_info", + true, args -> new CertificateInfo((String) args[0], (String) args[1], (String) args[2], (String) args[3], (String) args[4], + (boolean) args[5], (String) args[6])); + + static { + PARSER.declareString(constructorArg(), PATH); + PARSER.declareString(constructorArg(), FORMAT); + PARSER.declareStringOrNull(constructorArg(), ALIAS); + PARSER.declareString(constructorArg(), SUBJECT_DN); + PARSER.declareString(constructorArg(), SERIAL_NUMBER); + PARSER.declareBoolean(constructorArg(), HAS_PRIVATE_KEY); + PARSER.declareString(constructorArg(), EXPIRY); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + final CertificateInfo that = (CertificateInfo) other; + return this.path.equals(that.path) + && this.format.equals(that.format) + && this.hasPrivateKey == that.hasPrivateKey + && Objects.equals(this.alias, that.alias) + && this.serialNumber.equals(that.serialNumber) + && this.subjectDn.equals(that.subjectDn) + && this.expiry.equals(that.expiry); + } + + @Override + public int hashCode() { + return Objects.hash(path, format, alias, subjectDn, serialNumber, hasPrivateKey, expiry); + } + + public static CertificateInfo fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java index acdfc50b5a13a..fda7ecdd6d6a2 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java @@ -721,10 +721,16 @@ public void testApiNamingConventions() throws Exception { methods.containsKey(apiName.substring(0, apiName.length() - 6))); assertThat(method.getReturnType(), equalTo(Void.TYPE)); assertEquals(0, method.getExceptionTypes().length); - assertEquals(3, method.getParameterTypes().length); - assertThat(method.getParameterTypes()[0].getSimpleName(), endsWith("Request")); - assertThat(method.getParameterTypes()[1], equalTo(RequestOptions.class)); - assertThat(method.getParameterTypes()[2], equalTo(ActionListener.class)); + if (apiName.equals("security.get_ssl_certificates_async")) { + assertEquals(2, method.getParameterTypes().length); + assertThat(method.getParameterTypes()[0], equalTo(RequestOptions.class)); + assertThat(method.getParameterTypes()[1], equalTo(ActionListener.class)); + } else { + assertEquals(3, method.getParameterTypes().length); + assertThat(method.getParameterTypes()[0].getSimpleName(), endsWith("Request")); + assertThat(method.getParameterTypes()[1], equalTo(RequestOptions.class)); + assertThat(method.getParameterTypes()[2], equalTo(ActionListener.class)); + } } else { //A few methods return a boolean rather than a response object if (apiName.equals("ping") || apiName.contains("exist")) { @@ -735,7 +741,7 @@ public void testApiNamingConventions() throws Exception { assertEquals(1, method.getExceptionTypes().length); //a few methods don't accept a request object as argument - if (apiName.equals("ping") || apiName.equals("info")) { + if (apiName.equals("ping") || apiName.equals("info") || apiName.equals("security.get_ssl_certificates")) { assertEquals(1, method.getParameterTypes().length); assertThat(method.getParameterTypes()[0], equalTo(RequestOptions.class)); } else { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java index 778ec7b5707cd..f80cbb0e67fa3 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SecurityDocumentationIT.java @@ -27,12 +27,17 @@ import org.elasticsearch.client.security.ChangePasswordRequest; import org.elasticsearch.client.security.DisableUserRequest; import org.elasticsearch.client.security.EnableUserRequest; +import org.elasticsearch.client.security.GetSslCertificatesResponse; import org.elasticsearch.client.security.PutUserRequest; import org.elasticsearch.client.security.PutUserResponse; import org.elasticsearch.client.security.RefreshPolicy; import org.elasticsearch.client.security.EmptyResponse; +import org.elasticsearch.client.security.support.CertificateInfo; +import org.hamcrest.Matchers; import java.util.Collections; +import java.util.Iterator; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -175,6 +180,87 @@ public void onFailure(Exception e) { } } + public void testGetSslCertificates() throws Exception { + RestHighLevelClient client = highLevelClient(); + { + //tag::get-certificates-execute + GetSslCertificatesResponse response = client.security().getSslCertificates(RequestOptions.DEFAULT); + //end::get-certificates-execute + + assertNotNull(response); + + //tag::get-certificates-response + List certificates = response.getCertificates(); // <1> + //end::get-certificates-response + + assertThat(certificates.size(), Matchers.equalTo(9)); + final Iterator it = certificates.iterator(); + CertificateInfo c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=testnode-client-profile")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=Elasticsearch Test Node, OU=elasticsearch, O=org")); + assertThat(c.getPath(), Matchers.equalTo("testnode.crt")); + assertThat(c.getFormat(), Matchers.equalTo("PEM")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=OpenLDAP, OU=Elasticsearch, O=Elastic, L=Mountain View, ST=CA, C=US")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=Elasticsearch Test Node, OU=elasticsearch, O=org")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=Elasticsearch Test Client, OU=elasticsearch, O=org")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=ad-ELASTICSEARCHAD-CA, DC=ad, DC=test, DC=elasticsearch, DC=com")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=Elasticsearch Test Node")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=samba4")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + c = it.next(); + assertThat(c.getSubjectDn(), Matchers.equalTo("CN=Elasticsearch Test Node")); + assertThat(c.getPath(), Matchers.equalTo("testnode.jks")); + assertThat(c.getFormat(), Matchers.equalTo("jks")); + } + + { + // tag::get-certificates-execute-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(GetSslCertificatesResponse getSslCertificatesResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + + // end::get-certificates-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::get-certificates-execute-async + client.security().getSslCertificatesAsync(RequestOptions.DEFAULT, listener); // <1> + // end::end-certificates-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + public void testChangePassword() throws Exception { RestHighLevelClient client = highLevelClient(); char[] password = new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; diff --git a/client/rest-high-level/testnode.crt b/client/rest-high-level/testnode.crt new file mode 100644 index 0000000000000..08c160bcea5ff --- /dev/null +++ b/client/rest-high-level/testnode.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID0zCCArugAwIBAgIJALi5bDfjMszLMA0GCSqGSIb3DQEBCwUAMEgxDDAKBgNV +BAoTA29yZzEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEgMB4GA1UEAxMXRWxhc3Rp +Y3NlYXJjaCBUZXN0IE5vZGUwHhcNMTUwOTIzMTg1MjU3WhcNMTkwOTIyMTg1MjU3 +WjBIMQwwCgYDVQQKEwNvcmcxFjAUBgNVBAsTDWVsYXN0aWNzZWFyY2gxIDAeBgNV +BAMTF0VsYXN0aWNzZWFyY2ggVGVzdCBOb2RlMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3rGZ1QbsW0+MuyrSLmMfDFKtLBkIFW8V0gRuurFg1PUKKNR1 +Mq2tMVwjjYETAU/UY0iKZOzjgvYPKhDTYBTte/WHR1ZK4CYVv7TQX/gtFQG/ge/c +7u0sLch9p7fbd+/HZiLS/rBEZDIohvgUvzvnA8+OIYnw4kuxKo/5iboAIS41klMg +/lATm8V71LMY68inht71/ZkQoAHKgcR9z4yNYvQ1WqKG8DG8KROXltll3sTrKbl5 +zJhn660es/1ZnR6nvwt6xnSTl/mNHMjkfv1bs4rJ/py3qPxicdoSIn/KyojUcgHV +F38fuAy2CQTdjVG5fWj9iz+mQvLm3+qsIYQdFwIDAQABo4G/MIG8MAkGA1UdEwQC +MAAwHQYDVR0OBBYEFEMMWLWQi/g83PzlHYqAVnty5L7HMIGPBgNVHREEgYcwgYSC +CWxvY2FsaG9zdIIVbG9jYWxob3N0LmxvY2FsZG9tYWluggpsb2NhbGhvc3Q0ghds +b2NhbGhvc3Q0LmxvY2FsZG9tYWluNIIKbG9jYWxob3N0NoIXbG9jYWxob3N0Ni5s +b2NhbGRvbWFpbjaHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL +BQADggEBAMjGGXT8Nt1tbl2GkiKtmiuGE2Ej66YuZ37WSJViaRNDVHLlg87TCcHe +k2rdO+6sFqQbbzEfwQ05T7xGmVu7tm54HwKMRugoQ3wct0bQC5wEWYN+oMDvSyO6 +M28mZwWb4VtR2IRyWP+ve5DHwTM9mxWa6rBlGzsQqH6YkJpZojzqk/mQTug+Y8aE +mVoqRIPMHq9ob+S9qd5lp09+MtYpwPfTPx/NN+xMEooXWW/ARfpGhWPkg/FuCu4z +1tFmCqHgNcWirzMm3dQpF78muE9ng6OB2MXQwL4VgnVkxmlZNHbkR2v/t8MyZJxC +y4g6cTMM3S/UMt5/+aIB2JAuMKyuD+A= +-----END CERTIFICATE----- diff --git a/client/rest-high-level/testnode.jks b/client/rest-high-level/testnode.jks new file mode 100644 index 0000000000000000000000000000000000000000..ebe6146124e8fd607e46a1a3129bdf9b4de0370d GIT binary patch literal 9360 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 literal 0 HcmV?d00001 diff --git a/docs/java-rest/high-level/security/get-certificates.asciidoc b/docs/java-rest/high-level/security/get-certificates.asciidoc new file mode 100644 index 0000000000000..6820b1564fb8e --- /dev/null +++ b/docs/java-rest/high-level/security/get-certificates.asciidoc @@ -0,0 +1,53 @@ +[[java-rest-high-security-get-certificates]] +=== SSL Certificate API + +[[java-rest-high-security-get-certificates-execution]] +==== Execution + +The X.509 Certificates that are used to encrypt communications in an +Elasticsearch cluster using the `security().getSslCertificates()` method: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-certificates-execute] +-------------------------------------------------- + +[[java-rest-high-security-get-certificates-response]] +==== Response + +The returned `GetSslCertificatesResponse` contains a single field, `certificates`. +This field, accessed with `getCertificates` returns a List of `CertificateInfo` +objects containing the information for all the certificates used. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-certificates-response] +-------------------------------------------------- +<1> `certificates` is a List of `CertificateInfo` + +[[java-rest-high-security-get-certificates-execute-async]] +==== Asynchronous Execution + +This request can be executed asynchronously using the `security().getSslCertificatesAsync()` +method: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-certificates-execute-async] +-------------------------------------------------- +<1> The `ActionListener` to use when the execution completes. + +The asynchronous method does not block and returns immediately. Once the request +has completed the `ActionListener` is called back using the `onResponse` method +if the execution successfully completed or using the `onFailure` method if +it failed. + +A typical listener for a `GetSslCertificatesResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SecurityDocumentationIT.java[get-certificates-execute-listener] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument. +<2> Called in case of failure. The raised exception is provided as an argument. diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 4046a6fced175..b5bb41e981d57 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -305,11 +305,13 @@ The Java High Level REST Client supports the following Security APIs: * <> * <> * <> +* <> include::security/put-user.asciidoc[] include::security/enable-user.asciidoc[] include::security/disable-user.asciidoc[] include::security/change-password.asciidoc[] +include::security/get-certificates.asciidoc[] == Watcher APIs