3.4. Authentification du Sujet

L'authentification de Sujet exige une connexion jaas. Le processus de connexion consiste aux étapes suivantes :
  1. Une application instancie un LoginContext et passe le nom de la configuration de la connexion et un CallbackHandler pour remplir les objets Callback, selon la configuration LoginModule.
  2. Le LoginContext consulte une Configuration pour charger tous les LoginModules inclus dans la configuration de connexion nommée. Si aucune configuration nommée existe, la configuration other sera utilisée par défaut.
  3. L'application invoque la méthode LoginContext.login.
  4. La méthode login appelle tous les LoginModule téléchargés. Comme chaque LoginModule tente d'authentifier l'objet, il appelle la méthode handle sur le CallbackHandler associé pour obtenir les informations requises par le processus d'authentification. L'information requise est passée à la méthode handle sous la forme d'un tableau d'objets Callback. En cas de réussite, le LoginModule associe les principaux et les informations d'identification pertinents avec le sujet.
  5. Le LoginContext renvoie le statut d'authentification à l'application. Le renvoi par la méthode de connexion indique un succès. L'échec se traduit par une LoginException lancée par la méthode de connexion.
  6. Si l'authentification réussit, l'application extrait le Sujet authentifié par la méthode LoginContext.getSubject.
  7. Une fois l'étendue de l'authentification de l'objet terminée, tous les principaux et informations connexes associées au sujet par la méthode de connexion s'éliminent par la méthode LoginContext.logout.
La classe LoginContext fournit les méthodes de base d'authentification des sujets et offre un moyen de développer une application qui est indépendante de la technologie sous-jacente de l'authentification. Le LoginContext consulte une Configuration pour déterminer les services d'authentification configurés pour une application particulière. Les classes LoginModule représentent les services d'authentification. Par conséquent, vous pouvez brancher des modules de connexion différents dans une application sans modifier l'application. Le code suivant illustre les étapes requises par une application pour authentifier un sujet.
CallbackHandler handler = new MyHandler();
LoginContext lc = new LoginContext("some-config", handler);

try {
    lc.login();
    Subject subject = lc.getSubject();
} catch(LoginException e) {
    System.out.println("authentication failed");
    e.printStackTrace();
}
                        
// Perform work as authenticated Subject
// ...

// Scope of work complete, logout to remove authentication info
try {
    lc.logout();
} catch(LoginException e) {
    System.out.println("logout failed");
    e.printStackTrace();
}
                        
