Configurer un realm MySQL dans GlassFish

Dans la lignée des articles déjà publiés sur le thème de l'authentification dans GlassFish, je vous propose d'aborder cette fois-ci, par la réalisation d'un exemple d'application web, la configuration d'un realm JDBC faisant référence à une base données MySQL contenant les tables d'authentification des utilisateurs.
L'authentification utilisée sera de type BASIC.
Les mots de passe utilisateur seront quant à eux cryptés en MD5 dans la table des utilisateurs MySQL.

Je me suis inspiré en partie du Tutoriel Java EE dans sa version de janvier 2013 qui décrit pour l'application de démonstation Duke’s Forest, la procédure à suivre pour configurer un realm JDBC branché sur une base de données Java DB (Derby).
Nous verrons que cette application de démonstration JEE présente des zones d'ombre que je commenterai pour vous aider à mieux appréhender les mécanismes exposés dans cet article.

La plateforme technique utilisée pour rédiger cet article est constituée du JDK version 1.6, du serveur GlassFish version 3.1.2 qui inclut la librairie Mojarra JSF version 2.1.6. et du serveur de base de données MySQL version 5.6 accédée par la librairie JDBC mysql-connector-java-5.1.23-bin.jar.

L'application web demo_jdbcrealm que nous allons réaliser

L'application web que je vous propose de réaliser dans cet article est constituée de 3 vues JSF dont l'accès est restreint aux seuls rôles default_user_role, other_user_role et admin_role :
  • /default/index.xhtml est réservée aux utilisateurs disposant du rôle default_user_role.
  • /other/other_page.xhtml est réservée aux seuls utilisateurs disposant du rôle other_user_role.
  • /admin/admin_page.xhtml est réservée aux seuls utilisateurs disposant du rôle admin_role.
Les groupes utilisateurs disponibles dans la base de données sont users et admins et correspondent respectivement aux rôles other_user_role et admin_role.
Le realm est configuré de telle sorte que ses utilisateurs soient tous affectés au groupe default_group. Celui-ci est relié au rôle default_user_role. Ainsi tous les utilisateurs déclarés dans la base de données MySQL sont par défaut rattachés au groupe default_group dans le realm et au rôle default_user_role dans l'application web.
Les utilisateurs créés dans le realm sont user1, user2, user3 et user4 et ils s'authentifient tous les 4 avec le même mot de passe password.
  • user1 n'est affecté à aucun groupe dans la base de données.
  • user2 est affecté au groupe users.
  • user3 est affecté au groupe admins.
  • user4 est affecté à la fois aux groupes users et admins.

Mise en oeuvre du realm JDBC

Dans ce chapitre, nous créerons dans MySQL les tables de sécurité requises par le realm JDBC, puis configurerons dans GlassFish le pool de connexion JDBC d'accès aux tables de sécurité, la ressource JNDI d'accès au pool de connexion et enfin le realm JDBC proprement dit.

Création des tables d'authentification dans MySQL

Les tables nécessaires pour faire fonctionner le realm JDBC sont :
  • la table des utilisateurs autorisés à se connecter à l'application web que nous nommerons USERS. Elle comprend au minimum 2 colonnes, une colonne pour stocker l'identifiant de connexion de l'utilisateur et une deuxième pour stocker son mot de passe.
  • la table d'affectation des utilisateurs aux groupes d'utilisateurs que nous nommerons USERS_GROUPS. Elle comprend une première colonne pour stocker l'identifiant de connexion de l'utilisateur et une deuxième colonne pour contenir le nom du groupe auquel l'utilisateur est rattaché.

Nous ajouterons à ces 2 tables une troisième table optionnelle nommée GROUPS contenant tous les groupes utilisateurs qui peuvent être affectés aux utilisateurs de l'application. Sa colonne NAME contenant le nom du groupe, sera déclarée comme clé étrangère de la colonne GROUP_NAME de la table USERS_GROUPS, renforçant ainsi son intégrité.

