From 72626927646be82d8dcbe33156c70d66dbc695c9 Mon Sep 17 00:00:00 2001 From: Josha von Gizycki Date: Sat, 13 Sep 2025 21:25:29 +0200 Subject: [PATCH] change authentication modes --- src/main/kotlin/alfred/web/http/BuildsInfo.kt | 12 +++--- .../kotlin/alfred/web/http/HttpTrigger.kt | 23 ++++------- src/main/kotlin/alfred/web/http/Security.kt | 41 +++++++++++++++++-- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/alfred/web/http/BuildsInfo.kt b/src/main/kotlin/alfred/web/http/BuildsInfo.kt index d43232f..284aaa7 100644 --- a/src/main/kotlin/alfred/web/http/BuildsInfo.kt +++ b/src/main/kotlin/alfred/web/http/BuildsInfo.kt @@ -2,11 +2,11 @@ package alfred.web.http import alfred.web.core.Handles import alfred.web.core.build.BuildId +import jakarta.servlet.http.HttpServletRequest import org.springframework.http.MediaType import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController @@ -23,9 +23,8 @@ class BuildsInfo( fun info( @PathVariable("build") build: BuildId, - @RequestParam("key") - key: String? - ) = security.requireKey(build, key) { + req: HttpServletRequest + ) = security.requireAuth(build, req) { it } @@ -36,9 +35,8 @@ class BuildsInfo( fun handles( @PathVariable("build") build: BuildId, - @RequestParam("key") - key: String? - ) = security.requireKey(build, key) { + req: HttpServletRequest + ) = security.requireAuth(build, req) { handles.active(build) } diff --git a/src/main/kotlin/alfred/web/http/HttpTrigger.kt b/src/main/kotlin/alfred/web/http/HttpTrigger.kt index ae10665..dbb18c3 100644 --- a/src/main/kotlin/alfred/web/http/HttpTrigger.kt +++ b/src/main/kotlin/alfred/web/http/HttpTrigger.kt @@ -4,6 +4,7 @@ import alfred.web.core.build.BuildId import alfred.web.core.build.Builds import alfred.web.core.runner.GitRunner import alfred.web.core.runner.ScriptRunner +import jakarta.servlet.http.HttpServletRequest import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -30,15 +31,12 @@ class HttpTrigger( fun triggerGit( @PathVariable("build") build: BuildId, - @RequestParam("key") - key: String?, @RequestParam("rev") - rev: String - ) = security.requireKey(build, key) { + rev: String, + req: HttpServletRequest + ) = security.requireAuth(build, req) { val config = builds.buildConfig(build) - if (config.gitRepo == null) { - throw UnsupportedMode() - } + config.gitRepo ?: throw UnsupportedMode() val info = gitRunner.run(build, rev) @@ -57,15 +55,12 @@ class HttpTrigger( fun triggerScript( @PathVariable("build") build: BuildId, - @RequestParam("key") - key: String?, @RequestParam("rev") - rev: String? - ) = security.requireKey(build, key) { + rev: String?, + req: HttpServletRequest + ) = security.requireAuth(build, req) { val config = builds.buildConfig(build) - if (config.script == null) { - throw UnsupportedMode() - } + config.script ?: throw UnsupportedMode() val info = scriptRunner.run(build, rev) diff --git a/src/main/kotlin/alfred/web/http/Security.kt b/src/main/kotlin/alfred/web/http/Security.kt index 114026b..9b59dd2 100644 --- a/src/main/kotlin/alfred/web/http/Security.kt +++ b/src/main/kotlin/alfred/web/http/Security.kt @@ -3,19 +3,37 @@ package alfred.web.http import alfred.web.core.build.BuildConfig import alfred.web.core.build.BuildId import alfred.web.core.build.Builds +import jakarta.servlet.http.HttpServletRequest +import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.stereotype.Service +import java.util.Base64 @Service class Security( val builds: Builds ) { - fun requireKey(build: BuildId, apikey: String?, block: (BuildConfig) -> T): ResponseEntity<*> { + private val unauthorized = ResponseEntity( + HttpHeaders().also { + it.add(HttpHeaders.WWW_AUTHENTICATE, "Bearer") + it.add(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Alfred\"") + }, + HttpStatus.UNAUTHORIZED + ) + + fun requireAuth( + build: BuildId, + request: HttpServletRequest, + block: (BuildConfig) -> T + ): ResponseEntity<*> { + val auth = request.getHeader("Authorization") ?: return unauthorized + val token = bearerToken(auth) ?: basicAuthToken(auth) ?: return unauthorized + val buildConfig = builds.buildConfig(build) - if (buildConfig.apikey != "" && buildConfig.apikey != apikey) { - return ResponseEntity(HttpStatus.UNAUTHORIZED) + if (buildConfig.apikey != "" && buildConfig.apikey != token) { + return unauthorized } val entity = block(buildConfig) @@ -26,4 +44,21 @@ class Security( return ResponseEntity.ok(entity) } + private fun bearerToken(authHeader: String): String? { + return if (authHeader.startsWith("Bearer ")) { + authHeader.substring(7) + } else { + null + } + } + + private fun basicAuthToken(authHeader: String): String? { + return if (authHeader.startsWith("Basic ")) { + String(Base64.getDecoder().decode(authHeader.substring(6))) + .split(":")[1] + } else { + null + } + } + }