Yubikey est une clef de crypto qui permet d’avoir une authentification forte lors d’un processus de connexion à un site web (par ex : banque, web mail, etc….). Plusieurs sites web commencent à inclure cette fonctionnalité lors du processus d’authentification à leur service. L’utilisateur utilise un token généré par sa clef comme mot de passe. Ce mot de passe est aléatoire, est vérifié par le système et change à chaque utilisation. Si le mot de passe est intercepté par un tiers, ce dernier ne peut pas le rejouer pour s’authentifier.

But : Integration d’une authentification OTP via Yubico avec un serveur JBoss EAP.

Première étape : Le matériel

Pour cet exemple, les pré-requis suivants sont nécessaires :

  • un clef Yubico (à commander ici)
    • testé avec YubiKey NEO-n,
    • cela doit fonctionner avec une YubiKey Nano ou YubiKey Neo
  • une instance JBoss EAP ou Wildlfy
    • testé avec instance EAP 6.3
    • cela doit fonctionner avec toutes les versions JBoss EAP 6.X
    • cela doit fonctionner avec les Wildfly 8+

Cet exemple utilise le service Yubico Cloud Service, le serveur doit pouvoir se connecter à Internet afin de valider le token OTP.

Deuxième étape : Compiler le client Yubico Java

Recupérer le code source yubico-java-client et le compiler :

greg@a.net> git clone git@github.com:Yubico/yubico-java-client.git  
greg@a.net> cd yubico-java-client  
greg@a.net> mvn clean package  

.... OMIT .....  

[INFO] ------------------------------------------------------------------------  
[INFO] Reactor Summary:  
[INFO]  
[INFO] Yubico OTP validation client ....................... SUCCESS [  0.003 s]  
[INFO] Yubico OTP validation client protocol 1 ............ SUCCESS [  2.254 s]  
[INFO] Yubico OTP validation client protocol 2 ............ SUCCESS [  3.798 s]  
[INFO] Yubico JAAS module ................................. SUCCESS [  0.710 s]  
[INFO] yubico-demo-server ................................. SUCCESS [  2.782 s]  
[INFO] ------------------------------------------------------------------------  
[INFO] BUILD SUCCESS  
[INFO] ------------------------------------------------------------------------  
[INFO] Total time: 9.704 s  
[INFO] Finished at: 2015-03-01T16:42:11+01:00  
[INFO] Final Memory: 39M/228M  
[INFO] ------------------------------------------------------------------------  
greg@a.net>  

Vous allez recuperer deux JARs

Le premier JAR est le client au Cloud Yubico, le second est l’implementation du login module JAAS.

  • Le client Yubico Cloud controle et verifie l’OTP fourni par la clef Yubico et retourne une validation.
    • Client OTP Yubico OTP (protocole 2) : yubico-validation-client2-{Version}.jar
  • Le login module Yubico fourni l’implementation à plugger dans le serveur JBoss, il va faire appel à l’Yubico Cloud via son client et son API.
    • Module JAAS Yubico : yubico-jaas-module-{Version}.jar

Troisième étape: Creation du Module JBoss Yubico

JBoss ne propose pas par defaut de module Yubico, il faut le créer module.xml :

    <?xml version="1.0" encoding="UTF-8"?>  
    <!--  
      ~ JBoss, Home of Professional Open Source.  
      ~ Copyright 2014, Red Hat, Inc., and individual contributors  
      ~ as indicated by the @author tags. See the copyright.txt file in the  
      ~ distribution for a full listing of individual contributors.  
      ~  
      ~ This is free software; you can redistribute it and/or modify it  
      ~ under the terms of the GNU Lesser General Public License as  
      ~ published by the Free Software Foundation; either version 2.1 of  
      ~ the License, or (at your option) any later version.  
      ~  
      ~ This software is distributed in the hope that it will be useful,  
      ~ but WITHOUT ANY WARRANTY; without even the implied warranty of  
      ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
      ~ Lesser General Public License for more details.  
      ~  
      ~ You should have received a copy of the GNU Lesser General Public  
      ~ License along with this software; if not, write to the Free  
      ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
      ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.  
      --> 
    <module xmlns="urn:jboss:module:1.1" name="com.yubico">  
       <resources>  
         <resource-root path="yubico-jaas-module-3.0.0-SNAPSHOT.jar"/>  
         <resource-root path="yubico-validation-client2-3.0.0-SNAPSHOT.jar"/>  
         <resource-root path="vt-ldap-3.3.3.jar"/>  
       </resources>  
       <dependencies>  
         <module name="org.picketbox"/>  
         <module name="javax.api"/>  
         <module name="org.slf4j"/>  
         <module name="org.apache.commons.codec" />  
         <module name="javax.security.jacc.api" />   <!-- for a future propose -->  
         <module name="javax.servlet.api"/>          <!-- for a future propose -->  
         <module name="org.jboss.common-core"/>      <!-- for a future propose -->  
       </dependencies>  
    </module>  