Le nommage des tables de sécurité et de leus colonnes est laissé totalement libre. Lors de la configuration du realm JDBC, nous indiquerons le nom des tables et colonnes nécessaires à son fonctionnement.

Les commandes SQL de création de ces 3 tables vous sont fournies ci-dessous.

CREATE TABLE users (
  id int(11) NOT NULL AUTO_INCREMENT,
  login_name varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  password varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY users_login_name_uk (login_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Table of users';
 
CREATE TABLE groups (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY groups_name_uk (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Table of user groups';
 
CREATE TABLE users_groups (
  login_name varchar(50) NOT NULL,
  group_name varchar(50) NOT NULL,
  UNIQUE KEY users_groups_uk (login_name,group_name),
  KEY users_groups_group_name_fk (group_name),
  CONSTRAINT users_groups_login_name_fk FOREIGN KEY (login_name) REFERENCES users (login_name),
  CONSTRAINT users_groups_group_name_fk FOREIGN KEY (group_name) REFERENCES groups (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Table of groups to which the users belong';
Script SQL 1 : commandes MySQL de création des tables de sécurité pour le realm JDBC de l'application demo_jdbcrealm.

Les commandes SQL d'insertion des données de sécurité telles qu'elles vous ont été décrites au chapitre L'application web demo_jdbcrealm que nous allons réaliser sont les suivantes.

/* Rows of the table users */
INSERT INTO users (login_name, password) VALUES ('user1','5f4dcc3b5aa765d61d8327deb882cf99');
INSERT INTO users (login_name, password) VALUES ('user2','5f4dcc3b5aa765d61d8327deb882cf99');
INSERT INTO users (login_name, password) VALUES ('user3','5f4dcc3b5aa765d61d8327deb882cf99');
INSERT INTO users (login_name, password) VALUES ('user4','5f4dcc3b5aa765d61d8327deb882cf99');
 
/* Rows of the table groups */
INSERT INTO groups (name) VALUES ('users');
INSERT INTO groups (name) VALUES ('admins');
 
/* Rows of the table user_groups */
INSERT INTO users_groups (login_name, group_name) VALUES ('user2','users');
INSERT INTO users_groups (login_name, group_name) VALUES ('user3','admins');
INSERT INTO users_groups (login_name, group_name) VALUES ('user4','users');
INSERT INTO users_groups (login_name, group_name) VALUES ('user4','admins');
Script SQL 2 : commandes MySQL d'insertion des données de sécurité pour le realm JDBC de l'application demo_jdbcrealm.

Vous pouvez assez simplement remplacer le mot de passe dans la colonne PASSWORD de la table USERS en utilisant la commande MySQL SELECT MD5('lemotdepasse');, où lemotdepasse est le mot de passe à crypter en MD5.

Creation d'un pool de connexion JDBC à la base de données MySQL

Pour permettre au realm JDBC d'accéder à la base de données MySQL, nous allons tout d'abord déclarer un pool de connexion JDBC à l'aide de la Console d'Administration du Serveur GlassFish.
Pour cela, à partir de l'arbre de navigation situé sur la gauche, accédez à la page JDBC Connection Pools en suivant le chemin Resources > JDBC > JDBC Connection Pools. Cliquez ensuite sur le bouton New... pour ajouter un nouveau pool de connexion.
Depuis la page New JDBC Connection Pool (Step 1 of 2), renseignez les valeurs de champs suivantes :
Champ Valeur
Pool Name: testPool
Resource Type: javax.sql.ConnectionPoolDataSource
Database Driver Vendor: MySql
Tableau 1 : champs à renseigner à l'étape 1 pour créer le pool de connexion JDBC testPool. Cliquez ensuite sur le bouton Next pour accéder à la 2ème page nommée New JDBC Connection Pool (Step 2 of 2) et complétez les valeurs des propriétés du tableau Additional Properties situé en fin de page comme indiqué ci-dessous :
Propriété Valeur Commentaire
ServerName localhost Nom du serveur ou adresse IP du serveur MySQL sur lequel est installée la base de données contenant les tables de sécurité du realm.
Port 3306 Port TCP/IP d'accès au serveur MySQL.
DatabaseName testdb Nom de la base de données MySQL dans laquelle ont été créées les tables de sécurité du realm.
URL jdbc:mysql://localhost:3306/testdb URL JDBC d'accès à la base de données MySQL reprenant les informations saisies pour les propriétés ServerName, Port et DatabaseName.
User testuser Nom de l'utilisateur déclaré dans MySQL ayant un accès en lecture sur les tables de sécurité du realm.
Password userpassword Mot de passe de l'utilisateur testuser dans MySQL
Tableau 2 : propriétés additionnelles du pool de connexion JDBC testPool.

La valeur de la propriété URL n'est pas reconstituée automatiquement à partir des valeurs saisies pour les propriétés ServerName et DatabaseName. Aussi veillez à renseigner correctement cette propriété et à tester la connexion JDBC à l'aide du bouton Ping disponible sur la page Edit JDBC Connection Pool.

Creation d'une ressource JDBC pour le pool de connexion testPool

Le realm JDBC accèdera au pool de connexion configuré précédemment, par l'intermédiaire d'une ressource JNDI que nous devons à présent déclarer.
Pour cela, depuis la console d'administration de GlassFish, rendez-vous sur la page JDBC Resources en suivant dans le menu le chemin Resources > JDBC > JDBC Resources puis cliquez sur le bouton New...
Une fois la page New JDBC Resource affichée, saisissez le nom jdbc/test_mysql pour le champ JNDI Name et sélectionnez le pool de connexion testPool dans la liste Pool Name. Terminez en cliquant sur OK pour enregistrer la nouvelle ressource.

Creation du realm JDBC

Cette dernière étape de configuration de GlassFish consiste à créer le realm JDBC proprement dit. Ce dernier accédera aux tables de sécurité à travers la ressource JNDI jdbc/test_mysql que nous venons de déclarer.
Depuis la console d'administration de GlassFish, affichez la page Realms en suivant le menu Configurations > server-config > Security > Realms. Cliquez alors sur le bouton New... pour créer un nouveau realm.
Depuis la page New Realm, renseignez le champ Name à la valeur test-realm, sélectionnez la classe com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm dans la liste Class Name et complétez les propriétés spécifiques au realm JDBC comme indiqué dans le tableau suivant :
Propriété Valeur Commentaire
JAAS Context jdbcRealm Nom du contexte JAAS dont la valeur est spécifique à la classe JDBCRealm.
JNDI jdbc/test_mysql Nom JNDI de la ressource JDBC déclarée pour accéder au pool de connexion JDBC testPool.
User Table users Nom de la table des utilisateurs dans MySQL contenant leur identifiant de connexion et leur mot de passe.
User Name Column login_name Nom de la colonne dans la table des utilisateurs contenant leur identifiant de connexion à l'application.
Password Column password Nom de la colonne dans la table des utilisateurs contenant leur mot de passe.
Group Table users_groups Nom de la table contenant à la fois l'identifiant de connexion des utilisateurs et le nom des groupes auxquels ils appartiennent.
Group Name Column group_name Nom de la colonne de la table USERS_GROUPS contenant le nom des groupes auxquels les utilisateurs appartiennent.
Assign Groups default_group Nom des groupes supplémentaires auxquels tous les utilisateurs du realm appartiennent, en plus de ceux auxquels ils ont été rattachés dans la table USERS_GROUPS.
Digest Algorithm MD5 Nom de l'algorithme ayant servi à crypter les mots de passe contenus dans la colonne PASSWORD de la table USERS.
Tableau 3 : propriétés spécifiques à la classe JDBCRealm à renseigner pour le realm test-realm

Terminez en cliquant sur OK pour créer le realm.

Les modifications effectuées sur un realm depuis la console d'administration ne sont pas effectives immédiatement dans GlassFish. Il peut être nécessaire de redémarrer le serveur GlassFish pour constater les modifications.

Création de l'application web demo_jdbcrealm

demo_jdbcrealm projectFig. 1 - Projet demo_jdbcrealm dans NetBeans.

Il est temps à présent d'utiliser le realm test-realm configuré dans GlassFish dans une application web de démonstration.
Nous allons pour cela générer une application web java standard nommée demo_jdbcrealm et incluant les librairies du framework JSF que nous allons compléter comme expliqué dans les paragraphes suivants.

Création des vues JSF

Les 3 vues JSF suivantes affichent simplement l'identifiant de connexion de l'utilisateur authentifié et les rôles qui lui sont attribués

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Default Page</title>
    </h:head>
    <h:body>
        <h3>Default page for all authenticated users</h3>
        User login name: <strong>${request.remoteUser}</strong><br/>
        Authorized roles:<ul style="margin-top:0;">
            <h:panelGroup rendered="#{request.isUserInRole('default_user_role')}">
                <li style="font-weight:bold;">default_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('other_user_role')}">
                <li>other_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('admin_role')}">
                <li>admin_role</li>
            </h:panelGroup>
        </ul>
        Go to <h:link outcome="/other/other_page">the other page</h:link>.<br/>
        Go to <h:link outcome="/admin/admin_page">the administration page</h:link>.
    </h:body>
</html>
Page 1 : vue /default/index.xhtml de l'application web demo_jdbcrealm.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Other Page</title>
    </h:head>
    <h:body>
        <h3>Page for authorized users having the <q>other_user_role</q></h3>
        User login name: <strong>${request.remoteUser}</strong><br/>
        Authorized roles:<ul style="margin-top:0;">
            <h:panelGroup rendered="#{request.isUserInRole('default_user_role')}">
                <li>default_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('other_user_role')}">
                <li style="font-weight:bold;">other_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('admin_role')}">
                <li>admin_role</li>
            </h:panelGroup>
        </ul>
        Go back to <h:link outcome="/default/index">the default page</h:link>.
    </h:body>
</html>
Page 2 : vue /other/other_page.xhtml de l'application web demo_jdbcrealm.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Administration Page</title>
    </h:head>
    <h:body>
        <h3>Page for authorized users having the <q>admin_role</q></h3>
        User login name: <strong>${request.remoteUser}</strong><br/>
        Authorized roles:<ul style="margin-top:0;">
            <h:panelGroup rendered="#{request.isUserInRole('default_user_role')}">
                <li>default_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('other_user_role')}">
                <li>other_user_role</li>
            </h:panelGroup>
            <h:panelGroup rendered="#{request.isUserInRole('admin_role')}">
                <li style="font-weight:bold;">admin_role</li>
            </h:panelGroup>
        </ul>
        Go back to <h:link outcome="/default/index">the default page</h:link>.
    </h:body>
</html>
Page 3 : vue /admin/admin_page.xhtml de l'application web demo_jdbcrealm.

Déclaration du realm JDBC dans le descripteur web.xml

Dans le descripteur de déploiement web.xml qui suit, le realm JDBC test-realm est déclaré sous la balise <realm-name/>.
Sous la balise <security-constraint/>, le motif de l'URL des pages à sécuriser est précisé dans la balise <url-pattern/> et les rôles autorisés sous la balise <auth-constraint/>.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>default/index.xhtml</welcome-file>
    </welcome-file-list>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test-realm</realm-name>
    </login-config>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Default secure pages</web-resource-name>
            <url-pattern>/default/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>default_user_role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <role-name>default_user_role</role-name>
    </security-role>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Other secure pages</web-resource-name>
            <url-pattern>/other/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>other_user_role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <role-name>other_user_role</role-name>
    </security-role>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Administration secure pages</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin_role</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <role-name>admin_role</role-name>
    </security-role>
</web-app>
Config. 1 : descripteur de déploiement web.xml de l'application web demo_jdbcrealm.

Mise en relation des groupes et rôles dans le descripteur glassfish-web.xml

Pour finir, il ne nous reste plus qu'à associer les groupes du realm avec les rôles de l'application web dans le descripteur de déploiement spécifique glassfish-web.xml, sous la balise <security-role-mapping/>.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <security-role-mapping>
        <role-name>default_user_role</role-name>
        <group-name>default_group</group-name>
  </security-role-mapping>
  <security-role-mapping>
    <role-name>other_user_role</role-name>
    <group-name>users</group-name>
  </security-role-mapping>
  <security-role-mapping>
    <role-name>admin_role</role-name>
    <group-name>admins</group-name>
  </security-role-mapping>
</glassfish-web-app>
Config. 2 : descripteur de déploiement glassfish-web.xml de l'application web demo_jdbcrealm.

Test de l'application demo_jdbcrealm

Utilisateur user1

test user1 vue index Fig. 2 - test pour user1.

L'utilisateur user1 existe dans la table USERS du realm mais n'est rattaché à aucun groupe dans la table USERS_GROUPS.
Cependant, nous avons configuré le realm test-realm de sorte que ses utilisateurs soient tous affectés au groupe default_group (champ Assign Groups) et disposent en conséquence, du rôle default_user_role.

user1 peut alors accéder à la page /default/index.xhtml mais en revanche se voit refuser l'accès aux pages /other/other_page.xhtml et /admin/admin_page.xhtml, ne disposant pas des rôles requis (affichage de la page d'erreur HTTP Status 403 - Access to the requested resource has been denied).

