Advertisement
Guest User

Untitled

a guest
Mar 24th, 2015
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 6.60 KB | None | 0 0
  1.  
  2. import akka.pattern.AskTimeoutException
  3. import com.ctilogic.cvd.acl.api.AccountsAPI.GetAccount
  4. import com.ctilogic.cvd.acl.api.{Account, PrivilegedRoleRequest, Session, Roles}
  5. import com.ctilogic.cvd.acl.api.SessionsAPI.{TouchSession, CheckSession}
  6. import com.ctilogic.cvd.common.api.EntityId
  7. import com.ctilogic.cvd.common.aux.StackTraceHelper
  8. import com.ctilogic.cvd.common.messaging._
  9. import com.github.levkhomich.akka.tracing.TracingSupport
  10. import reactivemongo.bson.BSONObjectID
  11.  
  12. import scala.util.control.ControlThrowable
  13.  
  14.  
  15.  
  16. // TODO: doc
  17. abstract class RestRequestProcessor[+T <: RestRequest : Manifest]
  18.         extends RequestProcessor[T] with CommonAPIActor with DistributedServicesSupport
  19. {
  20.     import context.become
  21.  
  22.     private var _sessionId: Option[EntityId] = None
  23.     private var _sessionToken: Option[String] = None
  24.     private var _accountId: Option[EntityId] = None
  25.     private var _accountRoles: Set[Roles.Value] = Set.empty
  26.  
  27.     implicit protected val dispatcher = context.system.dispatchers.lookupHttpDispatcher
  28.  
  29.     def sessionId = _sessionId
  30.     def sessionToken = _sessionToken
  31.     def accountId = _accountId
  32.     def accountRoles = _accountRoles
  33.  
  34.     override protected def stages: Stage = super.stages compose handleAuthorization
  35.  
  36.     /**
  37.      * Provides backward compatibility for implicit rest response passing to the rootSender with errors in logs.
  38.      */
  39.     protected def passHttpResponseError: Receive = {
  40.         case r: RestResponse ⇒
  41.             log.error(s"Passing HTTP response $r from ${sender().path}; do not use it by default")
  42.             complete(r)
  43.     }
  44.  
  45.     override protected def handleDefaults = passHttpResponseError orElse super.handleDefaults
  46.  
  47.     protected def passHttpResponse: Receive = passHttpErrorResponse orElse passHttpCommonResponse
  48.  
  49.     protected def handleAuthorization(nextStage: Receive): Receive = {
  50.         case r: RestRequest ⇒
  51.             log.debug("Starting authorization")
  52.             _sessionId = r.$sessionId.map(BSONObjectID.apply)
  53.             _sessionToken = r.$sessionToken
  54.             log.debug(s"SessionId: ${_sessionId}; SessionToken: ${_sessionToken}")
  55.             log.debug(s"r.isInstanceOf[RequireAuthentication]: ${r.isInstanceOf[RequireAuthentication]}")
  56.             if (r.isInstanceOf[RequireAuthentication] && (_sessionId.isEmpty || _sessionToken.isEmpty))
  57.                 complete(ErrorResponse.Unauthorized)
  58.             else {
  59.                 stage(handleSession(nextStage))
  60.                 log.debug("Starting session processing")
  61.             }
  62.     }
  63.  
  64.  
  65.     protected def handleSession(nextStage: Receive): Receive = {
  66.         case r: RestRequest with RequireAuthentication ⇒
  67.             tellService(NodeRole.ACL, CheckSession(sessionId.get, sessionToken.get))
  68.             log.debug("Waiting for a Session(..)")
  69.             become(waitSession(nextStage))
  70.         case r: RestRequest ⇒
  71.             log.debug("Session not required")
  72.             stage(nextStage)
  73.             log.debug("Authorization complete going to next stage")
  74.     }
  75.  
  76.  
  77.     protected def waitSession(nextStage: Receive): Receive = {
  78.         case s: Session ⇒
  79.             _accountId = Some(s.accountId)
  80.             _accountRoles = s.roles
  81.  
  82.             log.debug("Session received accountId = ${_accountId}, roles = ${_accountRoles}")
  83.  
  84.             if (checkPrivilegedRequest(rootRequest)) {
  85.         tellService(NodeRole.ACL, TouchSession(s.id))
  86.                 stage(nextStage)
  87.                 log.debug("Authorization complete going to next stage")
  88.             }
  89.             else
  90.                 complete(ErrorResponse.Forbidden)
  91.  
  92.         case ErrorResponse.NotFound
  93.             complete(ErrorResponse.Unauthorized)
  94.     }
  95.  
  96.  
  97.     protected def checkPrivilegedRequest: (RestRequest ⇒ Boolean) = {
  98.         case r: RestRequest with PrivilegedRoleRequest ⇒
  99.             r.requiredRoles.subsetOf(accountRoles)
  100.         case _true
  101.     }
  102.  
  103.  
  104.     protected def passHttpErrorResponse: Receive = {
  105.         case e: ErrorResponse ⇒
  106.             log.info(s"Passing HTTP error response $e from ${sender().path}")
  107.             complete(e)
  108.     }
  109.  
  110.     protected def passHttpCommonResponse: Receive = {
  111.         case e: RestResponse ⇒
  112.             log.info(s"Passing HTTP response $e from ${sender().path}")
  113.             complete(e)
  114.     }
  115.  
  116.     override def handleTimeout = handleTimeoutWith(complete(ErrorResponse.RequestTimeout))
  117.  
  118.     override def handleUnexpected = {
  119.         case e ⇒
  120.             log.error(s"Handled unexpected message ${e.getClass.getName} from ${sender().path}")
  121.             complete(ErrorResponse.InternalServerError)
  122.     }
  123.  
  124.     protected def tellService(role: NodeRole.Value, request: InternalRequest): Unit =
  125.         tellService(NodeRole.ACL, request, rootRequest)
  126. }
  127.  
  128.  
  129.  
  130. /**
  131.  * This trait implements stackable pattern to provide Account object for the session handled by the request
  132.  * processor.
  133.  * This trait is private. The concrete implementations of this trait is [[HandleOptionAccount]], [[HandleAccount]].
  134.  */
  135. trait BaseHandleAccount extends RestRequestProcessor[RestRequest] {
  136.     import context.become
  137.  
  138.     protected var _account: Option[Account] = None
  139.  
  140.     abstract override protected def stages: Stage = super.stages compose handleAccount
  141.  
  142.     protected def handleAccount(nextStage: Receive): Receive = {
  143.         case _
  144.             log.debug("Trying to obtain account")
  145.             if (accountId.nonEmpty) {
  146.                 tellService(NodeRole.ACL, GetAccount(accountId.get))
  147.                 become {
  148.                     case a: Account ⇒ _account = Some(a)
  149.                         log.debug(s"Account received: $a; going to the next stage")
  150.                         stage(nextStage)
  151.                     case ErrorResponse.NotFound ⇒ onAccountNotFound(nextStage)
  152.                 }
  153.             }
  154.             else onAccountIdEmpty(nextStage)
  155.     }
  156.  
  157.     protected def onAccountNotFound(nextStage: Receive): Unit = {
  158.         log.debug("Account not found")
  159.         log.debug("Going to the next stage")
  160.         stage(nextStage)
  161.     }
  162.  
  163.     protected def onAccountIdEmpty(nextStage: Receive): Unit = {
  164.         log.debug("Unable to obtain account: accountId is empty")
  165.         log.debug("Going to the next stage")
  166.         stage(nextStage)
  167.     }
  168. }
  169.  
  170.  
  171.  
  172. /**
  173.  * This trait implements stackable pattern to provide optional Account object for the session handled by the request
  174.  * processor. The `account` will be None for request without session of session somehow not bound to any account.
  175.  */
  176. trait HandleOptionAccount extends BaseHandleAccount {
  177.     /**
  178.      * The account of the current session.
  179.      */
  180.     def account = _account
  181. }
  182.  
  183.  
  184. /**
  185.  * This trait implements stackable pattern to provide Account object for the session handled by the request
  186.  * processor. If session is empty or if related account object not found. Processor will complete with
  187.  * `ErrorResponse.InternalServerError`.
  188.  */
  189. trait HandleAccount extends BaseHandleAccount {
  190.     def account = _account.get
  191.  
  192.     override protected def onAccountIdEmpty(nextStage: Receive) = {
  193.         log.error("Unable to get account. accountId is empty")
  194.         complete(ErrorResponse.InternalServerError)
  195.     }
  196.  
  197.     override protected def onAccountNotFound(nextStage: Receive) = {
  198.         log.error("Unable to get account. Account not found.")
  199.         complete(ErrorResponse.InternalServerError)
  200.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement