Mise en oeuvre d’un serveur d’authentification SSO avec CAS et Memcached

sso

Après ce billet où j’ai détaillé la mise en place d’un load-balancing/failover a base de cascade de NS, nous allons passer aujourd’hui à la deuxième partie. Et surtout, au but dont je voulais vous parler dans ce petit challenge technique que mon ami Horacio m’a doucement poussé à réaliser (bien malgré lui :) c’était plutôt un défi personnel que j’avais envie aussi de concevoir).

Au fil de plusieurs discussions techniques enjouées (avec Horacio, le terme enjouée prend rapidement des allures de trolldi :D (private joke)), un système CAS a peuplé nos échanges et je vous en livre ici une explication dans le texte.

CAS (Central Authentication Service) est un système d’authentification unique basé sur une gestion de ticket provisoire.

Il permet à un utilisateur de ne s’authentifier qu’une fois sur un portail web pour avoir accès à diverses ressources (sites web différents la plupart du temps) qui se base également sur ce système d’authentification.
C’est le fameux SSO (Single Sign-On) dont vous avez peut-être entendu parlé.

Le challenge que je me suis donné est bien entendu de rendre cette solution hautement disponible. Si votre serveur CAS est inaccessible, c’est un lot non négligeable d’utilisateurs qui ne pourront plus s’authentifier, avec les désagréments qui vont avec (des gens en cravate partout dans votre bureau ou par dessus votre épaule pour savoir quand cela remarchera).

Quelques années en arrière, je vous avais parlé de Memcached et de la façon de le faire fonctionner en mode sécurisé. Et ça tombe bien, CAS supporte memcached :)

Nous allons considérer que vous avez vos deux serveurs en place, loadbalancés par une technique quelconque (avec PF sous OpenBSD, avec une cascade de NS, avec LVS sous Linux, une appliance propriétaire ou une IP FailOver, bref ce que vous voulez).

Première étape, déployer sur le deux serveurs, un memcached répliqué. Rien de bien compliqué si vous avez lu ce billet (je vous laisse bien évidemment validé que vos clés/valeurs se répliquent correctement).

Déployer un serveur Tomcat sur chacune de vos machines (Tomcat 6 ou 7 à votre convenance, prenez le Core) avec un java 1.6 minimum.
Wget, puis tar xzvf apache-tomcat-x.x.x.tar.gz etc… Rien de transcendant.

- Génération du certificat SSL

CAS exige une connexion https, donc nous allons générer un certificat pour nos tomcats.

serveur:/opt/tomcat7# keytool -genkey -alias tomcat -keyalg RSA -validity 365
Tapez le mot de passe du Keystore :
Quels sont vos prénom et nom ?
[Unknown] :  cas.guiguiabloc.fr
Quel est le nom de votre unité organisationnelle ?
[Unknown] :  guiguiabloc
Quelle est le nom de votre organisation ?
[Unknown] :  guiguiabloc
Quel est le nom de votre ville de résidence ?
[Unknown] :  Brest
Quel est le nom de votre état ou province ?
[Unknown] :  Bretagne
Quel est le code de pays à deux lettres pour cette unité ?
[Unknown] :  FR
Est-ce CN=cas.guiguiabloc.fr, OU=guiguiabloc, O=guiguiabloc, L=Brest, ST=Bretagne, C=FR ?
[non] :  oui
 
Spécifiez le mot de passe de la clé pour tomcat
(appuyez sur Entrée s'il s'agit du mot de passe du Keystore) :

