Asynchronous HTTP client for Play Framework with OAuth, OpenID, and SSL/TLS support
—
Comprehensive SSL and TLS configuration system for secure HTTPS connections with custom certificates, protocols, and security settings. Play WS provides extensive SSL configuration options for production security requirements.
Main SSL configuration class for customizing TLS settings.
/**
* SSL configuration for WS client
*/
case class SSLConfig(
default: Boolean = false,
protocol: String = "TLSv1.2",
checkRevocation: Option[Boolean] = None,
revocationLists: Option[Seq[URL]] = None,
enabledCipherSuites: Option[Seq[String]] = None,
enabledProtocols: Option[Seq[String]] = Some(Seq("TLSv1.2", "TLSv1.1", "TLSv1")),
disabledSignatureAlgorithms: Seq[String] = Seq("MD2", "MD4", "MD5"),
disabledKeyAlgorithms: Seq[String] = Seq("RSA keySize < 2048", "DSA keySize < 2048", "EC keySize < 224"),
keyManagerConfig: KeyManagerConfig = KeyManagerConfig(),
trustManagerConfig: TrustManagerConfig = TrustManagerConfig(),
hostnameVerifierClass: Class[_ <: HostnameVerifier] = classOf[DefaultHostnameVerifier],
secureRandom: Option[SecureRandom] = None,
debug: SSLDebugConfig = SSLDebugConfig(),
loose: SSLLooseConfig = SSLLooseConfig()
)Basic SSL Configuration:
import play.api.libs.ws.ssl._
import java.net.URL
// Default secure configuration
val sslConfig = SSLConfig()
// Custom protocol and cipher configuration
val customSslConfig = SSLConfig(
protocol = "TLSv1.2",
enabledProtocols = Some(Seq("TLSv1.2")),
enabledCipherSuites = Some(Seq(
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
))
)
// Apply to WS client configuration
val wsConfig = WSClientConfig(ssl = customSslConfig)Configuration for client certificates and private keys.
/**
* Key store configuration for client certificates
*/
case class KeyStoreConfig(
storeType: String = KeyStore.getDefaultType,
filePath: Option[String] = None,
data: Option[String] = None,
password: Option[String] = None
)
/**
* Key manager configuration
*/
case class KeyManagerConfig(
algorithm: String = KeyManagerFactory.getDefaultAlgorithm,
keyStoreConfigs: Seq[KeyStoreConfig] = Nil
)Client Certificate Configuration:
// Configure client certificate from file
val keyStoreConfig = KeyStoreConfig(
storeType = "PKCS12",
filePath = Some("/path/to/client-cert.p12"),
password = Some("keystore-password")
)
val keyManagerConfig = KeyManagerConfig(
keyStoreConfigs = Seq(keyStoreConfig)
)
val sslConfig = SSLConfig(
keyManagerConfig = keyManagerConfig
)Configuration for trusted certificate authorities.
/**
* Trust store configuration for CA certificates
*/
case class TrustStoreConfig(
storeType: String = KeyStore.getDefaultType,
filePath: Option[String],
data: Option[String]
)
/**
* Trust manager configuration
*/
case class TrustManagerConfig(
algorithm: String = TrustManagerFactory.getDefaultAlgorithm,
trustStoreConfigs: Seq[TrustStoreConfig] = Nil
)Custom Trust Store Configuration:
// Configure custom CA certificates
val trustStoreConfig = TrustStoreConfig(
storeType = "JKS",
filePath = Some("/path/to/truststore.jks")
)
val trustManagerConfig = TrustManagerConfig(
trustStoreConfigs = Seq(trustStoreConfig)
)
val sslConfig = SSLConfig(
trustManagerConfig = trustManagerConfig
)Comprehensive debugging options for SSL/TLS troubleshooting.
/**
* SSL debug configuration
*/
case class SSLDebugConfig(
all: Boolean = false,
ssl: Boolean = false,
certpath: Boolean = false,
ocsp: Boolean = false,
record: Option[SSLDebugRecordOptions] = None,
handshake: Option[SSLDebugHandshakeOptions] = None,
keygen: Boolean = false,
session: Boolean = false,
defaultctx: Boolean = false,
sslctx: Boolean = false,
sessioncache: Boolean = false,
keymanager: Boolean = false,
trustmanager: Boolean = false,
pluggability: Boolean = false
) {
/** Check if any debug options are enabled */
def enabled: Boolean
/** Enable all debug options */
def withAll: SSLDebugConfig
/** Enable certificate path debugging */
def withCertPath: SSLDebugConfig
/** Enable OCSP debugging */
def withOcsp: SSLDebugConfig
}
/**
* SSL debug record options
*/
case class SSLDebugRecordOptions(
plaintext: Boolean = false,
packet: Boolean = false
)
/**
* SSL debug handshake options
*/
case class SSLDebugHandshakeOptions(
data: Boolean = false,
verbose: Boolean = false
)SSL Debug Configuration:
// Enable comprehensive SSL debugging
val debugConfig = SSLDebugConfig(
all = true
)
// Enable specific debug categories
val specificDebugConfig = SSLDebugConfig(
certpath = true,
handshake = Some(SSLDebugHandshakeOptions(verbose = true)),
record = Some(SSLDebugRecordOptions(plaintext = true))
)
val sslConfig = SSLConfig(
debug = debugConfig
)Configuration for relaxing SSL security (development/testing only).
/**
* Loose SSL configuration (WARNING: Use only for development/testing)
*/
case class SSLLooseConfig(
allowWeakCiphers: Boolean = false,
allowWeakProtocols: Boolean = false,
allowLegacyHelloMessages: Option[Boolean] = None,
allowUnsafeRenegotiation: Option[Boolean] = None,
disableHostnameVerification: Boolean = false,
acceptAnyCertificate: Boolean = false
)Development SSL Configuration:
// WARNING: Only for development/testing
val looseSslConfig = SSLLooseConfig(
disableHostnameVerification = true,
acceptAnyCertificate = true
)
val developmentSslConfig = SSLConfig(
loose = looseSslConfig
)Build custom SSL contexts from configuration.
/**
* SSL context builder interface
*/
trait SSLContextBuilder {
def build(): SSLContext
}
/**
* Simple SSL context builder
*/
class SimpleSSLContextBuilder(
protocol: String,
keyManagers: Seq[KeyManager],
trustManagers: Seq[TrustManager],
secureRandom: Option[SecureRandom]
) extends SSLContextBuilder
/**
* Configuration-based SSL context builder
*/
class ConfigSSLContextBuilder(config: SSLConfig) extends SSLContextBuilderUtilities for working with SSL protocols and cipher suites.
/**
* SSL/TLS protocol utilities
*/
object Protocols {
/** Deprecated/insecure protocols to avoid */
val deprecatedProtocols: Set[String]
/** Recommended protocols for current Java version */
val recommendedProtocols: Array[String]
/** Default recommended protocol */
val recommendedProtocol: String
}
/**
* SSL cipher suite utilities
*/
object Ciphers {
/** Recommended cipher suites */
val recommendedCiphers: Seq[String]
/** Deprecated/weak cipher suites to avoid */
val deprecatedCiphers: Set[String]
}Protocol and Cipher Selection:
import play.api.libs.ws.ssl.{Protocols, Ciphers}
// Use recommended protocols and ciphers
val secureConfig = SSLConfig(
protocol = Protocols.recommendedProtocol,
enabledProtocols = Some(Protocols.recommendedProtocols.toSeq),
enabledCipherSuites = Some(Ciphers.recommendedCiphers)
)Build key stores from various sources.
/**
* Key store builder interface
*/
trait KeyStoreBuilder {
def build(): KeyStore
}
/**
* String-based key store builder (PEM format)
*/
class StringBasedKeyStoreBuilder(data: String) extends KeyStoreBuilder
/**
* File-based key store builder
*/
class FileBasedKeyStoreBuilder(
keyStoreType: String,
filePath: String,
password: Option[Array[Char]]
) extends KeyStoreBuilderConfigure JVM system properties for SSL.
/**
* System-level SSL configuration
*/
class SystemConfiguration {
/** Configure SSL system properties */
def configure(config: WSClientConfig): Unit
/** Configure unsafe renegotiation */
def configureUnsafeRenegotiation(allowUnsafeRenegotiation: Boolean): Unit
/** Configure legacy hello messages */
def configureAllowLegacyHelloMessages(allowLegacyHelloMessages: Boolean): Unit
/** Configure certificate revocation checking */
def configureCheckRevocation(checkRevocation: Boolean): Unit
}Production HTTPS Configuration:
import play.api.libs.ws.ssl._
import java.security.SecureRandom
val productionSslConfig = SSLConfig(
protocol = "TLSv1.2",
enabledProtocols = Some(Seq("TLSv1.2")),
enabledCipherSuites = Some(Seq(
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
)),
checkRevocation = Some(true),
secureRandom = Some(new SecureRandom())
)
val wsConfig = WSClientConfig(ssl = productionSslConfig)
val client = NingWSClient(NingWSClientConfig(wsClientConfig = wsConfig))Mutual TLS (mTLS) Configuration:
// Client certificate configuration
val clientKeyStore = KeyStoreConfig(
storeType = "PKCS12",
filePath = Some("/etc/ssl/client.p12"),
password = Some("client-cert-password")
)
// Custom CA trust store
val trustStore = TrustStoreConfig(
storeType = "JKS",
filePath = Some("/etc/ssl/ca-trust.jks")
)
val mtlsConfig = SSLConfig(
keyManagerConfig = KeyManagerConfig(
keyStoreConfigs = Seq(clientKeyStore)
),
trustManagerConfig = TrustManagerConfig(
trustStoreConfigs = Seq(trustStore)
)
)
val mtlsWsConfig = WSClientConfig(ssl = mtlsConfig)Self-Signed Certificate Configuration:
// Custom trust store with self-signed certificate
val selfSignedTrustStore = TrustStoreConfig(
storeType = "JKS",
filePath = Some("/path/to/self-signed-truststore.jks")
)
val selfSignedConfig = SSLConfig(
trustManagerConfig = TrustManagerConfig(
trustStoreConfigs = Seq(selfSignedTrustStore)
),
// Optional: disable hostname verification for self-signed certs
loose = SSLLooseConfig(
disableHostnameVerification = true
)
)SSL Configuration with Custom Hostname Verifier:
import javax.net.ssl.HostnameVerifier
class CustomHostnameVerifier extends HostnameVerifier {
override def verify(hostname: String, session: SSLSession): Boolean = {
// Custom hostname verification logic
hostname.endsWith(".trusted-domain.com")
}
}
val customVerifierConfig = SSLConfig(
hostnameVerifierClass = classOf[CustomHostnameVerifier]
)Debugging SSL Connection Issues:
// Enable comprehensive SSL debugging
val debugSslConfig = SSLConfig(
debug = SSLDebugConfig(
ssl = true,
handshake = Some(SSLDebugHandshakeOptions(verbose = true, data = true)),
record = Some(SSLDebugRecordOptions(plaintext = true)),
certpath = true,
trustmanager = true
)
)
// This will output detailed SSL information to console
val debugWsConfig = WSClientConfig(ssl = debugSslConfig)Install with Tessl CLI
npx tessl i tessl/maven-com-typesafe-play--play-ws-2-10