All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.marklogic.client.DatabaseClientFactory Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
/*
 * Copyright 2012-2019 MarkLogic Corporation
 *
 * Licensed 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 com.marklogic.client;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;

import com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator;
import com.marklogic.client.extra.httpclient.HttpClientConfigurator;
import com.marklogic.client.impl.DatabaseClientImpl;
import com.marklogic.client.impl.HandleFactoryRegistryImpl;
import com.marklogic.client.impl.OkHttpServices;
import com.marklogic.client.io.marker.ContentHandle;
import com.marklogic.client.io.marker.ContentHandleFactory;

/**
 * A Database Client Factory configures a database client for making
 * database requests.
 */
public class DatabaseClientFactory {

  static private ClientConfigurator clientConfigurator;
  static private HandleFactoryRegistry handleRegistry =
    HandleFactoryRegistryImpl.newDefault();

  /**
   * Authentication enumerates the methods for verifying a user and
   * password with the database.
   * @deprecated (as of 4.0.1) use BasicAuthContext, DigestAuthContext and KerberosAuthContext classes
   */
  @Deprecated
  public enum Authentication {
    /**
     * Minimal security unless used with SSL.
     */
    BASIC,
    /**
     * Moderate security without SSL.
     */
    DIGEST,
    /**
     * Authentication using Kerberos.
     */
    KERBEROS,
    /**
     * Authentication using Certificates;
     */
    CERTIFICATE,
	/**
	 * Authentication using SAML;
	 */
	SAML;
    /**
     * Returns the enumerated value for the case-insensitive name.
     * @param name	the name of the enumerated value
     * @return	the enumerated value
     */
    static public Authentication valueOfUncased(String name) {
      return Authentication.valueOf(name.toUpperCase());
    }
  }

  /**
   * An SSLHostnameVerifier checks whether a hostname is acceptable during SSL
   * authentication.  By default, {@link #COMMON} is used, allowing any level
   * of subdomains for SSL certificates with wildcard domains.  If only one
   * level of subdomains is allowed for SSL certificates with wildcard domains,
   * use {@link #STRICT}.
   */
  public interface SSLHostnameVerifier {
    /**
     * The ANY SSLHostnameVerifier allows any hostname, which can be useful
     * during initial development when a valid SSL certificate is not available
     * but is not recommended for production because it would permit an invalid
     * SSL certificate.
     */
    final static public Builtin ANY    = new Builtin("ANY");
    /**
     * The COMMON SSLHostnameVerifier applies common rules for checking
     * hostnames during SSL authentication (similar to
     * org.apache.http.conn.ssl.BrowserCompatHostnameVerifier). It allows any
     * level of subdomains for SSL certificates with wildcard domains.
     */
    final static public Builtin COMMON = new Builtin("COMMON");
    /**
     * The STRICT SSLHostnameVerifier applies strict rules
     * for checking hostnames during SSL authentication (similar to
     * org.apache.http.conn.ssl.StrictHostnameVerifier).  It allows one level
     * of subdomain for SSL certificates with wildcard domains like RFC 2818.
     */
    final static public Builtin STRICT = new Builtin("STRICT");

    /**
     * Checks during SSL authentication that a hostname matches the Common Name
     * or "DNS" Subject alts from the SSL certificate presented by the server.
     * @param hostname	the DNS host name of the server
     * @param cns	common names from the SSL certificate presented by the server
     * @param subjectAlts	alternative subject names from the SSL certificate presented by the server
     * @throws SSLException if the hostname isn't acceptable
     */
    public void verify(String hostname, String[] cns, String[] subjectAlts) throws SSLException;
    
    /**
     * HostnameVerifierAdapter verifies the hostname,SSLSession and X509Certificate certificate.
     * */
    static class HostnameVerifierAdapter implements HostnameVerifier {
    	private SSLHostnameVerifier verifier;

    	public HostnameVerifierAdapter(SSLHostnameVerifier verifier) {
	          this.verifier = verifier;
	        }
    	/**
    	 * verify method verifies the incoming hostname and SSLSession.
    	 * @param hostname denotes the hostname.
    	 * @param session represents the SSLSession containing the pper certificates.
    	 * @return true if the hostname and peer certificates are valid and false if they are invalid.
    	 * */
    	@Override
    	public boolean verify(String hostname, SSLSession session) {
    		try {
    			Certificate[] certificates = session.getPeerCertificates();
	            verify(hostname, (X509Certificate) certificates[0]);
	            return true;
	          } catch(SSLException e) {
	            return false;
	          }
	        }
    	/**
    	 * verify method verifies the hostname and X509Certificate certificate.
    	 * @param hostname denotes the hostname.
    	 * @param cert represents the X509Certificate certificate.
    	 * @throws SSLException if the hostname or certificate is/are invalid.
    	 * */
    	public void verify(String hostname, X509Certificate cert) throws SSLException {
    		ArrayList cnArray = new ArrayList<>();
    		try {
    			LdapName ldapDN = new LdapName(cert.getSubjectX500Principal().getName());
	            for(Rdn rdn: ldapDN.getRdns()) {
	              Object value = rdn.getValue();
	              if ( "CN".equalsIgnoreCase(rdn.getType()) && value instanceof String ) {
	                cnArray.add((String) value);
	              }
	            }
	            int type_dnsName = 2;
	            int type_ipAddress = 7;
	            ArrayList subjectAltArray = new ArrayList<>();
	            Collection> alts = cert.getSubjectAlternativeNames();
	            if ( alts != null ) {
	              for ( List alt : alts ) {
	                if ( alt != null && alt.size() == 2 && alt.get(1) instanceof String ) {
	                  Integer type = (Integer) alt.get(0);
	                  if ( type == type_dnsName || type == type_ipAddress ) {
	                    subjectAltArray.add((String) alt.get(1));
	                  }
	                }
	              }
	            }
	            String[] cns = cnArray.toArray(new String[cnArray.size()]);
	            String[] subjectAlts = subjectAltArray.toArray(new String[subjectAltArray.size()]);
	            verifier.verify(hostname, cns, subjectAlts);
	          } 
    		catch(CertificateParsingException e) {
	            throw new MarkLogicIOException(e);
	          } 
    		catch(InvalidNameException e) {
	            throw new MarkLogicIOException(e);
	          }
	        }
	   }

