Blog

Simple IP Access List for Play 2 with Java

Quite often we need to be able to grant access only for certain IPs to our application. The Play! Framework 2 doesn’t come with built in IP access lists, but it’s quite easy to develop such a function thanks to Action Composition. We wanted to have the possibility to annotate a controller class or method, specifying a group of IPs that should have access to it.

This post demonstrates a way to have a simple access list for just that.

Installation

Configuration

You configure the groups in applications.conf. It is mandatory to have atleast one ‘default’ group configured.

restricttohostgroup {
    groups {
	    default = ["0:0:0:0:0:0:0:1", "127.0.0.1", "10.0.0.", "192.168.0."],
	    admin = ["192.168.7."]
    },
    redirect = "http://github.com"
}

A group contains an array of IPs or a partial IP, like “192.168.0.”. At the time of writing, it does not support more advanced patterns like “192.168.0.0/16″. Basically it just tries to match the remote address against the pattern. Pull requests are welcome. :)

The ‘redirect’ key is optional, and may contain an URL where the denied requestor will be redirected to.

Usage

In your code, simply annotate the controller class or a controller method. This will restrict the controller or method to the group specified, or to ‘default’ if no group is specified. If a requestor is denied access, a Logger.warn() will be triggered with information about the denied request.

package controllers;

import play.mvc.Controller;
import play.mvc.Result;
import restrict.RestrictToHostGroup;
import views.html.index;

@RestrictToHostGroup   // Same as @RestrictToHostGroup("default")
public class Application extends Controller {

    public static Result index() {
        return ok(index.render("User."));
    }

    @RestrictToHostGroup("admin")
    public static Result admin() {
        return ok(index.render("Admin."));
    }
}

Example application

We’ve put up an sample application so you can play around with it a bit.

Enjoy!

Content Security Policy in Play! Framework 2

What is Content Security Policy (CSP)?

CSP is a security concept, developed by the Mozilla Foundation, that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. This post won’t go into details about CSP itself, but you can read all about it at Html5Rocks, Wikipedia and W3.

chromeviolation

Adding support for CSP in your project

1. Create a folder called csp under you app folder.
2. Copy the files ContentSecurityPolicy.java and ContentSecurityPolicyAction.java into the csp folder.
3. In you applications.conf, add the following:

csp {
    policy : "default-src 'self'"
}

4. Modify csp.policy key in applications.conf so that it matches the security you want for your application.

Usage

Simply annotate your controllers class or methods with @ContentSecurityPolicy. The header will be sent with each response from the server.

import csp.ContentSecurityPolicy;

@ContentSecurityPolicy
public class Application extends Controller {
  
    public static Result index() {
        return ok(index.render("Hi from index."));
    }

    public static Result blog() {
    	return ok(blog.render("All about my cats"));
    }
}

You can also override the default CSP, set in applications.conf, by setting the new CSP as a parameter to the annotation.

Example, allowing images from http://www.playframework.org on a controller method could look like this:

    @ContentSecurityPolicy("default-src 'self' ; img-src http://www.playframework.org")
    public static Result anotherPolicy() {
        return ok(index.render("Hi from anotherPolicy."));
    }

Getting reports

CSP supports reporting with “report-uri” directive. Following this directive, the client browser can send (POST) a report (JSON format) to the server with directives that has been violated. A sample report may look like this:

{
  "csp-report": {
    "document-uri": "http://example.org/page.html",
    "referrer": "http://evil.example.com/haxor.html",
    "blocked-uri": "http://evil.example.com/image.png",
    "violated-directive": "default-src 'self'",
    "original-policy": "default-src 'self'; report-uri http://example.org/csp-report.cgi"
  }
}

To catch these reports in you application, you first need to set up a route matching the report-uri directive. Say we have our CSP directive as follows:

@ContentSecurityPolicy("default-src 'self' ; report-uri /report")

Create a route to catch it:

POST    /report                     controllers.Application.cspReportParser()

Then create an controller action:

    @BodyParser.Of(BodyParser.Json.class)
    public static Result cspReportParser() {
        JsonNode json = request().body().asJson();
        if(json == null) {
            Logger.debug("no JSON payload");
            return badRequest("Expecting Json data");
        } else {
            Logger.debug(json.toString());
            return ok();
        }
    }

