Browse Source

Add HLRC docs for AuthN and TLS (#51355)

This commit adds examples in our documentation for

- An HLRC instance authenticating to an elasticsearch cluster using
an elasticsearch token service access token or an API key
- An HLRC instance connecting to an elasticsearch cluster that is
setup for TLS on the HTTP layer when the CA certificate of the
cluster is available either as a PEM file or a keystore
- An HLRC instance connecting to an elasticsearch cluster that
requires client authentication where the client key and certificate
are available in a keystore

Co-Authored-By: Lisa Cawley <lcawley@elastic.co>
Ioannis Kakavas 5 years ago
parent
commit
308f95d9f3

+ 89 - 3
client/rest/src/test/java/org/elasticsearch/client/documentation/RestClientDocumentation.java

@@ -51,10 +51,14 @@ import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLContext;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.Paths;
 import java.security.KeyStore;
 import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.util.Base64;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CountDownLatch;
 
 
@@ -379,11 +383,11 @@ public class RestClientDocumentation {
             //end::rest-client-config-disable-preemptive-auth
             //end::rest-client-config-disable-preemptive-auth
         }
         }
         {
         {
-            Path keyStorePath = Paths.get("");
             String keyStorePass = "";
             String keyStorePass = "";
             //tag::rest-client-config-encrypted-communication
             //tag::rest-client-config-encrypted-communication
-            KeyStore truststore = KeyStore.getInstance("jks");
-            try (InputStream is = Files.newInputStream(keyStorePath)) {
+            Path trustStorePath = Paths.get("/path/to/truststore.p12");
+            KeyStore truststore = KeyStore.getInstance("pkcs12");
+            try (InputStream is = Files.newInputStream(trustStorePath)) {
                 truststore.load(is, keyStorePass.toCharArray());
                 truststore.load(is, keyStorePass.toCharArray());
             }
             }
             SSLContextBuilder sslBuilder = SSLContexts.custom()
             SSLContextBuilder sslBuilder = SSLContexts.custom()
@@ -400,5 +404,87 @@ public class RestClientDocumentation {
                 });
                 });
             //end::rest-client-config-encrypted-communication
             //end::rest-client-config-encrypted-communication
         }
         }
+        {
+            //tag::rest-client-config-trust-ca-pem
+            Path caCertificatePath = Paths.get("/path/to/ca.crt");
+            CertificateFactory factory =
+                CertificateFactory.getInstance("X.509");
+            Certificate trustedCa;
+            try (InputStream is = Files.newInputStream(caCertificatePath)) {
+                trustedCa = factory.generateCertificate(is);
+            }
+            KeyStore trustStore = KeyStore.getInstance("pkcs12");
+            trustStore.load(null, null);
+            trustStore.setCertificateEntry("ca", trustedCa);
+            SSLContextBuilder sslContextBuilder = SSLContexts.custom()
+                .loadTrustMaterial(trustStore, null);
+            final SSLContext sslContext = sslContextBuilder.build();
+            RestClient.builder(
+                new HttpHost("localhost", 9200, "https"))
+                .setHttpClientConfigCallback(new HttpClientConfigCallback() {
+                    @Override
+                    public HttpAsyncClientBuilder customizeHttpClient(
+                        HttpAsyncClientBuilder httpClientBuilder) {
+                        return httpClientBuilder.setSSLContext(sslContext);
+                    }
+                });
+            //end::rest-client-config-trust-ca-pem
+        }
+        {
+            String trustStorePass = "";
+            String keyStorePass = "";
+            //tag::rest-client-config-mutual-tls-authentication
+            Path trustStorePath = Paths.get("/path/to/your/truststore.p12");
+            Path keyStorePath = Paths.get("/path/to/your/keystore.p12");
+            KeyStore trustStore = KeyStore.getInstance("pkcs12");
+            KeyStore keyStore = KeyStore.getInstance("pkcs12");
+            try (InputStream is = Files.newInputStream(trustStorePath)) {
+                trustStore.load(is, trustStorePass.toCharArray());
+            }
+            try (InputStream is = Files.newInputStream(keyStorePath)) {
+                keyStore.load(is, keyStorePass.toCharArray());
+            }
+            SSLContextBuilder sslBuilder = SSLContexts.custom()
+                .loadTrustMaterial(trustStore, null)
+                .loadKeyMaterial(keyStore, keyStorePass.toCharArray());
+            final SSLContext sslContext = sslBuilder.build();
+            RestClientBuilder builder = RestClient.builder(
+                new HttpHost("localhost", 9200, "https"))
+                .setHttpClientConfigCallback(new HttpClientConfigCallback() {
+                    @Override
+                    public HttpAsyncClientBuilder customizeHttpClient(
+                        HttpAsyncClientBuilder httpClientBuilder) {
+                        return httpClientBuilder.setSSLContext(sslContext);
+                    }
+                });
+            //end::rest-client-config-mutual-tls-authentication
+        }
+        {
+            //tag::rest-client-auth-bearer-token
+            RestClientBuilder builder = RestClient.builder(
+                new HttpHost("localhost", 9200, "http"));
+            Header[] defaultHeaders =
+                new Header[]{new BasicHeader("Authorization",
+                    "Bearer u6iuAxZ0RG1Kcm5jVFI4eU4tZU9aVFEwT2F3")};
+            builder.setDefaultHeaders(defaultHeaders);
+            //end::rest-client-auth-bearer-token
+        }
+        {
+            //tag::rest-client-auth-api-key
+            String apiKeyId = "uqlEyn8B_gQ_jlvwDIvM";
+            String apiKeySecret = "HxHWk2m4RN-V_qg9cDpuX";
+            String apiKeyAuth =
+                Base64.getEncoder().encodeToString(
+                    (apiKeyId + ":" + apiKeySecret)
+                        .getBytes(StandardCharsets.UTF_8));
+            RestClientBuilder builder = RestClient.builder(
+                new HttpHost("localhost", 9200, "http"));
+            Header[] defaultHeaders =
+                new Header[]{new BasicHeader("Authorization",
+                    "ApiKey " + apiKeyAuth)};
+            builder.setDefaultHeaders(defaultHeaders);
+            //end::rest-client-auth-api-key
+        }
+
     }
     }
 }
 }

