Spring Security, petit frère d'Acegi Security, est un framework qui fournit des mécanismes d'authentification et de sécurisation pour vos applications Java. Voici comment sécuriser votre application web en trois étapes...
Configuration dans le web.xml
Le fichier web.xml est le descripteur de déploiement de votre application web. Il est généralement situé dans le répertoire WEB-INF et définit les paramètres de base de votre application.
Commencez par définir un filtre de type FilterChainProxy dans le fichier web.xml.
<filter>
<filter-name>My Spring Security Filter Chain Proxy</filter-name>
<filter-class>org.springframework.security.web.FilterChainProxy</filter-class>
<init-param>
<param-name>targetBean</param-name>
<param-value>springSecurityFilterChainProxy</param-value>
</init-param>
</filter>
Puis définissez dessous les URLs concernées par ce filtre.
<filter-mapping>
<filter-name>My Spring Security Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Dans notre exemple, l'intégralité des URLs de l'application sont traitées par le filtre de Spring Security.
Configuration dans un fichier dédié
Une alternative consiste à créer un fichier de configuration dédié à la sécurité et à la référencer le dans votre
web.xml.
<import resource="classpath:applicationContext-security.xml"/>
Collez-y le contenu suivant
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns=http://www.springframework.org/schema/security
xmlns:beans="http://www.springframework.org/schema/beans" xmlnssi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schem...-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- dans la prochaine étape -->
</beans:beans>
Création des filtres de sécurité
Une chaîne de filtres ?
Le filtre définit dans le fichier de configuration est un bean de type
FilterChainProxy.
Le
FilterChainProxy définit une chaîne de filtre où chacun des filtres est appliqué en fonction du pattern de l'URL de la requête. Le paramétrage permet également de préciser l'ordre des filtres de sécurité de votre application.
A l'opposé, sous cousin le
DelegatingFilterProxy appliquera l'intégralité des filtres sur l'ensemble des URLs.
Ci-dessous est présenté un bean de type FilterChainProxy avec trois paramétrages de filtres différents.
<beans:bean id="springSecurityFilterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<beans:constructor-arg>
<beans:list>
<filter-chain pattern="/clog**" filters="httpSessionContextIntegrationFilter" />
<filter-chain pattern="/log/**" filters="httpSessionContextIntegrationFilter" />
<filter-chain pattern="/**" filters="httpSessionContextIntegrationFilter,exceptionTranslationFilter,filterSecurityInterceptor" />
</beans:list>
</beans:constructor-arg>
</beans:bean>
Les URLs respectant le motif "/clog**" ou "/log/**" sont filtrées par un filtre unique nommé
httpSessionContextIntegrationFilter.
Les autres URLs passeront dans trois filtres nommés respectivement
httpSessionContextIntegrationFilter,
exceptionTranslationFilter et
filterSecurityInterceptor.
Quelques filtres intéressants...
1 - Le SecurityContextPersistenceFilter
Le filtre
SecurityContextPersistenceFilter joue un double rôle.
Il est chargé de lier le contexte de sécurité (SecurityContext) à la session lors des requêtes HTTP. Le contexte de sécurité peut s'initialiser à l'aide du code Java suivant
SecurityContextHolder.getContext().setAuthentication(authManager)
où
authManager est un objet de type
org.springframework.security.authentication.AuthenticationManager
Il est chargé de supprimer le contexte de sécurité de la session HTTP lorsque l'utilisateur se déconnecte.
Le contexte de sécurité peut être supprimé à l'aide du code Java suivant
SecurityContextHolder.clearContext();
Le filtre peut être créé sans paramètres comme ci-dessous.
<beans:bean id="httpSessionContextIntegrationFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
2 - L'ExceptionTranslationFilter
Le filtre
ExceptionTranslationFilter est chargé de réceptionner les exceptions levées par
Spring Security. Ces exceptions seront généralement déclenchées par l'objet
AbstractSecurityInterceptor qui est le fournisseur principal des services d'autorisation. Dès lors, si une requête est effectuée sur une URL non autorisée, une erreur d'autorisation sera levée puis récupérée par le filtre
ExceptionTranslationFilter.
Dans un cas d'utilisation classique, il est possible de renseigner la propriété
authenticationEntryPoint, ce qui aura pour effet de réorienter toutes les requêtes non autorisées vers une page de login.
Ci-dessous un exemple de configuration pour un
ExceptionTranslationFilter
<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint">
<beans:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/start/index.jsp" />
</beans:bean>
</beans:property>
</beans:bean>
3 - Le FilterSecurityInterceptor
Le filtre
FilterSecurityInterceptor est chargé de sécuriser les URLs par profil d'utilisateur. Pour configurer le filtre, il nous faut
1/ Créer un manager d'authentification
2/ Créer un manager d'accès
3/ Définir une liste de motifs d'URLs par profil d'utilisateur
Il peut être crée avec la configuration suivante :
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<beans:property name="securityMetadataSource">
<filter-security-metadata-source>
<!-- Liste des règles -->
</filter-security-metadata-source>
</beans:property>
</beans:bean>
Un manager d'authentification peut être créé avec la configuration suivante.
<authentication-manager alias="authenticationManager">
<!-- Premier provider de credentials -->
<authentication-provider user-service-ref="dbAuthProvider" >
<password-encoder hash="md5" />
</authentication-provider>
<!-- Second provider de credentials -->
<authentication-provider ref="ldapAuthProvider">
<password-encoder hash="plaintext" />
</authentication-provider>
</authentication-manager>
On définit une liste de
providers à appeler dans l'ordre dans lesquels ils sont définis. Dans cet exemple, une première authentification est effectuée sur une base de donnée avant d'interroger un annuaire LDAP en cas d'échec sur la base de données.
Un manager d'accès peut être créé avec la configuration suivante.
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="allowIfAllAbstainDecisions"><beans:value>false</beans:value></beans:property>
<beans:property name="decisionVoters">
<beans:list>
<beans:bean id="authVoter" class="org.springframework.security.access.vote.AuthenticatedVoter"></beans:bean>
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<beans:property name="rolePrefix">
<beans:value></beans:value>
</beans:property>
</beans:bean>
</beans:list>
</beans:property>
</beans:bean>
Enfin la liste des URLs est définie en utilisant des balises
<intercept-url> à l'intérieur de la balise
<filter-security-metadata-source> que nous avons vu précédemment.
<intercept-url pattern="/log/**" access="permitAll" />
<intercept-url pattern="/forbidden/**" access="denyAll" />
<intercept-url pattern="/pro/pro_110.do" access="hasAnyRole('superviseur','gestionnaire')" />
<intercept-url pattern="/pro/pro_110.jsp" access="hasRole('superviseur')" />