Play 2.2 EssentialAction With Futures - scala

I'm trying to implement an authentication mechanism similar to this example:
def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
val maybeToken = requestHeader.headers.get("X-SECRET-TOKEN")
maybeToken map { token =>
action(token)(requestHeader) // apply requestHeader to EssentialAction produces the Iteratee[Array[Byte], SimpleResult]
} getOrElse {
Done(Unauthorized("401 No Security Token\n")) // 'Done' means the Iteratee has completed its computations
}
}
However, in my case I'm mapping a random token value to a session on the server side stored in Mongodb. The goal was to be able to let a user terminate all his other sessions at will.
However, the data I get from ReactiveMongo is going to be wrapped in a Future.
I would like something like this:
def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
val maybeToken = requestHeader.headers.get("session")
maybeToken map { token =>
//This returns a future..
Session.find(session).map { result =>
result match
case Some(session) => action(session)(requestHeader)
case None => Done(Unauthorized())
}
} getOrElse {
Done(Unauthorized("401 No Security Token\n")) // 'Done' means the Iteratee has completed its computations
}
}
Is this possible with EssentialAction?

Iteratee.flatten goes from Future[Iteratee[A, E]] => Iteratee[A, E] so you could do it like this:
def HasToken(action: String => EssentialAction): EssentialAction = EssentialAction { requestHeader =>
val maybeToken = requestHeader.headers.get("session")
val futureIteratee: Future[Iteratee[Array[Byte], SimpleResult]] = maybeToken map { token =>
//This returns a future..
Session.find(token).map {
case Some(session) => action(session)(requestHeader)
case None => Done[Array[Byte], SimpleResult](Unauthorized("Invalid token"))
}
} getOrElse {
Future.successful(Done[Array[Byte], SimpleResult](Unauthorized("401 No Security Token\n")))
}
Iteratee.flatten(futureIteratee)
}

You can use an ActionBuilder as the invokeBlock method return a Future[SimpleResult] so you can flatMap your future into a call to the underlying block
Something like
object Authenticated extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
Session.find(session).map { result =>
result match
case Some(session) => block(new AuthenticatedRequest(session))
case None => Unauthorized()
}
}
}
where AuthenticatedRequest is your request type that wraps your session object

Related

Why are Futures in scala realised using a collection in the companion object?

I'm not sure whether I chose the right title for my question..
I'm interested as to why the collection in the companion object is defined. Am I mistaken that this collection will have only one f in it? What I am seeing is a collection with exactly one element.
Here's the Future I'm dealing with:
trait Future[+T] { self =>
def onComplete(callback: Try[T] => Unit): Unit
def map[U](f: T => U) = new Future[U] {
def onComplete(callback: Try[U] => Unit) =
self onComplete (t => callback(t.map(f)))
}
def flatMap[U](f: T => Future[U]) = new Future[U] {
def onComplete(callback: Try[U] => Unit) =
self onComplete { _.map(f) match {
case Success(fu) => fu.onComplete(callback)
case Failure(e) => callback(Failure(e))
} }
}
def filter(p: T => Boolean) =
map { t => if (!p(t)) throw new NoSuchElementException; t }
}
Its companion object:
object Future {
def apply[T](f: => T) = {
val handlers = collection.mutable.Buffer.empty[Try[T] => Unit]
var result: Option[Try[T]] = None
val runnable = new Runnable {
def run = {
val r = Try(f)
handlers.synchronized {
result = Some(r)
handlers.foreach(_(r))
}
}
}
(new Thread(runnable)).start()
new Future[T] {
def onComplete(f: Try[T] => Unit) = handlers.synchronized {
result match {
case None => handlers += f
case Some(r) => f(r)
}
}
}
}
}
In my head I was imagining something like the following instead of the above companion object (notice how I replaced the above val handlers .. with var handler ..):
object Future {
def apply[T](f: => T) = {
var handler: Option[Try[T] => Unit] = None
var result: Option[Try[T]] = None
val runnable = new Runnable {
val execute_when_ready: Try[T] => Unit = r => handler match {
case None => execute_when_ready(r)
case Some(f) => f(r)
}
def run = {
val r = Try(f)
handler.synchronized {
result = Some(r)
execute_when_ready(r)
}
}
}
(new Thread(runnable)).start()
new Future[T] {
def onComplete(f: Try[T] => Unit) = handler.synchronized {
result match {
case None => handler = Some(f)
case Some(r) => f(r)
}
}
}
}
}
So why does the function execute_when_ready leads to stackoverflow, but that's not the case with handlers.foreach? what is the collection is offering me which I can't do without it? And is it possible to replace the collection with something else in the companion object?
The collection is not in the companion object, it is in the apply method, so there is a new instance for each Future. It is there because there can be multiple pending onComplete handlers on the same Future.
Your implementation only allows a single handler and silently removes any existing handler in onComplete which is a bad idea because the caller has no idea if a previous function has added an onComplete handler or not.
As noted in the comments, the stack overflow is because execute_when_ready calls itself if handler is None with no mechanism to stop the recursion.

