Ten Things You Can Do With Spring Security
One
You can specify the authorisation provider of your choice in your Spring XML config file. You do this by configuring anauthentication-manager as defined in Spring’s http://www.springframework.org/schema/security/spring-security-3.1.xsd schema. The simplified authentication-manager element definition looks something like this:<xs:element name="authentication-manager"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="authentication-provider"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="security:any-user-service"/> <xs:element name="password-encoder">...</xs:element> </xs:choice> <xs:attributeGroup ref="security:ap.attlist"/> </xs:complexType> </xs:element> <!-- This is BIG --> <xs:element name="ldap-authentication-provider">...</xs:element> </xs:choice> <xs:attributeGroup ref="security:authman.attlist"/> </xs:complexType> </xs:element>
This means that, for example, you can use any number of authentication providers including basic authentication and JDBC authentication as shown in the snippet below:
<authentication-manager alias="authenticationManager"> <authentication-provider> <user-service> <user authorities="ROLE_GUEST" name="guest" password=""/> </user-service> </authentication-provider> <authentication-provider> <jdbc-user-service data-source-ref="dataSource"/> </authentication-provider> </authentication-manager>
Two
You can configure authorisation rules in your Spring XML file by linking URLs to user roles using the intercept-url element. The intercept-url element is a child element of the http element, whose abridged definition looks like this:<xs:element name="http"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="intercept-url"> <xs:complexType> <xs:attributeGroup ref="security:intercept-url.attlist"/> </xs:complexType> </xs:element> <!-- Details omitted for clarity --> <xs:element name="access-denied-handler">...</xs:element> <xs:element name="form-login">...</xs:element> <xs:element name="openid-login">...</xs:element> <xs:element name="x509">...</xs:element> <xs:element ref="security:jee"/> <xs:element name="http-basic">...</xs:element> <xs:element name="logout">...</xs:element> <xs:element name="session-management">...</xs:element> <xs:element name="remember-me">...</xs:element> <xs:element name="anonymous">...</xs:element> <xs:element name="port-mappings">...</xs:element> <xs:element ref="security:custom-filter"/> <xs:element ref="security:request-cache"/> <xs:element name="expression-handler">...</xs:element> </xs:choice> <xs:attributeGroup ref="security:http.attlist"/> </xs:complexType> </xs:element>
Example usage:
<security:http> <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/> <security:intercept-url pattern="/account/**" access="hasRole('ROLE_USER')" /> <security:intercept-url pattern="/**" access="hasRole('ROLE_ANONYMOUS')" /> <!-- other elements removed for clarity --> </security:http>
Three
You can encode and validate passwords using several classes that implement Spring’sorg.springframework.security.authentication.encoding.PasswordEncoder interface. This only has two methods:encodePassword and isPasswordValid. Its many implementations include:- BaseDigestPasswordEncoder
- BasePasswordEncoder
- LdapShaPasswordEncoder
- Md4PasswordEncoder,
- Md5PasswordEncoder
- MessageDigestPasswordEncoder
- MessageDigestPasswordEncoder
- PlaintextPasswordEncoder
- ShaPasswordEncoder
Four
You can restrict access to page elements using Spring Security’s tag library. To use this library you include the following taglib definition in your JSP:<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
The taglib contains three useful tags:
- authorize
- authentication
- accesscontrollist
The most useful seems to be the authorize tag, which, taking examples from the Spring documentation, can be used in two ways. Firstly, you can authorize against roles:
<sec:authorize access="hasRole('supervisor')"> This content will only be visible to users who have the "supervisor" authority in their list of <tt>GrantedAuthority</tt>s. </sec:authorize>
...and secondly you can authorize against URLs
<sec:authorize url="/admin"> This content will only be visible to users who are authorized to send requests to the "/admin" URL. </sec:authorize>
The URL specified must tie in with the intercept-url tag described in item 2.
Five
You can perform method level authorization using Spring’s in-house annotations- @PreAuthorize("spEL expression")
- @PostAuthorize("spEL expression")
- @Secure
where the spEL expression can be anything, but is usually something like: hasRole('ROLE_USER').
To enable @PreAuthorize(...) and @PostAuthorize(...) add the following to your XML config file:
<global-method-security pre-post-annotations="enabled" />
@PreAuthorize(...) is used as shown in the following example:
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void deleteUser(String username);
To enable @Secure add the following to your Spring config file:
<global-method-security pre-post-annotations="enabled" />
Six
You can perform method level security using Spring’s JSR-250 implementation by adding the following to your Spring config file:<global-method-security jsr250-annotations=”enabled”/>
The JSR-250 security annotations are a sub set of the JSR-250 annotations and include:
- @RolesAllowed({“ROLE_USER”,”ROLE_ADMIN”})
- @PermitAll
- @DenyAll
When used, a JSR-250 annotation looks something like this:
@RolesAllowed({"ROLE_ADMIN","ROLE_USER"})
public void deleteUser(String username);
Seven
You can integrate Spring Security with OpenID authentication with a few simple steps. The first of these is writing a simple JSP form where the action value is set to j_spring_openid_security_check, which at its most minimal looks something like this:<form action="j_spring-openid-security-check" method="post"> <label for="openid_idenifier">Login</label>: <input id="openid_identifier" name="openid_identifier" type="text"/> <input type="submit" value="Login" /> </form>
The next step is add the openid-login element to http:
<xs:element name="http"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="openid-login"> <xs:annotation> <xs:documentation> Sets up form login for authentication with an Open ID identity </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="security:attribute-exchange" /> </xs:sequence> <xs:attributeGroup ref="security:form-login.attlist" /> <xs:attribute name="user-service-ref" type="xs:token"> <xs:annotation> <xs:documentation> A reference to a user-service (or UserDetailsService bean) Id </xs:documentation> </xs:annotation> </xs:attribute> </xs:complexType> </xs:element> <!-- Other elements omitted for clarity --> </xs:choice> </xs:complexType> </xs:element>
As all of openid-login child elements are optional, the simplest way to enable OpenID is to write:
<http auto-config="true"> <openid-login/> <!-- other tags and attributes omitted for clarity --> </http>
Lastly, you’ll need to add the spring-security-openid.jar to your project.
Eight
You can configure your app to authenticate users with an embedded LDAP (Lightweight Directory Access Protocol) Server using XML config. This is described in the abridged XML schema show below:<xs:element name="ldap-server"> <xs:complexType> <xs:attributeGroup ref="security:ldap-server.attlist" /> </xs:complexType> </xs:element> <xs:attributeGroup name="ldap-server.attlist"> <xs:attribute name="id" type="xs:token"> <xs:annotation> <xs:documentation> A bean identifier, used for referring to the bean elsewhere in the context. </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="port" type="xs:positiveInteger"/> <xs:attribute name="ldif" type="xs:string"> <xs:annotation> <xs:documentation> Explicitly specifies an ldif file resource to load into an embedded LDAP server. The default is classpath*:*.ldiff </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="root" type="xs:string"> <xs:annotation> <xs:documentation> Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org" </xs:documentation> </xs:annotation> </xs:attribute> </xs:attributeGroup>
The LDIF file, where LDIF stands for LDAP Interchange Format, is a plain text file format used to describe a set of LDAP records.
An example of the ldap-server element usage would be:
<ldap-server ldif="classpath:my-ldif-file.ldif" id="localserver" />
To use Spring Security LDAP integration, remember to include the spring-security-ldap.jar jar in your project’s POM.XML.
Nine
You can configure your app to authenticate users with remote LDAP (Lightweight Directory Access Protocol) Server using XML config. This is described in the abridged XML schema show below:<xs:element name="ldap-server"> <xs:complexType> <xs:attributeGroup ref="security:ldap-server.attlist" /> </xs:complexType> </xs:element> <xs:attributeGroup name="ldap-server.attlist"> <xs:attribute name="id" type="xs:token"> <xs:annotation> <xs:documentation> A bean identifier, used for referring to the bean elsewhere in the context. </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="url" type="xs:token"/> <xs:attribute name="port" type="xs:positiveInteger"/> <xs:attribute name="manager-dn" type="xs:string"> <xs:annotation> <xs:documentation> Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used. </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="manager-password" type="xs:string"> <xs:annotation> <xs:documentation> The password for the manager DN. This is required if the manager-dn is specified. </xs:documentation> </xs:annotation> </xs:attribute> </xs:attributeGroup>
The documentation states that the ldap-server element “Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied”.
This is an example of a really minimal configuration:
<ldap-server url="ldap://myServer/dc=captaindebug,dc=com:389" id="ldapExternal" manager-dn="uid=admin,ou=users,ou=systems" manager-password="s3cret"/>
Having configured the server, you also need to configure the LDAP authentication provider. There seem to be several methods of doing this and it’s not so straightforward, so more on that later, possibly...
Ten
You can add the requires-channel="https" attribute to your Spring Security Config's <intercept-url /> element to force any matching URL to use HTTPS. For example, if you wanted to ensure that password were always encrypted before being sent, then you could add this abridged XML to your config:<http auto-config="true" use-expressions="true"> <intercept-url pattern="/login" requires-channel="https"/> <!-- Other attributes and elements omitted --> </https>
There are another couple of things to do here, but more on that later...
You may have noticed that I’ve used the Spring Security XML schema file (http://www.springframework.org/schema/security/spring-security-3.1.xsd) to explain some of the features in my list of things you can do with Spring Security. That’s because I always treat the Spring XSDs as the definitive reference point for all things Spring. In November 2011 I wrote a blog on Spring’s JSR-250’s @PostConstruct Annotation that contained a mistake (Yes, it true it does happen), which was quite rightly pointed out by Spring’s Chris Beams - @CBeams, who left a comment on the JavaLobby Version of this blog. I decided to check the schemas and found that we were both wrong (although I was a lot more wrong than Chris) - the Captain Debug article is now, so far as I can tell, correct.
Application security is a pretty complex subject and if it’s something you’ll be looking at in depth then I suggest that you get a copy of Spring Security 3 by Peter Mularien - it’s also recommended by the Guys at Spring.
Finally, if there’s one key idea to appreciate about Spring Security is that, as an application bolt-on, it provides a really rich security feature set. You should therefore try to let Spring Security handle as much possible of your app’s security details rather than diving in and unnecessarily writing your own code.