ATTENTION : spéficiez bien le nom « loadbalancé » DNS de votre CAS (le nom utilisé pour joindre les deux instances dans le champ « Quels sont vos prénom et nom ? »

Décommentez la partie SSL dans le fichier server.xml de votre Tomcat (/TOMCAT_HOME/conf/server/xml)

<!--
   <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
   maxThreads="150" scheme="https" secure="true"                clientAuth="false" sslProtocol="TLS" />
-->
(Enlevez les <!-- et -->)

Exporter le certificat pour l’installer sur votre autre Tomcat

keytool -export -alias tomcat -file servercas.crt

Sur le deuxième serveur :

keytool -import -file servercas.crt -keystore $JAVA_HOME/jre/lib/security/cacerts -alias tomcat

Démarrer les tomcats (bin/startup.sh) et vérifier qu’ils sont bien accessibles sur le port 8443 en https.

- Installer Maven 2
Rendez vous sur le site du projet Maven et téléchargez la version 2.2.1 (la version 3 n’est pas encore recommandé pour CAS)

wget http://mirrors.ircam.fr/pub/apache/maven/maven-2/2.2.1/binaries/apache-maven-2.2.1-bin.tar.gz
tar xzvf apache-maven-2.2.1-bin.tar.gz
ln -s apache-maven-2.2.1 maven2

Ajouter l’emplacement des binaires Maven2 à votre PATH (et votre JAVA_HOME si cela n’a pas déjà été fait)

# export PATH=/opt/maven2/bin:$PATH
#export JAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.26/jre

(OUI ! je sais, j’ai une vieille version de JAVA toute pourrie sur mes serveurs de tests :D donc je vous laisse mettre à jour la votre)

Vérifier que Maven est opérationnel :

# mvn --version
Apache Maven 2.2.1 (r801777; 2009-08-06 21:16:01+0200)
Java version: 1.6.0_26
Java home: /usr/lib/jvm/java-6-sun-1.6.0.26/jre
Default locale: fr_FR, platform encoding: ISO-8859-15
OS name: "linux" version: "2.6.26-2-686" arch: "i386" Family: "unix"

(OUI ! Je sais, j’ai un kernel tout moisi. Ca suffit à la fin !)

- Installer CAS

Nous allons utiliser la version communautaire de CAS, conçu par l’université de Yale et maintenu désormais par le projet Jasig qui réunit diverses écoles.
Téléchargez la dernière version a ce jour (3.5.2) :
http://www.jasig.org/cas/download
Une fois le fichier détarré/dégzippé, créer votre propre environnement de travail :

cd /opt/cas-server-3.5.2
mkdir cas-guiguiabloc
cd cas-guiguiabloc

Dans le répertoire de votre projet, nous allons créer le fichier « de configuration » de CAS. Il contient les appels vers les différentes dépendances disponibles.
Ce fichier s’appelle pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd ">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.guiguiabloc.cas</groupId>
    <artifactId>cas-guiguiabloc</artifactId>
    <packaging>war</packaging>
    <version>1.1-SNAPSHOT</version>
 
    <build>
        <plugins>
            <plugin>
                 <artifactId>maven-war-plugin</artifactId>
                             <configuration>
                                 <warName>cas</warName>
                             </configuration>
                        </plugin>
        </plugins>
    </build>
 
    <dependencies>
        <dependency>
            <groupId>org.jasig.cas</groupId>
            <artifactId>cas-server-webapp</artifactId>
            <version>${cas.version}</version>
            <type>war</type>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.jasig.cas</groupId>
            <artifactId>cas-server-support-generic</artifactId>
            <version>${cas.version}</version>
            <type>jar</type>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.jasig.cas</groupId>
            <artifactId>cas-server-integration-memcached</artifactId>
            <version>${cas.version}</version>
            <type>jar</type>
        </dependency>
    </dependencies>
 
    <properties>
        <cas.version>3.5.2</cas.version>
    </properties>
 
        <repositories>
             <repository>
                  <id>ja-sig</id>
                  <url>http://oss.sonatype.org/content/repositories/releases/ </url>
             </repository>
        </repositories>
</project>

Je ne détaillerais pas tout, la documentation de CAS est assez explicite, mais dans notre exemple, nous allons utiliser une webapp générique, avec le support memcached et que Maven2 puisse utiliser les dépots publics de Jasig.

C’est parti pour une première compilation !

cd /opt/cas-server-3.5.2/cas-guiguiabloc
mvn clean package

Laisser le temps a Maven de télécharger Internet et le résultat devrait apparaitre

[INFO] [war:war {execution: default-war}]
[INFO] Packaging webapp
[INFO] Assembling webapp[cas-guiguiabloc] in [/opt/cas-server-3.5.2/cas-guiguiabloc/target/cas-guiguiabloc-1.0-SNAPSHOT]
[INFO] Processing war project
[INFO] Processing overlay[ id org.jasig.cas:cas-server-webapp]
[INFO] Webapp assembled in[4636 msecs]
[INFO] Building war: /opt/cas-server-3.5.2/cas-guiguiabloc/target/cas.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 minutes 36 seconds
[INFO] Finished at: Mon Nov 11 00:42:10 CET 2013
[INFO] Final Memory: 18M/44M
[INFO] ------------------------------------------------------------------------

En l’état, vous avez donc maintenant un joli cas.war dans le répertoire target de votre projet que vous pouvez déposer dans votre tomcat/webapps/.
Cela vous permet déjà de vérifier que tout fonctionne comme il se doit sur https://serveur:8443/cas

Maintenant, peaufinons tout cela :

serveur:/opt/cas-server-3.5.2/cas-guiguiabloc# mkdir -p src/main/webapp/WEB-INF

Dans ce répertoire WEB-INF, nous allons y copier le fichier :
/opt/cas-server-3.5.2/cas-guiguiabloc/target/cas-guiguiabloc-1.0-SNAPSHOT/WEB-INF/deployerConfigContext.xml
et le modifier pour inclure :
- l’authentification locale par un user/mot de passe
- le support de memcached

Pour l’authentification locale, ajouter la section suivante :

<bean class="org.jasig.cas.adaptors.generic.AcceptUsersAuthenticationHandler">
 <property name="users">
   <map>
   <entry>
   <key>
                                                                <value>guiguiabloc</value>
   </key>
                                                                <value>1234</value>
   </entry>
   </map>
   </property>
   </bean>

 

Ici nous créons un simple utilisateur « guiguiabloc » avec le mot de passe 1234.
En prod, vous pourrez utiliser un autre système d’authentification bien sur (LDAP etc…)

Pour le support memcached, voici la section a ajouter :

bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.MemCacheTicketRegistry">
  <constructor-arg index="0" ref="memcachedClient" />
  <constructor-arg index="1" value="21600" />
  <constructor-arg index="2" value="300" />
</bean>
<bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean"
      p:servers="127.0.0.1:11211"
      p:protocol="TEXT"
      p:locatorType="ARRAY_MOD"
      p:failureMode="Cancel"
      p:transcoder-ref="kryoTranscoder">
</bean>
<bean id="kryoTranscoder"
      class="org.jasig.cas.ticket.registry.support.kryo.KryoTranscoder"
      init-method="initialize">
  <constructor-arg index="0" value="8192" />
</bean>

Bien sur je ne peux que vous invitez a lire la documentation officielle :)
https://wiki.jasig.org/display/CASUM/MemcacheTicketRegistry

