Community contributed extensions

Shibboleth authentication module

The Shibboleth module provides integration with the Shibboleth authentication protocol. The Shibboleth protocol is a distributed single sign on service across multiple organizational boundaries popular in higher education. The protocol is divided into three components: Service Provider (SP), Identity Provider (IDP), and Discovery Service (DS/WAYF). This module facilitates your Play! application becomes a Service Provider.

Requirements
In order to use the shibboleth module you must proxy your Play! application behind a Shibboleth capable web server such as Apache, Lighttpd, or IIS. Install and configure Shibboleth on the proxy web server, then enable this module as described below.

This module offers a "lazy session" (sometimes refereed to as "passive session") model. Under this model the shibbolized proxy will not need to restrict access to any particular URLs. Instead when a user selects to login, or your applications forces the user to login, then the module will direct the user to the appropriate Shibboleth initiator. This will cause the user to authenticate with their IDP and returned back to your SP. After returning this module will intercept the Shibboleth provided attributes about the user and make them available to your application. The specific attributes available to your application will depend on the attribute release policy for the IDP/SP.

Enable the Shibboleth module for the application

In the /conf/dependencies.yml file, enable the this module by adding a line after require:


  require:
    - play -> shibboleth

Import Shibboleth routes

In the conf/routes file, import the default module routes by adding the line shown below. You may also define your own routes if you wish, Shibboleth requires a login, logout, and authentication route.


  #Import Shibboleth routes
  *      /                module:shibboleth

Configure Shibboleth authentication in Play

Shibboleth requires some configuration before it can be used at a practical minimum you must provide some shib.attribute.<Attribute Name> = <HTTP Header> attribute mappings. These map the Shibboleth attributes to session attributes that will be available to your application. You can use the shib.require parameter to indicate which of these attributes are required for successful authentication. You can also override the onAuthenticated() hook described below to implement more complex attribute mapping strategies.


  # Shibboleth attributes
  shib.require = email, firstName, lastName
  
  shib.attribute.email = SHIB-email
  shib.attribute.firstName = SHIB-givenName
  shib.attribute.lastName = SHIB_sn
  ...
  shib.attribute.<Attribute Name> = <HTTP Header>

Beyond the attributes you may also configure the specific initiators configured for starting the login / logout process. The values used below are the default initiators. You may use fully qualified urls (i.e. http://) or absolute urls (just /). However if you want the Shibboleth transaction to occur over SSL it’s best to set the protocol to https://. The return parameters (shib.login.return and shib.logout.return)are where the user will be sent after successfully completing the action. In the case of loginig in, the user will be returned to the URL they were attempting to access (i.e. a controller using the @\@With@ annotation). If there was inturrupted url then the user will be sent to the default return url defined in shib.login.return.

There is a debate about whether it is positive to even provide a logout function for Shibbilized applications, because users may not necessarily be logged out of any other applications that they may have previously logged in. By default the module disables the logout feature, however you may enable it by specifying shib.logout = true


  # Shibboleth login initiator
  shib.login.url = https://localhost/Shibboleth.sso/Login
  shib.login.return = http://localhost/
  
  # Shibboleth logout initiator (default false)
  shib.logout = true
  shib.logout.url = https://localhost/Shibboleth.sso/Logout
  shib.logout.return = http://localhost/

Configure Apache/Lighttpd

Apache set-up

Configure Apache’s virtual host or other directive to use shibboleth. The configuration provided below assumes lazy authentication, i.e. users will be able to access your application without authenticating. If you want only authenticated users accessing the application then set ShibRequireSessions On. When defining the proxy parameters it is highly advantageous to also use ProxyPreserveHost on so that your Play application knows what external host the application is being accessed from.


  AuthType shibboleth
  ShibURLScheme https
  ShibRequireSessions Off
  ShibUseHeaders On
  Require shibboleth

Lighttpd set-up

The module developers have not tested this configuration, but it should work. If you use lighttpd in your configuration let us know.


  server.name = "your_server_name"
  
  server.document-root = "/servers/tags/www/"
  
  fastcgi.server  = (
      "/Shibboleth.sso" => (("socket" => "/tmp/fcgi-resp.sock", 
            "bin-path" => "/servers/sapo-sp/lib/shibboleth/shibresponder", 
            "check-local" => "disable", 
            "mode" => "responder")),
      "/"   => (("socket" => "/tmp/fcgi-auth.sock", 
            "bin-path" => "/servers/sapo-sp/lib/shibboleth/shibauthorizer", 
            "check-local" => "disable", 
            "mode" => "authorizer"))
  )
  

Using Shibboleth in your application

The Shibboleth module works in a very similar manner to the default Security module. To protect a controller requiring authentication use the @\@With@ annotation. For example:


  @With(Shibboleth.class)
  public class Application extends Controller {
  
      public static void index() {
          render();
      }
  } 

In addition to using the controller.shib.Secure for restricting access to particular controllers you can also use it to customize how Shibboleth interacts with your application. Create a controller that extends the Shibboleth Secure class. When you do this you can add specific customization checks, for example:


  @With(Shibboleth.class)
  public class Application extends Controller {
      ...
      
      @Check("isAdmin")
      public static void modify() {
          render();
      }
  }

By default the Check annotation will always authorize all checks. You will need to customize the behavior by creating a controller in your application which extends Shibboleth’s Security class.


  package controllers;
  
  public class Security extends controller.shib.Security {
      ...
    
      static boolean check(String profile) {
          User user = User.find("byEmail", session.get("email")).first();
          if ("isAdmin".equals(profile)) {
              return user.admin;
          } else {
              return false;
          }
      }
  }

Other methods that can be customized are:

Tip
Shibboleth attributes may contain multiple values when this happens Shibboleth will encode all the attribute values seperated by a semicolon, and semicolons will be escaped with a \ character. You can use the static Shibboleth.split(attribute) method to easily split the attribute into it’s multiple components.

Testing with Shibboleth

Using a fully functional Shibboleth implementation for testing is often times impractical. This module allows you to mock shibboleth attributes so that in a testing environment you do not need to setup a Shibbolized proxy webserver. First turn on the mock implementation with shib = mock then provide a set of attributes to use when mocking Shibboleth: shib.mock.<HTTP Header> = <Header Value>. When any user attempts to login to your application with the Shibboleth mock turned on instead of using Shibboleth these attributes provided here will be assumed.


  %test.shib = mock
  %test.shib.mock.SHIB_email = [email protected]
  %test.shib.mock.SHIB_givenName = Bob
  %test.shib.mock.SHIB_sn = Smith
  ...
  %test.shib.mock.<HTTP Header> = <Header Value>

When developing functional application tests it is often usefull to authenticate as different users for individual test cases. The method described above does not allow this, however you can override these settings for a particular test case by using the MockShibboleth class directly. For example:


  @Test
  public void testShibbolethAuthentication() {
  
      MockShibboleth.removeAll();
      MockShibboleth.set("SHIB_email","[email protected]");
      MockShibboleth.set("SHIB_givenName", "Some");
      MockShibboleth.set("SHIB_sn", "One");
      
      final String LOGIN_URL = Router.reverse("shib.Shibboleth.login").url;
      Response response = GET(LOGIN_URL,true);
      assertIsOk(response);
      assertTrue(response.cookies.get("PLAY_SESSION").value
          .contains("[email protected]"));
  }
  
  @AfterClass
  public static void cleanup() {
      MockShibboleth.reload();
  }

More examples are provided in the Sample Shibboleth Application provided with the module.