Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play 2.0 Framework, using a BodyParser with an authenticated request

I'd like to be able to use a BodyParser on an authenticated request and I'm having trouble figuring out how to do that if my Authentication is set up like the ZenTasks example.

My authentication method,

def IsAuthenticated(f: => String => Request[AnyContent] => Result) = {
  Security.Authenticated(username, onUnauthorized) { user =>
    Action(request => f(user)(request))
  }
}

def HasRole(role: List[String])
  (f: => String => Request[AnyContent] => Result) = IsAuthenticated {
  user => request => if (role.contains(getRole(user))) {
    f(user)(request) // This function returns the result.
  } else {
    Results.Forbidden
  }
}

My controller method,

def controller = HasRole(List("admin")) { user => _ => { 
  Action(parse.temporaryFile){ implicit request =>
    request.body.moveTo(new File("/tmp/filepath"))
    Redirect(routes.home)
  }
}

This is the error I'm seeing,

[error]  found   : play.api.mvc.Action[play.api.libs.Files.TemporaryFile]
[error]  required: play.api.mvc.Result
[error]       Action(parse.temporaryFile){ implicit request =>
[error]                                  ^

Here is a related question: parse.json of authenticated play request

This person found a workaround, and I believe there is one for the temporary file example as well, but I'd like to know how (or why) what I'm doing is not working.

like image 600
Jeff Wu Avatar asked Jun 19 '12 15:06

Jeff Wu


1 Answers

I believe I've figured this out, mainly because I left some details out of the original question that I did not realize were important.

The problem was that I was wrapping an Action { Action { } } because the IsAuthenticated method already had a call to the Action function inside it. What I ended up doing was overloading the IsAuthenticated function with a method that took BodyParser as a parameter. Because I am using the TemporaryFile method, which is not a subclass of AnyContent, I also had to change the request type.

Now, this is what my Secured trait looks like:

def IsAuthenticated(f: => String => Request[Any] => Result) = {
  Security.Authenticated(username, onUnauthorized) { user =>
    Action(request => f(user)(request))
  }
}

def IsAuthenticated(b: BodyParser[Any] = parse.anyContent)
  (f: => String => Request[Any] => Result) = {
  Security.Authenticated(username, onUnauthorized) { user =>
    Action(b)(request => f(user)(request))
  }
}

def HasRole(role: List[String])(b: BodyParser[Any] = parse.anyContent)
  (f: => String => Request[Any] => Result) = IsAuthenticated(b) {
  user => request => getRole(user) match {
    case Some(r) if role.contains(r) => f(user)(request)
    case _ => Results.Forbidden
  }
}

And this is what my controller looks like:

def controller = HasRole(List("admin"))(parse.temporaryFile) { user => request =>
  request.body match {
    case b:TemporaryFile => b.moveTo(new File("/tmp/file"))
    case _ => Status(404)
  }
}

Hope this helps someone else!

like image 143
Jeff Wu Avatar answered Oct 13 '22 11:10

Jeff Wu