// A sample MyHandler class
class MyHandler 
    implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws
        IOException, UnsupportedCallbackException
    {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nc = (NameCallback)callbacks[i];
                nc.setName(username);
            } else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback pc = (PasswordCallback)callbacks[i];
                pc.setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                                                       "Unrecognized Callback");
            }
        }
    }
}
Les développeurs intègrent une technologie d'authentification en créant une implémentation de l'interface LoginModule. Cela permet à un administrateur d'ajouter des technologies d'authentification différentes dans une application. Vous pouvez enchaîner ensemble de multiples LoginModule afin de permettre à plus d'une technologie d'authentification de participer au processus d'authentification. Par exemple, un LoginModule peut effectuer une authentification par nom/mot de passe, tandis que l'autre peut créer une interface avec des périphériques matériels tels que des lecteurs de cartes ou des identificateurs biométriques.
Le cycle de vie d'un LoginModule est motivé par l'objet LoginContext avec lequel le client crée et publie la méthode login. Le processus se compose de deux phases. Les étapes du processus sont les suivantes :
  • Le LoginContext crée chaque LoginModule en utilisant son constructeur public no-arg.
  • Chaque LoginModule est initialisé par un appel à sa méthode d'initialisation. L'argument Subject est garanti d'être non-null. La signature de la méthode d'initialisation est : public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
  • La méthode login est appelée pour démarrer le processus d'authentification. Par exemple, une implémentation de la méthode peut inviter l'utilisateur à un nom d'utilisateur et à un mot de passe, et puis vérifiez les informations sur les données stockées dans un service d'attribution de noms comme NIS ou LDAP. Des implémentations alternatives pourraient créer des interfaces avec les cartes à puce et des dispositifs biométriques, ou simplement extraire les informations de l'utilisateur du système d'exploitation sous-jacent. La validation de l'identité de l'utilisateur par chaque LoginModule est considérée comme la phase 1 d'authentification JAAS. La signature de la méthode login est boolean login() throws LoginException. Une LoginException indique un échec. Une valeur retour true indique que la méthode a réussi, tandis qu'une valeur false indique que le module de login doit être ignoré.
  • Si la méthode d'authentification générale de LoginContext réussit, commit sera invoqué sur chaque LoginModule. Si la phase 1 réussit pour un module LoginModule, alors la méthode de validation continue en phase 2 et associe les principaux qui conviennent, les informations d'authentification publiques, et/ou les informations d'authentification privées au sujet. Si la phase 1 échoue pour LoginModule, alors commit retirera tout état d'authentification stocké auparavant, comme les noms d'utilisateur et les mots de passe. La signature de la méthode commit est: boolean commit() throws LoginException. Tout manquement de la phase de validation (commit) se traduit par l'exception LoginException. Un renvoi true indique que la méthode a réussi, alors qu'un renvoi false indique que le module de connexion doit être ignoré.
  • Si l'authentification globale du LoginContext échoue, la méthode abort sera appelée sur chaque LoginModule. La méthode abort supprime ou détruit tout état d'authentification créé par les méthodes de connexion ou d'initialisation. La signature de la méthode abort est boolean abort() throws LoginException. En cas d'impossibilité d'achever la phase d'abandon est indiquée en jetant une LoginException. Un retour de true indique que la méthode a réussi, alors qu'un retour de false indique que le module de connexion doit être ignoré.
  • Pour supprimer l'état d'authentification après une connexion réussie, l'application appelle logout sur le LoginContext. Il en résulte un appel de méthode logout sur chaque LoginModule. La méthode logout supprime les principaux et les informations d'identification associées initialement au sujet au cours de l'opération commit (validation). Les informations d'identification doivent être détruites après le retrait. La signature de la méthode logout est : boolean logout() throws LoginException. L'impossibilité d'achever le processus de déconnexion est indiquée par l'exception LoginException. Un renvoi true indique que la méthode a réussi, alors qu'un renvoi false indique que le module de connexion doit être ignoré.
Lorsqu'un LoginModule doit communiquer avec l'utilisateur pour obtenir des informations d'authentification, il utilise un objet CallbackHandler. Les applications implémentent l'interface CallbackHandler et le font passer au LoginContext, lequel envoie les informations d'authentification directement sur les modules de connexion sous-jacents.
Les modules de connexion utilisent le CallbackHandler à la fois pour recueillir les entrées d'utilisateurs, comme un mot de passe ou un PIN de smartcard, afin de fournir des informations aux utilisateurs, comme les informations d'état. En permettant à l'application de spécifier les CallbackHandler, les LoginModule sous-jacents restent indépendants des différentes façons dont les applications interagissent avec les utilisateurs. Par exemple, une implémentation de CallbackHandler d'une application GUI peut afficher une fenêtre pour solliciter une action d'utilisateur. En revanche, une implémentation CallbackHandler pour un environnement non graphique, comme un serveur d'applications, pourrait simplement obtenir des informations d'identification en utilisant un serveur d'application API. L'interface CallbackHandler dispose d'une méthode d'implémentation :
void handle(Callback[] callbacks)
    throws java.io.IOException, 
           UnsupportedCallbackException;
L'interface de Callback est la dernière classe d'authentification que nous allons regarder. Il s'agit d'une interface de marquage pour laquelle plusieurs implémentations par défaut sont fournies, y compris le NameCallback et le PasswordCallback utilisés dans un exemple précédent. Un LoginModule utilise un Callback pour demander des informations requises par le mécanisme d'authentification. Les LoginModule passent un tableau de Callback s directement à la méthode CallbackHandler.handle au cours de la phase d'ouverture de session d'authentification. Si un callbackhandler ne comprend pas comment utiliser un objet Callback passé dans la méthode handle, il lancera une exception UnsupportedCallbackException pour annuler l'appel d'ouverture de session.