From 42d86acd06857733694cd0ac405d7559701e48a1 Mon Sep 17 00:00:00 2001 From: pbatko-da Date: Tue, 25 Jan 2022 09:55:37 +0100 Subject: [PATCH] [User management] Disabling user management in auth when user management feature is disabled [DPP-827] (#12503) CHANGELOG_BEGIN CHANGELOG_END --- .../rxjava/grpc/helpers/LedgerServices.scala | 2 +- .../error/definitions/LedgerApiErrors.scala | 6 ++ .../AuthorizationInterceptor.scala | 85 ++++++++++++------- .../auth/AuthorizationInterceptorSpec.scala | 7 +- .../apiserver/StandaloneApiServer.scala | 2 +- 5 files changed, 69 insertions(+), 33 deletions(-) diff --git a/language-support/java/bindings-rxjava/src/test/scala/com/daml/ledger/rxjava/grpc/helpers/LedgerServices.scala b/language-support/java/bindings-rxjava/src/test/scala/com/daml/ledger/rxjava/grpc/helpers/LedgerServices.scala index fcdeec444008..15cfe274c8ce 100644 --- a/language-support/java/bindings-rxjava/src/test/scala/com/daml/ledger/rxjava/grpc/helpers/LedgerServices.scala +++ b/language-support/java/bindings-rxjava/src/test/scala/com/daml/ledger/rxjava/grpc/helpers/LedgerServices.scala @@ -94,7 +94,7 @@ final class LedgerServices(val ledgerId: String) { ): Server = { val authorizationInterceptor = AuthorizationInterceptor( authService, - new InMemoryUserManagementStore(), + Some(new InMemoryUserManagementStore()), executionContext, new ErrorCodesVersionSwitcher(enableSelfServiceErrorCodes = true), ) diff --git a/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala b/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala index 30918c946fe8..a3fe584fc2ab 100644 --- a/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala +++ b/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala @@ -304,6 +304,12 @@ object LedgerApiErrors extends LedgerApiErrorGroup { ) extends LoggingTransactionErrorImpl( cause = "The command is missing a (valid) JWT token" ) + + case class UserBasedAuthenticationIsDisabled()(implicit + loggingContext: ContextualizedErrorLogger + ) extends LoggingTransactionErrorImpl( + cause = "User based authentication is disabled." + ) } @Explanation("An internal system authorization error occurred.") diff --git a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/interceptor/AuthorizationInterceptor.scala b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/interceptor/AuthorizationInterceptor.scala index 992b64ac4cb0..07535bc04acb 100644 --- a/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/interceptor/AuthorizationInterceptor.scala +++ b/ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/interceptor/AuthorizationInterceptor.scala @@ -3,6 +3,7 @@ package com.daml.ledger.api.auth.interceptor +import com.daml.error.definitions.LedgerApiErrors import com.daml.error.{DamlContextualizedErrorLogger, ErrorCodesVersionSwitcher} import com.daml.ledger.api.auth._ import com.daml.ledger.api.domain.UserRight @@ -18,10 +19,12 @@ import scala.util.{Failure, Success, Try} /** This interceptor uses the given [[AuthService]] to get [[Claims]] for the current request, * and then stores them in the current [[Context]]. + * + * @param userManagementStoreO - use None if user management is disabled */ final class AuthorizationInterceptor( authService: AuthService, - userManagementStore: UserManagementStore, + userManagementStoreO: Option[UserManagementStore], implicit val ec: ExecutionContext, errorCodesVersionSwitcher: ErrorCodesVersionSwitcher, )(implicit loggingContext: LoggingContext) @@ -77,37 +80,59 @@ final class AuthorizationInterceptor( private[this] def resolveAuthenticatedUserRights(claimSet: ClaimSet): Future[ClaimSet] = claimSet match { case ClaimSet.AuthenticatedUser(userIdStr, participantId, expiration) => - Ref.UserId.fromString(userIdStr) match { - case Left(err) => - Future.failed( - errorFactories.invalidArgument(None)(s"token $err")(errorLogger) - ) - case Right(userId) => - userManagementStore - .listUserRights(userId) - .flatMap { - case Left(msg) => - Future.failed( - errorFactories.permissionDenied( - s"Could not resolve rights for user '$userId' due to '$msg'" - )(errorLogger) - ) - case Right(userClaims) => - Future.successful( - ClaimSet.Claims( - claims = userClaims.view.map(userRightToClaim).toList.prepended(ClaimPublic), - ledgerId = None, - participantId = participantId, - applicationId = Some(userId), - expiration = expiration, - resolvedFromUser = true, - ) - ) - } + for { + userManagementStore <- getUserManagementStore(userManagementStoreO) + userId <- getUserId(userIdStr) + userRightsResult <- userManagementStore.listUserRights(userId) + claimsSet <- userRightsResult match { + case Left(msg) => + Future.failed( + errorFactories.permissionDenied( + s"Could not resolve rights for user '$userId' due to '$msg'" + )(errorLogger) + ) + case Right(userClaims) => + Future.successful( + ClaimSet.Claims( + claims = userClaims.view.map(userRightToClaim).toList.prepended(ClaimPublic), + ledgerId = None, + participantId = participantId, + applicationId = Some(userId), + expiration = expiration, + resolvedFromUser = true, + ) + ) + } + } yield { + claimsSet } case _ => Future.successful(claimSet) } + private[this] def getUserManagementStore( + userManagementStoreO: Option[UserManagementStore] + ): Future[UserManagementStore] = + userManagementStoreO match { + case None => + Future.failed( + LedgerApiErrors.AuthorizationChecks.Unauthenticated + .UserBasedAuthenticationIsDisabled()(errorLogger) + .asGrpcError + ) + case Some(userManagementStore) => + Future.successful(userManagementStore) + } + + private[this] def getUserId(userIdStr: String): Future[Ref.UserId] = + Ref.UserId.fromString(userIdStr) match { + case Left(err) => + Future.failed( + errorFactories.invalidArgument(None)(s"token $err")(errorLogger) + ) + case Right(userId) => + Future.successful(userId) + } + private[this] def userRightToClaim(r: UserRight): Claim = r match { case UserRight.CanActAs(p) => ClaimActAsParty(Ref.Party.assertFromString(p)) case UserRight.CanReadAs(p) => ClaimReadAsParty(Ref.Party.assertFromString(p)) @@ -133,11 +158,11 @@ object AuthorizationInterceptor { def apply( authService: AuthService, - userManagementStore: UserManagementStore, + userManagementStoreO: Option[UserManagementStore], ec: ExecutionContext, errorCodesStatusSwitcher: ErrorCodesVersionSwitcher, ): AuthorizationInterceptor = LoggingContext.newLoggingContext { implicit loggingContext: LoggingContext => - new AuthorizationInterceptor(authService, userManagementStore, ec, errorCodesStatusSwitcher) + new AuthorizationInterceptor(authService, userManagementStoreO, ec, errorCodesStatusSwitcher) } } diff --git a/ledger/ledger-api-auth/src/test/suite/scala/com/digitalasset/ledger/api/auth/AuthorizationInterceptorSpec.scala b/ledger/ledger-api-auth/src/test/suite/scala/com/digitalasset/ledger/api/auth/AuthorizationInterceptorSpec.scala index 59369ed3b1a1..737b95b140b7 100644 --- a/ledger/ledger-api-auth/src/test/suite/scala/com/digitalasset/ledger/api/auth/AuthorizationInterceptorSpec.scala +++ b/ledger/ledger-api-auth/src/test/suite/scala/com/digitalasset/ledger/api/auth/AuthorizationInterceptorSpec.scala @@ -66,7 +66,12 @@ class AuthorizationInterceptorSpec val errorCodesStatusSwitcher = new ErrorCodesVersionSwitcher(usesSelfServiceErrorCodes) val authorizationInterceptor = - AuthorizationInterceptor(authService, userManagementService, global, errorCodesStatusSwitcher) + AuthorizationInterceptor( + authService, + Some(userManagementService), + global, + errorCodesStatusSwitcher, + ) val statusCaptor = ArgCaptor[Status] val metadataCaptor = ArgCaptor[Metadata] diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala index e89397032a9a..d63e45b4784b 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/StandaloneApiServer.scala @@ -128,7 +128,7 @@ object StandaloneApiServer { config.tlsConfig, AuthorizationInterceptor( authService, - userManagementStore, + Option.when(config.enableUserManagement)(userManagementStore), servicesExecutionContext, errorCodesVersionSwitcher, ) :: otherInterceptors,