L'erreur HTTP 403 peut facilement être interceptée pour afficher une page d'erreur personnalisée, en déclarant dans le descripteur de déploiement web.xml sous la balise <error-page/>, le code de l'erreur (<error-code>403</error-code) et la page à afficher pour cette erreur (<location>/error.xhtml?code=403</location>).

Utilisateur user2

test user2 vue other Fig. 3 - test pour user2.

L'utilisateur user2 quant à lui a été paramétré dans la base de données MySQL pour appartenir au groupe users et a été affecté dans le realm au groupe default_group.

Les rôles dont il dispose sont de ce fait other_user_role et default_user_role.

L'accès à la page d'administration lui est en revanche interdit.

Utilisateur user3

test user3 vue admin Fig. 4 - test pour user3.

L'utilisateur user3 appartient au groupe admins et dispose alors du rôle admin_role dans l'application web en complément du rôle par défaut defaut_user_role.

Pour lui cependant, l'accès à la page /other/other_page.xhtml lui est refusé n'appartenant pas au groupe users.

Utilisateur user4

test user4 vue index Fig. 5 - test pour user4.

Pour conclure nos tests avec l'utilisateur user4, nous sommes dans le cas de figure où il appartient à tous les groupes utilisateurs et par voie de conséquence peut naviguer à travers toutes les pages sécurisées de l'application.

