Groupe 1A (socle)

Date de création : 25 janvier 2005
Dernière modification : 31 janvier 2005
Diffusion : internet

Faire du https dans un canal

Ce document décrit comment un canal peut forcer des actions en https, ceci dans un environnement de partage de charge.

Problématique

Bien que les parties authentification et propagation de l'authentification soient prises en compte au sein d'esup-portail par le mécanisme du SSO CAS, il y a des cas ou il est nécessaire de protéger la communication en https.

C'est le cas, par exemple, du canal 'préférence', qui permet à l'utilisateur de modifier certains de ses 'attributs' LDAP, et même son mot de passe.

Il est alors nécessaire de demander le mot de passe actuel, et en cas de changement, le nouveau mot de passe.

Il est indispensable de protéger cet échange dans du https.

Il y a plusieurs problèmes à résoudre pour permettre à un canal de réaliser certaines transactions en https, puis de revenir ensuite dans du http.

Ce paragraphe décrit le fonctionnement normal du support des sessions des applications J2EE (donc d'esup-portail), puis les difficultés qui en découlent dans un environnement esup-portail de production.

Exemple qui va servir de support à l'explication

On imagine un cas de production, où plusieurs serveurs esup-portail sont mis en oeuvre en répartion de charge (load-balancing).

On distingue l'adresse virtuelle, c'est à dire l'url connue des utilisateurs (ici, http://ent.univ.fr), de l'adresse réelle des serveurs qui vont traiter les requêtes (ici, entx.univ.fr, x variant de 1 à 5 dans l'exemple).

Support des sessions dans esup-portail

C'est le moteur de servlets, en l'occurence, tomcat, qui se charge de la gestion des sessions.

Une session utilisateur est référencée à l'aide d'un identifiant de session (pour tomcat, le nom est JSESSIONID), qui contient une référence aux informations de la session.

Cette identifiant doit être transporté par le navigateur, afin que l'application (ici, esup-portail) puisse faire le lien entre la requête http et la session de l'utilisateur.

Le transport l'identifiant par le navigateur peut de faire de 2 manièresz :

Esup-portail utilise normalement le mécanisme de cookie pour transmettre l'identifiant de session ; en fait, c'est le moteur de servlet (en l'occurence, tomcat) qui gère celà de manière transparente.
Tomcat est également capable de traiter celà via un paramètre JSESSIONID transmis dans un GET HTTP.

Un cookie est positionné pour un domaine donné (ex : serv.univ.fr/appli1) . Le navigateur n'envoie ce cookie (en fait, l'écrit dans l'entête du message http) que lors des accès http vers le domaine concerné.
On ne peut pas positionner (ou lire) un cookie pour un domaine autre (ex : serv1.univ.fr ne peut pas lire un cookie positionné pour serv2.univ.fr, .. tout simplement parce que le navigateur ne lui présente pas les cookies qui ne sont pas dans son domaine).

Contraintes liées au mécanisme de partage de charge

Dans notre cas, les utilisateurs accèdent à http://ent.univ.fr. En fait, cette url est virtuelle, et renvoie les requêtes vers un serveur réel, par exemple http://ent2.univ.fr

Le cookie de session JSESSIONID est positionné par esup-portail pour le domaine ent.univ-nancy2.fr.

Problème 1 : si on désire poursuivre une session esup-portail en https, on doit le faire avec le même serveur réel ; le mécanisme de load-balancing s'appuie sur un cookie positionné par le load-balancer ; en https, le load-balancer est incapable de lire le cookie (communication cryptée) et donc la requete https sera dispatchée aléatoirement vers un des serveurs réels en ligne.

Solution 1 : le seul moyen pour arriver à passer de http vers https vers le même serveur réel est de renvoyer la requete https vers le serveur réel ; dans le cas exposé, le navigateur va passer de http://ent.univ.fr (donc via le load-balancer) vers https://ent2.univ.fr (directement).

Problème 2 : le cookie de session esup-portail (JSESSIONID) a été positionné par tomcat pour le domaine ent.univ.fr ; lorsque le navigateur accède au même serveur réel en https, le domaine est alors ent2.univ.fr. La requête http n'est pas porteuse du cookie de session ; la session n'est donc pas maintenue.

Solution 2 : lors du passage de http://ent.univ.fr vers https://ent2.univ.fr, on ajoute en paramètre du GET un paramètre contenant l'identifiant de session.

Il 'suffit' alors coté application de positionner un cookie de nom JSESSIONID avec l'identifiant précédent, et de rediriger à nouveau le navigatur vers l'url souhaitée, en https.

Le navigateur mémorise donc 2 cookies JSESSIONID de même valeur, l'un pour le domaine ent.univ.fr, l'autre pour le domaine ent2.univ.fr ; le second cookie est marqué automatiquement par tomcat comme sécurisé (car positionné en https).

Le retour en http vers ent.univ.fr peut donc se faire en maintenant la session.

Mise en oeuvre pratique

Le but est de masquer la complexité au canal utilisateur : récupération des urls virtuelles et réelles, récupération de l'identifiant de session (normalement, il faut un canal privilégié pour celà), construction de l'url d'appel https avec le JSESSIONID positionné, écriture d'un cookie (même remarque, il faudrait être privilégié), contruction de l'URL de retour http.

Ca a été réalisé grace à une servlet appelée HTTPSGateway, accessible à l'URL HTTPSGateway.

En fait, cette servlet réalise différentes actions en fonction d'un paramètre d'aiguillage.

On suppose dans l'exemple qu'esup-portail est accessible à l'URI /uPortal.

Installation

classe java

La servlet est implémentée sous la forme d'une classe classe java :
org.esupportail.portal.security.HTTPSGatewayServlet.java . Elle est incluse dans les distributions esup-portail issues d'uportal 2.4 à partir dd février 2005.

web.xml

La servlet doit être déclarée dans le web.xml d'esup-portail, et certains paramètres doivent lui être passés.

Voici un extrait du web.xml :

 <servlet>
<servlet-name>HTTPSGateway</servlet-name>
<servlet-class>org.esupportail.portal.security.HTTPSGatewayServlet</servlet-class>
<init-param>
<param-name>org.esupportail.portal.security.HTTPSGatewayServlet.sessionname</param-name>
<param-value>jsessionid</param-value>
</init-param>
<init-param>
<param-name>org.esupportail.portal.security.HTTPSGatewayServlet.virtualUrl</param-name>
<param-value>http://ent.univ.fr/uPortal</param-value>
</init-param>
<init-param>
<param-name>org.esupportail.portal.security.HTTPSGatewayServlet.realUrl</param-name>
<param-value>https://ent2.univ.fr/uPortal</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
... <servlet-mapping>
<servlet-name>HTTPSGateway</servlet-name>
<url-pattern>/HTTPSGateway</url-pattern>
</servlet-mapping>


Les paramètres passés sont le nom du cookie de session, l'url 'virtuelle' d'accès au portail et l'url réelle d'accès au host réel.

Initialisation

A l'initialisation, la servlet va charger les paramètres décrits précédemment.

Utilisation

On va décomposer le passage en https, puis le retour en http.
Par exemple, le canal 'préférences' a besoin du mot de passe utilisateur pour modifier des informations dans LDAP.

Côté source du canal

Voici un petit bout de code xsl permettant le passage en mode https, et le retour en http :

<a href="HTTPSGateway?tohttps={$baseActionURL}">Passer en securise</a>
<a href="HTTPSGateway?backhttp={$baseActionURL}">Passer en NON securise</a>

Passage en https

Imaginons que l'action 'normale' du formulaire aurait dû être :
href="{$baseActionURL}", ce qui est traduit par :
href="tag.fb07ff66e4cec5c3.render.userLayoutRootNode.target.ctf1.uP"
C'est donc une url relative par rapport à http://ent.univ-nancy2.fr/uPortal

Le canal utilisateur va modifier cette url pour la transformer comme ceci :
href="HTTPSGateway?tohttps={$baseActionURL}" , qui est traduit par :
href="HTTPSGateway?tohttps=tag.fb07ff66e4cec5c3.render.userLayoutRootNode.target.ctf1.uP"

C'est donc une url relative à http://ent.univ-nancy2.fr/uPortal. On fait appel à la servlet HTTPSGateway, avec le paramètre tohttps qui lui indique qu'on désire passer en https. Ce paramètre contient l'url que le canal aurait utilisé normalement.

HTTPSGateway s'exécute dans le contexte uportal ; elle va récupérer l'identifiant de session (ici, 79D18D7EBD2AEC0652BDD566B179B756), puis construire l'URL suivante :

https://ent2.univ.fr/uPortal/HTTPSGateway?esup_session=79D18D7EBD2AEC0652BDD566B179B756&inhttps=tag.fb07ff66e4cec5c3.render.userLayoutRootNode.target.ctf1.uP

et enfin forcer une redirection automatique du navigateur vers cette url

entrée en https

HTTPSGateway est donc à nouveau appelée, cette fois en https. Le paramètre inhttps lui indique que c'est une première requête https pour cette session utilisateur.

Elle récupére l'identifiant de session, puis va va écrire le cookie JSESSIONID pour le domaine ent2.univ.fr/uPortal avec sa valeur, puis provoquer une redirection automatique vers l'url relative désirée :
tag.fb07ff66e4cec5c3.render.userLayoutRootNode.target.ctf1.uP

Fonctionnement en https

A partir de ce moment, l'utilisateur est en session https vers le canal et l'action désirée.

Les redirections http sont en général très rapides, l'utilisateur ne les a quasiment pas vues se dérouler. La seule chose qui a changé, c'est l'url correspondant au serveur : de http://ent.univ.fr vers https://ent2.univ.fr

Lorsque le développeur du canal décide qu'il n'a plus besoin d'être en mode sécurisé, il va faire appel à nouveau à HTTPSGateway pour revenir en mode 'normal'

Retour en http

Le canal fait à nouveau appel à HTTPSGateway, comme pour le passage en https. La seule chose qui diffère, c'est le nom du paramètre : backhttp.

SSL Gateway recalcule l'adresse de retour http, et redirige automatiquement le navigateur vers cette URL.

Limitations

On ne peut pas faire appel à HTTPSGateway par un POST HTTP ; seul le GET est supporté.

Effets de bord

Il est possible qu'un utilisateur ne poursuive pas l'action en cours (exemple, changement de mot de passe), et fasse d'autre opérations dans le portail.

Ces opérations seront donc réalisées en https au lieu d'http, ce qui ne présente pas de problème majeur.