Example application

We’ve put up an sample application that you can download an play around with. Note that the sample uses Play 2.1-RC2.

To see the violations in your browser, bring forth the inspector.

firefoxviolation

If you just want to see the header sent in the server response, use cURL:

curl -i http://localhost:9000/

Credits, References and Thanks
- An Introduction to Content Security Policy by Mike West
- Writing Modules for Play 2, Interceptors by Steve Chaloner
- Play! Framework Gurus

Also, to improve the security of your app further, check out AuthenticityToken for Play2! by Olivier Refalo.

Play! Framework 2.0 + DataTables + Server-side processing

This post will describe how to set up a Play! Framework 2.0(.2) Java project with DataTables and server-side processing. The source code used in this example can be found on github.

Create a new project

Create a new Play! application and choose Create a simple Java application. In this example we will call our app dtapp.

$ play new dtapp

Download needed files

We are going to use DataTables with the jQuery style, so we need to download those packages.

1. Download DataTables (this post uses version 1.9.2)

  • Copy DataTables-1.9.2/media/css/demo_table_jui.css to dtapp/public/stylesheets/
  • Copy DataTables-1.9.2/media/js/jquery.dataTables.min.js to dtapp/public/javascripts/

2. Download a jQuery UI (this post uses version 1.8.21). You can choose what theme you like, this post will use UI lightness.

  • Copy jquery-ui/js/jquery-1.7.2.min.js to dtapp/public/javascripts/ (delete the old jquery-1.7.1.min.js)
  • Copy jquery-ui/js/jquery-ui-1.8.21.custom.min.js to dtapp/public/javascripts/
  • Copy query-ui/css/ui-lightness to dtapp/public/stylesheets/

3. Modify main.scala.html to include the new files:

@(title: String)(content: Html)

<!DOCTYPE html>

<html>
 <head>
 <title>@title</title>
 <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/demo_table_jui.css")">
 <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/ui-lightness/jquery-ui-1.8.21.custom.css")">
 <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
 <script src="@routes.Assets.at("javascripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
 <script src="@routes.Assets.at("javascripts/jquery-ui-1.8.21.custom.min.js")" type="text/javascript"></script>
 <script src="@routes.Assets.at("javascripts/jquery.dataTables.min.js")" type="text/javascript"></script>
 </head>
 <body>
 @content
 </body>
</html>

Create the Model

Our table will display information about contacts, so we need to create a Contact model. Create a file dtapp/app/models/Contact.java with the following content:

package models;

import java.util.*;
import javax.persistence.*;

import play.api.libs.Crypto;
import play.db.ebean.*;
import play.data.format.*;
import play.data.validation.*;

import play.Logger;

import com.avaje.ebean.*;

@Entity
public class Contact extends Model {

  @Id
  public Long id;

  @Constraints.Required
  public String name;

  public String title;
  public String email;

  public static Model.Finder<Long,Contact> find = new Model.Finder(Long.class, Contact.class);

  public static List<Contact> findAll() {
    return find.all();
  }

  public String toString() {
    return name;
  }
}

Create the view

Add a HTML-table and the needed javascript to index.scala.html. The javascript-snippet initializes DataTable and sets so that it will use server-side processing and jQuery UI. Note the sAjaxSource setting, that points to an application route.

@(message: String)

@main("Play!ing with DataTables") {

<script type="text/javascript">
  /* Table initialisation */
  $(document).ready(function() {
    $('#contacts_table').dataTable( {
      "bProcessing": true,
      "aaSorting": [[ 0, "asc" ]],
      "bServerSide": true,
      "bJQueryUI": true,
      "sPaginationType": "full_numbers",
      "sAjaxSource": "@routes.Application.list()"
    });
  });
</script>

<h2>Play!ing with DataTables</h2>

<table id="contacts_table" class='display'>
  <thead>
    <tr>
      <th>Name</th>
      <th>Title</th>
      <th>E-mail</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Row 1 Data 1</td>
      <td>Row 1 Data 2</td>
      <td>etc</td>
    </tr>
  </tbody>
</table>
}

