Showing posts with label Play Framework. Show all posts
Showing posts with label Play Framework. Show all posts

Friday, November 01, 2013

Add/Remove fields to Play's default case class JSON Writes

Play's JSON Macro Inception is great. For most of the time all you need to write for JSON parsing/serialization is something like:
implicit val personFormat = Json.format[Person]
In this example, Person is a case class model in your app.
case class Person(name: String, age: Int)
The implicit personFormat will silently help you whenever you need to either parse a piece of JSON to an instance of Person or serialize an instance of Person to a JSON string.
Now, let's add a boolean val inside the class constructor: isAdult
case class Person(name: String, age: Int) {
  val isAdult: Boolean = age >= 18
}
Since Play!'s JSON Macro Inception only works with the default apply and unapply methods of the case class, it won't include the isAdult in the JSON writes (reads doesn't make much sense here). There isn't much documentation on how to include this new field while still take advantage of the default Writes generated by Play's JSON Macro. Here is how you can achieve it using writes composition.
val personWrites = Json.writes[Person]
val writesWithNewField: Writes[Person] = (personWrites ~ (__ \ "isAdult").write[Boolean])((p: Person) => (p, p.isAdult))
This is not bad, but we can also introduce some generalized helper to minimize the boilerplate. Introducing the OWritesOpts class:
class OWritesOps[A](writes: OWrites[A]) {
  def addField[T: Writes](fieldName: String, field: A => T): OWrites[A] = 
    (writes ~ (__ \ fieldName).write[T])((a: A) => (a, field(a)))


  def removeField(fieldName: String): OWrites[A] = OWrites { a: A =>
    val transformer = (__ \ fieldName).json.prune
    Json.toJson(a)(writes).validate(transformer).get
  }
}

object OWritesOps {
  implicit def from[A](writes: OWrites[A]): OWritesOps[A] = new OWritesOps(writes)
}

With this class, you can add/remove field to default JSON writes like this:
//writes that replaces the age field with the isAdult field in the JSON output. 
val customWrites: Writes[Person] = Json.Writes[Person].
                                     addField("isAdult", _.isAdult).
                                     removeField("age")

That's it, enjoy. I am still new to Play!, if you have a better alternative, please suggest it in the comment. Will appreciate it, that's partly why I wrote this little blog post.

Thursday, August 29, 2013

CSRF protection in a Play+AngularJS application

From Wikipedia:
Cross-site request forgery, also known as a one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf[1]) or XSRF, is a type of malicious exploit of a website whereby unauthorized commands are transmitted from a user that the website trusts.[2] Unlike cross-site scripting (XSS), which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user's browser.
There are plenty of articles online explaining such attacks and measures against them. The basic idea of such protection is to generate a CSRF token per session and send that token in every following request through means other than the Cookie request header (because it's the one that browser automatically set and hence the vulnerability). Typically the token can be sent back in a custom request header or in the request query string or an hidden input value in forms. Play has a built-in filter that implements such token based CSFR protection(here is a great blog article about it). However it's based on html form(with automatic query string generation). In a single-page application that relies on Play as a pure server-side API, most requests are performed by AJAX without involving html form. In that case CSRF token has to be sent through a custom request header. Our application uses AngularJS as our front-end framework. AngularJS also provides some facility to guard against CSRF (from AngularJS' documentation):
Angular provides a mechanism to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. The header will not be set for cross-domain requests. To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on the first HTTP GET request. On subsequent XHR requests the server can verify that the cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that only JavaScript running on your domain could have sent the request.
So putting pieces together here is our implementation for CSFR protection in an AngularJS + Play application. The AngularJS side is automatic, so the work is at the play side to set token in the cookie and validate it.

When login succeeds, set the cookie that AngularJS consumers:
    Ok.withSession(("username" -> username).
       withCookies(Cookie("XSRF-TOKEN", createCSFRToken(username), httpOnly = false))
createCSFRToken is a function that hashes the username to a token so that the token is not reconstructible by attackers. httpOnly = true is there so that the cookie is readable by javascript (from the same domain of course).

For the following requests, here is the code to validate the token sent in the custom header (automatically set by AngularJS):
  def validateSessionUser(implicit request: RequestHeader): Option[String] = {
    request.session.get("username").filter { username =>
      request.headers.get("X-XSRF-TOKEN") == Some(createCSFRToken(username))
    }
  }
That's it. Feel free to ask any question in the comments.

Saturday, May 25, 2013

Case class enumeration in Play 2.1 Application (on top of Salat/MongoDB)

Recently in our Play 2.1(Scala) application I needed to implement a model that's like Java enum. Since scala's Enumeration class doesn't have a fantastic reputation, I decided to go with the case class approach. Our Play 2.1 application is a JSON REST API that sits on top of MongoDB, so I need to make sure that this model can have both JSON and MongoDBObject serialization wired up.
Let's start from Enum base trait
trait Enum[A] {
  trait Value { self: A => }
  val values: List[A]
  def parse(v: String) : Option[A] = values.find(_.toString() == v)
}
We'll see the use of the parse function later.

In our system we have a flag system for content entries. Here is the flag case class enum.
import com.novus.salat.annotations._

@Salat
sealed trait Flag extends Flag.Value

case object DEPRESSING extends Flag
case object VIOLENCE extends Flag
case object NSFW extends Flag

object Flag extends Enum[Flag] with SimpleEnumJson[Flag] {
  val values = List(DEPRESSING, VIOLENCE, NSFW)
}
The @Salat is needed for salat to map abstract class inheritance tree. SimpleEnumJson[T] is the one that provides Play 2.1 JSON API formats which you will need for JSON serialization. Here is its implementation.
import play.api.libs.json._

trait SimpleEnumJson[A] {
  self: Enum[A] =>

  implicit def reads: Reads[A] = new Reads[A] {
    def reads(json: JsValue): JsResult[A] = json match {
      case JsString(v) => parse(v) match {
        case Some(a) => JsSuccess(a)
        case _ => JsError(s"String value ($v) is not a valid enum item ")
      }
      case _ => JsError("String value expected")
    }
  }

  implicit def writes[A]: Writes[A] = new Writes[A] {
    def writes(v: A): JsValue = JsString(v.toString)
  }
}
As the name suggests, SimpleEnumJson uses the simple toString() of the enum item for JSON representation.
Note that we could place the items definitions inside the companion object, but unfortunately salat couldn't map the class that way.
This should be good enough for most cases, a simple case class based enum that can be used in any models.
Now let's make it a little more complex, let's say we need one more attribute in our Flag class: age rating - each flag indicates that the content is only appropriate for users above a certain age.
@Salat
sealed trait Flag extends Flag.Value {
  val ageRating : Int
}
case object DEPRESSING extends Flag { val ageRating = 18 }
case object VIOLENCE extends Flag { val ageRating = 16 }
case object NSFW extends Flag { val ageRating = 21 }
Now we need a bit more work for our JSON reads/writes, the SimpleEnumJSON[T] is no longer sufficient. Let's write a CompositeEnumJSON[T]
trait CompositeEnumJson[A] {
  self: Enum[A] =>
  implicit val reads = (__ \ 'name).read[String].map( parse(_).get )
  val nameWrite = (__ \ 'name).write[String]
  implicit val writes : OWrites[A]
}
Here we map a composite case class enum into a JsObject with a name field that holds the toString() value of the item. When we read from JSON, we only need the "name" field. We need concrete inheriting case class to implement the Json write:
object Flag extends Enum[Flag] with CompositeEnumJson[Flag] {
  val values = List(DEPRESSING, VIOLENCE, NSFW)
  implicit val writes : OWrites[Flag] = (
    nameWrite ~
    (__ \ 'ageRating).write[Int]
  )(unlift(unapply))

  def unapply(flag: Flag) = {
    Some(( flag.toString(), flag.ageRating ))
  }
}
There you have it - a composite case class based enum that can have attributes.
I hope you find this helpful and let me know if you have any suggestion for improvements.

Tuesday, May 07, 2013

Define arbitrary tasks in the Play 2.1 Framework (Rakes like)

Recently with the help from James Roper from Typesafe, I added some arbitrary tasks to our application so that we can seed some data from command line. These tasks are basically like rake tasks in which you can run fire up the application environment and perform code written for you application.

The idea is to create SBT tasks and then, quoted from James, "get a hold of the dependencies, create a new URLClassLoader with them, load the class you want to use from that classloader using reflection, and then invoke it."

Here is the code in the SBT build file Build.scala
import java.net.URLClassLoader
object ApplicationBuild extends Build {
//Other project settings such as appVersion and appDependencies

def registerTask(name: String, taskClass: String, description: String) = {
  val sbtTask = (dependencyClasspath in Runtime) map { (deps) =>
    val depURLs = deps.map(_.data.toURI.toURL).toArray
    val classLoader = new URLClassLoader(depURLs, null)
    val task = classLoader.
                 loadClass(taskClass).
                 newInstance().
                 asInstanceOf[Runnable]
    task.run()
  }
  TaskKey[Unit](name, description) <<= sbtTask.dependsOn(compile in Compile)
}

val main = play.Project(appName, appVersion, appDependencies).settings(
  registerTask("seed-data-book","tasks.SeedBooks", "seed for book table" ),
  registerTask("seed-data-user","tasks.SeedUsers", "seed for user table" )
)

Here is our task classes (I placed it in app/tasks)
package tasks
import play.core.StaticApplication

abstract class Task extends Runnable { 
  val application = new StaticApplication(new java.io.File("."))
}
    
class SeedBooks extends Task{
  def run {
    Book.dao.save(new Book("Introduction to Scala", "Martin Odersky"))
  }
}
    
class SeedUsers extends Task{
  def run {
    User.dao.save(new User("jRoper", "password"))
  }
}
I hope this helps. Feel free to ask any questions in the comments.