Spring Security

Introductie

Dit is een van de artikelen uit een reeks over Spring. Zie ook de volgende delen :

Introductie

Spring biedt security functionaliteit zoals authenticatie, authorisatie in een apart project

http://static.springsource.org/spring-security/site/

De ondersteuning is enorm uitgebreid en biedt veel meer dan de standaard JEE features. Met name ook integratie met verschillende standaarden zoals LDAP, OpenID, JAAS etc.
Net als bij JEE varieert de ondersteuning van basic authenticatie, gebruik makend van standaard login forms tot custom implementaties van authenticatie logic en forms.

Het Spring authenticatie model wordt ingevuld met een serie Authenticatie Providers voor gebruik van bijv. user/passwords in een bestand , in een database, in een externe LDAP provider. Voor database opgeslagen user/passwords kan gebruik worden gemaakt van een Spring standaard datamodel met standaard SQL, of eventueel custom SQL.
Het meest interessante is eigenlijk de LDAP of de geheel custom implementatie. Met dat laatste heb je volledige vrijheid in de wijze waarop het security data model er uitziet en hoe deze is geïmplementeerd. Met name in situaties waarbij geïntegreerd moet worden met bestaande security data bronnen.
Een AuthenticatieProvider class implementeert de authenticate() method waarmee kan worden ingelogd. Deze method geeft een Authenticator object terug met daarin de credentials en de autorisaties: een lijst rollen die aan de user zijn toegekend. Deze rollen worden weer gebruikt om autorisaties toe te kennen aan url paden en methods in de xml bestanden en via annotaties.

Om security te gebruiken is een combinatie van xml bestanden en classes met annotaties nodig.

  • applicationContext.xml : dit algemene Spring bestand Spring metagegevens wordt uitgebreid met diverse bean definities voor het uitvoeren van authenticatie en authorisatie taken. Dit bestand wordt opgeknipt in deelbestanden voor de verschillende Spring onderdelen zoals bijv. data-access, email en security.
  • web.xml : definieert de SecurityFilterChain : een filter die alle url calls controleert en definieert de application context xml bestanden die worden gebruikt, waaronder die voor security.

Daarnaast kunnen classes en JSP pagina’s worden uitgebreid met security functies en kunnen authorisatie definities worden toegevoegd middels annotaties. En uiteraard moet de Maven pom.xml worden uitgebreid met aanvullende Spring security module library dependencies.

applicationContext.xml

Voor het toevoegen van de Spring security metagegevens wordt het applicationContext.xml bestand gestructureerder opgezet door deze te verdelen in losse bestandsonderdelen. We krijgen dan bijv. de volgende bestanden:

  • applicationContext.xml : de algemene metagegevens
  • data-context.xml : de data access metagegevens
  • mail-context.xml : de email resource metagegevens
  • security-context.xml : de security metagegevens
  • [dispatcher-servletnaam]-servlet.xml : t.b.v. MVC, de ViewResolver configuratie van de DispatcherServlet.

Het applicationContext.xml bestand heeft nu alleen de volgende definities:

    <context:annotation-config/>
    <context:component-scan base-package="org.biz.employees" />
    <mvc:annotation-driven />

web.xml definities

Application Context bestanddefinities

Er wordt bij voorkeur geen gebruik gemaakt van includes in applicationContext.xml maar in plaats daarvan worden de verschillende bestanden gedefinieerd in web.xml waar deze worden gedefinieerd als een parameter “contextConfigLocation” binnen de context-param tag. Deze parameter wordt vervolgens weer toegevoegd aan de DispatcherServlet.

  <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/dispatcher-servlet.xml
            /WEB-INF/applicationContext.xml
            /WEB-INF/security-context.xml
            /WEB-INF/data-context.xml
            /WEB-INF/mail-context.xml
        </param-value>
  </context-param>

  <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class>
          <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
  </servlet>

