FakeRequest down-casted to RequestHeader - scala

I have a controller that is protected by an Authentication trait. The trait looks like this:
def isAuthenticated(f: => AccountDTO => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>
Action.async {
request => {
Future.successful(f(user)(request))
}
}
}
Everything works well when doing a normal request, but when doing unit tests I encounter problems.
I create the following fake request:
val goodRequest = FakeRequest("POST", "/platform/api/v1/files")
.withBody(Json.toJson(ScalaMockingUtil.fileValidMetadataJson))
.withHeaders((HeaderNames.AUTHORIZATION, "4322tertf2643t34t34"))
Next, I get my controller object and call the method by applying that FakeRequest:
val result: Iteratee[Array[Byte], Result] = filesController.createFileMetadata()(goodRequest)
The problem that I am facing is that somewhere along the line the FakeReuqest gets down-casted to RequestHeader. The problem seems to be the one described here: Unable to test controller using Action.async where the Action has two apply methods instead of one. however, I can't seem to be able to force the one that I need.
Any help is appreciated.

The solution (or a workaround) was to use call() instead of apply():
val result = call(filesController.createFileMetadata(), goodRequest)
Now everything works as intended.

Related

Asynchronous wait for database-value in Playframework (2.4-M3) and Slick (3.0.0-RC3)