Focus sur l'application de démonstration JEE Duke’s Forest

J'ai étudié et testé l'exemple Duke’s Forest du Tutoriel Java EE de janvier 2013 qui illustre notamment la configuration d'un realm JDBC.
J'étais particulièrement intrigué par la table PERSON_GROUPS car je n'arrivais pas à comprendre la place qu'elle pouvait occuper dans le mécanisme d'authentification.
Finalement, j'en suis arrivé à la conclusion que cette table n'était d'aucune utilité pour le realm configuré dans l'exemple Duke’s Forest. En effet, elle n'est pas référencée dans la configuration du realm JDBC. Seules les tables PERSON et GROUPS sont renseignées pour les champs respectifs User Table et Group Table. De plus, la structure de la table PERSON_GROUPS n'est pas adaptée à la configuration d'un realm JDBC, étant donné que sa colonne GROUPS_ID contient l'identifiant technique du groupe utilisateur et non pas son nom (USERS ou ADMINS), tel qu'il est attendu dans le champ Group Name Column de configuration du realm.
J'ai également fait le même constat pour la table GROUPS :
  • D'une part, elle est renseignée dans le champs Group Table ainsi que sa colonne name dans le champ Group Name Column. Or, la table GROUPS ne contient que la définition des groupes utilisateurs et par conséquent, ne joue pas la fonction attendue par le realm JDBC de mise en relation des groupes et des utilisateurs.
  • D'autre part, les groupes USERS et ADMINS sont renseignés pour le realm JDBC dans le champ Assign Groups, ce qui a pour effet de rendre inutile toute mise en relations des groupes et des utilisateurs dans la base de données, puisque tous les utilisateurs sont affectés à ces 2 groupes du fait de cette configuration.