A toute fin utile, vous trouverez ICI le fichier deployerConfigContext.xml que j’ai utilisé.

On recompile le WAR dans cas-guiguiabloc (mvn clean package) et on le copie dans nos webapps Tomcat (après avoir supprimé l’ancien répertoire cas)

Démarrez vos Tomcat et authentifiez vous sur la mire CAS, Tadam !
Si tout se passe bien, la connexion réussi et vous devez avoir un cookie CAS :

Name	CASTGC
Value	TGT-3-mcWQGjaB1bSHNScWUJbq2EyLsLm9vysjl6lIkaXfuN4TMFVTow-cas01.example.org
Domaine (host)	cas.guiguiabloc.fr
Chemin d'accès (path)	/cas/
Sécurisé	oui
Expire le	À la fin de la session

Et magie, sur vos deux memcached, vous allez retrouver votre ticket en recherchant la valeur du cookie en tant que clé :

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get TGT-3-mcWQGjaB1bSHNScWUJbq2EyLsLm9vysjl6lIkaXfuN4TMFVTow-cas01.example.org
VALUE TGT-3-mcWQGjaB1bSHNScWUJbq2EyLsLm9vysjl6lIkaXfuN4TMFVTow-cas01.example.org 0 386
BH .
guiguiablocuiduidgroupMembershipgroupMembershipeduPersonAffiliationeduPersonAffiliationauthenticationMethod?org.jasig.cas.adaptors.generic.AcceptUsersAuthenticationHandlerÞÉP!лôîJTGT-3-mcWQGjaB1bSHNScWUJbq2EyLsLm9vysjl6lIkaXfuN4TMFVTow-cas01.example.orgäÉPÞÉP+ST-6-iHWaAvdowI0WGE1du76P-cas01.example.org
END

