Skip to content
Permalink
Browse files

Preliminary support to disable validation of SSL certifications in Ht…

…tpClient

Fixes to URL parsing functionality
  • Loading branch information...
darkfrog26 committed Jul 3, 2019
1 parent db6c250 commit 7727e029cdb4a96f3c64fef17c85f52b667afc15
@@ -6,8 +6,10 @@ organization in ThisBuild := "io.youi"
version in ThisBuild := "0.11.12-SNAPSHOT"
scalaVersion in ThisBuild := "2.13.0"
crossScalaVersions in ThisBuild := List("2.13.0", "2.12.8", "2.11.12")
resolvers in ThisBuild += Resolver.sonatypeRepo("releases")
resolvers in ThisBuild += Resolver.sonatypeRepo("snapshots")
resolvers in ThisBuild ++= Seq(
Resolver.sonatypeRepo("releases"),
Resolver.sonatypeRepo("snapshots")
)
scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation", "-feature")

publishTo in ThisBuild := sonatypePublishTo.value
@@ -1,7 +1,9 @@
package io.youi.client

import java.io.{File, IOException}
import java.net.InetAddress
import java.net.{InetAddress, Socket}
import java.security.{KeyStore, SecureRandom}
import java.security.cert.X509Certificate
import java.util
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicLong
@@ -11,6 +13,7 @@ import io.youi.http.content._
import io.youi.net.ContentType
import okhttp3.Dns
import io.youi.stream._
import javax.net.ssl.{HostnameVerifier, HttpsURLConnection, SSLContext, SSLSession, SSLSocketFactory, TrustManager, TrustManagerFactory, X509TrustManager}

import scala.collection.JavaConverters._
import scala.concurrent.{ExecutionContext, Future, Promise}
@@ -24,6 +27,63 @@ import scala.util.{Failure, Success}
class JVMHttpClientImplementation(config: HttpClientConfig) extends HttpClientImplementation(config) {
private lazy val client = {
val b = new okhttp3.OkHttpClient.Builder()
b.sslSocketFactory(new SSLSocketFactory {
// private val default = SSLSocketFactory.getDefault.asInstanceOf[SSLSocketFactory]
private val disabled = {
val trustAllCerts = Array[TrustManager](new X509TrustManager {
override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}

override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}

override def getAcceptedIssuers: Array[X509Certificate] = null
})
val sc = SSLContext.getInstance("SSL")
sc.init(null, trustAllCerts, new SecureRandom)
sc.getSocketFactory
}
private def f: SSLSocketFactory = disabled //if (config.validateSSLCertificates) default else disabled

override def getDefaultCipherSuites: Array[String] = f.getDefaultCipherSuites

override def getSupportedCipherSuites: Array[String] = f.getSupportedCipherSuites

override def createSocket(socket: Socket, s: String, i: Int, b: Boolean): Socket = f.createSocket(socket, s, i, b)

override def createSocket(s: String, i: Int): Socket = f.createSocket(s, i)

override def createSocket(s: String, i: Int, inetAddress: InetAddress, i1: Int): Socket = f.createSocket(s, i, inetAddress, i1)

override def createSocket(inetAddress: InetAddress, i: Int): Socket = f.createSocket(inetAddress, i)

override def createSocket(inetAddress: InetAddress, i: Int, inetAddress1: InetAddress, i1: Int): Socket = f.createSocket(inetAddress, i, inetAddress1, i1)
}, new X509TrustManager {
// private val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
// private val default = {
// factory.init(KeyStore.getInstance(KeyStore.getDefaultType))
// factory.getTrustManagers.apply(0).asInstanceOf[X509TrustManager]
// }

override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {
if (config.validateSSLCertificates) {
// default.checkClientTrusted(x509Certificates, s)
}
}

override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {
if (config.validateSSLCertificates) {
// default.checkServerTrusted(x509Certificates, s)
}
}

override def getAcceptedIssuers: Array[X509Certificate] = //if (config.validateSSLCertificates) {
// default.getAcceptedIssuers
// } else {
Array.empty[X509Certificate]
// }
})
b.hostnameVerifier(new HostnameVerifier {
override def verify(s: String, sslSession: SSLSession): Boolean = true
})
b.connectTimeout(config.timeout.toMillis, TimeUnit.MILLISECONDS)
b.readTimeout(config.timeout.toMillis, TimeUnit.MILLISECONDS)
b.writeTimeout(config.timeout.toMillis, TimeUnit.MILLISECONDS)
@@ -41,6 +101,23 @@ class JVMHttpClientImplementation(config: HttpClientConfig) extends HttpClientIm
b.build()
}

/*def disableSSLVerification(): Unit = {
val trustAllCerts = Array[TrustManager](new X509TrustManager {
override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}
override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String): Unit = {}
override def getAcceptedIssuers: Array[X509Certificate] = null
})
val sc = SSLContext.getInstance("SSL")
sc.init(null, trustAllCerts, new SecureRandom)
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory)
val allHostsValid = new HostnameVerifier {
override def verify(s: String, sslSession: SSLSession): Boolean = true
}
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid)
}*/

