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
Publié dans tech notes | Tagué , , , , | Laisser un commentaire

Integration Apache Shiro et PrettyFaces

Shiro est une librairie java qui peut être utilisée pour gérer la sécurité d’une application web, standalone, ou mobile. Elle prend en charge l’authentification, les autorisations d’accès aux ressources, la cryptographie, et la gestion des sessions (cf http://www.infoq.com/articles/apache-shiro).

PrettyFaces est une librairie open source permettant de réaliser de la ré-écriture d’URL qui s’intègre avec la technologie JSF. Elle permet entre autre de créer des URLs qui peuvent être « bookmarquer »  (http://www.ocpsoft.org/prettyfaces/).

L’intégration de ces deux technologies est réellement très simple. Il suffit de déclarer les filtres nécessaires aux 2 librairies dans l’ordre suivant:

1/ filtre Shiro

Si vous utilisez Spring la déclaration est la suivante

Dans le descripteur de déploiement de l’application web « web.xml »


<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

Dans le fichier de configuration de spring


<!-- BEGIN OF SHIRO CONFIGURATION -->

<!-- Enable Shiro Annotations for Spring-configured beans. only run after -->
<!-- the lifecycleBeanProcessor has run: -->

<!-- AUTO PROXY -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>

<!-- ADVISOR -->
<bean id="authorizationAttributeSourceAdvisor" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>

<!-- SECURITY MANAGER -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="myRealm" />
</bean>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

<!-- SHIRO FILTER -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/connexion" />
<property name="successUrl" value="/welcome" />
<property name="unauthorizedUrl" value="/err404.jsp" />
<property name="filters">

<map>

</map>

</property>
<property name="filterChainDefinitions">
<value>
<!-- /connexion = ssl[8443],authc /accueil = anon /pages/** = authc *.xhtml = user -->
</value>
</property>
</bean>
<bean id="myRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="madatasource" />
<property name="authenticationQuery" value="select password from user where email = ?" />
<property name="userRolesQuery" value="select role_name from user_roles where username = ?" />
<property name="permissionsQuery" value="select permission from roles_permissions where role_name = ?" />
</bean>

<!-- END OF SHIRO CONFIGURATION -->

2/ filtre PrettyFaces

La définition du filtre PrettyFaces peut être réalisée comme suit dans le fichier web.xml.

</pre>
<blockquote>
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ASYNC</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<pre>

Prenez garde à respecter l’ordre de déclaration de sorte que PrettyFaces puisse ré-écrire les URLs. Dans Shiro vous pouvez utiliser la nouvelle URL générée par PrettyFaces.

Dans la configuration Shiro / spring, il n’est pas nécessaire d’utiliser le fichier de configuration shiro.ini. La configuration est réalisée directement dans le fichier de configuration de spring.

Publié dans tech notes | Tagué , | Laisser un commentaire

Problème de chargement des fontes « Failed to decode downloaded font »

Voici un lien vers un article permettant de résoudre cette problématique sur des projets utilisant maven

http://shortfastgood.blogspot.fr/2015/08/maven-build-and-webfonts.html

Publié dans tech notes, Uncategorized | Laisser un commentaire

Font Loading Techniques

Cette page est simplement un signet vers un site exposant les techniques d’amélioration des performances lors du chargement des fontes.

http://romain-menard.fr/cours/web/mooc/premiere-etape-changer-le-fond-de-page/

Publié dans tech notes | Tagué , , | Laisser un commentaire

Primefaces remotecommand – exécuter un traitement long tout en préservant les performances

Nous avons tous été confrontés à une expérience utilisateur désastreuse due à un problème de performance sur une page qui met en jeu des traitements complexes.

Une solution consiste à afficher immédiatement une partie des informations et à compléter les informations manquantes de la page quelques secondes plus tard lorsque toutes les données ont été collectées.

Pour résoudre cette difficulté vous pouvez utiliser le composant remoteCommand qui permet d’invoquer une méthode d’un bean.

<p:remoteCommand id="myRemoteCommand" name="myRemoteCommand" async="false" actionListener="#{bean.heavyWork}"
 update="widget" process="@this" autoRun="true"/>

Dans cet exemple la méthode bean.heavyWork() est invoquée immédiatement après le chargement de la page (autoRun= »true »). A la fin de l’exécution de la méthode l’élément « widget » de la page est mis à jour.

La zone de la page qui est mise à jour ne doit pas inclure le composant remoteCommand et le composant doit être intégré dans un formulaire.

Si vous déclenchez le composant remoteCommand à partir d’une fonction javascript vous pouvez également passer des paramètres à la commande.

$(document).ready(function() { 
 myRemoteCommand( [ { name: 'latitude', value: latitude }, { name: 'longitude', value: longitude } ] );
});

Dans ce cas on peut récupérer les paramètres dans la méthode bean.heavyWork en utilisant la méthode

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()

Dans cet exemple nous avons utilisé l’attribut async= »false » mais on pourrait parfaitement rendre le traitement asynchrone (avec async= »true ») et utiliser la commande « poll » pour rafraîchir la page avec les données issues du traitement.

http://www.jperf.com

 

 

 

Publié dans Primefaces | Tagué , | Laisser un commentaire

Primefaces – comment arrêter le polling

Le composant « poll » de Primefaces permet de lancer des requêtes périodiquement (selon un intervalle de temps exprimé en seconde). Il est possible d’interrompre cette action en fonction de l’état du serveur.

Imaginer par exemple que vous implémentiez un traitement long et que vous souhaitiez que certains éléments de la page soient rafraîchis, avec les informations issues de ce traitement, dès que l’action est terminée. Par ce que vous êtes soucieux des performances de l’application et de l’expérience utilisateur vous avez utilisé une commande asynchrone pour déclencher ce traitement.

Depuis la version 3 de Primefaces, la fin de l’action de « polling » est très simple à implémenter.

 <p:poll interval="5" timeout="4000"
 listener="#{bean.listen}"
 update="widget" autoStart="true" stop="#{bean.disable}" />

Dans cet exemple une requête est exécutée toutes les 5 secondes. La requête est considérée comme terminée après 4 secondes (timeout exprimé en ms). La méthode listen du bean permet de gérer le changement d’état du serveur et d’arrêter l’action de polling en positionnant la valeur de l’attribut disable du bean à true.

private boolean disable= false;
public void listen() {
 if(condition) {
 disable= true;
 }

Et c’est tout… Primefaces gère l’arrêt du « polling » automatiquement dès que l’attribut « stop » prend la valeur true.

Attention tout de même à prévoir de limiter le nombre de tentative de « polling » car si la condition d’arrêt n’est jamais remplie vous risqueriez de compromettre inutilement les performances de votre application.

http://www.jperf.com

Publié dans Primefaces | Tagué , | Laisser un commentaire

Modifier les paramètres de la JVM au runtime

Peut être avez vous eu besoin au cours de votre expérience de modifier les paramètres de lancement d’une JVM pour activer par exemple les traces du garbage collector?

Sachez qu’il existe un moyen de réaliser cette opération sans devoir arrêter / redémarrer le processus java.

La commande jinfo  affiche la configuration java d’un processus. Les informations éditées comprennent les propriétés système ainsi que les paramètres de lancement de la machine virtuelle.

Pour mémo voici, ci dessous, l’aide en ligne de la commande jinfo.

Usage:
jinfo [option] <pid> (to connect to running process)
jinfo [option] <executable <core> (to connect to a core file)
jinfo [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server)

where <option> is one of:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both of the above
-h | -help to print this help message

Savez vous que vous pouvez utiliser cette commande pour modifier dynamiquement les paramètres de la JVM? Effectivement en utilisant l’option « flag » vous pouvez activer ou désactiver un paramètre.

Par exemple:
La commande jps nous donne les ids des processus java présents sur la machine.
jps
3572 Jps
15484 Bootstrap
14744 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar

Si vous souhaitez activer les traces du garbage collector vous pouvez utiliser la commande suivante:

jinfo -flag +PrintGC 12278
jinfo -flag +PrintGCDetails 12278
permet d’afficher les traces détaillées sous la forme
[GC [PSYoungGen: 429689K->46346K(454656K)] 473190K->106420K(804352K), 0.0534327 secs] [Times: user=0.17 sys=0.00, real=0.05 secs]

http://www.jperf.com

Publié dans tech notes | Tagué , , | Laisser un commentaire