En conséquence, si je supprime les groupes USERS et ADMINS du champ Assign Groups, l'authentification ne fonctionne plus. Je constate également que le message SEC1111: Cannot load group for JDBC realm user [admin@example.com]. est affiché dans le journal du serveur GlassFish.
Pour ne plus avoir ce message d'erreur et pour faire fonctionner le realm JDBC, j'ai apporté les 2 corrections suivantes :
  • J'ai ajouté à la table PERSON_GROUPS une colonne nommée GROUP_NAME dans laquelle j'ai inséré les valeurs USERS et ADMINS en fonction de l'utilisateur.
  • J'ai ajusté les paramètres du realm JDBC en indiquant la table PERSON_GROUPS à la place de GROUPS et la colonne GROUP_NAME à la place de NAME.
Dans sa version corrigée, le groupe affecté à l'utilisateur dans la table PERSON_GROUPS redescend correctement à l'application web et les autorisations sur les URL paramétrées opérationnelles.

Tous commentaires de votre part sont les bienvenus pour confirmer ou nuancer les résultats de cette analyse.

En synthèse...

Pour conclure sur la mise en oeuvre d'un realm JDBC relié à une base de données MySQL, le gros de la tâche se situe dans la création des tables dans la base de données et dans la configuration de GlassFish (pool de connexion, ressource JNDI et realm JDBC).

