Accueil > Java EE, Outillage, Web > Retour sur la librairie de sécurité PAC4J présentée au Paris JUG

Retour sur la librairie de sécurité PAC4J présentée au Paris JUG

Un mot sur le JUG

Le Java User Group est toujours un réservoir de bonnes idées !
On y trouve, lors des rencontres mensuelles, des spécialistes sur tous types de techno mais exclusivement Java.
C’est un bon moyen de connaitre les nouveautés mais aussi de découvrir des produits / outils du marché présentés la plupart du temps par les créateurs/commiters eux mêmes !

La rencontre du 15 septembre était réservée aux librairies de sécurité pour Java, et plus précisément celle-ci : la librairie Open Source PAC4J pour « Profile & Authentication Client for Java ».

Sans titre 5

Et ce qui ne gâche rien, le créateur de cette librairie est français, j’y reviendrai à la fin.

Quelle est la problématique et/ou le besoin ?

Dans la quasi totalité des applications web, il est nécessaire d’ajouter une authentification.
Soit vous souhaitez réserver un contenu à certains types d’utilisateurs, soit il est nécessaire de savoir qui est connecté afin de répondre aux problématiques de persistances.
Il existe bien sur des dizaines de raisons d’ajouter une authentification, mais je vais me cantonner à ces deux là.

A ce stade de la réflexion, deux solutions s’offrent à vous :

  1. Création d’une authentification personnalisée
  2. Utilisation d’une authentification standard existante

Si vous vous lancez dans la solution 1, vous avez intérêt à avoir les reins solides, en effet aujourd’hui plus question d’y aller la fleur au fusil !
Les besoins de sécurité des entreprises sont en forte croissance, donc il faudra respecter les standards de sécurité, dans ce cas je vous invite à aller à la source : c’est à dire l’OWASP.
Cet organisme international est spécialisé dans la sécurité et il est le standard incontournable en la matière.
En ce qui nous concerne, je vous suggère de lire l’authentication cheat sheet.
C’est le minimum acceptable aujourd’hui (là on commence à rentrer dans le vif du sujet).
Et là, je ne parle même pas des besoins en cryptographie/stockage à mettre en place derrière cette solution 1 !

Évidemment, nous ne sommes pas tous des experts de la sécurité… et c’est là qu’intervient la solution 2.
Vous allez donc déléguer votre authentification à un système tiers et surtout utiliser un protocole standard.
En regardant un peu la littérature vous pourrez voir tout ceci :

  • OAuth (1.0 & 2.0)
  • CAS (1.0, 2.0, SAML, logout & proxy)
  • HTTP (form & basic auth authentications)
  • OpenID / OpenID Connect
  • LDAP
  • Base de données relationnelle

Rassurez-vous, ces protocoles sont intégrés à outrance dans les APIs JAVA de sécurité du marché.
Donc le développeur chevronné va développer sa solution et commencer l’intégration, mais non : stop !
C’est la raison d’être principale de cet article, il faut éviter de réinventer la roue !
Plus vous entrerez dans le sujet, plus vous allez vous apercevoir que tout est déjà fait.
Et ce, en respectant les standards, avec une maintenance suivie et une veille technologique continue.
Dans ce contexte, vous constaterez que PAC4J sera un allié de choix dans la réalisation de votre authentification.

Ainsi que le mode d’authentification, PAC4J propose déjà tout ceci :

  • OAuth
  • Bitbucket
  • CAS
  • DropBox
  • Facebook
  • Foursquare
  • GitHub
  • Google
  • LinkedIn
  • Orcid
  • PayPal
  • Strava
  • Twitter
  • Vk
  • WindowsLive
  • WordPress
  • Yahoo

La librairie gère bien sur les modes de connexion classiques tels que : LDAP, SGBD (voir les détails)

PAC4J (Profile & Authentication Client for Java)

Venons en au sujet principal de cet article.

Le fonctionnement de PAC4J

La librairie est découpée en deux parties :

  • Le coeur ou moteur PAC4J
  • Les implémentations multi-framework (pour s’adapter à votre application)

pac4j

Voici le principe :

