mirror of
https://github.com/apple/pkl.git
synced 2026-06-29 08:46:22 +02:00
Improve handling of CA certificates (#518)
Instead of bundling Pkl's built-in CA certificates as a class path resource and loading them at runtime, pass them to the native image compiler as the default SSL context's trust store. This results in faster SSL initialization and is more consistent with how default certificates are handled when running on the JVM. Further related improvements: - Remove HttpClientBuilder methods `addDefaultCliCertificates` and `addBuiltInCertificates`. - Remove pkl-certs subproject and the optional dependencies on it. - Move `PklCARoots.pem` to `pkl-cli/src/certs`. - Fix certificate related error messages that were missing an argument. - Prevent PklBugException if initialization of `CliBaseOptions.httpClient` fails. - Add ability to set CA certificates as a byte array - Add CA certificates option to message passing API
This commit is contained in:
@@ -12,9 +12,8 @@ import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import kotlin.io.path.copyTo
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.readBytes
|
||||
|
||||
class HttpClientTest {
|
||||
@Test
|
||||
@@ -52,14 +51,21 @@ class HttpClientTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can load certificates from file system`() {
|
||||
fun `can load certificates from regular file`() {
|
||||
assertDoesNotThrow {
|
||||
HttpClient.builder().addCertificates(FileTestUtils.selfSignedCertificate).build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `certificate file located on file system cannot be empty`(@TempDir tempDir: Path) {
|
||||
fun `can load certificates from a byte array`() {
|
||||
assertDoesNotThrow {
|
||||
HttpClient.builder().addCertificates(FileTestUtils.selfSignedCertificate.readBytes()).build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `certificate file cannot be empty`(@TempDir tempDir: Path) {
|
||||
val file = tempDir.resolve("certs.pem").createFile()
|
||||
|
||||
val e = assertThrows<HttpClientInitException> {
|
||||
@@ -69,56 +75,10 @@ class HttpClientTest {
|
||||
assertThat(e).hasMessageContaining("empty")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can load certificates from class path`() {
|
||||
assertDoesNotThrow {
|
||||
HttpClient.builder().addCertificates(javaClass.getResource("/org/pkl/certs/PklCARoots.pem")!!.toURI()).build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `only allows loading jar and file certificate URIs`() {
|
||||
assertThrows<HttpClientInitException> {
|
||||
HttpClient.builder().addCertificates(URI("https://example.com"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `certificate file located on class path cannot be empty`() {
|
||||
val uri = javaClass.getResource("emptyCerts.pem")!!.toURI()
|
||||
|
||||
val e = assertThrows<HttpClientInitException> {
|
||||
HttpClient.builder().addCertificates(uri).build()
|
||||
}
|
||||
|
||||
assertThat(e).hasMessageContaining("empty")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can load built-in certificates`() {
|
||||
assertDoesNotThrow {
|
||||
HttpClient.builder().addBuiltInCertificates().build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can load certificates from Pkl user home cacerts directory`(@TempDir tempDir: Path) {
|
||||
val certsDir = tempDir.resolve(".pkl")
|
||||
.resolve("cacerts")
|
||||
.createDirectories()
|
||||
.also { dir ->
|
||||
FileTestUtils.selfSignedCertificate.copyTo(dir.resolve("certs.pem"))
|
||||
}
|
||||
|
||||
assertDoesNotThrow {
|
||||
HttpClientBuilder(certsDir).addDefaultCliCertificates().build()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loading certificates from cacerts directory falls back to built-in certificates`(@TempDir certsDir: Path) {
|
||||
assertDoesNotThrow {
|
||||
HttpClientBuilder(certsDir).addDefaultCliCertificates().build()
|
||||
HttpClient.builder().build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,20 @@ package org.pkl.core.http
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.pkl.commons.createTempFile
|
||||
import org.pkl.commons.writeString
|
||||
import java.net.URI
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse.BodyHandlers
|
||||
import java.nio.file.Path
|
||||
|
||||
class LazyHttpClientTest {
|
||||
@Test
|
||||
fun `builds underlying client on first send`() {
|
||||
fun `builds underlying client on first send`(@TempDir tempDir: Path) {
|
||||
val certFile = tempDir.resolve("cert.pem").apply { writeString("broken") }
|
||||
val client = HttpClient.builder()
|
||||
.addCertificates(javaClass.getResource("brokenCerts.pem")!!.toURI())
|
||||
.addCertificates(certFile)
|
||||
.buildLazily()
|
||||
val request = HttpRequest.newBuilder(URI("https://example.com")).build()
|
||||
|
||||
@@ -21,9 +26,10 @@ class LazyHttpClientTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `does not build underlying client unnecessarily`() {
|
||||
fun `does not build underlying client unnecessarily`(@TempDir tempDir: Path) {
|
||||
val certFile = tempDir.createTempFile().apply { writeString("broken") }
|
||||
val client = HttpClient.builder()
|
||||
.addCertificates(javaClass.getResource("brokenCerts.pem")!!.toURI())
|
||||
.addCertificates(certFile)
|
||||
.buildLazily()
|
||||
|
||||
assertDoesNotThrow {
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.pkl.core.SecurityManagers
|
||||
import org.pkl.core.packages.PackageResolver
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Path
|
||||
|
||||
class ProjectDependenciesResolverTest {
|
||||
companion object {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
broken
|
||||
Reference in New Issue
Block a user