L'authentification illustrée dans cet article est de type BASIC mais rien ne vous empêche d'utiliser le realm JDBC avec une authentification de type FORM tel que cela vous est présenté dans l'article L'authentification FORM en JSF dans GlassFish également publié sur ce blog.

Selon le même principe, vous pouvez aussi choisir un autre algorythme de hashage du mot de passe que MD5 tel qu'il a été configuré dans l'application de démonstration. GlassFish supporte également l'algorithme SHA-256 pour un hashage plus robuste du mot de passe. Cet algorithme est d'ailleurs celui appliqué par défaut pour un realm JDBC depuis la version 3.1 de GlassFish, si le champ Digest Algorithm n'est pas renseigné.

Pour finir, il est important de noter que bien que le mot de passe soit crypté dans la base de données, il est transmis en clair dans la requête HTTP de demande d'authentification. Une configuration complémentaire de GlassFish est nécessaire pour créer un tunnel sécurisé SSL (accès en HTTPS) pour les échanges entre le Client et le Serveur, de sorte que le mot de passe soit crypté lors de sa transmission.

Code source de l'application de démonstration

Le code source de l'application web demo_jdbcrealm pré-configuré pour GlassFish et Ant peut être téléchargé sous la forme d'une archive ZIP en cliquant sur le lien ci-dessous :

Ce code source vous est mis à disposition uniquement à titre expérimental et à des fins éducatives. Vous restez par conséquent seul responsable de l'utilisation que vous en faites.

Articles connexes