Sans titre 3

  1. Envoi de l’utilisateur vers le fournisseur d’identité (CAS, SAML, OpenID Connect, OAuth, Google+, facebook, twitter etc..) pour qu’il saisisse son login/password
    • Le fournisseur peut demander à l’utilisateur quel type de données il souhaite transmettre au partenaire (votre application) : mail, nom, prénom etc…
  2. Redirection vers l’application avec les informations spécifiques permettant de vérifier l’authentification
  3. Validation de l’authentification de l’utilisateur dans votre application et récupération de son profil via le fournisseur d’identité

Quelles sont les applications couvertes par cette librairie ?

Réponse : toutes, car les protocoles usuels sont intégrés dans PAC4J.
On peut donc soit remplacer l’authentification existante par cette couche de sécurité, soit la compléter.
Dans le second cas, nous imaginons par exemple l’authentification d’un forum ou bien d’un blog avec un compte Facebook ou Twitter.
Pour l’utilisateur cela peut être plus pratique car il a moins de comptes à gérer.

L’intégration dans un nouveau projet

Si c’est un projet interne, il s’accompagnera certainement d’une authentification corporate, dans ce cas il faudra simplement choisir le modèle correspondant :

  • LDAP
  • CAS
  • HTTP
  • etc…

Nul besoin d’ajouter un framework de sécurité comme Spring Security, PAC4J s’insère dans l’application web avec :

  • Une ressource « filter » déclarée dans l’application
  • Une implémentation Java d’un client sélectionné (ici client est au sens de partenaire : CAS, SAML, Google etc…)

Pour illustrer ces propos, vous pouvez consulter le projet  j2e-pac4j-demo pour démarrer dans ce sens (pensez pour vos tests à mettre la version suivante dans le pom du projet maven)

L’implémentation à la charge du développeur est assez simple à réaliser, comme son créateur l’a mentionné lors de sa présentation : « il ne faut pas réinventer la roue ».

L’intégration dans un projet existant

Si on prend l’exemple d’une authentification avec le framework Spring Security qui est assez répandue, on peut tout à fait enrichir la configuration existante avec PAC4J.
Cette fois ci pas besoin d’écrire du code Java, la configuration Spring prend en charge les déclarations nécessaires.

Un exemple avec Spring Security

Vous pouvez vous inspirer du projet démo spring-security-pac4j-demo.

