Skip to content

Commit 15ac3d4

Browse files
feat(client): add https config options
1 parent 12282fa commit 15ac3d4

File tree

4 files changed

+182
-4
lines changed

4 files changed

+182
-4
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,27 @@ OrbClient client = OrbOkHttpClient.builder()
440440
.build();
441441
```
442442

443+
### HTTPS
444+
445+
> [!NOTE]
446+
> Most applications should not call these methods, and instead use the system defaults. The defaults include
447+
> special optimizations that can be lost if the implementations are modified.
448+
449+
To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:
450+
451+
```java
452+
import com.withorb.api.client.OrbClient;
453+
import com.withorb.api.client.okhttp.OrbOkHttpClient;
454+
455+
OrbClient client = OrbOkHttpClient.builder()
456+
.fromEnv()
457+
// If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.
458+
.sslSocketFactory(yourSSLSocketFactory)
459+
.trustManager(yourTrustManager)
460+
.hostnameVerifier(yourHostnameVerifier)
461+
.build();
462+
```
463+
443464
### Custom HTTP client
444465

445466
The SDK consists of three artifacts:

orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OkHttpClient.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import java.io.InputStream
1414
import java.net.Proxy
1515
import java.time.Duration
1616
import java.util.concurrent.CompletableFuture
17+
import javax.net.ssl.HostnameVerifier
18+
import javax.net.ssl.SSLSocketFactory
19+
import javax.net.ssl.X509TrustManager
1720
import okhttp3.Call
1821
import okhttp3.Callback
1922
import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -189,13 +192,28 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
189192

190193
private var timeout: Timeout = Timeout.default()
191194
private var proxy: Proxy? = null
195+
private var sslSocketFactory: SSLSocketFactory? = null
196+
private var trustManager: X509TrustManager? = null
197+
private var hostnameVerifier: HostnameVerifier? = null
192198

193199
fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
194200

195201
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
196202

197203
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
198204

205+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
206+
this.sslSocketFactory = sslSocketFactory
207+
}
208+
209+
fun trustManager(trustManager: X509TrustManager?) = apply {
210+
this.trustManager = trustManager
211+
}
212+
213+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
214+
this.hostnameVerifier = hostnameVerifier
215+
}
216+
199217
fun build(): OkHttpClient =
200218
OkHttpClient(
201219
okhttp3.OkHttpClient.Builder()
@@ -204,6 +222,19 @@ class OkHttpClient private constructor(private val okHttpClient: okhttp3.OkHttpC
204222
.writeTimeout(timeout.write())
205223
.callTimeout(timeout.request())
206224
.proxy(proxy)
225+
.apply {
226+
val sslSocketFactory = sslSocketFactory
227+
val trustManager = trustManager
228+
if (sslSocketFactory != null && trustManager != null) {
229+
sslSocketFactory(sslSocketFactory, trustManager)
230+
} else {
231+
check((sslSocketFactory != null) == (trustManager != null)) {
232+
"Both or none of `sslSocketFactory` and `trustManager` must be set, but only one was set"
233+
}
234+
}
235+
236+
hostnameVerifier?.let(::hostnameVerifier)
237+
}
207238
.build()
208239
.apply {
209240
// We usually make all our requests to the same host so it makes sense to

orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClient.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import java.time.Clock
1515
import java.time.Duration
1616
import java.util.Optional
1717
import java.util.concurrent.Executor
18+
import javax.net.ssl.HostnameVerifier
19+
import javax.net.ssl.SSLSocketFactory
20+
import javax.net.ssl.X509TrustManager
1821
import kotlin.jvm.optionals.getOrNull
1922

2023
class OrbOkHttpClient private constructor() {
@@ -32,8 +35,62 @@ class OrbOkHttpClient private constructor() {
3235

3336
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
3437
private var proxy: Proxy? = null
38+
private var sslSocketFactory: SSLSocketFactory? = null
39+
private var trustManager: X509TrustManager? = null
40+
private var hostnameVerifier: HostnameVerifier? = null
3541

36-
fun proxy(proxy: Proxy) = apply { this.proxy = proxy }
42+
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
43+
44+
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
45+
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
46+
47+
/**
48+
* The socket factory used to secure HTTPS connections.
49+
*
50+
* If this is set, then [trustManager] must also be set.
51+
*
52+
* If unset, then the system default is used. Most applications should not call this method,
53+
* and instead use the system default. The default include special optimizations that can be
54+
* lost if the implementation is modified.
55+
*/
56+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
57+
this.sslSocketFactory = sslSocketFactory
58+
}
59+
60+
/** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
61+
fun sslSocketFactory(sslSocketFactory: Optional<SSLSocketFactory>) =
62+
sslSocketFactory(sslSocketFactory.getOrNull())
63+
64+
/**
65+
* The trust manager used to secure HTTPS connections.
66+
*
67+
* If this is set, then [sslSocketFactory] must also be set.
68+
*
69+
* If unset, then the system default is used. Most applications should not call this method,
70+
* and instead use the system default. The default include special optimizations that can be
71+
* lost if the implementation is modified.
72+
*/
73+
fun trustManager(trustManager: X509TrustManager?) = apply {
74+
this.trustManager = trustManager
75+
}
76+
77+
/** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
78+
fun trustManager(trustManager: Optional<X509TrustManager>) =
79+
trustManager(trustManager.getOrNull())
80+
81+
/**
82+
* The verifier used to confirm that response certificates apply to requested hostnames for
83+
* HTTPS connections.
84+
*
85+
* If unset, then a default hostname verifier is used.
86+
*/
87+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
88+
this.hostnameVerifier = hostnameVerifier
89+
}
90+
91+
/** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
92+
fun hostnameVerifier(hostnameVerifier: Optional<HostnameVerifier>) =
93+
hostnameVerifier(hostnameVerifier.getOrNull())
3794

3895
/**
3996
* Whether to throw an exception if any of the Jackson versions detected at runtime are
@@ -177,7 +234,13 @@ class OrbOkHttpClient private constructor() {
177234
OrbClientImpl(
178235
clientOptions
179236
.httpClient(
180-
OkHttpClient.builder().timeout(clientOptions.timeout()).proxy(proxy).build()
237+
OkHttpClient.builder()
238+
.timeout(clientOptions.timeout())
239+
.proxy(proxy)
240+
.sslSocketFactory(sslSocketFactory)
241+
.trustManager(trustManager)
242+
.hostnameVerifier(hostnameVerifier)
243+
.build()
181244
)
182245
.build()
183246
)

orb-java-client-okhttp/src/main/kotlin/com/withorb/api/client/okhttp/OrbOkHttpClientAsync.kt

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import java.time.Clock
1515
import java.time.Duration
1616
import java.util.Optional
1717
import java.util.concurrent.Executor
18+
import javax.net.ssl.HostnameVerifier
19+
import javax.net.ssl.SSLSocketFactory
20+
import javax.net.ssl.X509TrustManager
1821
import kotlin.jvm.optionals.getOrNull
1922

2023
class OrbOkHttpClientAsync private constructor() {
@@ -32,8 +35,62 @@ class OrbOkHttpClientAsync private constructor() {
3235

3336
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
3437
private var proxy: Proxy? = null
38+
private var sslSocketFactory: SSLSocketFactory? = null
39+
private var trustManager: X509TrustManager? = null
40+
private var hostnameVerifier: HostnameVerifier? = null
3541

36-
fun proxy(proxy: Proxy) = apply { this.proxy = proxy }
42+
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
43+
44+
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
45+
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
46+
47+
/**
48+
* The socket factory used to secure HTTPS connections.
49+
*
50+
* If this is set, then [trustManager] must also be set.
51+
*
52+
* If unset, then the system default is used. Most applications should not call this method,
53+
* and instead use the system default. The default include special optimizations that can be
54+
* lost if the implementation is modified.
55+
*/
56+
fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply {
57+
this.sslSocketFactory = sslSocketFactory
58+
}
59+
60+
/** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */
61+
fun sslSocketFactory(sslSocketFactory: Optional<SSLSocketFactory>) =
62+
sslSocketFactory(sslSocketFactory.getOrNull())
63+
64+
/**
65+
* The trust manager used to secure HTTPS connections.
66+
*
67+
* If this is set, then [sslSocketFactory] must also be set.
68+
*
69+
* If unset, then the system default is used. Most applications should not call this method,
70+
* and instead use the system default. The default include special optimizations that can be
71+
* lost if the implementation is modified.
72+
*/
73+
fun trustManager(trustManager: X509TrustManager?) = apply {
74+
this.trustManager = trustManager
75+
}
76+
77+
/** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */
78+
fun trustManager(trustManager: Optional<X509TrustManager>) =
79+
trustManager(trustManager.getOrNull())
80+
81+
/**
82+
* The verifier used to confirm that response certificates apply to requested hostnames for
83+
* HTTPS connections.
84+
*
85+
* If unset, then a default hostname verifier is used.
86+
*/
87+
fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply {
88+
this.hostnameVerifier = hostnameVerifier
89+
}
90+
91+
/** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */
92+
fun hostnameVerifier(hostnameVerifier: Optional<HostnameVerifier>) =
93+
hostnameVerifier(hostnameVerifier.getOrNull())
3794

3895
/**
3996
* Whether to throw an exception if any of the Jackson versions detected at runtime are
@@ -177,7 +234,13 @@ class OrbOkHttpClientAsync private constructor() {
177234
OrbClientAsyncImpl(
178235
clientOptions
179236
.httpClient(
180-
OkHttpClient.builder().timeout(clientOptions.timeout()).proxy(proxy).build()
237+
OkHttpClient.builder()
238+
.timeout(clientOptions.timeout())
239+
.proxy(proxy)
240+
.sslSocketFactory(sslSocketFactory)
241+
.trustManager(trustManager)
242+
.hostnameVerifier(hostnameVerifier)
243+
.build()
181244
)
182245
.build()
183246
)

0 commit comments

Comments
 (0)