Skip to content

Posts tagged ‘Security’

12
Mar

Spring Security 3 integration with Active Directory LDAP

Introduction

This article describes the process for integrating Spring Security 3 with Microsoft Active Directory (AD) LDAP. Spring Security is a powerful and highly customizable authentication and access-control framework that can be used to secure web applications and web service end-points. For the sake of simplicity there are two user roles that will be applied in this example: Customer Service Officer and System Administrator.

The fictitious Web TwoPointOh application being secured is called “Orbiks” and if you follow this approach in a production environment take a deep breath and digest the contents of the OWASP Top Ten Web Application Security Risks to ensure you understand potential security risks and know how to minimise application vulnerabilities.

Spring Security 3.1

The new AD specific Authentication Provider in Spring Security 3.1 simplifies integration with Active Directory.

The following dependencies from Spring Security 3.1.0.RELEASE were referenced in this example:

  • spring-security-config
  • spring-security-core
  • spring-security-ldap
  • spring-security-web

It is also necessary to include a dependency for the latest release of spring-ldap.

Getting started

Specify the security filter chain in the web application deployment descriptor and the URL pattern it applies to. In our application, we want all URLs to be processed by the security filter so the following is used in web.xml:

<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> 

Ensure the security application context is loaded in the web.xml as follows:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
         classpath:applicationcontext-security.xml
         classpath:applicationcontext.xml
    </param-value>
</context-param>

Security Application Context

Spring Security allows fine-grained access to resources including method-level and action-level authorization but to keep things simple I will be securing application URLs. The web application has a log in page and a sign-up page so these pages will be excluded from the security intercept pattern to allow users to hit them without obviously needing to authenticate.

Spring Security Application Context

Create a file called applicationcontext-security.xml in the /WEB-INF directory as follows:


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:security="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <!-- LDAP server details --> 
    <security:authentication-manager>
        <security:authentication-provider ref="ldapActiveDirectoryAuthProvider" />
    </security:authentication-manager>

    <beans:bean id="grantedAuthoritiesMapper" class="net.comdynamics.orbiks.security.ActiveDirectoryGrantedAuthoritiesMapper"/>

    <beans:bean id="ldapActiveDirectoryAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
        <beans:constructor-arg value="comdynamics.net" />
        <beans:constructor-arg value="ldap://bigldap.comdynamics.net:389/" /> 
        <beans:property name="authoritiesMapper" ref="grantedAuthoritiesMapper" />
        <beans:property name="useAuthenticationRequestCredentials" value="true" />
        <beans:property name="convertSubErrorCodesToExceptions" value="true" />
    </beans:bean>

    <security:http auto-config="true" pattern="/**">
        <!-- Login pages -->
        <security:form-login login-page="/login.html" default-target-url="/user/home.html" 
            login-processing-url="/j_spring_security_check" authentication-failure-url="/login-error.html" />
        <security:logout logout-success-url="/login.html"/>

        <!-- Security zones -->
        <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
        <security:intercept-url pattern="/case-management/**" access="ROLE_CUSTOMER_SERVICE_OFFICER, ROLE_ADMIN" />
    </security:http>

</beans:beans>

The wildcard pattern match will result in all requests for resources in these paths being matched against the user principal that is attempting to access these resources.

A login page has been specified which redirects the user to the default-target-url on successful login when processed by the Spring Security filter. Login error redirects the user back to the login page requesting them to re-enter valid credentials.

Note: Applications that are secured to corporate Active Directory servers with large numbers of users and organizational units should specify the user-search-base and user-search-filter in the ldap-authentication-provider to refine the search path and reduce LDAP search times.

Granted Authorities

Granted Authorities represent the actions that a user can perform when successfully authenticated. A user may have one or more granted authorities and these authorities represent a role that maps to an LDAP group. The following enum contains GrantedAuthorities for the application:

package net.comdynamics.orbiks.security;

import org.springframework.security.core.GrantedAuthority;

/**
 * Maps groups defined in LDAP to roles for a specific user.
 */
public enum OrbiksAuthority implements GrantedAuthority {

    // These roles are specified in the security application context and are
    // mapped to LDAP roles by the AuthoritiesMapper
    ROLE_CUSTOMER_SERVICE_OFFICER, ROLE_ADMIN;

    public String getAuthority() {
        return name();
    }
}

Granted Authorities Mapper

Since the group names in AD are different to the roles specified in the security application context, a custom class has been written to map these roles to LDAP groups. The following table shows the correlation of Granted Authorities to LDAP groups.

Application Role Granted Authority Name LDAP Group Name
Customer Service Officer ROLE_CUSTOMER_SERVICE_OFFICER Orbiks-CustomerServiceOfficer
System Administrator ROLE_ADMIN Orbiks-SystemAdministrator


The groups should be contained within the same LDAP Organizational Unit (OU) and users should be added as members to these groups depending on their role. Users will need to authenticate with their domain account name (sAMAccountName) and password.

The custom GrantedAuthoritiesMapper implementation is as follows:

package net.comdynamics.orbiks.security;

import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;

/**
 * Maps groups defined in LDAP to roles for a specific user.
 */
public class ActiveDirectoryGrantedAuthoritiesMapper implements GrantedAuthoritiesMapper {

    // Constants for group defined in LDAP
    private static final String ROLE_ADMIN = "Orbiks-SystemAdministrator";
    private static final String ROLE_CUSTOMER_SERVICE_OFFICER = "Orbiks-CustomerServiceOfficer";

    public ActiveDirectoryGrantedAuthoritiesMapper() {
    }

    public Collection<? extends GrantedAuthority> mapAuthorities(
            final Collection<? extends GrantedAuthority> authorities) {

        Set<OrbiksAuthority> roles = EnumSet.noneOf(OrbiksAuthority.class);

        for (GrantedAuthority authority : authorities) {
            if (ROLE_CUSTOMER_SERVICE_OFFICER.equals(authority.getAuthority())) {
                roles.add(OrbiksAuthority.ROLE_OFFICER);
            } else if (ROLE_ADMIN.equals(authority.getAuthority())) {
                roles.add(OrbiksAuthority.ROLE_ADMIN);
            }
        }
        return roles;
    }
}

Conclusion

Spring Security 3.1 now provides simplified integration with Active Directory. Authentication and authorization is performed with the domain account of the user as there is no requirement to use an LDAP bind account.