override def send(request: HttpRequest,
executionContext: ExecutionContext): Future[HttpResponse] = {
val req = requestToOk(request)
@@ -19,7 +19,8 @@ case class HttpClient(request: HttpRequest,
sessionManager: Option[SessionManager],
interceptor: Interceptor,
dropNullValuesInJson: Boolean,
failOnHttpStatus: Boolean) {
failOnHttpStatus: Boolean,
validateSSLCertificates: Boolean) {
protected lazy val printer: Printer = Printer.spaces2.copy(dropNullValues = dropNullValuesInJson)

def modify(f: HttpRequest => HttpRequest): HttpClient = copy(request = f(request))
@@ -67,6 +68,7 @@ case class HttpClient(request: HttpRequest,
def dropNullValuesInJson(dropNullValuesInJson: Boolean): HttpClient = copy(dropNullValuesInJson = dropNullValuesInJson)
def failOnHttpStatus(failOnHttpStatus: Boolean): HttpClient = copy(failOnHttpStatus = failOnHttpStatus)
def noFailOnHttpStatus: HttpClient = failOnHttpStatus(failOnHttpStatus = false)
def ignoreSSLCertificates: HttpClient = copy(validateSSLCertificates = false)

def content(content: Content): HttpClient = modify(_.copy(content = Some(content)))
def content(content: Option[Content]): HttpClient = content match {
@@ -152,7 +154,8 @@ object HttpClient extends HttpClient(
sessionManager = HttpClientConfig.default().sessionManager,
interceptor = HttpClientConfig.default().interceptor,
dropNullValuesInJson = HttpClientConfig.default().dropNullValuesInJson,
failOnHttpStatus = HttpClientConfig.default().failOnHttpStatus
failOnHttpStatus = HttpClientConfig.default().failOnHttpStatus,
validateSSLCertificates = HttpClientConfig.default().validateSSLCertificates
) {
def autoCall[Response](c: blackbox.Context)
(implicit r: c.WeakTypeTag[Response]): c.Expr[Future[Response]] = {
@@ -17,7 +17,8 @@ case class HttpClientConfig(retries: Int = 0,
dns: DNS = DNS.default,
dropNullValuesInJson: Boolean = false,
sessionManager: Option[SessionManager] = None,
failOnHttpStatus: Boolean = true) {
failOnHttpStatus: Boolean = true,
validateSSLCertificates: Boolean = true) {
def retries(retries: Int): HttpClientConfig = copy(retries = retries)
def retryDelay(retryDelay: FiniteDuration): HttpClientConfig = copy(retryDelay = retryDelay)
def interceptor(interceptor: Interceptor): HttpClientConfig = copy(interceptor = interceptor)
@@ -21,6 +21,8 @@ case class Parameters(entries: List[(String, Param)]) {
replaceParam(key, List(value))
}

def param(key: String, param: Param): Parameters = copy(entries = key -> param :: removeParam(key).entries)

def appendParam(key: String, value: String): Parameters = {
val values = this.values(key)
replaceParam(key, value :: values)
@@ -40,9 +42,13 @@ case class Parameters(entries: List[(String, Param)]) {
val params = map.flatMap {
case (key, param) => {
val keyEncoded = URL.encode(key)
param.values.map { value =>
val valueEncoded = URL.encode(value)
s"$keyEncoded=$valueEncoded"
if (param.values.nonEmpty) {
param.values.map { value =>
val valueEncoded = URL.encode(value)
s"$keyEncoded=$valueEncoded"
}
} else {
List(keyEncoded)
}
}
}.mkString("&")
@@ -60,9 +66,13 @@ case class Parameters(entries: List[(String, Param)]) {
val params = map.flatMap {
case (key, param) => {
val keyEncoded = key
param.values.map { value =>
val valueEncoded = value
s"$keyEncoded=$valueEncoded"
if (param.values.nonEmpty) {
param.values.map { value =>
val valueEncoded = value
s"$keyEncoded=$valueEncoded"
}
} else {
List(keyEncoded)
}
}
}.mkString("&")
@@ -84,10 +94,10 @@ object Parameters {
} else {
var params = Parameters.empty
query.split('&').map(param => param.trim.splitAt(param.indexOf('='))).collect {
case (key, value) if key.nonEmpty => URL.decode(key) -> URL.decode(value.substring(1))
case (key, value) if value.nonEmpty => "query" -> URL.decode(value)
case (key, value) if key.nonEmpty => URL.decode(key) -> Param(List(URL.decode(value.substring(1))))
case (_, value) if value.nonEmpty => URL.decode(value) -> Param(Nil)
}.foreach {
case (key, value) => params = params.withParam(key, value)
case (key, value) => params = params.param(key, value)
}
params
}
@@ -13,6 +13,10 @@ class URLSpec extends WordSpec with Matchers {
url.path.encoded should equal("/")
url.port should equal(80)
}
"properly parse a simple URL with key-only param" in {
val url = URL("http://www.outr.com/test?wsdl")
url.parameters.encoded should be("?wsdl")
}
"properly parse a relative URL" in {
val url = URL("http://www.outr.com/examples/../images/test.png")
url.path.encoded should equal("/images/test.png")

0 comments on commit 7727e02

Please sign in to comment.
You can’t perform that action at this time.