Example #1
0
/**
 * <code>TcpConnector</code> can bind or sent to a given tcp port on a given host.
 *
 * @version $Revision$
 */
public class SslConnector extends TcpConnector {
  public static final String DEFAULT_KEYSTORE_TYPE = KeyStore.getDefaultType();

  private SecurityProviderFactory spFactory = new AutoDiscoverySecurityProviderFactory();
  private SecurityProviderInfo spInfo = spFactory.getSecurityProviderInfo();

  private String keyStore = null;
  private String keyPassword = null;
  private String storePassword = null;
  private String keyStoreType = DEFAULT_KEYSTORE_TYPE;
  private String keyManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
  private Provider provider = spFactory.getProvider();
  private String protocolHandler = spInfo.getProtocolHandler();
  private String clientKeyStore = null;
  private String clientKeyStorePassword = null;
  private String trustStore = null;
  private String trustStorePassword = null;
  private String trustStoreType = DEFAULT_KEYSTORE_TYPE;
  // default to key manager algorithm, overridable
  private String trustManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
  private TrustManagerFactory trustManagerFactory;
  private boolean explicitTrustStoreOnly = false;

  private KeyManagerFactory keyManagerFactory = null;
  private boolean requireClientAuthentication = true;

  public void doInitialise() throws InitialisationException {
    if (getProvider() == null) {
      throw new NullPointerException("The security provider cannot be null");
    }
    if (getKeyStore() != null) {
      if (getKeyPassword() == null) {
        throw new NullPointerException("The Key password cannot be null");
      }
      if (getStorePassword() == null) {
        throw new NullPointerException("The KeyStore password cannot be null");
      }
      if (getKeyManagerAlgorithm() == null) {
        throw new NullPointerException("The Key Manager Algorithm cannot be null");
      }
      if (getKeyStoreType() == null) {
        throw new NullPointerException("The KeyStore type cannot be null");
      }
    }

    if (getKeyStore() != null) {
      KeyStore keystore;
      try {
        Security.addProvider(getProvider());
        // Create keyStore
        keystore = KeyStore.getInstance(keyStoreType);
        InputStream is = IOUtils.getResourceAsStream(getKeyStore(), getClass());
        if (is == null) {
          throw new FileNotFoundException(
              "Failed to load keystore from classpath or local file: " + getKeyStore());
        }
        keystore.load(is, getKeyPassword().toCharArray());
      } catch (Exception e) {
        throw new InitialisationException(
            new Message(Messages.FAILED_LOAD_X, "KeyStore: " + getKeyStore()), e, this);
      }
      try {
        // Get key manager
        keyManagerFactory = KeyManagerFactory.getInstance(getKeyManagerAlgorithm());
        // Initialize the KeyManagerFactory to work with our keyStore
        keyManagerFactory.init(keystore, getStorePassword().toCharArray());
      } catch (Exception e) {
        throw new InitialisationException(
            new Message(Messages.FAILED_LOAD_X, "Key Manager (" + getKeyManagerAlgorithm() + ")"),
            e,
            this);
      }
    }

    if (getTrustStore() != null) {
      KeyStore truststore;
      try {
        truststore = KeyStore.getInstance(trustStoreType);
        InputStream is = IOUtils.getResourceAsStream(getTrustStore(), getClass());
        if (is == null) {
          throw new FileNotFoundException(
              "Failed to load truststore from classpath or local file: " + getTrustStore());
        }
        truststore.load(is, getTrustStorePassword().toCharArray());
      } catch (Exception e) {
        throw new InitialisationException(
            new Message(Messages.FAILED_LOAD_X, "TrustStore: " + getTrustStore()), e, this);
      }

      try {
        trustManagerFactory = TrustManagerFactory.getInstance(getTrustManagerAlgorithm());
        trustManagerFactory.init(truststore);
      } catch (Exception e) {
        throw new InitialisationException(
            new Message(
                Messages.FAILED_LOAD_X, "Trust Manager (" + getTrustManagerAlgorithm() + ")"),
            e,
            this);
      }
    }

    super.doInitialise();

    if (protocolHandler != null) {
      System.setProperty("java.protocol.handler.pkgs", protocolHandler);
    }
    if (clientKeyStore != null) {
      try {
        String clientPath = FileUtils.getResourcePath(clientKeyStore, getClass());
        System.setProperty("javax.net.ssl.keyStore", clientPath);
        System.setProperty("javax.net.ssl.keyStorePassword", clientKeyStorePassword);

        logger.info("Set Client Key store: javax.net.ssl.keyStore=" + clientPath);
      } catch (IOException e) {
        throw new InitialisationException(
            new Message(Messages.FAILED_LOAD_X, "Client KeyStore: " + clientKeyStore), e, this);
      }
    }

    if (trustStore != null) {
      System.setProperty("javax.net.ssl.trustStore", getTrustStore());
      System.setProperty("javax.net.ssl.trustStorePassword", getTrustStorePassword());
      logger.debug("Set Trust store: javax.net.ssl.trustStore=" + getTrustStore());
    } else if (!isExplicitTrustStoreOnly()) {
      logger.info("Defaulting trust store to client Key Store");
      trustStore = getClientKeyStore();
      trustStorePassword = getClientKeyStorePassword();
      System.setProperty("javax.net.ssl.trustStore", getTrustStore());
      System.setProperty("javax.net.ssl.trustStorePassword", getTrustStorePassword());
      logger.debug("Set Trust store: javax.net.ssl.trustStore=" + getTrustStore());
    }
  }

