diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 5f27461..f268189 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -9,11 +9,6 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: graalvm - java-version: 21 - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 - name: Execute Gradle build diff --git a/gbcs-api/src/main/java/net/woggioni/gbcs/api/Configuration.java b/gbcs-api/src/main/java/net/woggioni/gbcs/api/Configuration.java index 85fc6fc..81683a9 100644 --- a/gbcs-api/src/main/java/net/woggioni/gbcs/api/Configuration.java +++ b/gbcs-api/src/main/java/net/woggioni/gbcs/api/Configuration.java @@ -22,6 +22,7 @@ public class Configuration { Tls tls; boolean useVirtualThread; int maxRequestSize; + int incomingConnectionsBacklogSize; @Value public static class Group { @@ -109,7 +110,8 @@ public class Configuration { Authentication authentication, Tls tls, boolean useVirtualThread, - int maxRequestSize + int maxRequestSize, + int incomingConnectionsBacklogSize ) { return new Configuration( host, @@ -121,7 +123,8 @@ public class Configuration { authentication, tls, useVirtualThread, - maxRequestSize + maxRequestSize, + incomingConnectionsBacklogSize ); } } \ No newline at end of file diff --git a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/GradleBuildCacheServer.kt b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/GradleBuildCacheServer.kt index 938ed36..e533c17 100644 --- a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/GradleBuildCacheServer.kt +++ b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/GradleBuildCacheServer.kt @@ -75,7 +75,6 @@ import java.util.Base64 import java.util.regex.Matcher import java.util.regex.Pattern import javax.naming.ldap.LdapName -import javax.net.ssl.SSLEngine import javax.net.ssl.SSLPeerUnverifiedException @@ -85,6 +84,7 @@ class GradleBuildCacheServer(private val cfg: Configuration) { companion object { val DEFAULT_CONFIGURATION_URL by lazy { "classpath:net/woggioni/gbcs/gbcs-default.xml".toUrl() } + private const val SSL_HANDLER_NAME = "sslHandler" fun loadConfiguration(configurationFile: Path): Configuration { val doc = Files.newInputStream(configurationFile).use { @@ -122,7 +122,6 @@ class GradleBuildCacheServer(private val cfg: Configuration) { @Sharable private class ClientCertificateAuthenticator( authorizer: Authorizer, - private val sslEngine: SSLEngine, private val anonymousUserRoles: Set?, private val userExtractor: Configuration.UserExtractor?, private val groupExtractor: Configuration.GroupExtractor?, @@ -130,6 +129,9 @@ class GradleBuildCacheServer(private val cfg: Configuration) { override fun authenticate(ctx: ChannelHandlerContext, req: HttpRequest): Set? { return try { + val sslHandler = (ctx.pipeline().get(SSL_HANDLER_NAME) as? SslHandler) + ?: throw ConfigurationException("Client certificate authentication cannot be used when TLS is disabled") + val sslEngine = sslHandler.engine() sslEngine.session.peerCertificates.takeIf { it.isNotEmpty() }?.let { peerCertificates -> @@ -206,25 +208,20 @@ class GradleBuildCacheServer(private val cfg: Configuration) { private val exceptionHandler = ExceptionHandler() - private val basicAuthenticator by lazy { - NettyHttpBasicAuthenticator(cfg.users, RoleAuthorizer()) - } - - private fun getAuthenticator(sslHandler : SslHandler?) = when(val auth = cfg.authentication) { - is Configuration.BasicAuthentication -> basicAuthenticator - is Configuration.ClientCertificateAuthentication -> { - if(sslHandler == null) throw ConfigurationException("Client certificate authentication cannot be used when TLS is disabled") - ClientCertificateAuthenticator( - RoleAuthorizer(), - sslHandler.engine(), - cfg.users[""]?.roles, - userExtractor(auth), - groupExtractor(auth) - ) - } - else -> null + private val authenticator = when (val auth = cfg.authentication) { + is Configuration.BasicAuthentication -> NettyHttpBasicAuthenticator(cfg.users, RoleAuthorizer()) + is Configuration.ClientCertificateAuthentication -> { + ClientCertificateAuthenticator( + RoleAuthorizer(), + cfg.users[""]?.roles, + userExtractor(auth), + groupExtractor(auth) + ) } + else -> null + } + companion object { private fun createSslCtx(tls: Configuration.Tls): SslContext { val keyStore = tls.keyStore @@ -307,14 +304,14 @@ class GradleBuildCacheServer(private val cfg: Configuration) { override fun initChannel(ch: Channel) { val pipeline = ch.pipeline() - val sslHandler = sslContext?.newHandler(ch.alloc())?.also { - pipeline.addLast(it) + sslContext?.newHandler(ch.alloc())?.also { + pipeline.addLast(SSL_HANDLER_NAME, it) } pipeline.addLast(HttpServerCodec()) pipeline.addLast(HttpChunkContentCompressor(1024)) pipeline.addLast(ChunkedWriteHandler()) pipeline.addLast(HttpObjectAggregator(cfg.maxRequestSize)) - getAuthenticator(sslHandler)?.let { + authenticator?.let { pipeline.addLast(it) } pipeline.addLast(eventExecutorGroup, serverHandler) @@ -512,7 +509,7 @@ class GradleBuildCacheServer(private val cfg: Configuration) { group(bossGroup, workerGroup) channel(serverSocketChannel) childHandler(ServerInitializer(cfg, eventExecutorGroup)) - option(ChannelOption.SO_BACKLOG, 128) + option(ChannelOption.SO_BACKLOG, cfg.incomingConnectionsBacklogSize) childOption(ChannelOption.SO_KEEPALIVE, true) } diff --git a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt index 9dd8d03..c5dfc23 100644 --- a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt +++ b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt @@ -35,6 +35,8 @@ object Parser { ?.let(String::toBoolean) ?: true val maxRequestSize = root.renderAttribute("max-request-size") ?.let(String::toInt) ?: 67108864 + val incomingConnectionsBacklogSize = root.renderAttribute("incoming-connections-backlog-size") + ?.let(String::toInt) ?: 1024 var authentication: Authentication? = null for (child in root.asIterable()) { val tagName = child.localName @@ -138,7 +140,19 @@ object Parser { } } } - return Configuration(host, port, serverPath, users, groups, cache!!, authentication, tls, useVirtualThread, maxRequestSize) + return Configuration( + host, + port, + serverPath, + users, + groups, + cache!!, + authentication, + tls, + useVirtualThread, + maxRequestSize, + incomingConnectionsBacklogSize + ) } private fun parseRoles(root: Element) = root.asIterable().asSequence().map { diff --git a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Serializer.kt b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Serializer.kt index f84a231..9739365 100644 --- a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Serializer.kt +++ b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Serializer.kt @@ -16,6 +16,8 @@ object Serializer { return Xml.of(GBCS.GBCS_NAMESPACE_URI, GBCS.GBCS_PREFIX + ":server") { attr("use-virtual-threads", conf.isUseVirtualThread.toString()) attr("max-request-size", conf.maxRequestSize.toString()) + attr("incoming-connections-backlog-size", conf.incomingConnectionsBacklogSize.toString()) + // attr("xmlns:xs", GradleBuildCacheServer.XML_SCHEMA_NAMESPACE_URI) val value = schemaLocations.asSequence().map { (k, v) -> "$k $v" }.joinToString(" ") attr("xs:schemaLocation", value , namespaceURI = GBCS.XML_SCHEMA_NAMESPACE_URI) diff --git a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml index b130ada..97ca2b2 100644 --- a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml +++ b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml @@ -1,6 +1,7 @@ diff --git a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/schema/gbcs.xsd b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/schema/gbcs.xsd index 05319ba..ca56ae9 100644 --- a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/schema/gbcs.xsd +++ b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/schema/gbcs.xsd @@ -25,6 +25,7 @@ + diff --git a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractBasicAuthServerTest.kt b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractBasicAuthServerTest.kt index b8b3418..5301e67 100644 --- a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractBasicAuthServerTest.kt +++ b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractBasicAuthServerTest.kt @@ -45,7 +45,8 @@ abstract class AbstractBasicAuthServerTest : AbstractServerTest() { Configuration.BasicAuthentication(), null, true, - 0x10000 + 0x10000, + 100 ) Xml.write(Serializer.serialize(cfg), System.out) } diff --git a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractTlsServerTest.kt b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractTlsServerTest.kt index 256d3b9..085db3d 100644 --- a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractTlsServerTest.kt +++ b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/AbstractTlsServerTest.kt @@ -157,7 +157,8 @@ abstract class AbstractTlsServerTest : AbstractServerTest() { true ), false, - 0x10000 + 0x10000, + 100 ) Xml.write(Serializer.serialize(cfg), System.out) } diff --git a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/NoAuthServerTest.kt b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/NoAuthServerTest.kt index ad08211..31f85b6 100644 --- a/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/NoAuthServerTest.kt +++ b/gbcs-server/src/test/kotlin/net/woggioni/gbcs/server/test/NoAuthServerTest.kt @@ -46,7 +46,8 @@ class NoAuthServerTest : AbstractServerTest() { null, null, true, - 0x10000 + 0x10000, + 100 ) Xml.write(Serializer.serialize(cfg), System.out) }