package play.core.server.ssl
import play.core.server.ServerConfig
import play.server.api.SSLEngineProvider
import play.core.ApplicationProvider
import javax.net.ssl.{ TrustManager, KeyManagerFactory, SSLEngine, SSLContext, X509TrustManager }
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.io.{ FileInputStream, File }
import play.api.Logger
import scala.util.control.NonFatal
import play.utils.PlayIO
class DefaultSSLEngineProvider(serverConfig: ServerConfig, appProvider: ApplicationProvider) extends SSLEngineProvider {
import DefaultSSLEngineProvider._
val sslContext: SSLContext = createSSLContext(appProvider)
override def createSSLEngine: SSLEngine = {
sslContext.createSSLEngine()
}
def createSSLContext(applicationProvider: ApplicationProvider): SSLContext = {
val httpsConfig = serverConfig.configuration.underlying.getConfig("play.server.https")
val keyStoreConfig = httpsConfig.getConfig("keyStore")
val keyManagerFactory: KeyManagerFactory = if (keyStoreConfig.hasPath("path")) {
val path = keyStoreConfig.getString("path")
val keyStore = KeyStore.getInstance(keyStoreConfig.getString("type"))
val password = keyStoreConfig.getString("password").toCharArray
val algorithm = if (keyStoreConfig.hasPath("algorithm")) keyStoreConfig.getString("algorithm") else KeyManagerFactory.getDefaultAlgorithm
val file = new File(path)
if (file.isFile) {
val in = new FileInputStream(file)
try {
keyStore.load(in, password)
logger.debug("Using HTTPS keystore at " + file.getAbsolutePath)
val kmf = KeyManagerFactory.getInstance(algorithm)
kmf.init(keyStore, password)
kmf
} catch {
case NonFatal(e) => {
throw new Exception("Error loading HTTPS keystore from " + file.getAbsolutePath, e)
}
} finally {
PlayIO.closeQuietly(in)
}
} else {
throw new Exception("Unable to find HTTPS keystore at \"" + file.getAbsolutePath + "\"")
}
} else {
logger.warn("Using generated key with self signed certificate for HTTPS. This should not be used in production.")
FakeKeyStore.keyManagerFactory(serverConfig.rootDir)
}
val trustStoreConfig = httpsConfig.getConfig("trustStore")
val tm = if (trustStoreConfig.getBoolean("noCaVerification")) {
logger.warn("HTTPS configured with no client " +
"side CA verification. Requires http://webid.info/ for client certificate verification.")
Array[TrustManager](noCATrustManager)
} else {
logger.debug("Using default trust store for client side CA verification")
null
}
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(keyManagerFactory.getKeyManagers, tm, null)
sslContext
}
}
object DefaultSSLEngineProvider {
private val logger = Logger(classOf[DefaultSSLEngineProvider])
}
object noCATrustManager extends X509TrustManager {
val nullArray = Array[X509Certificate]()
def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String) {}
def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String) {}
def getAcceptedIssuers() = nullArray
}