Emmet security is implemented using the Spring Security framework, and is designed to be configured using Chico customization mechanisms as described in this page.
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:
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:
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".
The following steps should be sufficient to enable Emmet-based security in a webapp.
<!--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> <context-param>
<param-name>contextConfigProperties</param-name>
<param-value>classpath:build.properties,classpath:default-emmet-substitution.properties,classpath:substitution.properties</param-value>
</context-param>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.
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.
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.
This scheme is for testing Shibboleth integration, etcetera.
As you would expect, Spring Security splits the problem of access control into two parts:
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-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.
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.
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.
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.
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.
The normal use-case for SpringSecurity is divide the world of users into two classes:
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.
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:
The initial version is MySQL specific, and stores raw passwords in the database. We know the latter is a really bad idea ...
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.
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.
When fine-grained access control is implemented it will be described here.