fix(tournament): use HS256 director token for native tournament-server calls
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
The tournament-server only accepts HS256 tokens it issued; forwarding a NowChessSystems RS256 user token caused "unsupported algorithm". Proxied calls (start/join/withdraw/stream) targeting the native server now swap in the director token registered on that server. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+28
-2
@@ -6,6 +6,7 @@ import jakarta.enterprise.context.ApplicationScoped
|
|||||||
import jakarta.inject.Inject
|
import jakarta.inject.Inject
|
||||||
import jakarta.ws.rs.client.{Client, ClientBuilder, Entity}
|
import jakarta.ws.rs.client.{Client, ClientBuilder, Entity}
|
||||||
import jakarta.ws.rs.core.MediaType
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty
|
||||||
import scala.compiletime.uninitialized
|
import scala.compiletime.uninitialized
|
||||||
import scala.util.Try
|
import scala.util.Try
|
||||||
|
|
||||||
@@ -15,10 +16,35 @@ class ExternalTournamentClient:
|
|||||||
// scalafix:off DisableSyntax.var
|
// scalafix:off DisableSyntax.var
|
||||||
@Inject var objectMapper: ObjectMapper = uninitialized
|
@Inject var objectMapper: ObjectMapper = uninitialized
|
||||||
@volatile private var directorToken: Option[String] = None
|
@volatile private var directorToken: Option[String] = None
|
||||||
|
|
||||||
|
@ConfigProperty(name = "nowchess.tournament.native-server-url", defaultValue = "http://141.37.123.132:8086")
|
||||||
|
var nativeServerUrl: String = uninitialized
|
||||||
|
|
||||||
|
@ConfigProperty(name = "nowchess.tournament.director-name", defaultValue = "NowChess System")
|
||||||
|
var directorName: String = uninitialized
|
||||||
// scalafix:on
|
// scalafix:on
|
||||||
|
|
||||||
private def buildClient(): Client = ClientBuilder.newClient()
|
private def buildClient(): Client = ClientBuilder.newClient()
|
||||||
|
|
||||||
|
// The tournament-server only accepts HS256 tokens it issued. Never forward a NowChessSystems
|
||||||
|
// RS256 user token to it — swap in the director token registered on that server.
|
||||||
|
private def normalize(url: String): String = url.stripSuffix("/")
|
||||||
|
|
||||||
|
private def isNativeServer(serverUrl: String): Boolean =
|
||||||
|
nativeServerUrl.nonEmpty && normalize(serverUrl) == normalize(nativeServerUrl)
|
||||||
|
|
||||||
|
private def directorBearer(): Option[String] =
|
||||||
|
directorToken
|
||||||
|
.orElse {
|
||||||
|
val fresh = registerDirector(nativeServerUrl, directorName)
|
||||||
|
directorToken = fresh
|
||||||
|
fresh
|
||||||
|
}
|
||||||
|
.map(t => s"Bearer $t")
|
||||||
|
|
||||||
|
private def authFor(serverUrl: String, userAuth: Option[String]): Option[String] =
|
||||||
|
if isNativeServer(serverUrl) then directorBearer() else userAuth
|
||||||
|
|
||||||
def publishNative(serverUrl: String, directorName: String, form: String): Boolean =
|
def publishNative(serverUrl: String, directorName: String, form: String): Boolean =
|
||||||
val token = directorToken.orElse {
|
val token = directorToken.orElse {
|
||||||
val fresh = registerDirector(serverUrl, directorName)
|
val fresh = registerDirector(serverUrl, directorName)
|
||||||
@@ -105,7 +131,7 @@ class ExternalTournamentClient:
|
|||||||
Try {
|
Try {
|
||||||
val client = buildClient()
|
val client = buildClient()
|
||||||
val builder = client.target(s"$serverUrl/$path").request(MediaType.APPLICATION_JSON)
|
val builder = client.target(s"$serverUrl/$path").request(MediaType.APPLICATION_JSON)
|
||||||
val withAuth = authHeader.fold(builder)(h => builder.header("Authorization", h))
|
val withAuth = authFor(serverUrl, authHeader).fold(builder)(h => builder.header("Authorization", h))
|
||||||
val response = withAuth.post(Entity.json(""))
|
val response = withAuth.post(Entity.json(""))
|
||||||
try (response.getStatus, response.readEntity(classOf[String]))
|
try (response.getStatus, response.readEntity(classOf[String]))
|
||||||
finally
|
finally
|
||||||
@@ -132,7 +158,7 @@ class ExternalTournamentClient:
|
|||||||
Try {
|
Try {
|
||||||
val client = buildClient()
|
val client = buildClient()
|
||||||
val builder = client.target(s"$serverUrl/$path").request("application/x-ndjson")
|
val builder = client.target(s"$serverUrl/$path").request("application/x-ndjson")
|
||||||
val withAuth = authHeader.fold(builder)(h => builder.header("Authorization", h))
|
val withAuth = authFor(serverUrl, authHeader).fold(builder)(h => builder.header("Authorization", h))
|
||||||
val response = withAuth.get()
|
val response = withAuth.get()
|
||||||
if response.getStatus == 200 then Some(response.readEntity(classOf[java.io.InputStream]))
|
if response.getStatus == 200 then Some(response.readEntity(classOf[java.io.InputStream]))
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user