Deze opzet bleek nodig te zijn voor het in juiste volgorde laden van de verschillende onderdelen in de Spring Context. Er wordt hierna verder ingegaan op security-context.xml. De andere bestanden betreft andere Spring onderwerpen.

Security Filter definities

Hieronder de definities voor de security filters. Deze worden ondermeer gebruikt voor het doorgeven van de security context en het controleren van de benodigde autorisaties. Bij autorisatie conflicten kan dan een redirection naar een error page of een login page worden bewerkstelligd.

  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>

  <filter>
        <filter-name>encoding-filter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
  </filter>

  <filter-mapping>
        <filter-name>encoding-filter</filter-name>
        <url-pattern>/*</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

security-context.xml

Het bestand security-context.xml hebben we gedefinieerd om de security context definities te bevatten.
Hieronder een voorbeeld invulling voor een custom AuthenticationProvider.

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

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd


http://www.springframework.org/schema/security


http://www.springframework.org/schema/security/spring-security-3.1.xsd">

   <security:global-method-security secured-annotations="enabled" />

   <security:http auto-config="true" use-expressions="true" access-denied-page="/jsp/noaccess.jsp">
 <security:intercept-url pattern="/jsp/login.jsp" access="permitAll" />
         <security:intercept-url pattern="/control/util/**" access="hasRole('ROLE_ANONYMOUS')" />
         <security:intercept-url pattern="/control/user/**" access="hasRole('ROLE_ADMINISTRATOR')" />
         <security:intercept-url pattern="/control/role/**" access="hasRole('ROLE_ADMINISTRATOR')" />
         <security:intercept-url pattern="/control/department/**" access="hasRole('ROLE_USER')" />
         <security:intercept-url pattern="/control/employee/**" access="hasRole('ROLE_USER')" />
         <security:form-login login-page="/jsp/login.jsp"
                              login-processing-url="/loginProcess"
                              default-target-url="/jsp/index.jsp"
                              authentication-failure-url="/login.jsp?login_error=1"/>
         <security:logout logout-url="/logout" logout-success-url="/jsp/login.jsp" />
   </security:http>

   <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="customAuthenticationProvider" >
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="customAuthenticationProvider"
class="org.biz.employees.model.service.CustomAuthenticationProvider"/>
   </beans>

Als eerste wordt de volgende definitie toegevoegd om security annotaties te activeren:

  <security:global-method-security secured-annotations="enabled" />

Vervolgens worden toegevoegd:

  • een <security:http> tag met de authenticatie en autorisatie configuratie
  • een <security:authentication-manager> tag met de specificatie van de AuthenticationManager bestaande uit een of meer AuthenticationProviders, gedefinieerd in sub-tags
  • één of meer beans die de Authentication Providers specificeren. Dat kunnen standaard Spring providers zijn of eigen custom provider classes. Spring biedt diverse soorten voor bijv. user/passwords in bestandvorm, database opslag, externe LDAP providers, etc.

Custom Authentication Provider

Hieronder de voorbeeld definitie van een custom Authenticatie Provider. Deze definieert een custom class als sub-class van AuthenticationProvider. Deze custom class wordt met een bean tag expliciet gedefinieerd. Zie verderop voor een voorbeeld van de custom AuthenticationProvider class.

   <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="customAuthenticationProvider" >
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="customAuthenticationProvider"
  	  class="org.biz.employees.model.service.CustomAuthenticationProvider"/>

HTTP Authenticatie en Autorisatie definities

Hieronder de voorbeeld definitie van de security:http authenticatie en auorisatie definities.
NB: Autorisaties kunnen ook worden gedefinieerd in classes en JSP forms.

De <security:http> tag is een container voor inliggende definities. Hier wordt met een attribuut een page url gespecificeerd die wordt getoond bij het benaderen van een pagina zonder benodigde autorisatie.

De <security:intercept-url> tags specificeren de authorisaties. In het access attribuut worden de rollen gespecificeerd. Dat kan op 2 manieren: door het invullen van de “ROLE_xxx” teksten of met expression language (EL). Met het “use-expressions” attribuut wordt de ene of de andere manier ingesteld. Hieronder wordt gebruik gemaakt van EL.

Met de <security:form-login> tag wordt een custom login form gedefinieerd. Dat hoeft niet, als je deze weglaat zal Spring een eigen default login form gebruiken.

Met de <security:logout> tag wordt een logout url gespecificeerd waarmee de logout actie wordt uitgevoerd. Deze wordt voor een succesmelding gekoppeld aan een page url, wat ook de login page kan zijn.

   <security:http auto-config="true" use-expressions="true" access-denied-page="/jsp/noaccess.jsp">
 <security:intercept-url pattern="/jsp/login.jsp" access="permitAll" />
         <security:intercept-url pattern="/control/util/**" access="hasRole('ROLE_ANONYMOUS')" />
         <security:intercept-url pattern="/control/user/**" access="hasRole('ROLE_ADMINISTRATOR')" />
         <security:intercept-url pattern="/control/role/**" access="hasRole('ROLE_ADMINISTRATOR')" />
         <security:intercept-url pattern="/control/department/**" access="hasRole('ROLE_USER')" />
         <security:intercept-url pattern="/control/employee/**" access="hasRole('ROLE_USER')" />

         <security:form-login login-page="/jsp/login.jsp"
                             login-processing-url="/loginProcess"
                             default-target-url="/jsp/index.jsp"
                             authentication-failure-url="/login.jsp?login_error=1"/>
         <security:logout logout-url="/logout" logout-success-url="/jsp/login.jsp" />
   </security:http>

Custom AuthenticationProvider class

De custom AuthenticationProvider class ziet er ruwweg als volgt uit:

public class CustomAuthenticationProvider implements AuthenticationProvider  {

	@Override
	public Authentication authenticate(Authentication authentication) throws
AuthenticationException {
		String userName = authentication.getName();
		Object credentials = authentication.getCredentials();
		//Implement custom userName/password check
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
		return new UsernamePasswordAuthenticationToken(userName, credentials, authorities);

	@Override
	public boolean supports(Class<? extends Object> authentication) {
		return authentication.equals(UsernamePasswordAuthenticationToken.class);
	}
}

In de AuthenticationProvider wordt de custom logic toegevoegd om de username en password (credentials) te checken. Bijv. door hierin een data-access service te benaderen of een externe provider te benaderen. Verder wordt een zogenaamd Authentication object retour gegeven waarin de credentials incl. de authorisaties zijn toegevoegd.
De authorisaties worden opgeslagen in een List van het GrantedAuthority object en hebben de structuur “ROLE_” gevolgd door de rolnaam. Deze rol definities worden gebruikt om url paden en methods te voorzien van authorisaties. In het voorbeeld hiervoor wordt hard coded een rol “ROL_USER” toegevoegd, maar in de praktijk worden de rollen die als rechten aan een gebruiker zijn toegekend uiteraard ergens ander vandaan gehaald.

Gebruik van login form

Hieronder een voorbeeld van een custom JSP login form.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<%@ page import="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" %>
<%@ page import="org.springframework.security.web.WebAttributes" %>
<%@ page import="org.springframework.security.core.AuthenticationException" %>

<html>
<body>
<h1>Login</h1>

	<form name="f" action="<c:url value="/loginProcess" />" method="post">
		<table>
			<tr>
				<td>Username:</td>
				<td><input type="text"
						 name="j_username"
						 id="j_username" <c:if test="${not empty param.login_error}">value="<%= session.getAttribute(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY) %>"</c:if> /></td>
			</tr>
			<tr>
				<td>Password:</td>
				<td><input type="password" name="j_password" id="j_password" /></td>
			</tr>
			<tr><td colspan="2" align="center"><input name="submit" id="submit" type="submit" value="Login" /></td></tr>
		</table>
	</form>
	<c:if test="${not empty param.login_error}">
		<font color="red">
			Login fout!<br />
			Oorzaak: <%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %>
		</font>
	</c:if>

<sec:authorize access="isAuthenticated()">
   Je bent ingelogd!
</sec:authorize>

</body>
</html>

Gebruik van programmatische login

Naast gebruik van een default of custom login form, kan ook programmatisch een login worden uitgevoerd. Bijv. een scenario waarbij login via JavaScript en Ajax (bijv. via jQuery) wordt gedaan en de login user/password encrypted naar een login service worden gestuurd.
Hierna een code voorbeeld waarbij de authenticate() method van de custom AuthenticationProvider wordt aangeroepen.
Als eerste wordt met de user/password een token object gemaakt met behulp van de Spring class UsernamePasswordAuthenticationToken. Dit token is input voor de authenticate() method. Eventueel kan aan het token met de setDetails() method nog aanvullende specifieke security data worden toegevoegd. De authenticate() method geeft een Authentication object retour welke wordt opgeslagen in de Spring security context. Het Authentication kan naar behoefte worden opgevraagd om de inlog status te checken.

UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(username, password);
//token.setDetails(…any object with specific data…);
try {
   Authentication auth = authenticationManager.authenticate(token);
   SecurityContext securityContext = SecurityContextHolder.getContext();
   securityContext.setAuthentication(auth);
} catch (BadCredentialsException e) {
   …
}

Hieronder een voorbeeld van het opvragen van de inlog status. Eerst wordt het Authentication object opgevraagd uit de security contect. Vervolgens kan hierop met de isAuthenticated() method worden vastgesteld of de user is ingelogd. Verdere gegevens zoals username kunnen verder worden opgevraagd.

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userName = auth.getName();
if (auth.isAuthenticated()) {
return …;
} else {
	return …;
}

Authorisatie definities in Classes en (JSP) Forms

Behalve het autoriseren van url’s kunnen ook class methods van bijv. een DAO class worden geauthoriseerd met de annotatie @Secured(). In onderstaand voorbeeld wordt de method delete() geauthoriseerd voor de rol “ROLE_ADMINISTRATOR”.

@Secured ({"ROLE_ADMINISTRATOR"})
public void delete(User user) {
   …
}

In JSP forms kunnen autorisaties worden gecontroleerd met de sec:authorize tag:
Dat kan op 2 manieren: door het invullen van de “ROLE_xxx” teksten of met expression language (EL). De keuze hiervoor wordt ingesteld in het security-context.xml bestand met het “use-expressions” attribuut :.

Hieronder wordt gebruik gemaakt van “ROLE_xxx” tekst.

<sec:authorize ifAllGranted="ROLE_ ADMINISTRATOR ">
…
</sec:authorize>

Hieronder wordt gebruik gemaakt van EL.

<sec:authorize access="isAuthenticated()">
   Je bent ingelogd!
</sec:authorize>

Maven dependencies

Hieronder de gebruikte Maven dependencies. Omdat Spring Security een apart Spring project is zijn de versies ook afwijkend t.o.v. de algemene Spring core versies.

	<dependency>
	        <groupId>org.springframework.security</groupId>
	        <artifactId>spring-security-core</artifactId>
	        <version>3.1.3.RELEASE</version>
	</dependency>
	<dependency>
	        <groupId>org.springframework.security</groupId>
	        <artifactId>spring-security-web</artifactId>
	        <version>3.1.3.RELEASE</version>
	</dependency>
	<dependency>
	        <groupId>org.springframework.security</groupId>
	        <artifactId>spring-security-config</artifactId>
	        <version>3.1.3.RELEASE</version>
	</dependency>
	<dependency>
	        <groupId>org.springframework.security</groupId>
	        <artifactId>spring-security-taglibs</artifactId>
	        <version>3.1.3.RELEASE</version>
	</dependency>

This entry was posted in JEE, Security, Spring and tagged , . Bookmark the permalink.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd.

De volgende HTML tags en attributen zijn toegestaan: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>