Voici les pré-requis pour un authentification avec Twitter ou Facebook :

  1. Le fichier « web.xml » de la web application, ajout du filtre et listener Spring Security :
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml,classpath:securityContext.xml</param-value>
        </context-param>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    1. Le fichier context de l’application « applicationContext.xml » :
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-3.0.xsd">
      
          <bean id="servletContextAttributeExporter" class="org.springframework.web.context.support.ServletContextAttributeExporter">
              <property name="attributes">
                  <map>
                      <entry key="FacebookClient" value-ref="facebookClient" />
                      <entry key="TwitterClient" value-ref="twitterClient" />
                  </map>
              </property>
          </bean>
      
      </beans>
    2. Le fichier de configuration de Spring Security « securityContext.xml » :
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/security
                http://www.springframework.org/schema/security/spring-security-3.2.xsd">
      
          <security:authentication-manager alias="authenticationManager">
              <security:authentication-provider ref="clientProvider" />
          </security:authentication-manager>
      
      	<!-- urls and security configuration -->
          <security:http create-session="always" pattern="/facebook/**" entry-point-ref="facebookEntryPoint">
          	<security:request-cache ref="httpSessionRequestCache"/>
              <security:intercept-url pattern="/facebook/**" access="IS_AUTHENTICATED_FULLY" />
          </security:http>
      
          <security:http pattern="/twitter/**" entry-point-ref="twitterEntryPoint">
              <security:intercept-url pattern="/twitter/**" access="IS_AUTHENTICATED_FULLY" />
          </security:http>
      
      
      
      	<!-- entry points -->
          <bean id="facebookEntryPoint" class="org.pac4j.springframework.security.web.ClientAuthenticationEntryPoint">
              <property name="client" ref="facebookClient" />
          </bean>
      
          <bean id="twitterEntryPoint" class="org.pac4j.springframework.security.web.ClientAuthenticationEntryPoint">
              <property name="client" ref="twitterClient" />
          </bean>
      
      
      	<!-- clients definition -->
      
          <bean id="facebookClient" class="org.pac4j.oauth.client.FacebookClient">
              <property name="key" value="145278422258960" />
              <property name="secret" value="be21409ba8f39b5dae2a7de525484da8" />
          </bean>
      
          <bean id="twitterClient" class="org.pac4j.oauth.client.TwitterClient">
              <property name="key" value="CoxUiYwQOSFDReZYdjigBA" />
              <property name="secret" value="2kAzunH5Btc4gRSaMr7D7MkyoJ5u1VzbOOzE8rBofs" />
          </bean>
      
          <bean id="clients" class="org.pac4j.core.client.Clients">
              <property name="callbackUrl" value="http://localhost:8080/callback" />
              <property name="clients">
              	<list>
              		<ref bean="facebookClient" />
              		<ref bean="twitterClient" />
              	</list>
              </property>
          </bean>
      	
      	<!-- common to all clients -->
          <bean id="clientFilter" class="org.pac4j.springframework.security.web.ClientAuthenticationFilter">
          	<constructor-arg value="/callback"/>
              <property name="clients" ref="clients" />
              <property name="sessionAuthenticationStrategy" ref="sas" />
              <property name="authenticationManager" ref="authenticationManager" />
          </bean>
      
          <bean id="clientProvider" class="org.pac4j.springframework.security.authentication.ClientAuthenticationProvider">
              <property name="clients" ref="clients" />
          </bean>
          
          <bean id="httpSessionRequestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />
          
          <bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
      </beans>
    3. Ma JSP qui sert à rediriger vers l’authentification et qui sert aussi d’accueil :
    <%@page import="org.pac4j.springframework.security.authentication.ClientAuthenticationToken"%>
    <%@page import="org.springframework.security.core.context.SecurityContextHolder"%>
    <h1>protected area</h1>
    <a href="..">Back</a><br />
    <br /><br />
    <% ClientAuthenticationToken token = (ClientAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); %>
    profile : <%=token.getUserProfile()%><br />

    Et voila tout ! Le tester c’est l’adopter.

    Voici le test de cette « démo » avec la configuration précédente (fournisseur pris pour l’occasion : Twitter) :

     

    auth

     

    • Notez que Twitter décrit explicitement à l’utilisateur ce que votre application va recevoir le concernant.
    • Je suis redirigé vers mon application qui fait le reste, c’est à dire juste afficher mon profil récupéré (ici celui de facebook pour changer) :

     

    protected area
    
        Back
    
        profile : | id: 10153642573251168 | attributes: {access_token=CAACEIUTAlRABAHNdBv[...]jptaU3pOxSHLUElYcIK55vAZDZD, updated_time=2014-05-08T14:52:23CEST, gender=MALE, timezone=2, name=Sébastien Leboucher, link=https://www.facebook.com/app_scoped_user_id/12345678945788/, verified=true, last_name=Leboucher, third_party_id=ACBdEFGHiJKLM, locale=fr_FR, first_name=Sébastien} | roles: [] | permissions: [] | isRemembered: false |
    
    

    Un mot sur les fournisseurs, chaque fournisseur envoie des informations triviales sur votre profil :

    • nom
    • prénom
    • url de votre avatar
    • etc

    Il convient de vérifier les conditions générales de chaque fournisseur, dans le milieu professionnel la question se posera aussi avec les fournisseurs internes (CAS, LDAP etc…).

    Actualités

    La version 1.8 de la librairie vient d’arriver en release, voici les nouveautés :

    • Web services REST / HTTP (header, paramètre, IP)
    • LDAP, JWT, RDBMS, MongoDB
    • Gestion des autorisations

    Le créateur

    Jérôme LELEU est actuellement leader technique chez SFR, mais il participe aussi activement à la communauté :

    • Chairman SSO CAS
    • Committer Shiro
    • Créateur pac4j

    PAC4J vous intéresse ? Vous pouvez commencer par consulter la présentation réalisée par Jérôme au Paris JUG.

Categories: Java EE, Outillage, Web Tags: , , ,
  1. Pas encore de commentaire
  1. Pas encore de trackbacks


deux + = 6