diff --git a/compiler/damlc/tests/src/DA/Test/Repl.hs b/compiler/damlc/tests/src/DA/Test/Repl.hs index d7d760cc812a..9ad5417d2306 100644 --- a/compiler/damlc/tests/src/DA/Test/Repl.hs +++ b/compiler/damlc/tests/src/DA/Test/Repl.hs @@ -56,7 +56,7 @@ withTokenFile f = withResource acquire release (f . fmap fst) where acquire = mask_ $ do (file, delete) <- newTempFile - writeFile file ("Bearer " <> jwtToken) + writeFile file jwtToken pure (file, delete) release = snd diff --git a/daml-script/test/BUILD.bazel b/daml-script/test/BUILD.bazel index 0a0797a404c7..97f66d228291 100644 --- a/daml-script/test/BUILD.bazel +++ b/daml-script/test/BUILD.bazel @@ -167,7 +167,7 @@ genrule( outs = ["test-auth-token.jwt"], cmd = """ cat < $(location test-auth-token.jwt) -Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsiYWRtaW4iOmZhbHNlLCJhY3RBcyI6WyJBbGljZSIsIkJvYiJdfX0.UYogXMZvmhzzjmsmKayaDsI2hGKh1T2Sz5l9h4tdgGM +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsiYWRtaW4iOmZhbHNlLCJhY3RBcyI6WyJBbGljZSIsIkJvYiJdfX0.UYogXMZvmhzzjmsmKayaDsI2hGKh1T2Sz5l9h4tdgGM EOF """, ) diff --git a/docs/source/daml-script/index.rst b/docs/source/daml-script/index.rst index af650312037d..27d187ffd9e5 100644 --- a/docs/source/daml-script/index.rst +++ b/docs/source/daml-script/index.rst @@ -278,9 +278,8 @@ To run DAML script against the JSON API you have to pass the ``--json-api`` para ledger API command, e.g., one ``createCmd`` or one ``exerciseCmd``. #. The JSON API requires an authentication token even when it is run against an unauthenticated ledger. The authentication token must be - a JWT ``Bearer`` token so the ``--access-token-file`` passed to - ``daml script`` should only contain the actual JWT without the - ``Bearer`` prefix. + a JWT token so the ``--access-token-file`` passed to + ``daml script`` should contain the actual JWT token. #. The token must contain exactly one party in ``actAs`` and/or ``readAs``. This party will be used for ``submit`` and ``query``. Passing a party as the argument to ``submit`` and diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/LedgerClientJwt.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/LedgerClientJwt.scala index 9855ea86697a..3367cfdd3f48 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/LedgerClientJwt.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/LedgerClientJwt.scala @@ -48,7 +48,7 @@ object LedgerClientJwt { type AllocateParty = (Jwt, Option[Ref.Party], Option[String]) => Future[api.domain.PartyDetails] - private def bearer(jwt: Jwt): Some[String] = Some(s"Bearer ${jwt.value: String}") + private def bearer(jwt: Jwt): Some[String] = Some(jwt.value: String) def submitAndWaitForTransaction(client: LedgerClient): SubmitAndWaitForTransaction = (jwt, req) => client.commandServiceClient.submitAndWaitForTransaction(req, bearer(jwt)) diff --git a/ledger/ledger-api-auth-client/src/main/java/com/daml/ledger/api/auth/client/LedgerCallCredentials.java b/ledger/ledger-api-auth-client/src/main/java/com/daml/ledger/api/auth/client/LedgerCallCredentials.java index b444383f1aab..bdf885035436 100644 --- a/ledger/ledger-api-auth-client/src/main/java/com/daml/ledger/api/auth/client/LedgerCallCredentials.java +++ b/ledger/ledger-api-auth-client/src/main/java/com/daml/ledger/api/auth/client/LedgerCallCredentials.java @@ -28,7 +28,7 @@ public LedgerCallCredentials(String token) { @Override public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) { Metadata metadata = new Metadata(); - metadata.put(LedgerCallCredentials.header, token); + metadata.put(LedgerCallCredentials.header, token.startsWith("Bearer ") ? token : "Bearer " + token); applier.apply(metadata); } diff --git a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthService.scala b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthService.scala index bdd8f689b265..84445733b2a9 100644 --- a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthService.scala +++ b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthService.scala @@ -5,6 +5,8 @@ package com.daml.ledger.api.auth import java.util.concurrent.CompletionStage +import io.grpc.Metadata + /** An interface for authorizing the ledger API access to a participant. * * The AuthService is responsible for converting request metadata (such as @@ -12,6 +14,14 @@ import java.util.concurrent.CompletionStage * These claims are then used by the ledger API server to check whether the * request is authorized. * + * - The authorization information MUST be specified in the `Authorization` header. + * - The value of the `Authorization` header MUST start with `Bearer ` + * (notice the trailing space of the prefix). + * - An [[AuthService]] implementation MAY use other headers when converting metadata + * to claims. + * + * + * * For example, a participant could: * - Ask all ledger API users to attach an `Authorization` header * with a JWT token as the header value. @@ -27,4 +37,11 @@ trait AuthService { * Return a failed future to reject requests with an INTERNAL error status. */ def decodeMetadata(headers: io.grpc.Metadata): CompletionStage[Claims] + + /** + * The [[Metadata.Key]] to use for looking up the `Authorization` header in the + * request metadata. + */ + val AUTHORIZATION_KEY: Metadata.Key[String] = + Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) } diff --git a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceJWT.scala b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceJWT.scala index f6a007707fe1..a31e50392e77 100644 --- a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceJWT.scala +++ b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceJWT.scala @@ -43,7 +43,7 @@ class AuthServiceJWT(verifier: JwtVerifierBase) extends AuthService { for { headerValue <- Option - .apply(headers.get(AuthServiceJWT.AUTHORIZATION_KEY)) + .apply(headers.get(AUTHORIZATION_KEY)) .toRight(Error("Authorization header not found")) token <- bearerTokenRegex .findFirstMatchIn(headerValue) @@ -85,9 +85,6 @@ class AuthServiceJWT(verifier: JwtVerifierBase) extends AuthService { object AuthServiceJWT { final case class Error(message: String) - val AUTHORIZATION_KEY: Metadata.Key[String] = - Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) - def apply(verifier: com.auth0.jwt.interfaces.JWTVerifier) = new AuthServiceJWT(new JwtVerifier(verifier)) diff --git a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceStatic.scala b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceStatic.scala index a5cdc9292212..7e1154468b93 100644 --- a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceStatic.scala +++ b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthServiceStatic.scala @@ -14,8 +14,8 @@ import io.grpc.Metadata */ final class AuthServiceStatic(claims: PartialFunction[String, Claims]) extends AuthService { override def decodeMetadata(headers: Metadata): CompletionStage[Claims] = { - if (headers.containsKey(AuthServiceStatic.AUTHORIZATION_KEY)) { - val authorizationValue = headers.get(AuthServiceStatic.AUTHORIZATION_KEY) + if (headers.containsKey(AUTHORIZATION_KEY)) { + val authorizationValue = headers.get(AUTHORIZATION_KEY).stripPrefix("Bearer ") CompletableFuture.completedFuture(claims.lift(authorizationValue).getOrElse(Claims.empty)) } else { CompletableFuture.completedFuture(Claims.empty) @@ -24,8 +24,5 @@ final class AuthServiceStatic(claims: PartialFunction[String, Claims]) extends A } object AuthServiceStatic { - private val AUTHORIZATION_KEY: Metadata.Key[String] = - Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) - def apply(claims: PartialFunction[String, Claims]) = new AuthServiceStatic(claims) } diff --git a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Main.scala b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Main.scala index d178ec0245e0..255a80109c09 100644 --- a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Main.scala +++ b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Main.scala @@ -133,7 +133,7 @@ object Main { Files.write( changeExtension(outputFile, "-bearer.txt").toPath, - s"Bearer ${signed.value}".getBytes(StandardCharsets.UTF_8)) + signed.value.getBytes(StandardCharsets.UTF_8)) Files.write( changeExtension(outputFile, "-payload.json").toPath, diff --git a/ledger/sandbox/src/test/lib/scala/com/digitalasset/platform/sandbox/services/SandboxFixtureWithAuth.scala b/ledger/sandbox/src/test/lib/scala/com/digitalasset/platform/sandbox/services/SandboxFixtureWithAuth.scala index 247078573fea..8643085454bf 100644 --- a/ledger/sandbox/src/test/lib/scala/com/digitalasset/platform/sandbox/services/SandboxFixtureWithAuth.scala +++ b/ledger/sandbox/src/test/lib/scala/com/digitalasset/platform/sandbox/services/SandboxFixtureWithAuth.scala @@ -63,7 +63,6 @@ trait SandboxFixtureWithAuth extends SandboxFixture { self: Suite => .getOrElse(sys.error("Failed to generate token")) .value - def toHeader(payload: AuthServiceJWTPayload, secret: String = jwtSecret) = - s"Bearer ${signed(payload, secret)}" - + def toHeader(payload: AuthServiceJWTPayload, secret: String = jwtSecret): String = + signed(payload, secret) }