+ 56 - 2
docs/java-rest/low-level/configuration.asciidoc

@@ -64,21 +64,75 @@ include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-disa
 --------------------------------------------------
 --------------------------------------------------
 <1> Disable preemptive authentication
 <1> Disable preemptive authentication
 
 
+=== Other authentication methods
+
+==== Elasticsearch Token Service tokens
+
+If you want the client to authenticate with an Elasticsearch access token, set the relevant HTTP request header.
+If the client makes requests on behalf of a single user only, you can set the necessary `Authorization` header as a default header as shown
+in the following example:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-auth-bearer-token]
+--------------------------------------------------
+
+==== Elasticsearch API keys
+
+If you want the client to authenticate with an Elasticsearch API key, set the relevant HTTP request header.
+If the client makes requests on behalf of a single user only, you can set the necessary `Authorization` header as a default header as shown
+in the following example:
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-auth-api-key]
+--------------------------------------------------
+
 === Encrypted communication
 === Encrypted communication
 
 
-Encrypted communication can also be configured through the
+Encrypted communication using TLS can also be configured through the
 `HttpClientConfigCallback`. The
 `HttpClientConfigCallback`. The
 https://hc.apache.org/httpcomponents-asyncclient-dev/httpasyncclient/apidocs/org/apache/http/impl/nio/client/HttpAsyncClientBuilder.html[`org.apache.http.impl.nio.client.HttpAsyncClientBuilder`]
 https://hc.apache.org/httpcomponents-asyncclient-dev/httpasyncclient/apidocs/org/apache/http/impl/nio/client/HttpAsyncClientBuilder.html[`org.apache.http.impl.nio.client.HttpAsyncClientBuilder`]
  received as an argument exposes multiple methods to configure encrypted
  received as an argument exposes multiple methods to configure encrypted
  communication: `setSSLContext`, `setSSLSessionStrategy` and
  communication: `setSSLContext`, `setSSLSessionStrategy` and
  `setConnectionManager`, in order of precedence from the least important.
  `setConnectionManager`, in order of precedence from the least important.
- The following is an example:
+
+When accessing an Elasticsearch cluster that is setup for TLS on the HTTP layer, the client needs to trust the certificate that
+Elasticsearch is using.
+ The following is an example of setting up the client to trust the CA that has signed the certificate that Elasticsearch is using, when
+ that CA certificate is available in a PKCS#12 keystore:
 
 
 ["source","java",subs="attributes,callouts,macros"]
 ["source","java",subs="attributes,callouts,macros"]
 --------------------------------------------------
 --------------------------------------------------
 include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-encrypted-communication]
 include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-encrypted-communication]
 --------------------------------------------------
 --------------------------------------------------
 
 
+The following is an example of setting up the client to trust the CA that has signed the certificate that Elasticsearch is using, when
+that CA certificate is available as a PEM encoded file.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-trust-ca-pem]
+--------------------------------------------------
+
+When Elasticsearch is configured to require client TLS authentication, for example when a PKI realm is configured, the client needs to provide
+a client certificate during the TLS handshake in order to authenticate. The following is an example of setting up the client for TLS
+authentication with a certificate and a private key that are stored in a PKCS#12 keystore.
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-mutual-tls-authentication]
+--------------------------------------------------
+
+If the client certificate and key are not available in a keystore but rather as PEM encoded files, you cannot use them
+directly to build an SSLContext. You must rely on external libraries to parse the PEM key into a PrivateKey instance. Alternatively, you
+can use external tools to build a keystore from your PEM files, as shown in the following example:
+
+```
+openssl pkcs12 -export -in client.crt -inkey private_key.pem \
+        -name "client" -out client.p12
+```
+
 If no explicit configuration is provided, the http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores[system default configuration]
 If no explicit configuration is provided, the http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores[system default configuration]
 will be used.
 will be used.