From db3d1cb6a5dc1aa0fdee3fda79b4dc204cc4af48 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Fri, 9 Feb 2018 13:23:53 -0800 Subject: Overload authorize directive to check against service context This enables checking permissions when a service request is constructed synthetically. An example where this may be useful is in the case where an authorization token is not available as a header but can be obtained elsewhere, such as a session cookie. The service context may then be explicitly constructed with said token and reuse the existing permissions checking functionality. --- .../xyz/driver/core/rest/auth/AuthProvider.scala | 61 +++++++++++++--------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/main/scala/xyz/driver/core/rest/auth/AuthProvider.scala b/src/main/scala/xyz/driver/core/rest/auth/AuthProvider.scala index 9c89fc6..5ed98cc 100644 --- a/src/main/scala/xyz/driver/core/rest/auth/AuthProvider.scala +++ b/src/main/scala/xyz/driver/core/rest/auth/AuthProvider.scala @@ -28,37 +28,46 @@ abstract class AuthProvider[U <: User](val authorization: Authorization[U], log: */ def authenticatedUser(implicit ctx: ServiceRequestContext): OptionT[Future, U] + /** + * Verifies if a service context is authenticated and authorized to have `permissions` + */ + def authorize( + context: ServiceRequestContext, + permissions: Permission*): Directive1[AuthorizedServiceRequestContext[U]] = { + onComplete { + (for { + authToken <- OptionT.optionT(Future.successful(context.authToken)) + user <- authenticatedUser(context) + authCtx = context.withAuthenticatedUser(authToken, user) + authorizationResult <- authorization.userHasPermissions(user, permissions)(authCtx).toOptionT + + cachedPermissionsAuthCtx = authorizationResult.token.fold(authCtx)(authCtx.withPermissionsToken) + allAuthorized = permissions.forall(authorizationResult.authorized.getOrElse(_, false)) + } yield (cachedPermissionsAuthCtx, allAuthorized)).run + } flatMap { + case Success(Some((authCtx, true))) => provide(authCtx) + case Success(Some((authCtx, false))) => + val challenge = + HttpChallenges.basic(s"User does not have the required permissions: ${permissions.mkString(", ")}") + log.warn( + s"User ${authCtx.authenticatedUser} does not have the required permissions: ${permissions.mkString(", ")}") + reject(AuthenticationFailedRejection(CredentialsRejected, challenge)) + case Success(None) => + log.warn( + s"Wasn't able to find authenticated user for the token provided to verify ${permissions.mkString(", ")}") + reject(ValidationRejection(s"Wasn't able to find authenticated user for the token provided")) + case Failure(t) => + log.warn(s"Wasn't able to verify token for authenticated user to verify ${permissions.mkString(", ")}", t) + reject(ValidationRejection(s"Wasn't able to verify token for authenticated user", Some(t))) + } + } + /** * Verifies if request is authenticated and authorized to have `permissions` */ def authorize(permissions: Permission*): Directive1[AuthorizedServiceRequestContext[U]] = { serviceContext flatMap { ctx => - onComplete { - (for { - authToken <- OptionT.optionT(Future.successful(ctx.authToken)) - user <- authenticatedUser(ctx) - authCtx = ctx.withAuthenticatedUser(authToken, user) - authorizationResult <- authorization.userHasPermissions(user, permissions)(authCtx).toOptionT - - cachedPermissionsAuthCtx = authorizationResult.token.fold(authCtx)(authCtx.withPermissionsToken) - allAuthorized = permissions.forall(authorizationResult.authorized.getOrElse(_, false)) - } yield (cachedPermissionsAuthCtx, allAuthorized)).run - } flatMap { - case Success(Some((authCtx, true))) => provide(authCtx) - case Success(Some((authCtx, false))) => - val challenge = - HttpChallenges.basic(s"User does not have the required permissions: ${permissions.mkString(", ")}") - log.warn( - s"User ${authCtx.authenticatedUser} does not have the required permissions: ${permissions.mkString(", ")}") - reject(AuthenticationFailedRejection(CredentialsRejected, challenge)) - case Success(None) => - log.warn( - s"Wasn't able to find authenticated user for the token provided to verify ${permissions.mkString(", ")}") - reject(ValidationRejection(s"Wasn't able to find authenticated user for the token provided")) - case Failure(t) => - log.warn(s"Wasn't able to verify token for authenticated user to verify ${permissions.mkString(", ")}", t) - reject(ValidationRejection(s"Wasn't able to verify token for authenticated user", Some(t))) - } + authorize(ctx, permissions: _*) } } } -- cgit v1.2.3