made TLS client certificate request from the server configurable
All checks were successful
CI / build (push) Successful in 4m2s
All checks were successful
CI / build (push) Successful in 4m2s
This commit is contained in:
@@ -91,11 +91,14 @@ public class Configuration {
|
||||
boolean verifyClients;
|
||||
}
|
||||
|
||||
public enum ClientCertificate {
|
||||
REQUIRED, OPTIONAL
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Tls {
|
||||
KeyStore keyStore;
|
||||
TrustStore trustStore;
|
||||
boolean verifyClients;
|
||||
}
|
||||
|
||||
@Value
|
||||
@@ -111,6 +114,7 @@ public class Configuration {
|
||||
Path file;
|
||||
String password;
|
||||
boolean checkCertificateStatus;
|
||||
boolean requireClientCertificate;
|
||||
}
|
||||
|
||||
@Value
|
||||
|
@@ -208,15 +208,15 @@ class GradleBuildCacheServer(private val cfg: Configuration) {
|
||||
.map { it as X509Certificate }
|
||||
.toArray { size -> Array<X509Certificate?>(size) { null } }
|
||||
SslContextBuilder.forServer(serverKey, *serverCert).apply {
|
||||
if (tls.isVerifyClients) {
|
||||
clientAuth(ClientAuth.OPTIONAL)
|
||||
tls.trustStore?.let { trustStore ->
|
||||
val clientAuth = tls.trustStore?.let { trustStore ->
|
||||
val ts = loadKeystore(trustStore.file, trustStore.password)
|
||||
trustManager(
|
||||
ClientCertificateValidator.getTrustManager(ts, trustStore.isCheckCertificateStatus)
|
||||
)
|
||||
}
|
||||
}
|
||||
if(trustStore.isRequireClientCertificate) ClientAuth.REQUIRE
|
||||
else ClientAuth.OPTIONAL
|
||||
} ?: ClientAuth.NONE
|
||||
clientAuth(clientAuth)
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
|
@@ -142,10 +142,9 @@ object Parser {
|
||||
}
|
||||
|
||||
"tls" -> {
|
||||
val verifyClients = child.renderAttribute("verify-clients")
|
||||
?.let(String::toBoolean) ?: false
|
||||
var keyStore: KeyStore? = null
|
||||
var trustStore: TrustStore? = null
|
||||
|
||||
for (granChild in child.asIterable()) {
|
||||
when (granChild.localName) {
|
||||
"keystore" -> {
|
||||
@@ -167,15 +166,19 @@ object Parser {
|
||||
val checkCertificateStatus = granChild.renderAttribute("check-certificate-status")
|
||||
?.let(String::toBoolean)
|
||||
?: false
|
||||
val requireClientCertificate = child.renderAttribute("require-client-certificate")
|
||||
?.let(String::toBoolean) ?: false
|
||||
|
||||
trustStore = TrustStore(
|
||||
trustStoreFile,
|
||||
trustStorePassword,
|
||||
checkCertificateStatus
|
||||
checkCertificateStatus,
|
||||
requireClientCertificate
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
tls = Tls(keyStore, trustStore, verifyClients)
|
||||
tls = Tls(keyStore, trustStore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -154,9 +154,6 @@ object Serializer {
|
||||
|
||||
conf.tls?.let { tlsConfiguration ->
|
||||
node("tls") {
|
||||
if(tlsConfiguration.isVerifyClients) {
|
||||
attr("verify-clients", "true")
|
||||
}
|
||||
tlsConfiguration.keyStore?.let { keyStore ->
|
||||
node("keystore") {
|
||||
attr("file", keyStore.file.toString())
|
||||
@@ -177,6 +174,7 @@ object Serializer {
|
||||
attr("password", password)
|
||||
}
|
||||
attr("check-certificate-status", trustStore.isCheckCertificateStatus.toString())
|
||||
attr("require-client-certificate", trustStore.isRequireClientCertificate.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -183,7 +183,6 @@
|
||||
<xs:element name="keystore" type="gbcs:keyStoreType" />
|
||||
<xs:element name="truststore" type="gbcs:trustStoreType" minOccurs="0"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="verify-clients" type="xs:boolean" use="optional" default="false"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="keyStoreType">
|
||||
@@ -197,6 +196,7 @@
|
||||
<xs:attribute name="file" type="xs:string" use="required"/>
|
||||
<xs:attribute name="password" type="xs:string"/>
|
||||
<xs:attribute name="check-certificate-status" type="xs:boolean"/>
|
||||
<xs:attribute name="require-client-certificate" type="xs:boolean" use="optional" default="false"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="propertiesType">
|
||||
|
@@ -171,9 +171,8 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
|
||||
),
|
||||
Configuration.Tls(
|
||||
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
|
||||
Configuration.TrustStore(this.trustStoreFile, null, false),
|
||||
true
|
||||
),
|
||||
Configuration.TrustStore(this.trustStoreFile, null, false, false),
|
||||
)
|
||||
)
|
||||
Xml.write(Serializer.serialize(cfg), System.out)
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ class ConfigurationTest {
|
||||
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-default.xml",
|
||||
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-memcached.xml",
|
||||
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-tls.xml",
|
||||
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-memcached-tls.xml",
|
||||
]
|
||||
)
|
||||
@ParameterizedTest
|
||||
|
@@ -7,6 +7,7 @@ import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Order
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource
|
||||
import java.net.http.HttpClient
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
|
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<gbcs:server xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:gbcs="urn:net.woggioni.gbcs.server"
|
||||
xmlns:gbcs-memcached="urn:net.woggioni.gbcs.server.memcached"
|
||||
xs:schemaLocation="urn:net.woggioni.gbcs.server.memcached jpms://net.woggioni.gbcs.server.memcached/net/woggioni/gbcs/server/memcached/schema/gbcs-memcached.xsd urn:net.woggioni.gbcs.server jpms://net.woggioni.gbcs.server/net/woggioni/gbcs/server/schema/gbcs.xsd"
|
||||
>
|
||||
<bind host="0.0.0.0" port="8443" incoming-connections-backlog-size="4096"/>
|
||||
<connection
|
||||
max-request-size="67108864"
|
||||
idle-timeout="PT30S"
|
||||
read-idle-timeout="PT60S"
|
||||
write-idle-timeout="PT60S"
|
||||
read-timeout="PT5M"
|
||||
write-timeout="PT5M"/>
|
||||
<event-executor use-virtual-threads="true"/>
|
||||
<cache xs:type="gbcs-memcached:memcachedCacheType" max-age="P7D" max-size="16777216" compression-mode="zip">
|
||||
<server host="memcached" port="11211"/>
|
||||
</cache>
|
||||
<authorization>
|
||||
<users>
|
||||
<user name="woggioni">
|
||||
<quota calls="1000" period="PT1S"/>
|
||||
</user>
|
||||
<user name="gitea">
|
||||
<quota calls="10" period="PT1S" initial-available-calls="100" max-available-calls="100"/>
|
||||
</user>
|
||||
<anonymous>
|
||||
<quota calls="2" period="PT5S"/>
|
||||
</anonymous>
|
||||
</users>
|
||||
<groups>
|
||||
<group name="writers">
|
||||
<users>
|
||||
<user ref="woggioni"/>
|
||||
<user ref="gitea"/>
|
||||
</users>
|
||||
<roles>
|
||||
<reader/>
|
||||
<writer/>
|
||||
</roles>
|
||||
</group>
|
||||
</groups>
|
||||
</authorization>
|
||||
<authentication>
|
||||
<client-certificate>
|
||||
<user-extractor attribute-name="CN" pattern="(.*)"/>
|
||||
</client-certificate>
|
||||
</authentication>
|
||||
<tls>
|
||||
<keystore file="/home/luser/ssl/gbcs.woggioni.net.pfx" key-alias="gbcs.woggioni.net" password="KEYSTORE_PASSWOR" key-password="KEY_PASSWORD"/>
|
||||
<truststore file="/home/luser/ssl/woggioni.net.pfx" check-certificate-status="false" password="TRUSTSTORE_PASSWORD"/>
|
||||
</tls>
|
||||
</gbcs:server>
|
@@ -60,8 +60,8 @@
|
||||
<user-extractor pattern="user-pattern" attribute-name="CN"/>
|
||||
</client-certificate>
|
||||
</authentication>
|
||||
<tls verify-clients="true">
|
||||
<tls>
|
||||
<keystore file="keystore.pfx" key-alias="key1" password="password" key-password="key-password"/>
|
||||
<truststore file="truststore.pfx" password="password" check-certificate-status="true" />
|
||||
<truststore file="truststore.pfx" password="password" check-certificate-status="true" require-client-certificate="true"/>
|
||||
</tls>
|
||||
</gbcs:server>
|
Reference in New Issue
Block a user