Terminaison SSL avec Apache2/Tomcat/Shiro

Cet article est une note technique permettant de mettre en oeuvre une terminaison SSL dans un environnement Apache2 / Tomcat / Shiro+Spring.

Apache Shiro est une librairie permettant de mettre en oeuvre des fonctions de sécurisation d’une application web. Elle présente approximativement les mêmes fonctionnalités que la solution Spring security. On peut noter toutefois qu’elle permet de sécuriser également des applications standalone, qu’elle intègre nativement la fonction « remember me », etc.

Quelle est précisément la problématique?

Dans une infrastructure de production, l’accès à certaines ressources peuvent être protégées par un protocole sécuritaire (SSL) mais les autres composants de l’infrastructure qui sont déployés dans une zone de confiance n’ont pas vocation à utiliser ce protocole qui ajoute un « overhead » qui n’est pas nécessaire dès lors que les communications sont réputées fiables.

Dans cet article, je détaillerai la mise en oeuvre de ce mécanisme (terminaison SSL) dans un contexte Shiro / spring qui présente une petite difficulté.

La mise en oeuvre de Shiro avec Spring n’est pas l’objet de cette note, cependant voici un extrait de la configuration permettant d’activer Shiro et de configurer l’utilisation de SSL pour sécuriser l’accès à certaines ressources de l’application. C’est le filtre Shiro qui porte cette configuration.


<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/connexion" />
<property name="filters">
<util:map>
<entry key="authc">
<bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
</entry>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/javax.faces.resource/** = anon
/connexion = ssl[${ssl.port}],authc
/moncompte = user
/** = anon
</value>
</property>
</bean>

Nous notons simplement que l’utilisation du filtre PassThruAuthenticationFilter est intéressant car il permet de mettre en place une logique de validation spécifique à l’application. Ce filtre n’autorise l’accès aux ressources que si l’utilisateur est authentifié ou lorsque la ressource demandée correspond à la page d’authentification. Dans cette configuration la ressource identifée par « /connexion » nécessite la mise en oeuvre du protocole SSL. Cette vérification est assurée par la déclaration du filtre SSL (ssl[${ssl.port}]) implémentée par défaut par la classe org.apache.shiro.web.filter.authz.SslFilter.
L’accès à la ressource « /moncompte » est protégée par le filtre UserFilter qui par défaut vérifie que l’utilisateur est connu soit parce qu’il est authentifié soit parce que la fonction « remember me » permet d’identifier l’utilisateur.

Avec cette configuration, si l’utilisateur n’est pas identifié et essaye d’accéder à la ressource « /moncompte », il va être automatiquement redirigé vers la page de login protégée par le protocole SSL. Cependant on souhaite mettre en place une terminaison SSL au niveau du reverse proxy Apache, mais on veut également s’assurer que la requête d’authentification est sécurisée. Or que fait le filtre SSL de Shiro? Il vérifie que la requête utilise le port SSL configuré par la variable ${ssl.port}, et que la requête est sécurisée. Shiro utilise notamment la méthode ServletRequest.isSecure() pour vérifier que la requête est effectivement sécurisée.

Si la configuration du reverse proxy redirige uniquement les hôtes virtuels déclarés pour les protocoles (http et https) vers un port non sécurisé d’un serveur Tomcat, et que l’un de ces critères n’est pas respecté, les mécanismes de redirection mis en jeu provoquent une erreur HTTP 310 « Too many Redirects ».

Un des moyens permettant de mettre en place la terminaison SSL et d’indiquer à la librairie que la requête d’authentification est effectivement sécurisée, consiste à créer une entête HTTP spécifique indiquant que le reverse proxy a détecté l’utilisation d’un protocole sécurisé et de configurer Tomcat afin qu’il interprète cet entête et intègre ces informations dans le contenu de la requête.

Pour mettre en place cette logique, il est nécessaire :

  • sur le reverse proxy
    Activer le module header (sudo a2enmod headers);
    Mettre en place les directives d’écriture du header « X-Forwarded-Proto » sur chaque hôte virtuel;
    Par exemple pour un serveur Tomcat écoutant à l’adresse localhost:9090

    <VirtualHost *:80>
    ServerName www.mondomaine.com
    ServerAlias www.mondomaine.com
    ServerAdmin webmaster@mondomaine.com
    <span style="color: #ffcc00;">RequestHeader set X-Forwarded-Proto "http"</span>
    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass / http://localhost:9090/
    ProxyPassReverse / http://localhost:9090/
    ....
    <VirtualHost *:443>
    ServerName www.mondomaine.com
    ServerAlias www.mondomaine.com
    ServerAdmin webmaster@test.mondomaine.com
    <span style="color: #ffcc00;">RequestHeader set X-Forwarded-Proto "https"</span>
    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass / http://localhost:9090/
    ProxyPassReverse / http://localhost:9090/
    ...
    
  • Sur le serveur Tomcat
    Définir une valve dans la configuration du serveur Tomcat qui permet d’interpréter cet entête HTTP.
    Par exemple:

    <Valve>
    className="org.apache.catalina.valves.RemoteIpValve"
    protocolHeader="x-forwarded-proto"
    protocolHeaderHttpsValue="https"
    httpServerPort="80"
    httpsServerPort="443"
    />
    

    Ces paramètres indiquent notamment :
    « protocolHeader » le nom de l’entête HTTP qui désigne la nature du protocole utilisé. Dans cet article l’entête « x-forwarded-proto » porte cette définition;
    « protocolHeaderHttpsValue » la valeur de l’entête « protocolHeader » qui identifie que le protocole est sécurisé;
    ainsi que d’autres attributs dont vous pouvez avoir besoin qui sont décrits dans la documentation officielle (https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html).

Une fois ces modifications réalisées et les serveurs redémarrés, l’erreur HTTP 310 « Too many Redirects » que nous rencontrions précédemment disparaît, et la terminaison SSL sur le reverse proxy est opérationnelle.

http://www.jperf.com

Publicités

A propos jlerbsc

founder of JavaPerf Consulting Http://www.jperf.com
Cet article, publié dans tech notes, est tagué , , , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s