Copier le ainsi que les jar dans le répertoire suivant :

    $JBOSS_HOME/module/com/yubico/main

Ne pas oublier le copier le jar suivant, à récupérer de son cache maven après compilation :

    edu.vt.middleware:vt-ldap:3.3.3

Tips : Pour mode debug rapide, faire un lien symbolique (Unix like seulement)

4ème étape : Get client Id & Secret Key for your JBoss Instance

Pour utiliser le Service Cloud Yubico, il est nécessaire de générer un Client Id et un Secret Key (ou aussi Client Key)

https://upgrade.yubico.com/getapikey/

Yubico API step 1

Yubico API step 2

Info utilisées en 7ème étape

5ème étape : Le PublicId des Yubico Key de vos utilisateurs

Chacun de vos utilisateurs doit vous fournir le PublicId de sa clef via la site suivant :

https://demo.yubico.com/start/otp/standard

Yubico KEY step 1

Yubico KEY step 2

Utiliser le champ Identity comme PublicId

6ème étape : Création de la correspondance entre le PublicId et le Login de l’utilisateur

Créer un fichier de correspondance entre le PublicId de l’utilisateur et son login, comme ceci :

greg@a.net> cat ${jboss.server.config.dir}/id2name_textfile.conf  
yk.<PublicId>.user = <login>  

Il s’agit d’une option au module JAAS Yubico pour authentifier l’utilisateur. Un utilisateur ne pourra pas utiliser une clef inconnue au système.

7ème étape : La configuration de l’instance JBoss

Création d’un security domaine dans le fichier standalone.xml.

<security-domain name="yubico-auth" cache-type="default">  
      <authentication>  
          <login-module code="com.yubico.jaas.YubikeyLoginModule" flag="required" module="com.yubico">  
              <module-option name="clientId" value="12123"/>  
              <module-option name="clientKey" value="U873jhsYT629uuh7gban65+p2Io="/> <!-- client Key aka secret Key -->  
              <module-option name="id2name_textfile" value="${jboss.server.config.dir}/id2name_textfile.conf"/>  
          </login-module>  
      </authentication>  
      <mapping>  
          <mapping-module code="SimpleRoles" type="role">  <!-- for example only -->  
              <module-option name="<PublicId>" value="manager"/>  
          </mapping-module>  
      </mapping>  
</security-domain>  

On configure ensuite un module mapping pour récuperer les rôles de l’utilisateur. Il est bien sûr possible de changer via une autre source de données.

8ème étape : Configuration de l’application JAVA EE

Du pur standard JBoss, inclure le nom du security domain dans le fichier jboss-web.xml, comme suit :

<?xml version="1.0" encoding="UTF-8"?>  
<jboss-web>  
   <security-domain>yubico-auth</security-domain>  
</jboss-web>

9ème étape : Création du mécanisme d’authentification

Dans la page de formulaire de login.

<form method='post' action='j_security_check'>  
  <input type='text' name='j_username'>  
  <input type='password' name='j_password'>  
</form>  

dans le fichier web.xml

