Skip to content

Commit c243301

Browse files
committed
wip
1 parent fb46994 commit c243301

File tree

1 file changed

+129
-58
lines changed
  • plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp

1 file changed

+129
-58
lines changed

plugins/amazonq/shared/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/lsp/TrustChainUtilTest.kt

Lines changed: 129 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,153 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp
55

6+
import com.github.tomakehurst.wiremock.WireMockServer
67
import com.github.tomakehurst.wiremock.common.Slf4jNotifier
7-
import com.github.tomakehurst.wiremock.common.ssl.KeyStoreSettings
8+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration
89
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig
9-
import com.github.tomakehurst.wiremock.junit5.WireMockExtension
1010
import com.intellij.testFramework.ApplicationExtension
11+
import com.intellij.util.net.ssl.CertificateManager
12+
import org.assertj.core.api.Assertions.assertThat
1113
import org.junit.jupiter.api.Test
1214
import org.junit.jupiter.api.extension.ExtendWith
13-
import org.junit.jupiter.api.extension.RegisterExtension
1415
import java.net.URI
1516
import java.security.cert.X509Certificate
16-
1717
import java.math.BigInteger
1818
import java.security.KeyPairGenerator
1919
import java.security.KeyStore
20-
import java.util.*
2120
import org.bouncycastle.asn1.x500.X500Name
22-
import org.bouncycastle.asn1.x509.*
23-
import org.bouncycastle.cert.X509v3CertificateBuilder
21+
import org.bouncycastle.asn1.x509.BasicConstraints
22+
import org.bouncycastle.asn1.x509.Extension
23+
import org.bouncycastle.asn1.x509.GeneralName
24+
import org.bouncycastle.asn1.x509.GeneralNames
25+
import org.bouncycastle.asn1.x509.KeyUsage
2426
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
2527
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
2628
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
29+
import org.junit.jupiter.api.extension.AfterAllCallback
30+
import org.junit.jupiter.api.extension.ExtensionContext
2731
import software.aws.toolkits.core.utils.outputStream
2832
import java.nio.file.Files
2933
import java.nio.file.Path
3034
import java.security.KeyPair
3135
import java.security.PrivateKey
3236
import java.time.Instant
3337
import java.time.temporal.ChronoUnit
38+
import java.util.Date
3439