I'd like to keep my application as asynchronously as possible. Now I have this repository:
object LanguageRepository extends LanguageRepositoryTrait
{
private val languages = TableQuery[Languages]
private def db:Database = Database.forDataSource(DB.getDataSource())
private def filterQuery(id: Long): Query[Languages, Language, Seq] = languages.filter(_.id === id)
private def filterCode(code: String): Query[Languages, Language, Seq] = languages.filter(_.code === code)
private def all() : Query[Languages, Language, Seq] = languages
override def find(id: Long): Future[Language] =
{
try db.run(filterQuery(id).result.head)
finally db.close()
}
override def find(code: String): Future[Language] =
{
try db.run(filterCode(code).result.head)
finally db.close()
}
override def get(): Future[Seq[Language]] =
{
try db.run(all().result)
finally db.close()
}
}
When I call a url like "domain.tld/{language}" I want to check whether the given language(code) actually exists. Like, if the site isn't available in french (fr) I want to throw an exception or a 404.
Now, my problem is that this whole asynchronously thing is pretty cool and while I do think to understand the theory behind it, I'm rather baffled right now. I mean, I want this to be non-blocking (and asynchronously, which is the reason for me using Future and async ;))
In my controller I want to do something like:
def checkLanguage(language:String) = Action
{
val lang:Future[Language] = languageRepository.find(language)
lang.onComplete
{
case Success(s) = Ok("Yay")
case Failure(f) = 404("Oh no!")
}
}
Of course this can't work, but that's a schema of how I want to have things working. I want to wait or postpone the rendering of the site, until it's confirmed that the given language-code is valid or invalid.
I had a look at the Playframeworks async-documentation for 2.3.6 (https://www.playframework.com/documentation/2.3.6/ScalaAsync) but I couldn't really get this to work as intended.
Any input appreciated!
From your db query don't use .head instead use .headOption. that way ur return type will be a Future [Option [x]]
In ur controller u can do something like this
Lang.map { case Some (x) => Ok (x)
case None => 404 ( "not found ")
}
Try this,
Action.async {
val lang:Future[Option[Language]] = languageRepository.find(language)
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
}
First of all, I am assuming that if there is a possibility that a language will not exist then languageRepository.find(language) should return an Option of Language. Change Future[Language] to Future[Result] and use Action.async instead of Action
Now for some explanation, Action takes a block whose result should be Result. However, what you get is Future[Option[Language]]. Play provides async method for Action which needs Future[Result] and it takes cares of completing the request.
So, you need to convert Future[Option[Language]] to Future[Result].
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
We map over the lang, if the Option[Language] is not None then we convert it to Ok("yay") else we convert it to NotFound
Even, If you don't get Option[Language], the idea remains the same. Convert Future[Language] to Future[Result] and use Action.async instead of Action

Extend SecureActionBuilder to Validate Request Before Parsing the Body

I am working on writing a web application that takes multipart files as input and uploads them to an S3 instance. Since some of the files can be very large, I am using a custom Body Parser to send the chunks to S3 as they come in.
I want to do validation on the request prior to uploading the file (to check that the user has permission/enough space, etc). From reading the Play docs, it seems like extending ActionBuilder is the right way to do this. I noticed in SecureSocial, there is a SecureActionBuilder and I believe I should extend this in order to build a secure action (which is what I want).
I tried this simple test to see if I could print out the userId, therefore being able to perform actions based on the user.
object FileValidationAction extends SecuredActionBuilder {
def invokeBlock[A](request: SecuredRequest[A], block: SecuredRequest[A] => Future[SimpleResult]) = {
Logger.info("User id is " + request.user.userProfile.userId)
block(request)
}
}
However, the method never got called.
Next, I tried overriding the method from the SecuredActionBuilder object:
object FileValidationAction extends SecuredActionBuilder {
override def invokeBlock[A](request: Request[A], block: SecuredRequest[A] => Future[SimpleResult]) = {
val securedResult: Option[SecuredRequest[A]] = request match {
case r: SecuredRequest[A] => Option(r)
case _ => None
}
Logger.info("Calling action ------- WOO!")
securedResult match {
case Some(r) =>
block(r)
case _ =>
Future.successful(Forbidden)
}
}
}
That method gets called but the request coming in is not a SecuredRequest as I was hoping.
How do I build a SecuredAction, using a custom body parser, that I can do validation on before it completes (or even starts) the upload?
EDIT:
To clarify, I will be calling the Action with the following method signature:
def upload = FileValidationAction(streamingBodyParser(streamConstructor)) { request =>
The problem is that you are not invoking the original code in SecuredActionBuilder that actually checks if the user is there and constructs the SecuredRequest instance.
Something like this should work:
// A sample usage of the action
def checkFile = FileValidationAction { request =>
Ok("")
}
// The builder implementation
object FileValidationAction extends FileValidationActionBuilder {
def apply[A]() = new FileValidationActionBuilder()
}
class FileValidationActionBuilder(authorize: Option[Authorization[DemoUser]] = None) extends SecuredActionBuilder(authorize) {
def validateFile[A](block: SecuredRequest[A] => Future[SimpleResult]): SecuredRequest[A] => Future[SimpleResult] = { securedRequest =>
Logger.info(s"User id is ${securedRequest.user.main.userId}")
block(securedRequest)
}
override def invokeBlock[A](request: Request[A], block: (SecuredRequest[A]) => Future[SimpleResult]): Future[SimpleResult] = {
invokeSecuredBlock(authorize, request, validateFile(block))
}
}
You would need to add this inside the controller where you plan to use this actions. If you need to use it in multiple controllers then create a trait that you can extend with this.
Also note that in this sample code I am using the DemoUser type I have in the samples. You will need to change that to the type you are using in your app to represent users.

How to wrap Actions (in any order) when using Play's ActionBuilder?

I am using Play's ActionBuilder to create various Actions that secure my controllers. For instance, I implemented IsAuthenticated to make sure that certain actions can only be accessed if the user would be logged in:
case class AuthRequest[A](user: String, request: Request[A]) extends WrappedRequest[A](request)
private[controllers] object IsAuthenticated extends ActionBuilder[AuthRequest] {
def invokeBlock[A](req: Request[A], block: (AuthRequest[A]) => Future[SimpleResult]) = {
req.session.get("user").map { user =>
block(new AuthRequest(user, req))
} getOrElse {
Future.successful(Results.Unauthorized("401 No user\n"))
}
}
}
Using IsAuthenticated I can (1) restrict an action to users who are logged in, and (b) access the user being logged in:
def auth = IsAuthenticated { implicit authRequest =>
val user = authRequest.user
Ok(user)
}
Furthermore, I use ActionBuilder HasToken to ensure that an action was invoked with a token being present in the request's header (and, I can access the token value):
case class TokenRequest[A](token: String, request: Request[A]) extends WrappedRequest[A](request)
private[controllers] object HasToken extends ActionBuilder[TokenRequest] {
def invokeBlock[A](request: Request[A], block: (TokenRequest[A]) => Future[SimpleResult]) = {
request.headers.get("X-TOKEN") map { token =>
block(TokenRequest(token, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No Security Token\n"))
}
}
}
That way, I can make sure that an action was called with that token present:
def token = HasToken { implicit tokeRequest =>
val token = tokeRequest.token
Ok(token)
}
So far, so good...
But, how could I wrap (or, nest / compose) such actions as those defined above? For instance, I would like to ensure (a) that a user would be logged in and (b) that the token would be present:
def tokenAndAuth = HasToken { implicit tokeRequest =>
IsAuthenticated { implicit authRequest =>
val token = tokeRequest.token
val user = authRequest.user
}
}
However, the above action does not compile. I tried many different implementations but always failed to achieve the desired behavior.
In general terms: How could I compose Actions defined using Play's ActionBuilder in arbitrary order? In the above example, it would not matter if I would wrap IsAuthenticated in HasToken or the other way around -- the effect would be the same: the user would have to be logged in and would have to present the token.
Note: I have created a Gist that provides the complete source code.
ActionBuilder
ActionBuilders are not made for ad-hoc composition, but rather to build a hierarchy of actions so you end up using only a couple of actions throughout your controllers.
So in your example you should build IsAuthenticated on top of HasToken as I illustrated here.
This is a viable solution and can actually simplify your code. How often do you really need to compose on the spot?
EssentialAction
Ad-hoc composition could be achieved with EssentialActions (simply because they haven't changed from 2.1), but they have a few downsides, as Johan pointed out. Their API is not really intended for ad-hoc use either, and Iteratees are too low-level and too cumbersome for controller actions.
Actions
So finally your last option would be to write Actions directly. Actions do not support passing a WrappedRequest by default (that's why ActionBuilder exists). However you can still pass a WrappedRequest and have the next Action deal with it.
The following is the best I have come up with so far and is rather fragile I guess.
case class HasToken[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Future[SimpleResult] = {
request.headers.get("X-TOKEN") map { token =>
action(TokenRequest(token, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No Security Token\n"))
}
}
lazy val parser = action.parser
}
case class IsAuthenticated[A](action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Future[SimpleResult] = {
request.session.get("user").map { user =>
action(new AuthRequest(user, request))
} getOrElse {
Future.successful(Results.Unauthorized("401 No user\n"))
}
}
lazy val parser = action.parser
}
object ActionComposition extends Controller {
def myAction = HasToken {
Action.async(parse.empty) { case TokenRequest(token, request) =>
Future {
Ok(token)
}
}
}
def myOtherAction = IsAuthenticated {
Action(parse.json) { case AuthRequest(user, request) =>
Ok
}
}
def both = HasToken {
IsAuthenticated {
Action(parse.empty) { case AuthRequest(user, request: TokenRequest[_]) =>
Ok(request.token)
}
}
}
}
Results
You can also compose at the Result level and only use the built-in actions. This is especially useful when trying to factor out error handling and other repetitive stuff. I have an example here.
Conclusion
We are still missing the capabilities that Play 2.1's action composition offered. So far to me it seems that ActionBuilder + Result composition is the winner as its successor.
The output from an action builder is an action, an action is essentially a function from request => future result, so you can actually just call it like this:
def tokenAndAuth = HasToken.async { implicit tokenRequest =>
IsAuthenticated { implicit authRequest =>
val token = tokenRequest
val user = authRequest.user
Ok("woho!")
}(tokenRequest) // <-- call the inner action yourself, returns Future[SimpleResult]
}
There may be problems if there is a body that you want to parse though, I think it will be parsed by the body parser of the outer request but I'm not sure what the inner one will do if you would specify a parser.
The reason why you cannot do this in a simpler way is that you do not only want to compose logic but also pass data into each action, if you had actions that would just bail on missing auth or token you could absolutely compose them as the play docs on action composition describes.
Side note: since you are only looking at headers and not accessing the body in either of your custom action decorators it might be a better idea to look into EssentialAction:s as those would let you reject the request without first parsing the body when auth or token is missing.

Play Framework 2.2 action composition returning a custom object

I am trying to create a custom play.api.mvc.Action which can be used to populate a CustomerAccount based on the request and pass the CustomerAccount into the controller.
Following the documentation for Play 2.2.x I've created an Action and ActionBuilder but I cannot seem to return the CustomerAccount from within the action.
My current code is:
case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)
case class Account[A](action: Action[A]) extends Action[A] {
lazy val parser = action.parser
def apply(request: Request[A]): Future[SimpleResult] = {
AccountService.getBySubdomain(request.host).map { account =>
// Do something to return the account like return a new AccountWrappedRequest?
action(AccountWrappedRequest(account, request))
} getOrElse {
Future.successful(NotFound(views.html.account_not_found()))
}
}
}
object AccountAction extends ActionBuilder[AccountWrappedRequest] {
def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
// Or here to pass it to the next request?
block(request) // block(AccountWrappedRequest(account??, request))
}
override def composeAction[A](action: Action[A]) = Account(action)
}
Note: This will not compile because the block(request) function is expecting a type of AccountWrappedRequest which I cannot populate. It will compile when using a straight Request
Additionally...
Ultimately I want to be able to combine this Account action with an Authentication action so that the CustomerAccount can be passed into the Authentication action and user authentication can be provided based on that customer's account. I would then want to pass the customer account and user into the controller.
For example:
Account(Authenticated(Action))) { request => request.account; request.user ... } or better yet as individual objects not requiring a custom request object.
I'm not sure if this is the best way to do it but I have managed to come up with a solution that seems to work pretty well.
The key was to match on the request converting it into an AccountWrappedRequest inside invokeBlock before passing it on to the next request. If another Action in the chain is expecting a value from an earlier action in the chain you can then similarly match the request converting it into the type you need to access the request parameters.
Updating the example from the original question:
case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)
case class Account[A](action: Action[A]) extends Action[A] {
lazy val parser = action.parser
def apply(request: Request[A]): Future[SimpleResult] = {
AccountService.getBySubdomain(request.host).map { account =>
action(AccountWrappedRequest(account, request))
} getOrElse {
Future.successful(NotFound(views.html.account_not_found()))
}
}
}
object AccountAction extends ActionBuilder[AccountWrappedRequest] {
def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
request match {
case req: AccountRequest[A] => block(req)
case _ => Future.successful(BadRequest("400 Invalid Request"))
}
}
override def composeAction[A](action: Action[A]) = Account(action)
}
Then inside the apply() method of another Action (the Authenticated action in my case) you can similarly do:
def apply(request: Request[A]): Future[SimpleResult] = {
request match {
case req: AccountRequest[A] => {
// Do something that requires req.account
val user = User(1, "New User")
action(AuthenticatedWrappedRequest(req.account, user, request))
}
case _ => Future.successful(BadRequest("400 Invalid Request"))
}
}
And you can chain the actions together in the ActionBuilder
override def composeAction[A](action: Action[A]) = Account(Authenticated(action))
If AuthenticatedWrappedRequest is then passed into the controller you would have access to request.account, request.user and all the usual request parameters.
As you can see there are a couple of cases where the response is unknown which would generate a BadRequest. In reality these should never get called as far as I can tell but they are in there just incase.
I would love to have some feedback on this solution as I'm still fairly new to Scala and I'm not sure if there might be a better way to do it with the same result but I hope this is of use to someone too.
I wrote a standalone small (ish) example that does what you're looking for:
https://github.com/aellerton/play-login-example
I gave up trying to use the Security classes that exist in the play framework proper. I'm sure they're good, but I just couldn't understand them.
Brief guide...
In the example code, a controller is declared as using the AuthenticatedRequests trait:
object UserSpecificController extends Controller with AuthenticatedRequests {
...
}
Forcing any page to require authentication (or redirect to get it) is done with the RequireAuthentication action:
def authenticatedIndex = RequireAuthentication { implicit request: AuthenticatedRequest[AnyContent] =>
Ok("This content will be accessible only after logging in)
}
Signing out is done by using the AbandonAuthentication action:
def signOut = AbandonAuthentication { implicit request =>
Ok("You're logged out.").withNewSession
}
Note that for this to work, you must override methods from the AuthenticatedRequests trait, e.g.:
override def authenticationRequired[A](request: Request[A]): Future[SimpleResult] = {
Future.successful(
Redirect(routes.LoginController.showLoginForm).withSession("goto" -> request.path)
)
}
There's more to it; best to see the code.
HTH
Andrew

BodyParser to return Result based on request body

I want to implement a BodyParser which parses and validates request.body, it's based on parse.json and currently looks like this:
def parseModel[A](implicit reads: Reads[A]): BodyParser[JsResult[A]] =
parse.json.map(_.validate[A])
The problem is it is currently of type BodyParser[JsResult[A]] while I want it to be of type BodyParser[A]. In case of JsError I want it basically to return 400 Bad Request with validation errors.
In Play API docs I can't find a method which allows me to inspect result of previous body parser and return a result or continue to a controller.
A BodyParser, after parsing the body, produces an Either[SimpleResult, A], where SimpleResult is an error result that should be returned immediately instead of processing the action. The convenience methods on BodyParser don't let you do this, so instead, create a new body parser that delegates to the JSON body parser:
def validateJson[A](implicit reads: Reads[A]) = new BodyParser[A] {
def apply(request: RequestHeader) = parse.json(request).map(_.right.flatMap { json =>
json.validate[A].asEither.left.map(e => BadRequest(JsError.toFlatJson(e)))
})
}
You can see here that we're mapping the result of the parse, and then taking the right value (a successful parse, will be JsValue), and calling flatMap on it. Our flatMap method converts the JsResult from validate to an Either[JsError, A], so we're halfway there with A, after that we map the left JsError to SimpleResult, and we're good to go.
Ok, I've implemented the desired behaviour via a method which produces an Action:
def validateJson[A](implicit reads: Reads[A]) =
parse.json.map(_.validate[A])
def ModelAction[A](action: A => Result)(implicit r: Reads[A]) =
Action(validateJson[A]) { request =>
request.body match {
case JsSuccess(model, _) => action(model)
case JsError(e) => BadRequest(JsError.toFlatJson(e))
}
}
I can use it like this:
def create = ModelAction[MyModel] { model =>
???
}
I'm still interested if it's possible to do the same with BodyParser and if I need to do so or it's better as it is now?