How to implement multiple thread pools in a Play application using cats-effect IO

In my Play application, I service my requests usings cats-effect's IO, instead of Future in the controller, like this (super-simplified):
def handleServiceResult(serviceResult: ServiceResult): Result = ...
def serviceMyRequest(request: Request): IO[ServiceResult] = ...
def myAction = Action { request =>
handleServiceResult(
serviceMyRequest(request).unsafeRunSync()
)
}
Requests are then processed (asynchronously) on Play's default thread pool. Now, I want to implement multiple thread pools to handle different sorts of requests. Were I using Futures, I could do this:
val myCustomExecutionContext: ExecutionContext = ...
def serviceMyRequest(request: Request): Future[ServiceResult] = ...
def myAction = Action.async { request =>
Future(serviceMyRequest(request))(myCustomExecutionContext)
.map(handleServiceResult)(defaultExecutionContext)
}
But I'm not using Futures, I'm using IO, and I'm not sure about the right way to go about implementing it. This looks promising, but seems a bit clunky:
def serviceMyRequest(request: Request): IO[ServiceResult] = ...
def myAction = Action { request =>
val ioServiceResult = for {
_ <- IO.shift(myCustomExecutionContext)
serviceResult <- serviceMyRequest(request)
_ <- IO.shift(defaultExecutionContext)
} yield {
serviceResult
}
handleServiceResult(ioServiceResult.unsafeRunSync())
}
Is this the right way to implement it? Is there a best practice here? Am I screwing up badly? Thanks.
Ok, so since this doesn't seem to be well-trodden ground, this is what I ended up implementing:
trait PlayIO { self: BaseControllerHelpers =>
implicit class IOActionBuilder[A](actionBuilder: ActionBuilder[Request, A]) {
def io(block: Request[A] => IO[Result]): Action[A] = {
actionBuilder.apply(block.andThen(_.unsafeRunSync()))
}
def io(executionContext: ExecutionContext)(block: Request[A] => IO[Result]): Action[A] = {
val shiftedBlock = block.andThen(IO.shift(executionContext) *> _ <* IO.shift(defaultExecutionContext))
actionBuilder.apply(shiftedBlock.andThen(_.unsafeRunSync()))
}
}
}
Then (using the framework from the question) if I mix PlayIO into the controller, I can do this,
val myCustomExecutionContext: ExecutionContext = ...
def handleServiceResult(serviceResult: ServiceResult): Result = ...
def serviceMyRequest(request: Request): IO[ServiceResult] = ...
def myAction = Action.io(myCustomExecutionContext) { request =>
serviceMyRequest(request).map(handleServiceResult)
}
such that I execute the action's code block on myCustomExecutionContext and then, once complete, thread-shift back to Play's default execution context.
Update:
This is a bit more flexible:
trait PlayIO { self: BaseControllerHelpers =>
implicit class IOActionBuilder[R[_], A](actionBuilder: ActionBuilder[R, A]) {
def io(block: R[A] => IO[Result]): Action[A] = {
actionBuilder.apply(block.andThen(_.unsafeRunSync()))
}
def io(executionContext: ExecutionContext)(block: R[A] => IO[Result]): Action[A] = {
if (executionContext == defaultExecutionContext) io(block) else {
val shiftedBlock = block.andThen(IO.shift(executionContext) *> _ <* IO.shift(defaultExecutionContext))
io(shiftedBlock)
}
}
}
}
Update2:
Per the comment above, this will ensure we always shift back to the default thread pool:
trait PlayIO { self: BaseControllerHelpers =>
implicit class IOActionBuilder[R[_], A](actionBuilder: ActionBuilder[R, A]) {
def io(block: R[A] => IO[Result]): Action[A] = {
actionBuilder.apply(block.andThen(_.unsafeRunSync()))
}
def io(executionContext: ExecutionContext)(block: R[A] => IO[Result]): Action[A] = {
if (executionContext == defaultExecutionContext) io(block) else {
val shiftedBlock = block.andThen { ioResult =>
IO.shift(executionContext).bracket(_ => ioResult)(_ => IO.shift(defaultExecutionContext))
}
io(shiftedBlock)
}
}
}
}