3540
@ExtendWith(ApplicationExtension::class)
36-
class TrustChainUtilTest {
41+
class TrustChainUtilTest : AfterAllCallback {
3742
companion object {
38-
@RegisterExtension
39-
@JvmStatic
40-
val wm1 = WireMockExtension.newInstance()
41-
.options(
42-
wireMockConfig()
43-
.httpDisabled(true)
44-
.http2TlsDisabled(true)
45-
.keystorePath(Files.createTempFile("certs", "jks").toAbsolutePath().apply { CertificateGenerator.generateCertificateChain(this) }.toString())
46-
.keystoreType("jks")
47-
.keystorePassword("changeit")
48-
.keyManagerPassword("changeit")
49-
.dynamicHttpsPort()
50-
.notifier(Slf4jNotifier(true))
51-
)
52-
.build()
43+
private val certs = CertificateGenerator.generateCertificateChain()
44+
}
45+
46+
override fun afterAll(context: ExtensionContext) {
47+
CertificateManager.getInstance().customTrustManager.apply {
48+
certificates.toList().forEach { removeCertificate(it) }
49+
}
50+
51+
assertThat(CertificateManager.getInstance().customTrustManager.certificates).isEmpty()
52+
}
53+
54+
@Test
55+
fun `returns chain from server if leaf is trust anchor`() {
56+
mockWithOptions(
57+
{
58+
it.keystorePath(
59+
Files.createTempFile("certs", "jks")
60+
.toAbsolutePath()
61+
.apply {
62+
CertificateGenerator.saveToKeyStore(
63+
this,
64+
certs.values.first(),
65+
certs.keys.take(2).toTypedArray(),
66+
)
67+
}
68+
.toString()
69+
)
70+
}
71+
) {
72+
val trustChain = TrustChainUtil.getTrustChain(URI("https://localhost:${it.httpsPort()}"))
73+
// leaf, intermediate
74+
assertThat(trustChain)
75+
.isEqualTo(certs.keys.take(2).toList())
76+
}
77+
}
78+
79+
@Test
80+
fun `returns entire chain if CA is trusted`() {
81+
CertificateManager.getInstance().customTrustManager.addCertificate(certs.keys.last())
82+
83+
mockWithOptions(
84+
{
85+
it.keystorePath(
86+
Files.createTempFile("certs", "jks")
87+
.toAbsolutePath()
88+
.apply {
89+
CertificateGenerator.saveToKeyStore(
90+
this,
91+
certs.values.first(),
92+
certs.keys.take(2).toTypedArray(),
93+
)
94+
}
95+
.toString()
96+
)
97+
}
98+
) {
99+
val trustChain = TrustChainUtil.getTrustChain(URI("https://localhost:${it.httpsPort()}"))
100+
// leaf, intermediate, root
101+
assertThat(trustChain)
102+
.isEqualTo(certs.keys.toList())
103+
}
53104
}
54105

55106
@Test
56-
fun `TrustChainUtil should return a valid trust chain`() {
57-
val trustChain = TrustChainUtil.getTrustChain(URI("https://localhost:${wm1.httpsPort}"))
58-
println(trustChain)
59-
assert(trustChain.isNotEmpty())
107+
fun `returns entire chain if CA is trusted but only returns leaf`() {
108+
CertificateManager.getInstance().customTrustManager.addCertificate(certs.keys.last())
109+
110+
mockWithOptions(
111+
{
112+
it.keystorePath(
113+
Files.createTempFile("certs", "jks")
114+
.toAbsolutePath()
115+
.apply {
116+
CertificateGenerator.saveToKeyStore(
117+
this,
118+
certs.values.first(),
119+
certs.keys.take(1).toTypedArray(),
120+
)
121+
}
122+
.toString()
123+
)
124+
}
125+
) {
126+
val trustChain = TrustChainUtil.getTrustChain(URI("https://localhost:${it.httpsPort()}"))
127+
// leaf, intermediate, root
128+
assertThat(trustChain)
129+
.isEqualTo(certs.keys.toList())
130+
}
131+
}
132+
133+
private fun mockWithOptions(options: (WireMockConfiguration) -> Unit, runnable: (WireMockServer) -> Unit) {
134+
val server = WireMockServer(
135+
wireMockConfig()
136+
.httpDisabled(true)
137+
.http2TlsDisabled(true)
138+
.keystoreType("jks")
139+
.keystorePassword("changeit")
140+
.keyManagerPassword("changeit")
141+
.dynamicHttpsPort()
142+
.notifier(Slf4jNotifier(true))
143+
.apply { options(this) }
144+
)
145+
146+
try {
147+
server.start()
148+
149+
runnable(server)
150+
} finally {
151+
server.stop()
152+
}
60153
}
61154
}
62155

@@ -66,7 +159,7 @@ class CertificateGenerator {
66159
private const val SIGNATURE_ALGORITHM = "SHA256withRSA"
67160
private const val KEY_SIZE = 4096
68161

69-
fun generateCertificateChain(keystorePath: Path) {
162+
fun generateCertificateChain(): Map<X509Certificate, KeyPair> {
70163
// Generate Root CA
71164
val rootKeyPair = generateKeyPair()
72165
val rootCert = generateRootCertificate(rootKeyPair)
@@ -87,12 +180,10 @@ class CertificateGenerator {
87180
intermediateKeyPair.private
88181
)
89182

90-
// Store in KeyStore
91-
saveToKeyStore(
92-
keystorePath,
93-
rootKeyPair, rootCert,
94-
intermediateKeyPair, intermediateCert,
95-
leafKeyPair, leafCert
183+
return linkedMapOf(
184+
leafCert to leafKeyPair,
185+
intermediateCert to intermediateKeyPair,
186+
rootCert to rootKeyPair,
96187
)
97188
}
98189

@@ -213,7 +304,7 @@ class CertificateGenerator {
213304
GeneralName(GeneralName.dNSName, "localhost"),
214305
GeneralName(GeneralName.iPAddress, "127.0.0.1"),
215306
GeneralName(GeneralName.iPAddress, "::1")
216-
)
307+
)
217308
)
218309

219310
addExtension(
@@ -230,14 +321,10 @@ class CertificateGenerator {
230321
.getCertificate(certBuilder.build(signer))
231322
}
232323

233-
private fun saveToKeyStore(
324+
fun saveToKeyStore(
234325
keystorePath: Path,
235-
rootKeyPair: KeyPair,
236-
rootCert: X509Certificate,
237-
intermediateKeyPair: KeyPair,
238-
intermediateCert: X509Certificate,
239326
leafKeyPair: KeyPair,
240-
leafCert: X509Certificate
327+
trustChain: Array<X509Certificate>
241328
) {
242329
val password = "changeit".toCharArray()
243330

@@ -246,28 +333,12 @@ class CertificateGenerator {
246333
load(null, password)
247334
}
248335

249-
// Store root CA
250-
// keyStore.setKeyEntry(
251-
// "root",
252-
// rootKeyPair.private,
253-
// password,
254-
// arrayOf(rootCert)
255-
// )
256-
257-
// // Store intermediate CA
258-
// keyStore.setKeyEntry(
259-
// "intermediate",
260-
// intermediateKeyPair.private,
261-
// password,
262-
// arrayOf(intermediateCert, rootCert)
263-
// )
264-
265336
// Store leaf certificate
266337
keyStore.setKeyEntry(
267338
"leaf",
268339
leafKeyPair.private,
269340
password,
270-
arrayOf(leafCert, intermediateCert)
341+
trustChain
271342
)
272343

273344
// Save to file

0 commit comments

Comments
 (0)