Set up the route
Now we need to set up a route for the Ajax-call. Add the following line to your dtapp/conf/routes:

GET /search controllers.Application.list()

Set up the controller

This is where the tricky part is. DataTables with server-side processing sends a long query-string to the Application.list(). The query-string contains information like search-string, sorting, pagination etc. We need to get the query-string, find out what it wants, get the data it wants from the database and return it. DataTables expects Application.list() to give back a JSON-string containing the needed information to be displayed. The real magic here is EBeans Page<T>, a class that will help us to easily get the data we need.

Your dtapp/app/controllers/Application.java should look like this:

package controllers;

import play.*;
import play.libs.Json;
import play.mvc.*;
import play.data.*;

import models.*;
import views.html.*;

import java.util.*;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

import com.avaje.ebean.Expr;
import com.avaje.ebean.Page;

public class Application extends Controller {

  public static Result index() {
    return ok(index.render("Your new application is ready."));
  }

  public static Result list() {
    /**
     * Get needed params
     */
    Map<String, String[]> params = request().queryString();

    Integer iTotalRecords = Contact.find.findRowCount();
    String filter = params.get("sSearch")[0];
    Integer pageSize = Integer.valueOf(params.get("iDisplayLength")[0]);
    Integer page = Integer.valueOf(params.get("iDisplayStart")[0]) / pageSize;

    /**
     * Get sorting order and column
     */
    String sortBy = "name";
    String order = params.get("sSortDir_0")[0];

    switch(Integer.valueOf(params.get("iSortCol_0")[0])) {
      case 0 : sortBy = "name"; break;
      case 1 : sortBy = "title"; break;
      case 2 : sortBy = "email"; break;
    }

    /**
     * Get page to show from database
     * It is important to set setFetchAhead to false, since it doesn't benefit a stateless application at all.
     */
    Page<Contact> contactsPage = Contact.find.where(
      Expr.or(
        Expr.ilike("name", "%"+filter+"%"),
        Expr.or(
          Expr.ilike("title", "%"+filter+"%"),
          Expr.ilike("email", "%"+filter+"%")
        )
      )
    )
    .orderBy(sortBy + " " + order + ", id " + order)
    .findPagingList(pageSize).setFetchAhead(false)
    .getPage(page);

    Integer iTotalDisplayRecords = contactsPage.getTotalRowCount();

    /**
     * Construct the JSON to return
     */
    ObjectNode result = Json.newObject();

    result.put("sEcho", Integer.valueOf(params.get("sEcho")[0]));
    result.put("iTotalRecords", iTotalRecords);
    result.put("iTotalDisplayRecords", iTotalDisplayRecords);

    ArrayNode an = result.putArray("aaData");

    for(Contact c : contactsPage.getList()) {
      ObjectNode row = Json.newObject();
      row.put("0", c.name);
      row.put("1", c.title);
      row.put("2", c.email);
      an.add(row);
    }

    return ok(result);
 }
}

Set up the sample data

Now we just need to create some sample data so that we can try out our shiny new table. Download initial-data.yml and place it in your dtapp/conf/. Then create dtapp/app/Global.java, that will import the sample data, with the following content:

import play.*;
import play.libs.*;
import java.util.*;
import com.avaje.ebean.*;
import models.*;
import java.util.concurrent.*;

public class Global extends GlobalSettings {

  @Override
  public void onStart(Application app) {

    /**
     * Here we load the initial data into the database
     */
    if(Ebean.find(Contact.class).findRowCount() == 0) {
      Map<String,List<Object>> all = (Map<String,List<Object>>)Yaml.load("initial-data.yml");
      Ebean.save(all.get("contacts"));
    }
  }
}

The last thing you have to do is enable H2 database for your application. Uncomment the following lines in dtapp/conf/application.conf:

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
ebean.default="models.*"

Ready to run!

You should now be able to run your application. DataTables will only fetch the needed data. Try searching for different terms, pagination etc. The table should update directly. Try adding more sample data to the yaml-file to see how it behaves. Try bringing front your web browsers Inspector and see what query and data is sent.

Enjoy!