Vos deux serveurs CAS se partagent la même source d’information de tickets valides :D

J’espère que cette petite approche de CAS vous aura émoustillé. Bien entendu, il existe plein d’options de compilation et de configuration qui vous permettrons d’avoir un/des serveur(s) CAS aux petits oignons.

Si vous souhaitez maintenant intégrer votre serveur web à CAS (avec Apache par exemple), vous trouverez un très bon tuto ici :
https://ucdavis.jira.com/wiki/display/IETP/mod_auth_cas
Pour info, la méthode la plus facile pour compiler le mod_auth_cas avec apxs2 est :

apxs2 -i -lssl -lcurl -c mod_auth_cas.c cas_saml_attr.c

Amusez-vous bien :D

Ce billet a été posté dans architecture, linux, sécurité et taggé , , . Bookmark ce permalink.

8 commentaires sur “Mise en oeuvre d’un serveur d’authentification SSO avec CAS et Memcached

  1. Aaaah bah enfin ! ;) Il a mis le temps à venir, saymal de teaser comme ça puis de laisser le bec dans l’eau après ;)

    On va se laisser un peu de temps pour ingérer puis digérer tout ça, je te ferais peut-être un retour … :P

    Merci pour ce billet et cette suite.

  2. ah ah ah Cooltrane :D
    C’est vrai qu’il a était long a venir celui là ;) Mais je ne te cacherais pas qu’il a était aussi long a « simplifier » pour un billet :p
    Je suis évidemment très demandeur de ton retour :) Les billets un peu trop techniques étant souvent les parents pauvres de ce blog en matière de réactions :D

  3. Bonjour,
    Et merci pour ton tuto, il m’a éclairé sur certains aspects de l’installation du CAS. Après avoir fusionné 50 (j’exagère, mais si peu…) docs et tutos sur comment « monter un serveur cas avec une base ldap », je suis arrivé à faire fonctionner la chose sur une debian.
    Ma question est : « Et maintenant … Comment je cas(ifie) une appli web ou l’accès à un serveur web ???
    Là, la documentation est encore plus rare…
    Si vous avez des infos, je suis preneur
    Merci
    Jean

  4. Salut a toi merci pour ce billet que je trouve super interessant. je suis etudiant en administraton syteme et jai pour theme de fin d’etude « la cassification de plusieurs applications web utilisant une BD MYSQL ». jusqu’ici les recherches que j’ai effectuees ne me permettent pas d’avancer. j’ai deja deploye CAS il ne me reste plus qu’a activer les services et les connecter a la BD. besoin de ton aide please.

  5. c’est vrai que le lien est assez explicite mais je rencontre de nombreux problemes dans la compilation de CAS. quels sont les conseils que tu pourrais me donner pour la compilation.

    NB: mon reseau ne comporte aucun serveur proxy

  6. Bonjour,

    Le protocole CAS est simple et puissant et le serveur CAS est vraiment un bon choix de SSO. Malheureusement, il n’est pas toujours aisé de l’installer et de le régler correctement. De plus, s’il s’agit de développer une application raccordée à un serveur CAS, il est souvent peu intéressant de perdre du temps côté serveur, quand le vrai travail est côté client CAS.

    Il existe maintenant le fournisseur de serveurs CAS dans le cloud : http://www.casinthecloud.com, avec lequel vous pouvez tester gratuitement jusqu’à 3 serveurs CAS sans limite de temps. En quelques minutes et clics, le serveur CAS (dernière version : 4.0) est créé et prêt à être utilisé.

    Cdlt,
    Jérôme LELEU
    Fondateur de CAS in the cloud