play framework - how can i call this function for the authenticated user in this code play2 scala zentasks - scala

in the play2 scala zentasks sample application the code snippet looks like this
def IsAuthenticated(f: => String => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
What I need to do is call this function in model
def AddOnline(email: String, contact: Contact) = {
DB.withConnection { implicit connection =>
SQL(
"""
update contact
set online_status = {'online'} //I want to write the value contact.status=online
where email = {email}
"""
).on(
'email -> contact.email,
'online_status -> contact.online_status
).executeUpdate()
}
}
But my challenge here is to call this AddOnline function every time a certain user is authenticated by the above piece of code. Can someone suggest how I should go about this? I am a novice in this and I am going round and round in circles without making any progress

You can call the addOnline method from the IsAuthenticated like this:
def IsAuthenticated(f: => String => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>
// Do what you need to do here before the action is called
Contact.addOnline(user)
Action(request => f(user)(request))
}
Please note that the user is not the user object but just the email of the authenticated user.
Also, as you are only adding the online status of the user it looks like you can simplify your AddOnline method to something like this.
def addOnline(email: String) = {
DB.withConnection { implicit connection =>
SQL(
"""
update contact
set online_status = 'online'
where email = {email}
"""
).on(
'email -> email,
).executeUpdate()
}

Related

Play Framework Authentication in a single page app

I am trying to add authentication to my Play Framework single page app.
What I would like to have is something like:
def unsecured = Action {
Ok("This action is not secured")
}
def secured = AuthorizedAction {
// get the authenticated user's ID somehow
Ok("This action is secured")
}
For a traditional web app, I had previously done this, following Play Framework docs:
def authenticate = Action { implicit request =>
loginForm.bindFromRequest.fold(
formWithErrors => BadRequest(views.html.login(formWithErrors)),
user => {
Redirect(routes.Application.home).withSession(Security.username -> user._1)
}
)
}
def logout = Action {
Redirect(routes.Auth.login).withNewSession.flashing(
"success" -> "You are now logged out."
)
}
and the Authorized Action is extending ActionBuilder as follows:
object AuthorizedAction extends ActionBuilder[Request] with Results {
/**
* on auth success: proceed with the request
* on auth failure: redirect to login page with flash
*/
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
// TODO: is "isDefined" enough to determine that user is logged in?
if(request.session.get("username").isDefined) {
block(request)
}
else {
Future.successful(Redirect(routes.Auth.login).flashing(
"failure" -> "You must be logged in to access this page."
))
}
}
}
For single page applications however, this approach doesn't exactly work anymore.
This article by James Ward explains how the new approach is to be designed, and includes a Java implementation:
Securing SPA and rest services
The implementation was redone in Scala by Marius Soutier: Securing SPA in Scala
In his example, he implements a Security trait:
trait Security { self: Controller =>
val cache: CacheApi
val AuthTokenHeader = "X-XSRF-TOKEN"
val AuthTokenCookieKey = "XSRF-TOKEN"
val AuthTokenUrlKey = "auth"
/** Checks that a token is either in the header or in the query string */
def HasToken[A](p: BodyParser[A] = parse.anyContent)(f: String => Long => Request[A] => Result): Action[A] =
Action(p) { implicit request =>
val maybeToken = request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey))
maybeToken flatMap { token =>
cache.get[Long](token) map { userid =>
f(token)(userid)(request)
}
} getOrElse Unauthorized(Json.obj("err" -> "No Token"))
}
}
Functions are now secured like this instead of a plain Action:
def ping() = HasToken() { token => userId => implicit request =>
user.findByID (userId) map { user =>
Ok(Json.obj("userId" -> userId)).withToken(token -> userId)
} getOrElse NotFound (Json.obj("err" -> "User Not Found"))
}
where .withToken is defined as:
implicit class ResultWithToken(result: Result) {
def withToken(token: (String, Long)): Result = {
cache.set(token._1, token._2, CacheExpiration)
result.withCookies(Cookie(AuthTokenCookieKey, token._1, None, httpOnly = false))
}
def discardingToken(token: String): Result = {
cache.remove(token)
result.discardingCookies(DiscardingCookie(name = AuthTokenCookieKey))
}
}
I am not liking how complex the "ping" function above has become, and would have preferred to use an Action Builder (like the first example), where auth failure is caught and dealt with at a single point. (as of now, if I want to secure functions ping2 and ping3, each one has to check whether the user is found and deal with the "not found" case)
I have tried to put together an action builder, inspired by Marius' implementation, most particularly his use of the cacheApi which is necessary.
However the AuthorizedAction is an object, and cacheApi needs to be injected (so need to change the object to singleton class), or cannot be declared in an object without being defined.
I also feel like the AuthorizedAction needs to remain an object, in order to be used as:
def secured = AuthorizedAction {
Would anyone please clear up the confusion, and possibly help with some implementation details?
Thanks a lot
The simplest way in my opinion is to go with ActionBuilder. You can define an action builder as a class (and pass it some dependencies) or as an object.
First you'll need to define a type a request that will contain the information about the user:
// You can add other useful information here
case class AuthorizedRequest[A](request: Request[A], user: User) extends WrappedRequest(request)
Now define your ActionBuilder
class AuthorizedAction(userService: UserService) extends ActionBuilder[AuthorizedRequest] {
override def invokeBlock[A](request: Request[A], block: (AuthorizedRequest[A]) ⇒ Future[Result]): Future[Result] = {
request.headers.get(AuthTokenHeader).orElse(request.getQueryString(AuthTokenUrlKey)) match {
case Some(token) => userService.findByToken(token).map {
case Some(user) =>
val req = AuthorizedRequest(request, user)
block(req)
case None => Future.successful(Results.Unauthorized)
}
case None => Future.successful(Results.Unauthorized)
}
}
}
Now you can use it in your controller:
val authorizedAction = new AuthorizedAction(userService)
def ping = authorizedAction { request =>
Ok(Json.obj("userId" -> request.user.id))
}

Writing Body Parser with Security Trait for multipartFormData, Play Framework

I'm trying to upload an image at the same time when I submit the form, after some research I tried using mutlipartFormData to accomplish the feat.
This is my form submission function header after following the tutorials.
def insert = withInsert(parse.multipartFormData) { username => implicit request =>
I used security trait to check for user (withUser), login time (withAuth) and permission (withInsert)
def withUser(f: => String => Request[AnyContent] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
def withAuth(f: => String => Request[AnyContent] => Result) = withUser { user => request =>
var timestamp = request.session.get("timestamp")
timestamp.map { timestamp =>
if(System.currentTimeMillis - timestamp.toLong < (3600*1000))
f(user)(request)
else
onUnauthorized(request)
}
.getOrElse{
onUnauthorized(request)
}
}
def withInsert[A](p: BodyParser[A])(f: String => Request[A] => Result) = withAuth { username => request =>
val permission = User.checkAuth("Page", username)
if(permission.page_insert == 1)
Action(p)(request => f(username)(request))
else
onPermissionDenied(request)
}
def onPermissionDenied(request: RequestHeader) = Results.Redirect(routes.Page.index)
As the insert function needed a body parser, I modified the (withInsert) trait to support a body parser. But, then I got a compile error on this line.
Action(p)(request => f(username)(request))
type mismatch; found : play.api.mvc.Action[A] required: play.api.mvc.Result
I'm quite lost to what is wrong here, any help is greatly appreciated.
Edit:
I've tried to do exactly what the tutorial did, abandoning the usage of withAuth on the security trait
def withInsert[A](p: BodyParser[A])(f: String => Request[A] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
val permission = User.checkAuth("Page", user)
if(permission.page_insert == 1)
Action(p)(request => f(user)(request))
else
onPermissionDenied(request)
}
}
this code results in another compile error on the same line, but with different error
not found: value request
After removing the permission checking, it returns no compile error.
def withInsert[A](p: BodyParser[A])(f: String => Request[A] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(p)(request => f(user)(request))
}
}
But I need the program to check for permission before running functions and not just username (Current user has logged in or not). Is there a way to do this?
I need a workaround so that I could apply the permission checking and the body parser to the trait.

what have i done wrong trying to call the model with form value

This:
def signup = Action { implicit request =>
signupForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.login(loginForm,formWithErrors)),
signer =>
Signup.insert(signer)
Redirect(routes.Application.login)
)
}
give me this error (value Redirect is not a member of Int possible cause: maybe a semicolon is missing before `value Redirect'?)
if i comment out Signup.insert(signer) its fine but i want it to call that...
but when i use this its fine:
def save = IsAuthenticated { username => implicit request =>
User.findByEmail(username).map { user =>
personForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.person_views.createForm(formWithErrors, user)),
person => {
Person.insert(person)
Redirect(routes.Persons.list()).flashing("success" -> "success")
}
)
//}.getOrElse(Forbidden)
}.getOrElse(Forbidden)
}
Try this:
def signup = Action { implicit request =>
signupForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.login(loginForm,formWithErrors)),
signer => {
Signup.insert(signer)
Redirect(routes.Application.login)
}
)
}
Basically, the way it was written before was like you were writing:
Signup.insert(signer) Redirect(routes.Application.login)
Which means, when the insert is done, apply the Redirect method on the result, the result of the insert, I assume, is an Int, hence the error message:
value Redirect is not a member of Int possible cause

Can someone explain what the following code snippets means in Play framework (Scala)?

Please take a look at the following code
Application.scala
def Online = Action { implicit request =>
loginForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.login(formWithErrors)),
user => Contact.AddOnline("email" -> user._1)
)
followed by
trait Secured {
/**
* Retrieve the connected user email.
*/
private def username(request: RequestHeader) =
request.session.get("email")
/**
* Redirect to login if the user in not authorized.
*/
private def onUnauthorized(request: RequestHeader) =
Home.flashing("failure"->"You are not logged in");
// --
/**
* Action for authenticated users.
*/
def IsAuthenticated(f: => String => Request[AnyContent] => Result)=
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
--
My Problem is I am trying to call a piece of code called setOnline(user.email). This code sets a certain user's status as online only after he is authenticated. In the above given code I would like to call my setOnline(user.email) function but I am not sure where or how I should call. I have been trying for the past 4 hours without any luck. The main problem is I do not understand how the above piece of code works completely (as it is not my code).
This code....
def Online = Action { implicit request =>
loginForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.login(formWithErrors)),
user => Contact.AddOnline("email" -> user._1)
)
is an action that binds a request to a Form object called loginForm. It will check to see if the form has errors, if it does then it will display the form with those errors. If not, then it will invoke Contact.AddOnline.
And this...
def IsAuthenticated(f: => String => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>Action(request => f(user)(request))
is an Action that wraps itself around another action (action composition) to determine if the given username is authenticated or not. If it is not authorized, then it will invoke the "onUnauthorized" function which will flash "You are not logged in". Which in reality will not work. You should write your "onUnauthorized" similar to this...
private def onUnauthorized(request: RequestHeader) =
Redirect(routes.Home.url).flashing("You are not logged in")

How do I access post data from scala play?

I have a route that is type "POST". I am sending post data to the page. How do I access that post data. For example, in PHP you use $_POST
How do I access the post data in scala and play framework?
As of Play 2.1, there are two ways to get at POST parameters:
1) Declaring the body as form-urlencoded via an Action parser parameter, in which case the request.body is automatically converted into a Map[String, Seq[String]]:
def test = Action(parse.tolerantFormUrlEncoded) { request =>
val paramVal = request.body.get("param").map(_.head)
}
2) By calling request.body.asFormUrlEncoded to get the Map[String, Seq[String]]:
def test = Action { request =>
val paramVal = request.body.asFormUrlEncoded.get("param").map(_.head)
}
Here you've got good sample how it's done in Play:
https://github.com/playframework/Play20/blob/master/samples/scala/zentasks/app/controllers/Application.scala
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
) verifying ("Invalid email or password", result => result match {
case (email, password) => User.authenticate(email, password).isDefined
})
)
/**
* Handle login form submission.
*/
def authenticate = Action { implicit request =>
loginForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.login(formWithErrors)),
user => Redirect(routes.Projects.index).withSession("email" -> user._1)
)
}
It's described in the documentation of the forms submission
as #Marcus points out, bindFromRequest is the preferred approach. For simple one-off cases, however, a field
<input name="foo" type="text" value="1">
can be accessed via post'd form like so
val test = Action { implicit request =>
val maybeFoo = request.body.get("foo") // returns an Option[String]
maybeFoo map {_.toInt} getOrElse 0
}
Here you've got good sample how it's done in Play 2:
def test = Action(parse.tolerantFormUrlEncoded) { request =>
val paramVal = request.body.get("param").map(_.head).getorElse("");
}