package io.dropwizard.logging;

import ch.qos.logback.core.spi.DeferredProcessingAware;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import javax.annotation.Nullable;
import javax.net.SocketFactory;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;

An AppenderFactory implementation which provides an appender that writes events to a TCP socket secured by the TLS/SSL protocol on the presentation layer.

Configuration Parameters:
Name Default Description
keyStorePath (none) The path to the Java key store which contains the host certificate and private key.
keyStorePassword (none) The password used to access the key store.
keyStoreType JKS The type of key store (usually JKS, PKCS12, JCEKS, Windows-MY, or Windows-ROOT).
keyStoreProvider (none) The JCE provider to use to access the key store.
trustStorePath (none) The path to the Java key store which contains the CA certificates used to establish trust.
trustStorePassword (none) The password used to access the trust store.
trustStoreType JKS The type of trust store (usually JKS, PKCS12, JCEKS, Windows-MY, or Windows-ROOT).
trustStoreProvider (none) The JCE provider to use to access the trust store.
jceProvider (none) The name of the JCE provider to use for cryptographic support.
validateCerts false Whether or not to validate TLS certificates before starting. If enabled, Dropwizard will refuse to start with expired or otherwise invalid certificates.
validatePeers false Whether or not to validate TLS peer certificates.
supportedProtocols JVM default A list of protocols (e.g., SSLv3, TLSv1) which are supported. All other protocols will be refused.
excludedProtocols [SSL, SSLv2, SSLv2Hello, SSLv3] A list of protocols (e.g., SSLv3, TLSv1) which are excluded. These protocols will be refused.
supportedCipherSuites JVM default A list of cipher suites (e.g., TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) which are supported. All other cipher suites will be refused
excludedCipherSuites [.*_(MD5|SHA|SHA1)$] A list of cipher suites (e.g., TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) which are excluded. These cipher suites will be refused.