  public String getProtocol() {
    return "SSL";
  }

  public String getKeyStore() {
    return keyStore;
  }

  public void setKeyStore(String keyStore) {
    this.keyStore = keyStore;
  }

  public String getKeyPassword() {
    return keyPassword;
  }

  public void setKeyPassword(String keyPassword) {
    this.keyPassword = keyPassword;
  }

  public String getStorePassword() {
    return storePassword;
  }

  public void setStorePassword(String storePassword) {
    this.storePassword = storePassword;
  }

  public String getTrustStoreType() {
    return trustStoreType;
  }

  public void setTrustStoreType(String trustStoreType) {
    this.trustStoreType = trustStoreType;
  }

  public TrustManagerFactory getTrustManagerFactory() {
    return trustManagerFactory;
  }

  public void setTrustManagerFactory(TrustManagerFactory trustManagerFactory) {
    this.trustManagerFactory = trustManagerFactory;
  }

  public String getTrustManagerAlgorithm() {
    return trustManagerAlgorithm;
  }

  public void setTrustManagerAlgorithm(String trustManagerAlgorithm) {
    this.trustManagerAlgorithm = trustManagerAlgorithm;
  }

  public String getKeyStoreType() {
    return keyStoreType;
  }

  public void setKeyStoreType(String keyStoreType) {
    this.keyStoreType = keyStoreType;
  }

  public String getKeyManagerAlgorithm() {
    return keyManagerAlgorithm;
  }

  public void setKeyManagerAlgorithm(String keyManagerAlgorithm) {
    this.keyManagerAlgorithm = keyManagerAlgorithm;
  }

  public boolean isRequireClientAuthentication() {
    return requireClientAuthentication;
  }

  public void setRequireClientAuthentication(boolean requireClientAuthentication) {
    this.requireClientAuthentication = requireClientAuthentication;
  }

  public KeyManagerFactory getKeyManagerFactory() {
    return keyManagerFactory;
  }

  public Provider getProvider() {
    return provider;
  }

  public void setProvider(Provider provider) {
    this.provider = provider;
  }

  public String getProtocolHandler() {
    return protocolHandler;
  }

  public void setProtocolHandler(String protocolHandler) {
    this.protocolHandler = protocolHandler;
  }

  public String getClientKeyStore() {
    return clientKeyStore;
  }

  public void setClientKeyStore(String clientKeyStore) throws IOException {
    this.clientKeyStore = clientKeyStore;
    if (this.clientKeyStore != null) {
      this.clientKeyStore = FileUtils.getResourcePath(clientKeyStore, getClass());
      logger.debug("Normalised clientKeyStore path to: " + getClientKeyStore());
    }
  }

  public String getClientKeyStorePassword() {
    return clientKeyStorePassword;
  }

