Skip to content
This repository has been archived by the owner on Sep 12, 2021. It is now read-only.

Commit

Permalink
Merge fafd8a6 into 3c860cf
Browse files Browse the repository at this point in the history
  • Loading branch information
GonzaGonza committed May 9, 2015
2 parents 3c860cf + fafd8a6 commit fba1524
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 12 deletions.
26 changes: 19 additions & 7 deletions silhouette/app/com/mohiva/play/silhouette/api/Authorization.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package com.mohiva.play.silhouette.api

import play.api.i18n.Messages
import play.api.mvc.RequestHeader
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

/**
* A trait to define Authorization objects that let you hook
Expand All @@ -38,7 +40,7 @@ trait Authorization[I <: Identity] {
* @param messages The messages for the current language.
* @return True if the user is authorized, false otherwise.
*/
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Boolean
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Future[Boolean]
}

/**
Expand All @@ -59,8 +61,8 @@ object Authorization {
* @return The authorization.
*/
def unary_! : Authorization[I] = new Authorization[I] {
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Boolean = {
!self.isAuthorized(identity)
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Future[Boolean] = {
self.isAuthorized(identity).map(x => !x)
}
}

Expand All @@ -71,8 +73,13 @@ object Authorization {
* @return The authorization.
*/
def &&(authorization: Authorization[I]): Authorization[I] = new Authorization[I] {
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Boolean = {
self.isAuthorized(identity) && authorization.isAuthorized(identity)
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Future[Boolean] = {
val leftF = self.isAuthorized(identity)
val rightF = authorization.isAuthorized(identity)
for {
left <- leftF
right <- rightF
} yield left && right
}
}

Expand All @@ -83,8 +90,13 @@ object Authorization {
* @return The authorization.
*/
def ||(authorization: Authorization[I]): Authorization[I] = new Authorization[I] {
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Boolean = {
self.isAuthorized(identity) || authorization.isAuthorized(identity)
def isAuthorized(identity: I)(implicit request: RequestHeader, messages: Messages): Future[Boolean] = {
val leftF = self.isAuthorized(identity)
val rightF = authorization.isAuthorized(identity)
for {
left <- leftF
right <- rightF
} yield left || right
}
}
}
Expand Down
24 changes: 20 additions & 4 deletions silhouette/app/com/mohiva/play/silhouette/api/Silhouette.scala
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,17 @@ trait Silhouette[I <: Identity, A <: Authenticator] extends Controller with Logg
* @return A handler result.
*/
protected def invokeBlock[B, T](block: SecuredRequest[B] => Future[HandlerResult[T]])(implicit request: Request[B]): Future[HandlerResult[T]] = {
handleAuthentication.flatMap {
withAuthorization(handleAuthentication).flatMap {
// A user is both authenticated and authorized. The request will be granted
case (Some(authenticator), Some(identity)) if authorize.isEmpty || authorize.get.isAuthorized(identity) =>
case (Some(authenticator), Some(identity), Some(authorized)) if authorized =>
env.eventBus.publish(AuthenticatedEvent(identity, request, request2Messages))
handleBlock(authenticator, a => block(SecuredRequest(identity, a, request)))
// A user is authenticated but not authorized. The request will be forbidden
case (Some(authenticator), Some(identity)) =>
case (Some(authenticator), Some(identity), _) =>
env.eventBus.publish(NotAuthorizedEvent(identity, request, request2Messages))
handleBlock(authenticator, _ => handleNotAuthorized(request).map(r => HandlerResult(r)))
// An authenticator but no user was found. The request will ask for authentication and the authenticator will be discarded
case (Some(authenticator), None) =>
case (Some(authenticator), None, _) =>
env.eventBus.publish(NotAuthenticatedEvent(request, request2Messages))
for {
result <- handleNotAuthenticated(request)
Expand All @@ -383,6 +383,22 @@ trait Silhouette[I <: Identity, A <: Authenticator] extends Controller with Logg
handleNotAuthenticated(request).map(r => HandlerResult(r))
}
}

/**
* Adds the authorization status to the authentication result.
*
* @param result The authentication result.
* @param request The current request header.
* @return The authentication result with the additional authorization status.
*/
private def withAuthorization(result: Future[(Option[Either[A, A]], Option[I])])(implicit request: RequestHeader) = {
result.flatMap {
case (a, Some(i)) =>
authorize.map(_.isAuthorized(i)).getOrElse(Future.successful(true)).map(b => (a, Some(i), Some(b)))
case (a, i) =>
Future.successful((a, i, None))
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,8 @@ class SilhouetteSpec extends PlaySpecification with Mockito with JsonMatchers {
* @param messages The messages for the current language.
* @return True if the user is authorized, false otherwise.
*/
def isAuthorized(identity: FakeIdentity)(implicit request: RequestHeader, messages: Messages): Boolean = isAuthorized
def isAuthorized(identity: FakeIdentity)(implicit request: RequestHeader, messages: Messages): Future[Boolean] = {
Future.successful(isAuthorized)
}
}
}

0 comments on commit fba1524

Please sign in to comment.