For more configuration parameters, see TcpSocketAppenderFactory.
See Also:
Since:2.0
/** * An {@link AppenderFactory} implementation which provides an appender that writes events to a TCP socket * secured by the TLS/SSL protocol on the presentation layer. * <p/> * <b>Configuration Parameters:</b> * <table> * <tr> * <td>Name</td> * <td>Default</td> * <td>Description</td> * </tr> * <tr> * <td>{@code keyStorePath}</td> * <td>(none)</td> * <td> * The path to the Java key store which contains the host certificate and private key. * </td> * </tr> * <tr> * <td>{@code keyStorePassword}</td> * <td>(none)</td> * <td> * The password used to access the key store. * </td> * </tr> * <tr> * <td>{@code keyStoreType}</td> * <td>{@code JKS}</td> * <td> * The type of key store (usually {@code JKS}, {@code PKCS12}, {@code JCEKS}, * {@code Windows-MY}, or {@code Windows-ROOT}). * </td> * </tr> * <tr> * <td>{@code keyStoreProvider}</td> * <td>(none)</td> * <td> * The JCE provider to use to access the key store. * </td> * </tr> * <tr> * <td>{@code trustStorePath}</td> * <td>(none)</td> * <td> * The path to the Java key store which contains the CA certificates used to establish * trust. * </td> * </tr> * <tr> * <td>{@code trustStorePassword}</td> * <td>(none)</td> * <td>The password used to access the trust store.</td> * </tr> * <tr> * <td>{@code trustStoreType}</td> * <td>{@code JKS}</td> * <td> * The type of trust store (usually {@code JKS}, {@code PKCS12}, {@code JCEKS}, * {@code Windows-MY}, or {@code Windows-ROOT}). * </td> * </tr> * <tr> * <td>{@code trustStoreProvider}</td> * <td>(none)</td> * <td> * The JCE provider to use to access the trust store. * </td> * </tr> * <tr> * <td>{@code jceProvider}</td> * <td>(none)</td> * <td>The name of the JCE provider to use for cryptographic support.</td> * </tr> * <tr> * <td>{@code validateCerts}</td> * <td>false</td> * <td> * Whether or not to validate TLS certificates before starting. If enabled, Dropwizard * will refuse to start with expired or otherwise invalid certificates. * </td> * </tr> * <tr> * <td>{@code validatePeers}</td> * <td>false</td> * <td> * Whether or not to validate TLS peer certificates. * </td> * </tr> * <tr> * <td>{@code supportedProtocols}</td> * <td>JVM default</td> * <td> * A list of protocols (e.g., {@code SSLv3}, {@code TLSv1}) which are supported. All * other protocols will be refused. * </td> * </tr> * <tr> * <td>{@code excludedProtocols}</td> * <td>[SSL, SSLv2, SSLv2Hello, SSLv3]</td> * <td> * A list of protocols (e.g., {@code SSLv3}, {@code TLSv1}) which are excluded. These * protocols will be refused. * </td> * </tr> * <tr> * <td>{@code supportedCipherSuites}</td> * <td>JVM default</td> * <td> * A list of cipher suites (e.g., {@code TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}) which * are supported. All other cipher suites will be refused * </td> * </tr> * <tr> * <td>{@code excludedCipherSuites}</td> * <td>[.*_(MD5|SHA|SHA1)$]</td> * <td> * A list of cipher suites (e.g., {@code TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}) which * are excluded. These cipher suites will be refused. * </td> * </tr> * </table> * <p/> * For more configuration parameters, see {@link TcpSocketAppenderFactory}. * * @see TcpSocketAppenderFactory * @since 2.0 */
@JsonTypeName("tls") public class TlsSocketAppenderFactory<E extends DeferredProcessingAware> extends TcpSocketAppenderFactory<E> { @Nullable private String keyStorePath; @Nullable private String keyStorePassword; @NotEmpty private String keyStoreType = "JKS"; @Nullable private String keyStoreProvider; @Nullable private String trustStorePath; @Nullable private String trustStorePassword; @NotEmpty private String trustStoreType = "JKS"; @Nullable private String trustStoreProvider; @Nullable private String jceProvider; @Nullable private List<String> supportedProtocols; @Nullable private List<String> excludedProtocols; @Nullable private List<String> supportedCipherSuites; @Nullable private List<String> excludedCipherSuites; private boolean validateCerts; private boolean validatePeers; @JsonProperty public boolean isValidatePeers() { return validatePeers; } @JsonProperty public void setValidatePeers(boolean validatePeers) { this.validatePeers = validatePeers; } @JsonProperty public boolean isValidateCerts() { return validateCerts; } @JsonProperty public void setValidateCerts(boolean validateCerts) { this.validateCerts = validateCerts; } @JsonProperty @Nullable public List<String> getExcludedCipherSuites() { return excludedCipherSuites; } @JsonProperty public void setExcludedCipherSuites(List<String> excludedCipherSuites) { this.excludedCipherSuites = excludedCipherSuites; } @JsonProperty @Nullable public List<String> getSupportedCipherSuites() { return supportedCipherSuites; } @JsonProperty public void setSupportedCipherSuites(List<String> supportedCipherSuites) { this.supportedCipherSuites = supportedCipherSuites; } @JsonProperty @Nullable public List<String> getExcludedProtocols() { return excludedProtocols; } @JsonProperty public void setExcludedProtocols(List<String> excludedProtocols) { this.excludedProtocols = excludedProtocols; } @JsonProperty @Nullable public List<String> getSupportedProtocols() { return supportedProtocols; } @JsonProperty public void setSupportedProtocols(List<String> supportedProtocols) { this.supportedProtocols = supportedProtocols; } @JsonProperty @Nullable public String getTrustStoreProvider() { return trustStoreProvider; } @JsonProperty public void setTrustStoreProvider(String trustStoreProvider) { this.trustStoreProvider = trustStoreProvider; } @JsonProperty @Nullable public String getTrustStoreType() { return trustStoreType; } @JsonProperty public void setTrustStoreType(String trustStoreType) { this.trustStoreType = trustStoreType; } @JsonProperty @Nullable public String getTrustStorePassword() { return trustStorePassword; } @JsonProperty public void setTrustStorePassword(String trustStorePassword) { this.trustStorePassword = trustStorePassword; } @JsonProperty @Nullable public String getTrustStorePath() { return trustStorePath; } @JsonProperty public void setTrustStorePath(String trustStorePath) { this.trustStorePath = trustStorePath; } @JsonProperty @Nullable public String getKeyStoreProvider() { return keyStoreProvider; } @JsonProperty public void setKeyStoreProvider(String keyStoreProvider) { this.keyStoreProvider = keyStoreProvider; } @JsonProperty @Nullable public String getKeyStoreType() { return keyStoreType; } @JsonProperty public void setKeyStoreType(String keyStoreType) { this.keyStoreType = keyStoreType; } @JsonProperty @Nullable public String getKeyStorePassword() { return keyStorePassword; } @JsonProperty public void setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; } @JsonProperty @Nullable public String getKeyStorePath() { return keyStorePath; } @JsonProperty public void setKeyStorePath(String keyStorePath) { this.keyStorePath = keyStorePath; } @JsonProperty @Nullable public String getJceProvider() { return jceProvider; } @JsonProperty public void setJceProvider(String jceProvider) { this.jceProvider = jceProvider; } private SslContextFactory createSslContextFactory() { SslContextFactory factory = new SslContextFactory.Server(); if (keyStorePath != null) { factory.setKeyStorePath(keyStorePath); } factory.setKeyStoreType(keyStoreType); if (keyStorePassword != null) { factory.setKeyStorePassword(keyStorePassword); } if (keyStoreProvider != null) { factory.setKeyStoreProvider(keyStoreProvider); } if (trustStorePath != null) { factory.setTrustStorePath(trustStorePath); } if (trustStorePassword != null) { factory.setTrustStorePassword(trustStorePassword); } factory.setTrustStoreType(trustStoreType); if (trustStoreProvider != null) { factory.setTrustStoreProvider(trustStoreProvider); } factory.setValidateCerts(validateCerts); factory.setValidatePeerCerts(validatePeers); if (supportedProtocols != null) { factory.setIncludeProtocols(supportedProtocols.toArray(new String[0])); } if (excludedProtocols != null) { factory.setExcludeProtocols(excludedProtocols.toArray(new String[0])); } if (supportedCipherSuites != null) { factory.setIncludeCipherSuites(supportedCipherSuites.toArray(new String[0])); } if (excludedCipherSuites != null) { factory.setExcludeCipherSuites(excludedCipherSuites.toArray(new String[0])); } if (jceProvider != null) { factory.setProvider(jceProvider); } return factory; } @Override protected SocketFactory socketFactory() { final SslContextFactory sslContextFactory = createSslContextFactory(); try { sslContextFactory.start(); } catch (Exception e) { throw new IllegalStateException("Unable to configure SSLContext", e); } // We use an adapter over the `newSslSocket` call of Jetty's `SslContextFactory`, because it provides more // advanced socket configuration than Java's `SSLSocketFactory`. return new SocketFactory() { @Override public Socket createSocket() throws IOException { return sslContextFactory.newSslSocket(); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return unsupported(); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return unsupported(); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return unsupported(); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return unsupported(); } private Socket unsupported() { throw new UnsupportedOperationException("Only createSocket is supported"); } }; } }