Emmet Security Configuration

Emmet security is implemented using the Spring Security framework, and is designed to be configured using Chico customization mechanisms as described in this page.


Simple Emmet Security Configuration

The Emmet security configurations are defined in the XML wiring files in the "WEB-INF" directory, and controlled by the "emmet.security", "emmet.site" and "emmet.userDetails" substitution properties. Assuming that you are using Emmet security in a webapp that has been preconfigured to use Emmet, your configuration primary configuration effort may consist of just setting these three properties.

The "emmet.security" property can have the following values:

none
security is disabled
simple
simple form-based authentication
openid-hybrid
a hybrid security scheme with both form-based and OpenId authentication.
shibboleth
a security scheme using Shibboleth alone
test
a test scheme combining Shibboleth and form-based authentication.

Descriptions of the template security schemes are provided below. (Of course you are free to create your own scheme from scratch.)

The "emmet.userDetails" property can have the following values:

test
use a hard-wired in-memory user details store populated with test accounts / details.
emmet
use the "emmet" user details store backed by an SQL database. Note that this setting needed for the Emmet servlet to work.

The "emmet.site" property selects site-specific access control wirings. The default site values for a stand-alone Emmet site and Danno / Dannotate site are respectively are "emmet" and "danno".

Enabling Emmet Security in a New Project

The following steps should be sufficient to enable Emmet-based security in a webapp.

  1. Ensure that the following lines are present in the webapp's "web.xml" file.
      <!--START: SECURITY-->
        <filter>
          <filter-name>springSecurityFilterChain</filter-name>
          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
      
        <filter-mapping>
          <filter-name>springSecurityFilterChain</filter-name>
          <url-pattern>/*</url-pattern>
        </filter-mapping>
  1. Ensure that "/WEB-INF/Emmet-security.xml" is included in the "contextConfigLocation" context property at the top of the "web.xml" file.
  2. Change the contents of the listener-class element to "au.edu.diasb.chico.config.ContextLoaderListener".
  3. Ensure that the webapp's "web.xml" file includes a context parameter called "contextConfigProperties" that lists the relevant properties files; e.g.
      <context-param>
        <param-name>contextConfigProperties</param-name>
        <param-value>classpath:build.properties,classpath:default-emmet-substitution.properties,classpath:substitution.properties</param-value>
      </context-param>
  4. Ensure that there is a "/WEB-INF/siteTailoring.xml" file in your webapp, and that the bean properties in that file specify the relevant properties files.
  5. Override the settings of "emmet.security", "emmet.site" and "emmet.userDetails" (as required) in your "substitution.properties" file.
  6. Ensure that the contents of your "Emmet-siteAuthorization-*.xml" file corresponds to your website organization.

Security scheme "none"

This scheme disables all access control for the Danno servlet itself. It is theoretically possible to implement some degree of access control in a front-end webserver (e.g. Apache HTTPD) but fine-grained access control is not possible.

Security scheme "simple"

This scheme enables simple access control with a login form and a user details store selected by the userDetails property. SpringSecurity's remember-me, anonymous and logout functionality is also enabled.

Security scheme "openid-hybrid"

This scheme enables a scheme that supports both OpenID authentication and user / password authentication using credentials in a local user details store. For registered users (with OpenID or user/password credentials), the local user details store provides the authorities that are granted on successful login. Non-registered users with valid OpenID credentials are granted (configurable) default authorities. The scheme also allows you to configure the set of OpenID providers deemed to provide acceptable credentials.

Security scheme "test"

This scheme is for testing Shibboleth integration, etcetera.

Spring Security Overview

As you would expect, Spring Security splits the problem of access control into two parts:

  • Authentication - this is the process of establishing who the user is.
  • Authorization - deciding what an authenticated user is allowed to do.

Once the user has been authenticated and authorized, an Authorization object is created and populated with the user's identity and authorities; i.e. roles or permissions. This Authorization object is tied to a Spring-managed session cookie that is stored in the user's web browser. Each time the user (or the Dannotate / PageRepeater servlet acting on the user's behalf) makes a Danno request, the Authorization is checked to see the request should be performed. Coarse-grained checks are made by SpringSecurity filters as configured below; e.g. using <intercept-url> elements. Fine-grained checks may be implemented by the webapp's servlets or by post-invocation filters.

Spring supported login mechanisms

Spring-mediated authentication typically kicks in when the user makes a request that requires more than the base level (anonymous) authorizations. This causes Spring to respond to the request with a 401 error with a HTTP Basic or Digest authorization challenge, or a 302 redirect to a login page.

In the former case, the user's web browser responds to the challenge by requesting a username and password directly from the user, and repeating the original request with the user's credentials. In the case of HTTP Basic, the credentials are sent in the clear in every request from then on. (This is very insecure if there is a possibility that someone may be monitoring network traffic!) In the case of HTTP Digest, the browser creates a secure hash of the user's password and a "nonce" supplied in the challenge. This is more secure, but it still requires the server-side (i.e. Danno) to have a clear copy of the user's password.

In the latter case, the user's web browser loads the login form and waits for the user to enter (for example) a username and password. When the user clicks "submit", the credentials are sent to the Danno service and checked. If all is well, the browser is sent another redirect response, this time telling it to repeat the original request. This response also replaces the session cookie with one that says the user is logged in. (The interactions need to be a bit different when Dannotate or the page repeater is involved, but the basic pattern is the same.) This process is secure provided that the login page is delivered via HTTPS rather than plain HTTP and the submit button sends the user's credentials using HTTPS.

Spring supports a number of ways of authenticating the user. On the simple end, you can create a local UserDetailsStore containing a locally maintained list of user names, passwords (in clear or hashed) and permissions. If you have an existing LDAP system you can authenticate using it. Or you can use OpenID, JAAS, JOSSO and many other solutions.

In the simple model, the login page asks the the user name and password directly. However, is is also possible to delegate this part of the process to a third-party authenticator. For instance, if OpenID is available, the initial login page could offer the choice of entering a local user name and password, or the URL of an OpenID provider. When a user takes the latter course, his or her browser will be redirected to a page on the OpenID provider's website that asks for credentials for that site and for permission to pass the authentic identity to (in this case) Danno.

Spring Security configuration.

The following example shows Spring configuration excerpts that use a simple in-memory UserDetailsStore.

    <http>
        ...
        <form-login/>
        <logout/>
    </http>
    
    <authentication-provider>
        <user-service>
            <user name="steve" password="yyy" 
                  authorities="ROLE_ADMIN,ROLE_USER,ROLE_ANNOTATOR" />
            <user name="ron" password="zzz" 
                  authorities="ROLE_USER,ROLE_ANNOTATOR" />
            <user name="george" password="ppp" 
                  authorities="ROLE_USER" />
            <user name="oai" password="qqq" 
                  authorities="ROLE_USER,ROLE_OAI_USER" />
        </user-service>
    </authentication-provider>

The <http> element includes elements to configure the authentication mechanisms that will be available to the end user. In this case, we have specified that a form-based login be used with a default login form. Alternatives include <http-basic> for HTTP basic authentication and <openid-login> for form-based login with the (user) option of using a remote OpenID provider to login. Other elements allow you to configure a "logout" URL (as shown) or a "remember me" checkbox.

The result of (successful) authentication is an authentic user and an associated set of "granted authorities". Depending on how you model your access control, the latter could be "roles" in the system or "permissions". Either way, Spring Security allows for two approaches for determining whether the authentic user is allowed to perform a requested operation.

The simple approach is to match the request URL against a sequence of patterns. When a match succeeds, Spring checks whether the user's authorities include all of the required authorities associated with the pattern. With this approach, the authorization scheme can be expressed entirely in the Spring Security wiring file using the <intercept-url> element. For example:

   <http auto-config='true'>
        <intercept-url pattern="/" filters="none" />
        <intercept-url pattern="/*.html" filters="none" />
        <intercept-url pattern="/stylesheets/*" filters="none" />
        ...
        <intercept-url pattern="/oai2" access="ROLE_OAI_USER" />
        <intercept-url pattern="/annotea/**" 
                       method="GET" access="ROLE_USER" />
        <intercept-url pattern="/annotea/**" 
                       access="ROLE_USER,ROLE_ANNOTATOR" />
        ...
    </http>

The <intercept-url> elements above come in two forms. The first form (i.e. those with 'filters="none"') simply say that no access control is performed for URLs matching the corresponding 'pattern'. So the example above declares that the base URL, all top-level HTML files and everything in the stylesheets directory are not subject to access control.

The second form uses an 'access' property to specify a set of required authorities. So the example above declares that an "/oai2" request requires the "ROLE_OAI_USER" authority, the GET requests on the annotea interface require "ROLE_USER", and the other requests (POST, PUT and DELETE) require both "ROLE_USER" and "ROLE_ANNOTATOR" authorities.

The general rule with <intercept-url> elements is that they are compared against the request URL in the order that they are listed in the XML file until one of them matches. Once a match is found, the access rule is applied and processing ends, either allowing the request or rejecting it. If there are URLs that could match more than one element pattern, you need to arrange the elements so that the one with the rule that you want to apply appears first.

Unfortunately, there are some important "gotchas" in the way that <intercept-url> elements are handled by Spring that are not properly documented in the SpringSecurity documentation.

  • An element with "filters='none'" attribute disables the entire security chain for URLs matching the pattern. If you include a "requires-channel" attribute as well, it will have no effect. If other elements have the same pattern or a subpattern they will have no effect, no matter where they are in the parent <http> element.
  • Elements with a "method='...'" attribute take precedence over elements without this attribute, no matter where they are in the parent <http> element.

Securing pages with HTTPS

If you are using form-based login rather than HTTP Basic / Digest Authentication (and this is generally a better idea), it is important that you secure your login page using HTTPS. This protects against spoofing (provided that the user is paying attention), and encrypts username and password information sent over the network.

Depending on your use-cases, it may be worthwhile securing other web pages or (more generally) interactions with HTTPS. This section discusses the mechanics of doing this.

Note however, that an HTTPS-secured page imposes extra overheads on the server side. It is not advisable to secure pages / interactions unless there is a good case for doing so.

Architectural considerations

HTTPS presents a problem if you are using an Apache httpd front-end for the Tomcat instance that runs your Danno server. The root problem is that Apache does not implement the client-side of the HTTPS. So, if you use Apache as a reverse proxy for Danno, all interactions between Apache and Tomcat must use HTTP rather than HTTPS. This in turn means that Apache must be enabled with HTTPS, and it (not Danno) must ensure that key Danno URLs such as the login form are only accessed using HTTPS.

For details on configuring HTTPS in Tomcat, refer to the documentation for your version of Tomcat (for example the SSL Configuration HOW-TO page), or follow the instructions in the "$CATALINA_HOMEconf/server.xml" file.

For details on configuring HTTPS in Apache, refer to the Apache SSL/TLS Encryption page for your version of Apache.

Spring Security configuration of HTTPS

If you are intending to use HTTPS for pages or requests that Danno exposes, you can (and should) configure Spring Security to require that HTTPS is used for those pages. This is done by adding a "requires-channel" attribute to the relevant <intercept-url> element; for example:

    <http>
        ...
        <intercept-url pattern="/secure/login.html" 
                       access="IS_AUTHENTICATED_ANONYMOUSLY" 
                       requires-channel="https"/>
        <intercept-url pattern="/secure/**" 
                       access="ROLE_SPECIAL_USER" 
                       requires-channel="https" />
        ...
    </http>

On the other hand, if you have an Apache httpd front-end, you (probably) should not configure any pages / requests to require HTTPS.

Danno-specific security goals and mechanisms.

The normal use-case for SpringSecurity is divide the world of users into two classes:

  • Registered users are authenticated by some means using a trusted local or external authentication service. Authorization information is obtained from the same service or (in the case of OpenId) from a local user details service that is keyed on the user's external identity URL.
  • All others access the system in a non-authenticated fashion as anonymous users.

The prototypical use-cases for Danno are a little different. On the one hand, we want to be able to support users who are registered with some authentication provider but not formally registered as Danno users. On the other hand we need to be able to support multiple authentication mechanisms in the same installation. For example, ALA needs to use the (Shibboleth-based) AAF for authenticating Australian researchers and academics, OpenID (or similar) for other members of the public and locally managed authentication for special cases.

We are in the process of developing custom SpringSecurity components to support these requirements and more general "user management" requirements for the ALA as a whole. The following sections lists key components that we are in the process of developing.

  • EmmetUserDetailsService

    The EmmetUserDetailsService is a custom User Details Service that supports a richer model of user details than the default store, without going to the extent of a full-blown LDAP service. The key features will include:

    • Support for users with multiple "identity" URLs.
    • Support for one-time passwords, password expiry and password reuse restrictions.
    • Support for extensible user profile information and preference storage.
    • Persistence in a local RDBMs.
    • The ability to populate a test details store by Spring DI using bean wiring files.

    The initial version is MySQL specific, and stores raw passwords in the database. We know the latter is a really bad idea ...

EmmetController

The EmmetController is a Spring MVC bean that implements the nascent Emmet user management subsystem. When completed, it will be RESTful and will provide web APIs for user account administration.

The initial version supports only creation of the accounts and the changing of passwords.

Shibboleth support components

Since SpringSecurity includes no standard components for integrating with Shibboleth authentication, we will be implementing our own. (The "eSciDoc.org" project have managed to do this, so we'll be borrowing ideas from them.)

Note that using Shibboleth entails using an Apache front-end for any Java-based web services that require access control. Specifically, you need to configure the Apache server to use the "mod_shib" module and to provide details of the IdP(s) that you plan to use for authentication. As far as we know, there is no all-Java alternative at the moment.

A "HOW TO" section on configuring Apache will be provided in due course.

Danno fine-grained access control

When fine-grained access control is implemented it will be described here.