    /**
     * Builtin supports builtin implementations of SSLHostnameVerifier.
     */
    public class Builtin implements SSLHostnameVerifier {
      private String name;
      private Builtin(String name) {
        super();
        this.name = name;
      }
      @Override
      public void verify(String hostname, String[] cns, String[] subjectAlts) throws SSLException {
        throw new MarkLogicInternalException(
          "SSLHostnameVerifier.Builtin called directly instead of passed as parameter");
      }
      /**
       * Returns the name of the built-in.
       * @return	the built-in name
       */
      public String getName() {
        return name;
      }
      
    }
  }

  /**
   * A HandleFactoryRegistry associates IO representation classes
   * with handle factories. The API uses the registry to create
   * a content handle to act as an adapter for a supported
   * IO representation class.  The IO class and its instances can
   * then be passed directly to convenience methods.
   * The default registry associates the content handles provided
   * by the API and the supported IO representation classes.
   * Create instances of this interface only if you need to modify
   * the default registry.
   * @see DatabaseClientFactory#getHandleRegistry()
   * @see DatabaseClientFactory.Bean#getHandleRegistry()
   */
  public interface HandleFactoryRegistry {
    /**
     * Associates a factory for content handles with the classes
     * for IO representations known to the factory.
     * @param factory	a factory for creating content handle instances
     */
    public void register(ContentHandleFactory factory);
    /**
     * Associates a factory for content handles with the specified classes
     * for IO representations.
     * @param factory	a factory for creating content handle instances
     * @param ioClasses	the IO classes for which the factory should create handles
     */
    public void register(ContentHandleFactory factory, Class... ioClasses);
    /**
     * Returns whether the registry associates the class with a factory.
     * @param ioClass	the class for an IO representation
     * @return	true if a factory has been registered
     */
    public boolean isRegistered(Class ioClass);
    /**
     * Returns the classes for the IO representations for which a factory
     * has been registered.
     * @return	the IO classes
     */
    public Set> listRegistered();
    /**
     * Creates a ContentHandle if the registry has a factory
     * for the class of the IO representation.
     * @param type	the class for an IO representation
     * @param  the registered type for the returned handle
     * @return	a content handle or null if no factory supports the class
     */
    public  ContentHandle makeHandle(Class type);
    /**
     * Removes the classes from the registry
     * @param ioClasses	one or more registered classes for an IO representation
     */
    public void unregister(Class... ioClasses);
    /**
     * Create a copy of the current registry
     * @return	a copy of the current registry
     */
    public HandleFactoryRegistry copy();
  }

  /**
   * A ClientConfigurator provides custom configuration for the communication library
   * used to sending client requests and receiving server responses.
   * @see com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator
   * @param 	the configurable class for the communication library
   */
  public interface ClientConfigurator {
    /**
     * Called as the last step in configuring the communication library.
     * @param client	the configurable object for the communication library
     */
    public void configure(T client);
  }

  private DatabaseClientFactory() {
  }

  public interface SecurityContext {
    /**
     * Returns the SSLContext for an SSL client.
     * @return	the SSL context
     */
    SSLContext getSSLContext();

    /**
     * Set the context without a trust manager
     * @param context - the SSLContext object required for the SSL connection
     * @deprecated	(as of 4.0.1) use SecurityContext.withSSLContext(SSLContext,X509TrustManager)
     */
    @Deprecated
    void setSSLContext(SSLContext context);

    /*
     * Returns the host verifier.
     * @return	the host verifier
     */
    SSLHostnameVerifier getSSLHostnameVerifier();

    /**
     * Specifies the host verifier for a client that verifies hosts for
     * additional security.
     * @param verifier	the host verifier
     */
    void setSSLHostnameVerifier(SSLHostnameVerifier verifier);

    /**
     * Set the context without a trust manager
     * @param context - the SSLContext object required for the SSL connection
     * @deprecated	(as of 4.0.1) use SecurityContext.withSSLContext(SSLContext,X509TrustManager)
     * @return a context containing authentication information
     */
    @Deprecated
    SecurityContext withSSLContext(SSLContext context);