  public void setClientKeyStorePassword(String clientKeyStorePassword) {
    this.clientKeyStorePassword = clientKeyStorePassword;
  }

  public String getTrustStore() {
    return trustStore;
  }

  public void setTrustStore(String trustStore) throws IOException {
    this.trustStore = trustStore;
    if (this.trustStore != null) {
      this.trustStore = FileUtils.getResourcePath(trustStore, getClass());
      logger.debug("Normalised trustStore path to: " + getTrustStore());
    }
  }

  public String getTrustStorePassword() {
    return trustStorePassword;
  }

  public void setTrustStorePassword(String trustStorePassword) {
    this.trustStorePassword = trustStorePassword;
  }

  public boolean isExplicitTrustStoreOnly() {
    return explicitTrustStoreOnly;
  }

  public void setExplicitTrustStoreOnly(boolean explicitTrustStoreOnly) {
    this.explicitTrustStoreOnly = explicitTrustStoreOnly;
  }
}
Example #2
0
/**
 * Support for configuring TLS/SSL connections.
 *
 * <h2>Introduction</h2>
 *
 * This class was introduced to centralise the work of TLS/SSL configuration. It is intended to be
 * backwards compatible with earlier code (as much as possible) and so is perhaps more complex than
 * would be necessary if starting from zero - the main source of confusion is the distinction
 * between direct and indirect creation of sockets and stores.
 *
 * <h2>Configuration</h2>
 *
 * The documentation in this class is intended more for programmers than end uses. If you are
 * configuring a connector the interfaces {@link org.mule.umo.security.TlsIndirectTrustStore},
 * {@link TlsDirectTrustStore}, {@link TlsDirectKeyStore} and {@link TlsIndirectKeyStore} should
 * provide guidance to individual properties. In addition you should check the documentation for the
 * specific protocol / connector used and may also need to read the discussion on direct and
 * indirect socket and store creation below (or, more simply, just use whichever key store interface
 * your connector implements!).
 *
 * <h2>Programming</h2>
 *
 * This class is intended to be used as a delegate as we typically want to add security to an
 * already existing connector (so we inherit from that connector, implement the appropriate
 * interfaces from {@link org.mule.umo.security.TlsIndirectTrustStore}, {@link TlsDirectTrustStore},
 * {@link TlsDirectKeyStore} and {@link TlsIndirectKeyStore}, and then forward calls to the
 * interfaces to an instance of this class).
 *
 * <p>For setting System properties (and reading them) use {@link TlsPropertiesMapper}. This can
 * take a "namespace" which can then be used by {@link TlsPropertiesSocketFactory} to construct an
 * appropriate socket factory. This approach (storing to proeprties and then retrieving that
 * information later in a socket factory) lets us pass TLS/SSL configuration into libraries that are
 * configured by specifying on the socket factory class.
 *
 * <h2>Direct and Indirect Socket and Store Creation</h2>
 *
 * For the SSL transport, which historically defined parameters for many different secure
 * transports, the configuration interfaces worked as follows:
 *
 * <dl>
 *   <dt>{@link TlsDirectTrustStore}
 *   <dd>Used to generate trust store directly and indirectly for all TLS/SSL conections via System
 *       properties
 *   <dt>{@link TlsDirectKeyStore}
 *   <dd>Used to generate key store directly
 *   <dt>{@link TlsIndirectKeyStore}
 *   <dd>Used to generate key store indirectly for all TLS/SSL conections via System properties
 * </dl>
 *
 * Historically, many other transports relied on the indirect configurations defined above. So they
 * implemented {@link org.mule.umo.security.TlsIndirectTrustStore} (a superclass of {@link
 * TlsDirectTrustStore}) and relied on {@link TlsIndirectKeyStore} from the SSL configuration. For
 * continuity these interfaces continue to be used, even though the configurations are now typically
 * (see individual connector/protocol documentation) specific to a protocol or connector. <em>Note -
 * these interfaces are new, but the original code had those methods, used as described. The new
 * interfaces only make things explicit.</em>
 *
 * <p><em>Note for programmers</em> One way to understand the above is to see that many protocols
 * are handled by libraries that are configured by providing either properties or a socket factory.
 * In both cases (the latter via {@link TlsPropertiesSocketFactory}) we continue to use properties
 * and the "indirect" interface. Note also that the mapping in {@link TlsPropertiesMapper} correctly
 * handles the asymmetry, so an initial call to {@link TlsConfiguration} uses the keystore defined
 * via {@link TlsDirectKeyStore}, but when a {@link TlsConfiguration} is retrieved from System
 * proerties using {@link TlsPropertiesMapper#readFromProperties(TlsConfiguration,
 * java.util.Properties)} the "indirect" properties are supplied as "direct" values, meaning that
 * the "indirect" socket factory can be retrieved from {@link #getKeyManagerFactory()}. It just
 * works.
 */
public final class TlsConfiguration
    implements TlsDirectTrustStore, TlsDirectKeyStore, TlsIndirectKeyStore {

  public static final String DEFAULT_KEYSTORE = ".keystore";
  public static final String DEFAULT_KEYSTORE_TYPE = KeyStore.getDefaultType();
  public static final String DEFAULT_SSL_TYPE = "SSLv3";
  public static final String JSSE_NAMESPACE = "javax.net";

  private Log logger = LogFactory.getLog(getClass());

  private SecurityProviderFactory spFactory = new AutoDiscoverySecurityProviderFactory();
  private SecurityProviderInfo spInfo = spFactory.getSecurityProviderInfo();
  private Provider provider = spFactory.getProvider();
  private String sslType = DEFAULT_SSL_TYPE;

  // global
  private String protocolHandler = spInfo.getProtocolHandler();

  // this is the key store that is generated in-memory and available to connectors explicitly.
  // it is local to the socket.
  private String keyStoreName = DEFAULT_KEYSTORE; // was default in https but not ssl
  private String keyPassword = null;
  private String keyStorePassword = null;
  private String keystoreType = DEFAULT_KEYSTORE_TYPE;
  private String keyManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
  private KeyManagerFactory keyManagerFactory = null;

  // this is the key store defined in system properties that is used implicitly.
  // note that some transports use different namespaces within system properties,
  // so this is typically global across a particular transport.
  // it is also used as the trust store defined in system properties if no other trust
  // store is given and explicitTrustStoreOnly is false
  private String clientKeyStoreName = null;
  private String clientKeyStorePassword = null;
  private String clientKeyStoreType = DEFAULT_KEYSTORE_TYPE;

  // this is the trust store used to construct sockets both explicitly
  // and globally (if not set, see client key above) via the jvm defaults.
  private String trustStoreName = null;
  private String trustStorePassword = null;
  private String trustStoreType = DEFAULT_KEYSTORE_TYPE;
  private String trustManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
  private TrustManagerFactory trustManagerFactory = null;
  private boolean explicitTrustStoreOnly = false;
  private boolean requireClientAuthentication = false;

  /**
   * Support for TLS connections with a given initial value for the key store
   *
   * @param keyStore initial value for the key store
   */
  public TlsConfiguration(String keyStore) {
    this.keyStoreName = keyStore;
  }

  // note - in what follows i'm using "raw" variables rather than accessors because
  // i think the names are clearer.  the API names for the accessors are historical
  // and not a close fit to actual use (imho).

  /**
   * @param anon If the connection is anonymous then we don't care about client keys
   * @param namespace Namespace to use for global properties (for JSSE use JSSE_NAMESPACE)
   * @throws InitialisationException ON initialisation problems
   */
  public void initialise(boolean anon, String namespace) throws InitialisationException {
    if (logger.isDebugEnabled()) {
      logger.debug("initialising: anon " + anon);
    }
    validate(anon);

    Security.addProvider(provider);
    System.setProperty("java.protocol.handler.pkgs", protocolHandler);

    if (!anon) {
      initKeyManagerFactory();
    }
    initTrustManagerFactory();

    if (null != namespace) {
      new TlsPropertiesMapper(namespace).writeToProperties(System.getProperties(), this);
    }
  }

  private void validate(boolean anon) throws InitialisationException {
    assertNotNull(getProvider(), "The security provider cannot be null");
    if (!anon) {
      assertNotNull(getKeyStore(), "The KeyStore location cannot be null");
      assertNotNull(getKeyPassword(), "The Key password cannot be null");
      assertNotNull(getStorePassword(), "The KeyStore password cannot be null");
      assertNotNull(getKeyManagerAlgorithm(), "The Key Manager Algorithm cannot be null");
    }
  }

  private void initKeyManagerFactory() throws InitialisationException {
    if (logger.isDebugEnabled()) {
      logger.debug("initialising key manager factory from keystore data");
    }
    KeyStore tempKeyStore;
    try {
      tempKeyStore = KeyStore.getInstance(keystoreType);
      InputStream is = IOUtils.getResourceAsStream(keyStoreName, getClass());
      if (null == is) {
        throw new FileNotFoundException(
            CoreMessages.cannotLoadFromClasspath("Keystore: " + keyStoreName).getMessage());
      }
      tempKeyStore.load(is, keyStorePassword.toCharArray());
    } catch (Exception e) {
      throw new InitialisationException(
          CoreMessages.failedToLoad("KeyStore: " + keyStoreName), e, this);
    }
    try {
      keyManagerFactory = KeyManagerFactory.getInstance(getKeyManagerAlgorithm());
      keyManagerFactory.init(tempKeyStore, keyPassword.toCharArray());
    } catch (Exception e) {
      throw new InitialisationException(CoreMessages.failedToLoad("Key Manager"), e, this);
    }
  }

  private void initTrustManagerFactory() throws InitialisationException {
    if (null != trustStoreName) {
      trustStorePassword = null == trustStorePassword ? "" : trustStorePassword;

      KeyStore trustStore;
      try {
        trustStore = KeyStore.getInstance(trustStoreType);
        InputStream is = IOUtils.getResourceAsStream(trustStoreName, getClass());
        if (null == is) {
          throw new FileNotFoundException(
              "Failed to load truststore from classpath or local file: " + trustStoreName);
        }
        trustStore.load(is, trustStorePassword.toCharArray());
      } catch (Exception e) {
        throw new InitialisationException(
            CoreMessages.failedToLoad("TrustStore: " + trustStoreName), e, this);
      }

      try {
        trustManagerFactory = TrustManagerFactory.getInstance(trustManagerAlgorithm);
        trustManagerFactory.init(trustStore);
      } catch (Exception e) {
        throw new InitialisationException(
            CoreMessages.failedToLoad("Trust Manager (" + trustManagerAlgorithm + ")"), e, this);
      }
    }
  }

  private static void assertNotNull(Object value, String message) {
    if (null == value) {
      throw new IllegalArgumentException(message);
    }
  }

  private static String defaultForNull(String value, String deflt) {
    if (null == value) {
      return deflt;
    } else {
      return value;
    }
  }

  public SSLSocketFactory getSocketFactory()
      throws NoSuchAlgorithmException, KeyManagementException {
    return getSslContext().getSocketFactory();
  }

  public SSLServerSocketFactory getServerSocketFactory()
      throws NoSuchAlgorithmException, KeyManagementException {
    return getSslContext().getServerSocketFactory();
  }

  public SSLContext getSslContext() throws NoSuchAlgorithmException, KeyManagementException {
    KeyManager[] keyManagers =
        null == getKeyManagerFactory() ? null : getKeyManagerFactory().getKeyManagers();
    TrustManager[] trustManagers =
        null == getTrustManagerFactory() ? null : getTrustManagerFactory().getTrustManagers();

    SSLContext context = SSLContext.getInstance(getSslType());
    // TODO - nice to have a configurable random number source set here
    context.init(keyManagers, trustManagers, null);
    return context;
  }

  public String getSslType() {
    return sslType;
  }

  public void setSslType(String sslType) {
    this.sslType = sslType;
  }

  public Provider getProvider() {
    return provider;
  }

  public void setProvider(Provider provider) {
    this.provider = provider;
  }

  public String getProtocolHandler() {
    return protocolHandler;
  }

  public void setProtocolHandler(String protocolHandler) {
    this.protocolHandler = protocolHandler;
  }

  public SecurityProviderFactory getSecurityProviderFactory() {
    return spFactory;
  }

  public void setSecurityProviderFactory(SecurityProviderFactory spFactory) {
    this.spFactory = spFactory;
  }

  // access to the explicit key store variables

  public String getKeyStore() {
    return keyStoreName;
  }

  public void setKeyStore(String name) throws IOException {
    keyStoreName = name;
    if (null != keyStoreName) {
      keyStoreName = FileUtils.getResourcePath(keyStoreName, getClass());
      if (logger.isDebugEnabled()) {
        logger.debug("Normalised keyStore path to: " + keyStoreName);
      }
    }
  }

  public String getKeyPassword() {
    return keyPassword;
  }

  public void setKeyPassword(String keyPassword) {
    this.keyPassword = keyPassword;
  }

  public String getStorePassword() {
    return keyStorePassword;
  }

  public void setStorePassword(String storePassword) {
    this.keyStorePassword = storePassword;
  }

  public String getKeystoreType() {
    return keystoreType;
  }

  public void setKeystoreType(String keystoreType) {
    this.keystoreType = keystoreType;
  }

  public String getKeyManagerAlgorithm() {
    return keyManagerAlgorithm;
  }

  public void setKeyManagerAlgorithm(String keyManagerAlgorithm) {
    this.keyManagerAlgorithm = keyManagerAlgorithm;
  }

  public KeyManagerFactory getKeyManagerFactory() {
    return keyManagerFactory;
  }

  // access to the implicit key store variables

  public String getClientKeyStore() {
    return clientKeyStoreName;
  }

  public void setClientKeyStore(String name) throws IOException {
    clientKeyStoreName = name;
    if (null != clientKeyStoreName) {
      clientKeyStoreName = FileUtils.getResourcePath(clientKeyStoreName, getClass());
      if (logger.isDebugEnabled()) {
        logger.debug("Normalised clientKeyStore path to: " + clientKeyStoreName);
      }
    }
  }

  public String getClientKeyStorePassword() {
    return clientKeyStorePassword;
  }

  public void setClientKeyStorePassword(String clientKeyStorePassword) {
    this.clientKeyStorePassword = clientKeyStorePassword;
  }

  public void setClientKeyStoreType(String clientKeyStoreType) {
    this.clientKeyStoreType = clientKeyStoreType;
  }

  public String getClientKeyStoreType() {
    return clientKeyStoreType;
  }

  // access to trust store variables

  public String getTrustStore() {
    return trustStoreName;
  }

  public void setTrustStore(String name) throws IOException {
    trustStoreName = name;
    if (null != trustStoreName) {
      trustStoreName = FileUtils.getResourcePath(trustStoreName, getClass());
      if (logger.isDebugEnabled()) {
        logger.debug("Normalised trustStore path to: " + trustStoreName);
      }
    }
  }

  public String getTrustStorePassword() {
    return trustStorePassword;
  }

  public void setTrustStorePassword(String trustStorePassword) {
    this.trustStorePassword = trustStorePassword;
  }

  public String getTrustStoreType() {
    return trustStoreType;
  }

  public void setTrustStoreType(String trustStoreType) {
    this.trustStoreType = trustStoreType;
  }

  public String getTrustManagerAlgorithm() {
    return trustManagerAlgorithm;
  }

  public void setTrustManagerAlgorithm(String trustManagerAlgorithm) {
    this.trustManagerAlgorithm =
        defaultForNull(trustManagerAlgorithm, spInfo.getKeyManagerAlgorithm());
  }

  public TrustManagerFactory getTrustManagerFactory() {
    return trustManagerFactory;
  }

  public void setTrustManagerFactory(TrustManagerFactory trustManagerFactory) {
    this.trustManagerFactory = trustManagerFactory;
  }

  public boolean isExplicitTrustStoreOnly() {
    return explicitTrustStoreOnly;
  }

  public void setExplicitTrustStoreOnly(boolean explicitTrustStoreOnly) {
    this.explicitTrustStoreOnly = explicitTrustStoreOnly;
  }

  public boolean isRequireClientAuthentication() {
    return requireClientAuthentication;
  }

  public void setRequireClientAuthentication(boolean requireClientAuthentication) {
    this.requireClientAuthentication = requireClientAuthentication;
  }
}