PlayFramework migration 2.5.x to 2.6.x deprecated Action.async

Trying to migrate from 2.5.x to 2.6.x. I have trait Secured with old method IsAuthenticatedAsync, i'm trying to write new method IsAuthenticatedAsyncNew. Compiler says that Action.async is deprecated, so I tried to replace Action.asyinc block with ActionBuilder but I'm struggling as I can't find good 2.6.x examples how to do this.
trait Secured {
private def username(request: RequestHeader) = request.session.get("username")
private def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login())
def userService: UserService
def cc: ControllerComponents
/**
* Async action for authenticated users.
*/
def IsAuthenticatedAsync(f: => User => Request[AnyContent] => Future[Result]) = Security.Authenticated(username, onUnauthorized) { user =>
Action.async{ implicit request =>
val _user = userService.findByUsername(user)
if(_user.nonEmpty)
f(_user.get)(request)
else
Future.successful(Results.Redirect(routes.Application.login()))
}
}
def IsAuthenticatedAsyncNew(f: => User => Request[AnyContent] => Future[Result]) = new ActionBuilder[Request, AnyContent] {
override def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]) = {
val username = request.session.get("username")
val user = userService.findByUsername(username.get)
user match {
case Some(user) => f(user)(request)
case None => Future.successful(Results.Redirect(routes.Application.login()))
}
}
override protected def executionContext: ExecutionContext = cc.executionContext
override def parser: BodyParser[AnyContent] = cc.parsers.defaultBodyParser
}
}
Compiler returns error
Error:(40, 36) type mismatch;
found : play.api.mvc.Request[A]
required: play.api.mvc.Request[play.api.mvc.AnyContent]
case Some(user) => f(user)(request)
If i change footprint of method to
override def invokeBlock(request: Request[AnyContent], block: Request[AnyContent] => Future[Result])
then it doesn't ovveride nothing ... Can it be done this way at all?
Action in play 2.6 is defined in BaseController trait as
def Action: ActionBuilder[Request, AnyContent] = controllerComponents.actionBuilder
This means that you can simply replace Action.async with cc.actionBuilder.async(...)
or even copy that method
def Action = cc.actionBuilder
and use Action.async as previously.

Play2.2.x, BodyParser, Authentication, and Future[Result]

I'm trying to implement authentication in my Play 2.2.1 app, and I can't quite figure out how to make it work with an action that returns a Future[Result].
This post describes pretty close to what I'm trying to do, except without returning Future[Result]:
Play 2.0 Framework, using a BodyParser with an authenticated request
How can I get it to work with Futures? I.e. how would I implement this function:
def IsAuthenticated(f: => String => Request[Any] => Future[Result])
or, better yet, this function:
def IsAuthenticated[A}(b:BodyParser[A])(f: => String => Request[Any] => Future[Result])
which would feed into this function:
def AuthenticatedUser(g: Account => Request[AnyContent] => SimpleResult) = IsAuthenticated {...}
to wrap asynchronous actions in my controllers?
This part I can do:
def IsAuthenticated(f: => String => Request[AnyContent] => Future[SimpleResult]) = {
Security.Authenticated(email, onUnauthorized) {
user => Action.async(request => f(user)(request))
}
}
But if I try to use IsAuthenticated in my wrapper function:
def AuthenticatedUser(g: Account => Request[AnyContent] => Future[SimpleResult]) = IsAuthenticated {
email => implicit request => Account.find(email).map {
opt => opt match {
case Some(account) => g(account)(request)
case None => Future(onUnauthorized(request))
}
}
}
(Account.find returns a Future[Option[Account]] 'cause it's a mongodb call that may take some time. The desire to do the future thing right is what's causing me so much grief now)
I can't get AuthenticatedUser to satisfy the compiler. It says it's getting a Future[Future[SimpleResult]] instead of a Future[SimpleResult].
So, how best to build this whole thing? I need to be able to make authentication wrappers that rely on db calls that are asynchronous.
I'm sure I'm just dense and missing something obvious...
EDIT: Here's what I ended up with. Thank you Jean for pointing me in the right direction.
I found AuthenticatedController while rooting around and it's pretty close to what I'm looking for. I wanted two types of authentication: User (authenticated user) and Administrator (to wrap code for admin tasks).
package controllers
import models.Account
import play.api.mvc._
import scala.concurrent.Future
trait Secured {
class AuthenticatedRequest[A](val account: Account, request: Request[A]) extends WrappedRequest[A](request)
object User extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
request.session.get("email") match {
case Some(email) => {
Account.find(email).flatMap {
case Some(account) => {
block(new AuthenticatedRequest(account, request))
}
case _ => Future(Results.Redirect(routes.Index.index()))
}
}
case _ => Future(Results.Redirect(routes.Index.index()))
}
}
}
object Administrator extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[SimpleResult]) = {
request.session.get("email") match {
case Some(email) => {
Account.find(email).flatMap {
case Some(account) => if (account.admin) {
block(new AuthenticatedRequest(account, request))
} else {
Future(Results.Redirect(routes.Index.index()))
}
case _ => Future(Results.Redirect(routes.Index.index()))
}
}
case _ => Future(Results.Redirect(routes.Index.index()))
}
}
}
}
There have been changes in play 2.2 to make it easier to compose actions. The resource you are referring to is outdated.
Instead you should create a custom action builder by extending ActionBuilder to create your action, this will get you all the fancy apply methods you may need (including async support and all)
For example you may do :
trait MyAction extends Results{
class MyActionBuilder[A] extends ActionBuilder[({ type R[A] = Request[A] })#R] {
def invokeBlock[A](request: Request[A],
block: Request[A] => Future[SimpleResult]) ={
// your authentication code goes here :
request.cookies.get("loggedIn").map { _=>
block(request)
} getOrElse Future.successful(Unauthorized)
}
}
object MyAction extends MyActionBuilder
}
which you can then use as such :
object MyController extends Controller with MyAction{
def authenticatedAction=MyAction {
Ok
}
def asyncAuthenticatedAction=MyAction.async {
Future.successful(Ok)
}
def authenticatedActionWithBodyParser = MyAction(parse.json){ request =>
Ok(request.body)
}
}
For brevity's sake I used a very trivial authentication mechanism you will want to change that :)
Additionally, you can create a custom "request" type to provide additional information. For instance you could define a AuthenticatedRequest as such :
case class AuthenticatedRequest[A](user: User, request: Request[A]) extends WrappedRequest(request)
Provided you have a way to get your user such as
object User{
def find(s:String): Option[User] = ???
}
Then change your builder definition a bit as such
class MyActionBuilder[A] extends
ActionBuilder[({ type R[A] = AuthenticatedRequest[A] })#R] {
def invokeBlock[A](request: Request[A],
block: AuthenticatedRequest[A] => Future[SimpleResult]) ={
// your authentication code goes here :
(for{
userId <- request.cookies.get("userId")
user <- User.find(userId.value)
}yield {
block(AuthenticatedRequest(user,request))
}) getOrElse Future.successful(Unauthorized)
}
}
Your controller now has access to your user in authenticatedActions:
object MyController extends Controller with MyAction{
val logger = Logger("application.controllers.MyController")
def authenticatedAction=MyAction { authenticatedRequest =>
val user = authenticatedRequest.user
logger.info(s"User(${user.id} is accessing the authenticatedAction")
Ok(user.id)
}
def asyncAuthenticatedAction = MyAction.async { authenticatedRequest=>
Future.successful(Ok(authenticatedRequest.user.id))
}
def authenticatedActionWithBodyParser = MyAction(parse.json){ authenticatedRequest =>
Ok(authenticatedRequest.body)
}
}

How do I secure file upload in Play! Framework (Scala)

I have implemented a Secured trait as described in the tutorial:
trait Secured {
...
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
...
}
And using it like this:
def list = IsAuthenticated { username => _ =>
...
}
Now, I have the following definition for file uploads:
def upload = Action(parse.multipartFormData) { request =>
...
}
Is it possible to combine IsAuthenticated and parse.multipartFormData so I am able to check the user during the file upload?
The version you implemented doesn't receive a BodyParser. In the tutorial there is a version that accepts BodyParsers:
def Authenticated[A](p: BodyParser[A])(f: AuthenticatedRequest[A] => Result) = {
Action(p) { request =>
request.session.get("user").flatMap(u => User.find(u)).map { user =>
f(AuthenticatedRequest(user, request))
}.getOrElse(Unauthorized)
}
}
Use this one. All the code you need is at the bottom of the page.
You may have to overload the function.
def IsAuthenticated[A](p: BodyParser[A])(f: => String => Request[A] => Result): Action[A] ={
...
}
def IsAuthenticated[AnyContent](f: => String => Request[AnyContent] => Result): Action[AnyContent] =
IsAuthenticated(BodyParsers.parse.anyContent)(f)
I've done something similar in my application.