    /**
     * The SSLContext should be initialized with KeyManager and TrustManager
     * using a KeyStore. 
*
* * If we init the sslContext with null TrustManager, it would use the * <java-home>/lib/security/cacerts file for trusted root certificates, if * javax.net.ssl.trustStore system property is not set and * <java-home>/lib/security/jssecacerts is not present. See JSSE * Reference Guide for more information on SSL and TrustManagers.
*
* * If self signed certificates, signed by CAs created internally are used, * then the internal CA's root certificate should be added to the keystore. * See this link * for adding a root certificate in the keystore. * * @param context - the SSLContext object required for the SSL connection * @param trustManager - X509TrustManager with which we initialize the * SSLContext * @return a context containing authentication information */ SecurityContext withSSLContext(SSLContext context, X509TrustManager trustManager); /** * Specifies the host verifier for a client that verifies hosts for * additional security. * @param verifier the host verifier * @return a context configured with the host verifier */ SecurityContext withSSLHostnameVerifier(SSLHostnameVerifier verifier); } private static class AuthContext implements SecurityContext { SSLContext sslContext; X509TrustManager trustManager; SSLHostnameVerifier sslVerifier; @Override public SSLContext getSSLContext() { return sslContext; } @Override @Deprecated public void setSSLContext(SSLContext context) { this.sslContext = context; } @Override public SSLHostnameVerifier getSSLHostnameVerifier() { return sslVerifier; } @Override public void setSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; } public X509TrustManager getTrustManager() { return this.trustManager; } @Override @Deprecated public SecurityContext withSSLContext(SSLContext context) { this.sslContext = context; return this; } @Override public SecurityContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } @Override public SecurityContext withSSLContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; return this; } } public static class BasicAuthContext extends AuthContext { String user; String password; public BasicAuthContext(String user, String password) { this.user = user; this.password = password; } public String getUser() { return user; } public String getPassword() { return password; } @Override @Deprecated public BasicAuthContext withSSLContext(SSLContext context) { this.sslContext = context; return this; } @Override public BasicAuthContext withSSLContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; return this; } @Override public BasicAuthContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } } public static class DigestAuthContext extends AuthContext { String user; String password; public DigestAuthContext(String user, String password) { this.user = user; this.password = password; } public String getUser() { return user; } public String getPassword() { return password; } @Override @Deprecated public DigestAuthContext withSSLContext(SSLContext context) { this.sslContext = context; return this; } @Override public DigestAuthContext withSSLContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; return this; } @Override public DigestAuthContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } } public static class KerberosAuthContext extends AuthContext { Map krbOptions; public Map getKrbOptions() { return krbOptions; } public KerberosAuthContext() { krbOptions = Collections.unmodifiableMap(new KerberosConfig().toOptions()); } public KerberosAuthContext(String principal) { krbOptions = Collections.unmodifiableMap(new KerberosConfig().withPrincipal(principal).toOptions()); } public KerberosAuthContext(KerberosConfig krbConfig) { krbOptions = Collections.unmodifiableMap(krbConfig.toOptions()); } @Override @Deprecated public KerberosAuthContext withSSLContext(SSLContext context) { this.sslContext = context; return this; } @Override public KerberosAuthContext withSSLContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; return this; } @Override public KerberosAuthContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } } /** * A SAMLAuthContext is used for authorization using SAML. * It consists of a authorization token each with an expiration time stamp. * SAMLAuthContext asks for a new token with a new expiration time stamp if * the previous token expires and the session is still valid. */ public static class SAMLAuthContext implements SecurityContext { private String token; private SSLContext sslContext; private X509TrustManager trustManager; private SSLHostnameVerifier sslVerifier; private AuthorizerCallback authorizer; private ExpiringSAMLAuth authorization; private RenewerCallback renewer; /** * @return the X509TrustManagerused for authentication. */ public X509TrustManager getTrustManager() { return trustManager; } /** * Replaces the token with new SAML authorization token. */ public SAMLAuthContext(String authorizationToken) { this.token = authorizationToken; } public SAMLAuthContext(AuthorizerCallback authorizer) { this.authorizer = authorizer; } public SAMLAuthContext(ExpiringSAMLAuth authorization, RenewerCallback renewer) { this.authorization = authorization; this.renewer = renewer; } /** * @return the SAML authentication token. */ public String getToken() { return token; } public AuthorizerCallback getAuthorizer() { return authorizer; } public RenewerCallback getRenewer() { return renewer; } public ExpiringSAMLAuth getAuthorization() { return authorization; } /** * ExpiringSAMLAuth is used by SAMLAuthContext for reauthorization. */ public interface ExpiringSAMLAuth { /** * @return a new SAML assertion token. */ public String getAuthorizationToken(); /** * @return the expiration time stamp of the newly generated SAML assertion token. */ public Instant getExpiry(); } /** * newExpiringSAMLAuth is used to provide a new token with a new expiration time stamp. * @param authorizationToken refers to the new SAML token. * @param expiry refers to the expiration time stamp of authorizationToken. * @return an ExpiringSAMLAuth instance. */ public static ExpiringSAMLAuth newExpiringSAMLAuth(final String authorizationToken, final Instant expiry) { return new ExpiringSAMLAuth() { @Override public Instant getExpiry() { return expiry; } @Override public String getAuthorizationToken() { return authorizationToken; } }; } @FunctionalInterface public interface AuthorizerCallback extends Function { } @FunctionalInterface public interface RenewerCallback extends Function { } @Override public SAMLAuthContext withSSLContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; return this; } @Override public SAMLAuthContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } @Override public SSLContext getSSLContext() { return sslContext; } @Override @Deprecated public void setSSLContext(SSLContext context) { this.sslContext = context; } @Override public SSLHostnameVerifier getSSLHostnameVerifier() { return sslVerifier; } @Override public void setSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; } @Override @Deprecated public SecurityContext withSSLContext(SSLContext context) { this.sslContext = context; return this; } } public static class KerberosConfig { private boolean refreshKrb5Config; private String principal = null; private boolean useTicketCache = true; private String ticketCache = null; private boolean renewTGT = false; private boolean doNotPrompt = true; private boolean useKeyTab = false; private String keyTab = null; private boolean storeKey = false; private boolean isInitiator = true; private boolean useFirstPass = false; private boolean tryFirstPass = false; private boolean storePass = false; private boolean clearPass = false; private boolean debug = false; public KerberosConfig() { } public KerberosConfig withRefreshKrb5Config(boolean refreshKrb5Config) { this.refreshKrb5Config = refreshKrb5Config; return this; } public String getRefreshKrb5Config() { return String.valueOf(this.refreshKrb5Config); } public KerberosConfig withPrincipal(String principal) { this.principal = principal; return this; } public String getPrincipal() { return this.principal; } public KerberosConfig withUseTicketCache(boolean useTicketCache) { this.useTicketCache = useTicketCache; return this; } public String getUseTicketCache() { return String.valueOf(this.useTicketCache); } public KerberosConfig withTicketCache(String ticketCache) { this.ticketCache = ticketCache; return this; } public String getTicketCache() { return this.ticketCache; } public KerberosConfig withRenewTGT(boolean renewTGT) { this.renewTGT = renewTGT; return this; } public String getRenewTGT() { return String.valueOf(this.renewTGT); } public KerberosConfig withDoNotPrompt(boolean doNotPrompt) { this.doNotPrompt = doNotPrompt; return this; } public String getDoNotPrompt() { return String.valueOf(this.doNotPrompt); } public KerberosConfig withUseKeyTab(boolean useKeyTab) { this.useKeyTab = useKeyTab; return this; } public String getUseKeyTab() { return String.valueOf(this.useKeyTab); } public KerberosConfig withKeyTab(String keyTab) { this.keyTab = keyTab; return this; } public String getKeyTab() { return this.keyTab; } public KerberosConfig withStoreKey(boolean storeKey) { this.storeKey = storeKey; return this; } public String getStoreKey() { return String.valueOf(this.storeKey); } public KerberosConfig withUseFirstPass(boolean useFirstPass) { this.useFirstPass = useFirstPass; return this; } public String getUseFirstPass() { return String.valueOf(this.useFirstPass); } public KerberosConfig withTryFirstPass(boolean tryFirstPass) { this.tryFirstPass = tryFirstPass; return this; } public String getTryFirstPass() { return String.valueOf(this.tryFirstPass); } public KerberosConfig withStorePass(boolean storePass) { this.storePass = storePass; return this; } public String getStorePass() { return String.valueOf(this.storePass); } public KerberosConfig withClearPass(boolean clearPass) { this.clearPass = clearPass; return this; } public String getClearPass() { return String.valueOf(this.clearPass); } public KerberosConfig withInitiator(boolean initiator) { this.isInitiator = initiator; return this; } public String getInitiator() { return String.valueOf(this.isInitiator); } public KerberosConfig withDebug(boolean debug) { this.debug = debug; return this; } public String getDebug() { return String.valueOf(this.debug); } public Map toOptions() { Map options = new HashMap<>(); options.put("refreshKrb5Config", getRefreshKrb5Config()); if (getPrincipal() != null) options.put("principal", getPrincipal()); options.put("useTicketCache", getUseTicketCache()); if (getUseTicketCache().equals("true") && getTicketCache() != null) options.put("ticketCache", getTicketCache()); options.put("renewTGT", getRenewTGT()); options.put("doNotPrompt", getDoNotPrompt()); options.put("useKeyTab", getUseKeyTab()); if (getUseKeyTab().equals("true") && getKeyTab() != null) options.put("keyTab", getKeyTab()); options.put("storeKey", getStoreKey()); options.put("useFirstPass", getUseFirstPass()); options.put("tryFirstPass", getTryFirstPass()); options.put("storePass", getStorePass()); options.put("clearPass", getClearPass()); options.put("isInitiator", getInitiator()); options.put("debug", getDebug()); return options; } } public static class CertificateAuthContext extends AuthContext { String certFile; String certPassword; /** * Creates a CertificateAuthContext by initializing the SSLContext * of the HTTPS channel with the SSLContext object passed. The KeyManager of * the SSLContext should be initialized with the appropriate client * certificate and client's private key * @param context the SSLContext with which we initialize the * CertificateAuthContext * @deprecated (as of 4.0.1) use CertificateAuthContext(SSLContext,X509TrustManager) */ @Deprecated public CertificateAuthContext(SSLContext context) { this.sslContext = context; } /** * Creates a CertificateAuthContext by initializing the SSLContext of the * HTTPS channel with the SSLContext object passed and using the TrustManger * passed. The KeyManager of the SSLContext should be initialized with the * appropriate client certificate and client's private key * * @param context the SSLContext with which we initialize the * CertificateAuthContext * @param trustManager the X509TrustManager object which is responsible for * deciding if a credential should be trusted or not. */ public CertificateAuthContext(SSLContext context, X509TrustManager trustManager) { this.sslContext = context; this.trustManager = trustManager; } /** * Creates a CertificateAuthContext by initializing the SSLContext * of the HTTPS channel with the SSLContext object passed and assigns the * SSLHostnameVerifier passed to be used for checking host names. The KeyManager of * the SSLContext should be initialized with the appropriate client * certificate and client's private key * @param context the SSLContext with which we initialize the * CertificateAuthContext * @param verifier a callback for checking host names * @deprecated (as of 4.0.1) use CertificateAuthContext(SSLContext,SSLHostnameVerifier,X509TrustManager) */ @Deprecated public CertificateAuthContext(SSLContext context, SSLHostnameVerifier verifier) { this.sslContext = context; this.sslVerifier = verifier; } /** * Creates a CertificateAuthContext by initializing the SSLContext of the * HTTPS channel with the SSLContext object passed and assigns the * SSLHostnameVerifier passed to be used for checking host names. The * KeyManager of the SSLContext should be initialized with the appropriate * client certificate and client's private key * * @param context the SSLContext with which we initialize the * CertificateAuthContext * @param verifier a callback for checking host names * @param trustManager the X509TrustManager object which is responsible for * deciding if a credential should be trusted or not. */ public CertificateAuthContext(SSLContext context, SSLHostnameVerifier verifier, X509TrustManager trustManager) { this.sslContext = context; this.sslVerifier = verifier; this.trustManager = trustManager; } /** * Creates a CertificateAuthContext with a PKCS12 file. The SSLContext is * created from the information in the PKCS12 file. This constructor should * be called when the export password of the PKCS12 file is empty. * * @param certFile the p12 file which contains the client's private key and * the client's certificate chain * @throws CertificateException if any of the certificates in the certFile * cannot be loaded * @throws UnrecoverableKeyException if the certFile has an export password * @throws KeyManagementException if initializing the SSLContext with the * KeyManager fails * @throws IOException if there is an I/O or format problem with the * keystore data, if a password is required but not given, or if * the given password was incorrect or if the certFile path is * invalid or if the file is not found If the error is due to a * wrong password, the cause of the IOException should be an * UnrecoverableKeyException. */ @Deprecated public CertificateAuthContext(String certFile) throws CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { this.certFile = certFile; this.certPassword = ""; this.sslContext = createSSLContext(); } /** * Creates a CertificateAuthContext with a PKCS12 file. The SSLContext is * created from the information in the PKCS12 file. This constructor should * be called when the export password of the PKCS12 file is empty. * * @param certFile the p12 file which contains the client's private key and * the client's certificate chain * @param trustManager the X509TrustManager object which is responsible for * deciding if a credential should be trusted or not. * @throws CertificateException if any of the certificates in the certFile * cannot be loaded * @throws UnrecoverableKeyException if the certFile has an export password * @throws KeyManagementException if initializing the SSLContext with the * KeyManager fails * @throws IOException if there is an I/O or format problem with the * keystore data, if a password is required but not given, or if * the given password was incorrect or if the certFile path is * invalid or if the file is not found If the error is due to a * wrong password, the cause of the IOException should be an * UnrecoverableKeyException. */ public CertificateAuthContext(String certFile, X509TrustManager trustManager) throws CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { this.certFile = certFile; this.trustManager = trustManager; this.certPassword = ""; this.sslContext = createSSLContext(); } /** * Creates a CertificateAuthContext with a PKCS12 file. The SSLContext * is created from the information in the PKCS12 file. This constructor * should be called when the export password of the PKCS12 file is non-empty. * @param certFile the p12 file which contains the client's private key * and the client's certificate chain * @param certPassword the export password of the p12 file * @throws CertificateException if any of the certificates in the certFile cannot be loaded * @throws UnrecoverableKeyException if the certFile has an export password * @throws KeyManagementException if initializing the SSLContext with the KeyManager fails * @throws IOException if there is an I/O or format problem with the keystore data, * if a password is required but not given, or if the given password was * incorrect or if the certFile path is invalid or if the file is not found * If the error is due to a wrong password, the cause of the IOException * should be an UnrecoverableKeyException. */ @Deprecated public CertificateAuthContext(String certFile, String certPassword) throws CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { this.certFile = certFile; this.certPassword = certPassword; this.sslContext = createSSLContext(); } /** * Creates a CertificateAuthContext with a PKCS12 file. The SSLContext * is created from the information in the PKCS12 file. This constructor * should be called when the export password of the PKCS12 file is non-empty. * @param certFile the p12 file which contains the client's private key * and the client's certificate chain * @param trustManager the X509TrustManager object which is responsible for * deciding if a credential should be trusted or not. * @param certPassword the export password of the p12 file * @throws CertificateException if any of the certificates in the certFile cannot be loaded * @throws UnrecoverableKeyException if the certFile has an export password * @throws KeyManagementException if initializing the SSLContext with the KeyManager fails * @throws IOException if there is an I/O or format problem with the keystore data, * if a password is required but not given, or if the given password was * incorrect or if the certFile path is invalid or if the file is not found * If the error is due to a wrong password, the cause of the IOException * should be an UnrecoverableKeyException. */ public CertificateAuthContext(String certFile, String certPassword, X509TrustManager trustManager) throws CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { this.certFile = certFile; this.certPassword = certPassword; this.trustManager = trustManager; this.sslContext = createSSLContext(); } private SSLContext createSSLContext() throws CertificateException, IOException, UnrecoverableKeyException, KeyManagementException { if(certPassword == null) { throw new IllegalArgumentException("Certificate export password must not be null"); } KeyStore keyStore = null; KeyManagerFactory keyManagerFactory = null; KeyManager[] keyMgr = null; try { keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException( "CertificateAuthContext requires KeyManagerFactory.getInstance(\"SunX509\")"); } try { keyStore = KeyStore.getInstance("PKCS12"); } catch (KeyStoreException e) { throw new IllegalStateException("CertificateAuthContext requires KeyStore.getInstance(\"PKCS12\")"); } try { FileInputStream certFileStream = new FileInputStream(certFile); try { keyStore.load(certFileStream, certPassword.toCharArray()); } finally { if (certFileStream != null) certFileStream.close(); } keyManagerFactory.init(keyStore, certPassword.toCharArray()); keyMgr = keyManagerFactory.getKeyManagers(); sslContext = SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException | KeyStoreException e) { throw new IllegalStateException("The certificate algorithm used or the Key store " + "Service provider Implementaion (SPI) is invalid. CertificateAuthContext " + "requires SunX509 algorithm and PKCS12 Key store SPI", e); } TrustManager[] trustManagers = trustManager == null ? null : new TrustManager[] {trustManager}; sslContext.init(keyMgr, trustManagers, null); return sslContext; } @Override public CertificateAuthContext withSSLHostnameVerifier(SSLHostnameVerifier verifier) { this.sslVerifier = verifier; return this; } public String getCertificate() { return certFile; } public String getCertificatePassword() { return certPassword; } } /** * Creates a client to access the database by means of a REST server * without any authentication. Such clients can be convenient for * experimentation but should not be used in production. * * @param host the host with the REST server * @param port the port for the REST server * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port) { return newClient(host, port, null, null, null, null, null, null); } /** * Creates a client to access the database by means of a REST server * without any authentication. Such clients can be convenient for * experimentation but should not be used in production. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for the REST server) * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port, String database) { return newClient(host, port, database, null, null, null, null, null); } /** * Creates a client to access the database by means of a REST server. * * @param host the host with the REST server * @param port the port for the REST server * @param securityContext the security context created depending upon the * authentication type - BasicAuthContext, DigestAuthContext or KerberosAuthContext * and communication channel type (SSL) * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port, SecurityContext securityContext) { return newClient(host, port, null, securityContext, null); } /** * Creates a client to access the database by means of a REST server. * * @param host the host with the REST server * @param port the port for the REST server * @param securityContext the security context created depending upon the * authentication type - BasicAuthContext, DigestAuthContext or KerberosAuthContext * and communication channel type (SSL) * @param connectionType whether the client connects directly to the MarkLogic host * or using a gateway such as a load balancer * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port, SecurityContext securityContext, DatabaseClient.ConnectionType connectionType) { return newClient(host, port, null, securityContext, connectionType); } /** * Creates a client to access the database by means of a REST server. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for * the REST server) * @param securityContext the security context created depending upon the * authentication type - BasicAuthContext, DigestAuthContext or KerberosAuthContext * and communication channel type (SSL) * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port, String database, SecurityContext securityContext) { return newClient(host, port, database, securityContext, null); } /** * Creates a client to access the database by means of a REST server. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for * the REST server) * @param securityContext the security context created depending upon the * authentication type - BasicAuthContext, DigestAuthContext or KerberosAuthContext * and communication channel type (SSL) * @param connectionType whether the client connects directly to the MarkLogic host * or using a gateway such as a load balancer * @return a new client for making database requests */ static public DatabaseClient newClient(String host, int port, String database, SecurityContext securityContext, DatabaseClient.ConnectionType connectionType) { OkHttpServices services = new OkHttpServices(); services.connect(host, port, database, securityContext); if (clientConfigurator != null) { if ( clientConfigurator instanceof OkHttpClientConfigurator ) { OkHttpClient client = services.getClientImplementation(); OkHttpClient.Builder clientBuilder = client.newBuilder(); ((OkHttpClientConfigurator) clientConfigurator).configure( clientBuilder ); ((OkHttpServices) services).setClientImplementation(clientBuilder.build()); } else if ( clientConfigurator instanceof HttpClientConfigurator ) { // do nothing as we not longer use HttpClient so there's nothing this can configure } else { throw new IllegalArgumentException("A ClientConfigurator must implement OkHttpClientConfigurator"); } } DatabaseClientImpl client = new DatabaseClientImpl( services, host, port, database, securityContext, connectionType ); client.setHandleRegistry(getHandleRegistry().copy()); return client; } static private SecurityContext makeSecurityContext(String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) { if ( Authentication.BASIC == type ) { return new BasicAuthContext(user, password) .withSSLContext(context) .withSSLHostnameVerifier(verifier); } else if ( Authentication.DIGEST == type ) { return new DigestAuthContext(user, password) .withSSLContext(context) .withSSLHostnameVerifier(verifier); } else { throw new IllegalStateException("makeSecurityContext should only be called with BASIC or DIGEST Authentication"); } } /** * Creates a client to access the database by means of a REST server. * * @param host the host with the REST server * @param port the port for the REST server * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type) { return newClient(host, port, null, makeSecurityContext(user, password, type, null, null), null); } /** * Creates a client to access the database by means of a REST server. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for the REST server) * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, String database, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type) { return newClient(host, port, database, makeSecurityContext(user, password, type, null, null), null); } /** * Creates a client to access the database by means of a REST server. * * @param host the host with the REST server * @param port the port for the REST server * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @param context the SSL context for authenticating with the server * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type, SSLContext context) { return newClient(host, port, null, makeSecurityContext(user, password, type, context, SSLHostnameVerifier.COMMON), null); } /** * Creates a client to access the database by means of a REST server. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for the REST server) * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @param context the SSL context for authenticating with the server * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, String database, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type, SSLContext context) { return newClient(host, port, database, makeSecurityContext(user, password, type, context, SSLHostnameVerifier.COMMON), null); } /** * Creates a client to access the database by means of a REST server. * * @param host the host with the REST server * @param port the port for the REST server * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @param context the SSL context for authenticating with the server * @param verifier a callback for checking hostnames * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) { return newClient(host, port, null, makeSecurityContext(user, password, type, context, verifier), null); } /** * Creates a client to access the database by means of a REST server. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param host the host with the REST server * @param port the port for the REST server * @param database the database to access (default: configured database for the REST server) * @param user the user with read, write, or administrative privileges * @param password the password for the user * @param type the type of authentication applied to the request * @param context the SSL context for authenticating with the server * @param verifier a callback for checking hostnames * @return a new client for making database requests * @deprecated (as of 4.0.1) use {@link #newClient(String host, int port, String database, SecurityContext securityContext)} */ @Deprecated static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) { return newClient(host, port, database, makeSecurityContext(user, password, type, context, verifier), null); } /** * Returns the default registry with factories for creating handles * as adapters for IO representations. To create custom registries, * use * @return the default registry */ static public HandleFactoryRegistry getHandleRegistry() { return handleRegistry; } /** * Removes the current registered associations so the * handle registry is empty. */ static public void clearHandleRegistry() { handleRegistry = new HandleFactoryRegistryImpl(); } /** * Initializes a handle registry with the default associations * between the content handles provided by the API and the supported * IO representation classes. Use this method only after clearing * or overwriting associations in the handle registry. */ static public void registerDefaultHandles() { HandleFactoryRegistryImpl.registerDefaults(getHandleRegistry()); } /** * Adds a listener that provides custom configuration when a communication library * is created. * @see com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator * @param configurator the listener for configuring the communication library */ static public void addConfigurator(ClientConfigurator configurator) { if (!HttpClientConfigurator.class.isInstance(configurator) && !OkHttpClientConfigurator.class.isInstance(configurator)) { throw new IllegalArgumentException( "Configurator must implement OkHttpClientConfigurator" ); } clientConfigurator = configurator; } /** * A Database Client Factory Bean provides an object for specifying configuration * before creating a client to make database requests. * *

For instance, a Spring configuration file might resemble the following * example:

*
   * <bean name="databaseClientFactory"
   * 	   class="com.marklogic.client.DatabaseClientFactory.Bean">
   *   <property name="host"                value="localhost"/>
   *   <property name="port"                value="8012"/>
   *   <property name="user"                value="rest-writer-user"/>
   *   <property name="password"            value="rest-writer-password"/>
   *   <property name="authenticationValue" value="digest"/>
   * </bean>
   *
   * <bean name="databaseClient"
   * 	   class="com.marklogic.client.DatabaseClient"
   * 	   factory-bean="databaseClientFactory"
   * 	   factory-method="newClient"/>
   * 
*/ static public class Bean implements Serializable { private static final long serialVersionUID = 1L; private String host; private int port; private String database; private String user; private String password; private Authentication authentication; private String externalName; private SecurityContext securityContext; private DatabaseClient.ConnectionType connectionType; private HandleFactoryRegistry handleRegistry = HandleFactoryRegistryImpl.newDefault(); transient private SSLContext context; transient private SSLHostnameVerifier verifier; /** * Zero-argument constructor for bean applications. Other * applications can use the static newClient() factory methods * of DatabaseClientFactory. */ public Bean() { super(); } /** * Returns the host for clients created with a * DatabaseClientFactory.Bean object. * @return the client host */ public String getHost() { return host; } /** * Specifies the host for clients created from a * DatabaseClientFactory.Bean object. * @param host the client host */ public void setHost(String host) { this.host = host; } /** * Returns the port for clients created with a * DatabaseClientFactory.Bean object. * @return the client port */ public int getPort() { return port; } /** * Specifies the port for clients created with a * DatabaseClientFactory.Bean object. * @param port the client port */ public void setPort(int port) { this.port = port; } /** * Returns the user authentication for clients created with a * DatabaseClientFactory.Bean object. * @return the user * @deprecated (as of 4.0.1) use SecurityContext.getUser() with BasicAuthContext or DigestAuthContext */ @Deprecated public String getUser() { return user; } /** * Specifies the user authentication for clients created with a * DatabaseClientFactory.Bean object. * @param user the user * @deprecated (as of 4.0.1) use constructors for BasicAuthContext or DigestAuthContext */ @Deprecated public void setUser(String user) { this.user = user; } /** * Returns the password authentication for clients created with a * DatabaseClientFactory.Bean object. * @return the password * @deprecated (as of 4.0.1) use SecurityContext.getUser() with BasicAuthContext or DigestAuthContext */ @Deprecated public String getPassword() { return password; } /** * Specifies the password authentication for clients created with a * DatabaseClientFactory.Bean object. * @param password the password * @deprecated (as of 4.0.1) use constructors for BasicAuthContext or DigestAuthContext */ @Deprecated public void setPassword(String password) { this.password = password; } /** * Returns the external name for Kerberos clients created with a * DatabaseClientFactory.Bean object. * @return the external name */ public String getExternalName() { return externalName; } /** * Specifies the external name for Kerberos clients created with a * DatabaseClientFactory.Bean object. * @param externalName the external name */ public void setExternalName(String externalName) { this.externalName = externalName; } /** * Returns the authentication type for clients created with a * DatabaseClientFactory.Bean object. * @return the authentication type * @deprecated (as of 4.0.1) use instanceof on any SecurityContext to get its type */ @Deprecated public Authentication getAuthentication() { return authentication; } /** * Specifies the authentication type for clients created with a * DatabaseClientFactory.Bean object. * @param authentication the authentication type * @deprecated (as of 4.0.1) use constructor for any SecurityContext */ @Deprecated public void setAuthentication(Authentication authentication) { this.authentication = authentication; } /** * Specifies the authentication type for clients created with a * DatabaseClientFactory.Bean object based on a string value. * @param authentication the authentication type * @deprecated (as of 4.0.1) use constructor for any SecurityContext */ @Deprecated public void setAuthenticationValue(String authentication) { this.authentication = Authentication.valueOfUncased(authentication); } /** * Returns the database for clients created with a * DatabaseClientFactory.Bean object. * @return the database */ public String getDatabase() { return database; } /** * Specifies the database for clients created with a * DatabaseClientFactory.Bean object. * * The CallManager interface can only call an endpoint for the configured content database * of the appserver. You cannot specify the database when constructing a client for working * with a CallManager. * * @param database a database to pass along to new DocumentManager and QueryManager instances */ public void setDatabase(String database) { this.database = database; } /** * Returns the SSLContext for SSL clients created with a * DatabaseClientFactory.Bean object. * @return the SSL context * @deprecated (as of 4.0.1) use SecurityContext.getSSLContext() */ @Deprecated public SSLContext getContext() { return context; } /** * Specifies the SSLContext for clients created with a * DatabaseClientFactory.Bean object that authenticate with SSL. * @param context the SSL context * @deprecated (as of 4.0.1) use SecurityContext.withSSLContext(SSLContext,X509TrustManager) */ @Deprecated public void setContext(SSLContext context) { this.context = context; } /** * Returns the host verifier for clients created with a * DatabaseClientFactory.Bean object. * @return the host verifier * @deprecated (as of 4.0.1) use SecurityContext.getSSLHostnameVerifier() */ @Deprecated public SSLHostnameVerifier getVerifier() { return verifier; } /** * Specifies the host verifier for clients created with a * DatabaseClientFactory.Bean object that verify hosts for * additional security. * @param verifier the host verifier * @deprecated (as of 4.0.1) use SecurityContext.setSSLHostnameVerifier(SSLHostnameVerifier) * or SecurityContext.withSSLHostnameVerifier(SSLHostnameVerifier) */ @Deprecated public void setVerifier(SSLHostnameVerifier verifier) { this.verifier = verifier; } /** * Returns the security context for clients created with a * DatabaseClientFactory.Bean object - BasicAuthContext, DigestAuthContext * or KerberosAuthContext * @return the security context */ public SecurityContext getSecurityContext() { return securityContext; } /** * Specifies the security context for clients created with a * DatabaseClientFactory.Bean object * @param securityContext the security context - BasicAuthContext, * DigestAuthContext or KerberosAuthContext */ public void setSecurityContext(SecurityContext securityContext) { this.securityContext = securityContext; } /** * Identifies whether the client connects directly with a MarkLogic host * or by means of a gateway such as a load balancer. * @return the connection type */ public DatabaseClient.ConnectionType getConnectionType() { return connectionType; } /** * Specify whether the client connects directly with a MarkLogic host * or by means of a gateway such as a load balancer. * @param connectionType the connection type */ public void setConnectionType(DatabaseClient.ConnectionType connectionType) { this.connectionType = connectionType; } /** * Returns the registry for associating * IO representation classes with handle factories. * @return the registry instance */ public HandleFactoryRegistry getHandleRegistry() { return handleRegistry; } /** * Removes the current registered associations so the * handle registry is empty. */ public void clearHandleRegistry() { this.handleRegistry = new HandleFactoryRegistryImpl(); } /** * Initializes a handle registry with the default associations * between the content handles provided by the API and the supported * IO representation classes. Use this method only after clearing * or overwriting associations in the handle registry. */ public void registerDefaultHandles() { HandleFactoryRegistryImpl.registerDefaults(getHandleRegistry()); } /** * Creates a client for bean applications based on the properties. * Other applications can use the static newClient() factory methods * of DatabaseClientFactory. * The client accesses the database by means of a REST server. * @return a new client for making database requests */ public DatabaseClient newClient() { DatabaseClientImpl client = (DatabaseClientImpl) DatabaseClientFactory.newClient( host, port, database, (securityContext!=null? securityContext:makeSecurityContext(user, password, authentication, context, verifier)), connectionType); client.setHandleRegistry(getHandleRegistry().copy()); return client; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy