|
Safran utilise l'API JAAS (Java Authentication and Authorization Service) pour gérer l'authentification entre les clients et le serveur.
JAAS met en oeuvre un module serveur ainsi qu'un module client. Lorsque le client fait une demande d'authentification il envoie une requête au serveur. Cette requête comporte le domaine de sécurité sur lequel on souhaite s'authentifier (plusieurs domaines de sécurité de niveaux différents peuvent être mis en place dans JBoss). Ce domaine de sécurité défini, entre autre, le type d'authentification souhaité. Dans le cas de Safran l'authentification se fait par login / mot de passe. Pour récuperer le login / mot de passe JAAS fait appel à un CallBack client qui doit implementer les methodes renvoyant les données nécessaires . Une fois que le serveur est en possession des informations de connexion il utilise la méthode de validation de ces informations (définie par le domaine de sécurité). Pour le cas de Safran le domaine de sécurité implique la validation des données via une requête dans une base de données.
La manière dont JAAS est intégré dans les serveurs d'application diffère significativement. Safran utilise un serveur JBoss, nous détaillerons ici uniquement l'implémentation de JASS dans ce serveur.
Configuration serveur :
Dans un premier temps nous allons redéfinir la méthode de verification du mot de passe utilisée par JBoss. Cela nous permet d'avoir un contrôle sur ce qu'il faut faire en cas de saisie d'un mauvais mot de passe : quand un mauvais mot de passe est saisi alors nous incrémentons un compteur qui, lorsqu'il atteindra un certain seuil, bloquera le compte de l'utilisateur.
public class SafranDatabaseServerLoginModule extends DatabaseServerLoginModule {
@Override
protected boolean validatePassword(String arg0/*mot de passe fourni*/, String arg1/*mot de passe attendu*/) {
String login = getUsername();
Logger log = Logger.getLogger(this.getClass());
SI_AuthentificationbeanAuthentification = (SI_Authentification)(new InitialContext().lookup(SI_Authentification.LOCAL_NAME));
if (!arg0.equals(arg1)) {
log.debug("Mauvais mot de passe !");
int compteur = beanAuthentification.ajouterUneConnexionEchouee(login);
Logger.getLogger(this.getClass()).debug("Ajout d'une connexion echouée à l'utilisateur : " + compteur);
return false;
} else {
beanUtilisateur.remiseAZeroDuCompteurDesConnexionsEchouees(login);
}
return super.validatePassword(arg0, arg1);
}
}
Toujours dans cette même classe : nous verifions ensuite lors de la procédure de login si le compte est actif ou non. dans le cas où le compte est inactif le login doit échouer :
@Override
public boolean login() throws LoginException {
String utilisateur = getUsernameAndPassword()[0];
try {
SI_AuthentificationbeanAuthentification = (SI_Authentification)(new InitialContext().lookup(SI_Authentification.LOCAL_NAME));
boolean isActif = beanAuthentification.isActive(utilisateur);
if (!isActif) {
return false;
}
} catch (EJBException ex) {
log.error("Exception : " + ex.getMessage());
return false;
}
return super.login();
}
Il faut ensuite configurer le fichier login-config.xml de JBoss pour définir le type d'authentification du domaine de sécurité. Le domaine de securité de Safran est appelé "SafranSecurityDomain" et utilise une authentification de base de données de type "SafranDatabaseServerLoginModule" (qui est une sous-classe de "DatabaseServerLoginModule" : une classe de JBoss) :
<application-policy name = "SafranSecurityDomain">
<authentication>
<login-module code = "fr.xter.safran.serveur.authentification.SafranDatabaseServerLoginModule" flag = "required">
<module-option name = "unauthenticatedIdentity">guest</module-option>
<module-option name = "dsJndiName">java:/MySQLDS</module-option>
<!-- MySQL -->
<module-option name = "principalsQuery">call safran_login(?)</module-option>
<module-option name = "rolesQuery">call safran_roles(?)</module-option>
</login-module>
</authentication>
</application-policy>
Dans ce fichier de configuration on doit egalement préciser les paramètres de la connexion à la base de données (MySQLDS dans ce cas) ainsi que deux requêtes. La premiere requête "PrincipalsQuery" sert à recuperer le mot de passe par rapport à un login passé en paramètre. La seconde requête sert à recupérer une liste de textes correspondants aux droits auquels peut prétendre un utilisateur (grace au login passé en paramètre).
Pour que les accès aux couches metiers soit possible (lors de la procédure de vérification des comptes utilisateurs dans la classe DatabaseServerLoginModule) nous devons également définir un domaine de sécurité interne à JBoss qui authentifie automatiquement un utilisateur "admin" :
<application-policy name="SafranDomaineInterne">
<authentication>
<login-module code="org.jboss.security.auth.spi.IdentityLoginModule" flag="required">
<module-option name="principal">admin</module-option>
<module-option name="roles">admin</module-option>
</login-module>
</authentication>
</application-policy>
Pour finir la configuration coté serveur, nous devons indiquer quels sont les beans qui seront soumis au domaine de sécurité. pour cela nous créons un fichier jboss.xml dans le repertoire META-INF du jar de déploiement :
<jboss>
<security-domain>java:/jaas/SafranSecurityDomain</security-domain>
<enterprise-beans>
<session>
<ejb-name>SB_Authentification</ejb-name>
<security-domain>java:/jaas/SafranDomaineInterne</security-domain>
</session>
</enterprise-beans>
</jboss>
Nous definissons un domaine de sécurité particulier pour le bean Authentification (SB_Authentification est l'implementation de l'interface SI_Authentification utilisée dans DatabaseServerLoginModule ). Ce bean ne possède qu'une interface local et ne doit servir qu'au serveur d'application pour gérer l'authentification des clients.
Configuration client :
Dans un premier temps nous créons notre classe de gestion de CallBack pour que le serveur puisse venir recupérer les informations de connexion :
public class SafranLoginHandler implements CallbackHandler {
private String login;
private char[] password;
public SafranLoginHandler(String login, String password) {
this.login = login;
this.password = password.toCharArray();
}
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(login);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callbacks[i];
pc.setPassword(password);
}
}
}
Il faut creer un fichier de configuration pourJAAS qui décrit pour chaque domaine de sécurité le type d'authentification. Pour Safran nous n'avons q'un seul domaine pour le client. le fichier se nomme jaas.conf :
SafranSecurityDomain {
org.jboss.security.ClientLoginModule required;
};
Le type de sécurité est défini avec un ClientLoginModule qui est une classe qui attendra un handler du type CallBackHandler lors de son instanciation (handler que nous avons implementé précédement). Pour que ce fichier puisse être utilisé par l'application nous devons faire l'association avec la propriété système java.security.auth.login.config. Pour cela nous lançons l'application cliente avec la ligne de commande suivante :
java -j safranClient.jar -Djava.security.auth.login.config=jaas.conf
Il ne nous reste plus qu'à faire appel au module d'authentification au moment du lancement de l'application :
SafranLoginHandler handler = new SafranLoginHandler("mon_login","mon_mot_de_passe");
LoginContext loginContext = new LoginContext("SafranSecurityDomain", handler);
loginContext.login();
Chaque appel aux sessions beans serveur sera dorénavant dans le contexte de sécurité.
|
Commentaires utilisateurs (0)
|
|
|