<web-app>  
<security-constraint>  
  <web-resource-collection>  
   <web-resource-name>User Auth</web-resource-name>  
   <url-pattern>/auth/*</url-pattern>  
  </web-resource-collection>  
<auth-constraint>  
  <role-name>admin</role-name>  
  <role-name>manager</role-name>  
</auth-constraint>  
</security-constraint>  

<login-config>  
<auth-method>FORM</auth-method>  
  <realm-name>User Auth</realm-name>  
  <form-login-config>  
   <form-login-page>login.jsp</form-login-page>  
   <form-error-page>error.jsp</form-error-page>  
  </form-login-config>  
</login-config>  

<security-role>  
  <role-name>admin</role-name>  
</security-role>  
<security-role>  
  <role-name>manager</role-name>  
</security-role>  
</web-app>  

NB : Il est possible dans notre exemple de configurer le mode BASIC authentication.

10ème étape : Test et mode debug

Afin de contrôler le bon fonctionnement on passe en mode log verbeu

TRACE [org.jboss.as.web.security]  Begin invoke, caller=null  
DEBUG [org.apache.catalina.authenticator]  Security checking request GET /form-auth/  
DEBUG [org.apache.catalina.authenticator]   Calling hasUserDataPermission()  
DEBUG [org.apache.catalina.authenticator]   Calling authenticate()  
DEBUG [org.apache.catalina.authenticator]  Save request in session 'bIbbT0CwH9ICDj-apERnL29O'  
DEBUG [org.apache.catalina.authenticator]   Failed authenticate() test  
TRACE [org.jboss.as.web.security]  End invoke, caller=null  
TRACE [org.jboss.as.web.security]  Begin invoke, caller=null  
DEBUG [org.apache.catalina.authenticator]  Security checking request POST /form-auth/j_security_check  
DEBUG [org.apache.catalina.authenticator]  Authenticating username '<LOGIN_USER>'  
DEBUG [com.yubico.jaas.YubikeyLoginModule]  Initializing YubikeyLoginModule  
DEBUG [com.yubico.jaas.YubikeyLoginModule]  Trying to instantiate com.yubico.jaas.impl.YubikeyToUserMapImpl  
DEBUG [com.yubico.jaas.YubikeyLoginModule]  Begin OTP login  
TRACE [com.yubico.jaas.YubikeyLoginModule]  Checking OTP <XXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY>  
TRACE [com.yubico.jaas.YubikeyLoginModule]  OTP <XXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY> verify result : OK  
INFO  [com.yubico.jaas.YubikeyLoginModule]  OTP verified successfully (YubiKey id XXXXXXXXXXXX)  
DEBUG [com.yubico.jaas.YubikeyLoginModule]  Check if YubiKey XXXXXXXXXXXX belongs to user LOGIN_USER  
TRACE [com.yubico.jaas.YubikeyLoginModule]  In commit()  
DEBUG [com.yubico.jaas.YubikeyLoginModule]  Committing principal <YubikeyPrincipal>XXXXXXXXXXXX  
TRACE [org.jboss.as.web.security]  User: <LOGIN_USER> is authenticated  
DEBUG [org.apache.catalina.authenticator]  Authentication of '<LOGIN_USER>' was successful  
DEBUG [org.apache.catalina.authenticator]  Redirecting to original '/form-auth/'  
DEBUG [org.apache.catalina.authenticator]   Failed authenticate() test ??/form-auth/j_security_check  
TRACE [org.jboss.as.web.security]  End invoke, caller=null  
TRACE [org.jboss.as.web.security]  Begin invoke, caller=null  
TRACE [org.jboss.as.web.security]  Restoring principal info from cache  
DEBUG [org.apache.catalina.authenticator]  Security checking request GET /form-auth/  
DEBUG [org.apache.catalina.authenticator]   Calling hasUserDataPermission()  
DEBUG [org.apache.catalina.authenticator]   Calling authenticate()  
DEBUG [org.apache.catalina.authenticator]  Restore request from session 'bIbbT0CwH9ICDj-apERnL29O'  
DEBUG [org.apache.catalina.authenticator]  Authenticated '<LOGIN_USER>' with type 'FORM'  
DEBUG [org.apache.catalina.authenticator]  Proceed to restored request  
DEBUG [org.apache.catalina.authenticator]   Calling accessControl()  
TRACE [org.jboss.as.web.security]  hasRole:RealmBase says:true::Authz framework says:true:final=true  
TRACE [org.jboss.as.web.security]  hasResourcePermission:RealmBase says:true::Authz framework says:true:final=true  
DEBUG [org.apache.catalina.authenticator]   Successfully passed all security constraints  
TRACE [org.jboss.as.web.security]  End invoke, caller=null  

Dans les traces, on retrouve les principales informations de l’utilisateur :

<LOGIN_USER> : the login user
XXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY : the OTP sent to Yubico Cloud Service
XXXXXXXXXXXX : the Public Id, the Yubico key user

Liens utiles :

Glossaire :