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;
|
boolean verifyClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ClientCertificate {
|
||||||
|
REQUIRED, OPTIONAL
|
||||||
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
public static class Tls {
|
public static class Tls {
|
||||||
KeyStore keyStore;
|
KeyStore keyStore;
|
||||||
TrustStore trustStore;
|
TrustStore trustStore;
|
||||||
boolean verifyClients;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
@@ -111,6 +114,7 @@ public class Configuration {
|
|||||||
Path file;
|
Path file;
|
||||||
String password;
|
String password;
|
||||||
boolean checkCertificateStatus;
|
boolean checkCertificateStatus;
|
||||||
|
boolean requireClientCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@@ -208,15 +208,15 @@ class GradleBuildCacheServer(private val cfg: Configuration) {
|
|||||||
.map { it as X509Certificate }
|
.map { it as X509Certificate }
|
||||||
.toArray { size -> Array<X509Certificate?>(size) { null } }
|
.toArray { size -> Array<X509Certificate?>(size) { null } }
|
||||||
SslContextBuilder.forServer(serverKey, *serverCert).apply {
|
SslContextBuilder.forServer(serverKey, *serverCert).apply {
|
||||||
if (tls.isVerifyClients) {
|
val clientAuth = tls.trustStore?.let { trustStore ->
|
||||||
clientAuth(ClientAuth.OPTIONAL)
|
val ts = loadKeystore(trustStore.file, trustStore.password)
|
||||||
tls.trustStore?.let { trustStore ->
|
trustManager(
|
||||||
val ts = loadKeystore(trustStore.file, trustStore.password)
|
ClientCertificateValidator.getTrustManager(ts, trustStore.isCheckCertificateStatus)
|
||||||
trustManager(
|
)
|
||||||
ClientCertificateValidator.getTrustManager(ts, trustStore.isCheckCertificateStatus)
|
if(trustStore.isRequireClientCertificate) ClientAuth.REQUIRE
|
||||||
)
|
else ClientAuth.OPTIONAL
|
||||||
}
|
} ?: ClientAuth.NONE
|
||||||
}
|
clientAuth(clientAuth)
|
||||||
}.build()
|
}.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -142,10 +142,9 @@ object Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"tls" -> {
|
"tls" -> {
|
||||||
val verifyClients = child.renderAttribute("verify-clients")
|
|
||||||
?.let(String::toBoolean) ?: false
|
|
||||||
var keyStore: KeyStore? = null
|
var keyStore: KeyStore? = null
|
||||||
var trustStore: TrustStore? = null
|
var trustStore: TrustStore? = null
|
||||||
|
|
||||||
for (granChild in child.asIterable()) {
|
for (granChild in child.asIterable()) {
|
||||||
when (granChild.localName) {
|
when (granChild.localName) {
|
||||||
"keystore" -> {
|
"keystore" -> {
|
||||||
@@ -167,15 +166,19 @@ object Parser {
|
|||||||
val checkCertificateStatus = granChild.renderAttribute("check-certificate-status")
|
val checkCertificateStatus = granChild.renderAttribute("check-certificate-status")
|
||||||
?.let(String::toBoolean)
|
?.let(String::toBoolean)
|
||||||
?: false
|
?: false
|
||||||
|
val requireClientCertificate = child.renderAttribute("require-client-certificate")
|
||||||
|
?.let(String::toBoolean) ?: false
|
||||||
|
|
||||||
trustStore = TrustStore(
|
trustStore = TrustStore(
|
||||||
trustStoreFile,
|
trustStoreFile,
|
||||||
trustStorePassword,
|
trustStorePassword,
|
||||||
checkCertificateStatus
|
checkCertificateStatus,
|
||||||
|
requireClientCertificate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tls = Tls(keyStore, trustStore, verifyClients)
|
tls = Tls(keyStore, trustStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -154,9 +154,6 @@ object Serializer {
|
|||||||
|
|
||||||
conf.tls?.let { tlsConfiguration ->
|
conf.tls?.let { tlsConfiguration ->
|
||||||
node("tls") {
|
node("tls") {
|
||||||
if(tlsConfiguration.isVerifyClients) {
|
|
||||||
attr("verify-clients", "true")
|
|
||||||
}
|
|
||||||
tlsConfiguration.keyStore?.let { keyStore ->
|
tlsConfiguration.keyStore?.let { keyStore ->
|
||||||
node("keystore") {
|
node("keystore") {
|
||||||
attr("file", keyStore.file.toString())
|
attr("file", keyStore.file.toString())
|
||||||
@@ -177,6 +174,7 @@ object Serializer {
|
|||||||
attr("password", password)
|
attr("password", password)
|
||||||
}
|
}
|
||||||
attr("check-certificate-status", trustStore.isCheckCertificateStatus.toString())
|
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="keystore" type="gbcs:keyStoreType" />
|
||||||
<xs:element name="truststore" type="gbcs:trustStoreType" minOccurs="0"/>
|
<xs:element name="truststore" type="gbcs:trustStoreType" minOccurs="0"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
<xs:attribute name="verify-clients" type="xs:boolean" use="optional" default="false"/>
|
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="keyStoreType">
|
<xs:complexType name="keyStoreType">
|
||||||
@@ -197,6 +196,7 @@
|
|||||||
<xs:attribute name="file" type="xs:string" use="required"/>
|
<xs:attribute name="file" type="xs:string" use="required"/>
|
||||||
<xs:attribute name="password" type="xs:string"/>
|
<xs:attribute name="password" type="xs:string"/>
|
||||||
<xs:attribute name="check-certificate-status" type="xs:boolean"/>
|
<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>
|
||||||
|
|
||||||
<xs:complexType name="propertiesType">
|
<xs:complexType name="propertiesType">
|
||||||
|
@@ -171,9 +171,8 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
|
|||||||
),
|
),
|
||||||
Configuration.Tls(
|
Configuration.Tls(
|
||||||
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
|
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
|
||||||
Configuration.TrustStore(this.trustStoreFile, null, false),
|
Configuration.TrustStore(this.trustStoreFile, null, false, false),
|
||||||
true
|
)
|
||||||
),
|
|
||||||
)
|
)
|
||||||
Xml.write(Serializer.serialize(cfg), System.out)
|
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-default.xml",
|
||||||
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-memcached.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-tls.xml",
|
||||||
|
"classpath:net/woggioni/gbcs/server/test/valid/gbcs-memcached-tls.xml",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
@@ -7,6 +7,7 @@ import org.bouncycastle.asn1.x500.X500Name
|
|||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Order
|
import org.junit.jupiter.api.Order
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.params.provider.ArgumentsSource
|
||||||
import java.net.http.HttpClient
|
import java.net.http.HttpClient
|
||||||
import java.net.http.HttpRequest
|
import java.net.http.HttpRequest
|
||||||
import java.net.http.HttpResponse
|
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"/>
|
<user-extractor pattern="user-pattern" attribute-name="CN"/>
|
||||||
</client-certificate>
|
</client-certificate>
|
||||||
</authentication>
|
</authentication>
|
||||||
<tls verify-clients="true">
|
<tls>
|
||||||
<keystore file="keystore.pfx" key-alias="key1" password="password" key-password="key-password"/>
|
<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>
|
</tls>
|
||||||
</gbcs:server>
|
</gbcs:server>
|
Reference in New Issue
Block a user