/* * Copyright (c) 2019 MarkLogic Corporation */ package com.marklogic.xcc.examples; import java.io.FileInputStream; import java.net.URI; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import com.marklogic.xcc.ContentSource; import com.marklogic.xcc.ContentSourceFactory; import com.marklogic.xcc.Request; import com.marklogic.xcc.ResultSequence; import com.marklogic.xcc.SecurityOptions; import com.marklogic.xcc.Session; /** *

* A version of the Hello World example that connects to a server using SSL/TLS. *

*

* This example can load a specified key store of trusted signing authorities, use the Java default * key store, or use a stub that accepts any server certificate. It can also load client certificates * from a specified key store, or connect without a certificate. *

*

* In part to demonstrate the available configuration options, connections are forced to use TLS with * strong ciphers using 256 bit keys, as might be desirable with highly sensitive data being transmitted * over public networks. *

*

* Click here for the source code for this class. *

*/ public class HelloSecureWorld { public static void main(String[] args) throws Exception { if ((args.length < 2) || (args.length > 4)) { System.err.println("usage: xccs://user:password@host:port/contentbase trustJKS|DEFAULT|ANY [clientJKS [passphrase]]"); System.err.println(); System.err.println("trustJKS may be one of:"); System.err.println(" path to use Java Key Store containing trusted signing authorities."); System.err.println(" DEFAULT to use Java default cacerts file."); System.err.println(" ANY to accept any server certificate."); System.err.println(); System.err.println("clientJKS is optional path to Java Key Store containing client certificates."); System.err.println(); System.err.println("passphrase is optional passphrase for client key store."); return; } // Create a URI object from the supplied argument URI uri = new URI(args[0]); String trustJKS = args[1]; TrustManager[] trustManagers; if (trustJKS.equals("DEFAULT")) { // Use Java defaults. trustManagers = null; } else if (trustJKS.equals("ANY")) { // Trust anyone. trustManagers = new TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // nothing to do } public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // nothing to do } public X509Certificate[] getAcceptedIssuers() { return null; } } }; } else { // Load key store with trusted signing authorities. KeyStore trustedKeyStore = KeyStore.getInstance("JKS"); trustedKeyStore.load(new FileInputStream(args[1]), null); // Build trust manager to validate server certificates using the specified key store. TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); trustManagerFactory.init(trustedKeyStore); trustManagers = trustManagerFactory.getTrustManagers(); } String clientJKS = (args.length > 2) ? args[2] : null; String passphrase = (args.length > 3) ? args[3] : ""; KeyManager[] keyManagers; if (clientJKS == null) { // Don't use client certificate. keyManagers = null; } else { // Load key store with client certificates. KeyStore clientKeyStore = KeyStore.getInstance("JKS"); try (FileInputStream is = new FileInputStream(clientJKS)) { clientKeyStore.load(is, null); } // Get key manager to provide client credentials. KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyManagerFactory.init(clientKeyStore, passphrase.toCharArray()); keyManagers = keyManagerFactory.getKeyManagers(); } // Get an SSLContext that supports the desired protocol; SSLv3 or TLSv1. SSLContext sslContext = SSLContext.getInstance("TLSv1"); // Initialize the SSL context with key and trust managers. sslContext.init(keyManagers, trustManagers, null); // Create a security options object for use by the secure content source. SecurityOptions securityOptions = new SecurityOptions(sslContext); // Limit acceptable protocols; SSLv3 and/or TLSv1 (optional) securityOptions.setEnabledProtocols(new String[] { "TLSv1" }); // Limit acceptable cipher suites. (optional) // See ciphers man page or TLS 1.0 / SSL 3.0 specifications. securityOptions.setEnabledCipherSuites(new String[] { "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA" }); // Obtain a ContentSource object for the server at the URI. // ContentSources can create many Sessions. ContentSources are // tightly bound to a host/port, but user, password and contentbase, // if provided, are defaults and may be overridden for each Session. ContentSource contentSource = ContentSourceFactory.newContentSource(uri, securityOptions); // Create a Session, which encapsulates host, port, user and // password, and an optional contentbase id. If Contentbase is // not specified, the default configured on the server for the // host/port will be used. // Sessions represent a dialog with a contentbase and may hold // state related to that dialog. A Session is also the factory // for Request objects. Sessions are lightweight and relatively // cheap to create -- don't bother pooling them, they do not // represent connections. Session session = contentSource.newSession(); // Create an ad-hoc Request, which contains XQuery code to be // evaluated. Requests are mutable and may be re-used repeatedly // and in any order. Request request = session.newAdhocQuery("\"Hello World\""); // Submit the Request and return a new ResultSequence object. // By default, the result will be cached and need not be closed. ResultSequence rs = session.submitRequest(request); // Print the String representation of the ResultSequence. // In this case, there is only one item in the sequence. // Not that "asString()" is different than "toString()". // The asString() method returns the value of the object // after converting it to String form. But toString() // returns a descriptive String that summarizes the state // of an object. System.out.println(rs.asString()); // All done session.close(); } }