Vous êtes sur la page 1sur 31

Présentation du cours

‰ Ce cours montre comment sécuriser une


application Java EE : réserver l’accès de pages
Sécurité dans Java EE Web ou de méthodes d’EJB à certains utilisateurs
‰ Toute la sécurité n’est pas standardisée dans
Java EE ; pour les parties non standardisées, des
Université de Nice - Sophia Antipolis exemples de configuration sont donnés pour le
serveur d’application GlassFish
Richard Grin
Version 0.17 – 17/9/13

R. Grin Sécurité Java EE page 2

Plan (1/2) Plan (2/2)


‰ Généralités sur la sécurité ‰ Un exemple avec template
‰ Présentation de la sécurité dans Java EE ‰ Logs dans GlassFish – mise au point
‰ Déclaration des rôles ‰ Gérer les mots de passe
‰ Authentification
‰ Protection des pages Web
‰ Protéger les méthodes des EJB
‰ Code Java pour la sécurité
‰ Configuration de GlassFish

R. Grin Sécurité Java EE page 3 R. Grin Sécurité Java EE page 4

‰ Réserver des parties d’une application à certains


utilisateurs implique de gérer
n l’authentification des utilisateurs
Généralités sur la sécurité n la vérification des autorisations

R. Grin Sécurité Java EE page 5 R. Grin Sécurité Java EE page 6

1
Authentification Autorisation
‰ Obtenir l’identité des utilisateurs et vérifier qu’un ‰ Lorsqu’un utilisateur est entré dans l’application,
utilisateur est bien celui qu’il prétend être vérifier qu’il a bien le droit
‰ Le plus souvent, il s’agit de demander le nom et n d’accéder aux ressources (pages Web, base
le mot de passe de l’utilisateur de données,…)
n d’accomplir des actions sur ces ressources
(par exemple les consulter, les modifier, les
supprimer)
n de lancer des opérations

R. Grin Sécurité Java EE page 7 R. Grin Sécurité Java EE page 8

Transport des informations


‰ Protéger les informations qui transitent sur le ‰ Ce support n’abordera que l’authentification par
réseau contre des personnes non autorisés : mot de passe et les autorisations
n empêcher la lecture des données ‰ Il n’abordera pas, par exemple, l’étude des
confidentielles certificats et de la signature des documents
n repérer qu’une information transmise a été ‰ Les transparents suivants donnent la terminologie
modifiée par une tierce personne avant habituelle liée à la sécurité
d’arriver à destination

R. Grin Sécurité Java EE page 9 R. Grin Sécurité Java EE page 10

Utilisateur Principal
‰ L’utilisateur d’une application est identifié par des
‰ Une fois qu’il est authentifié, l’utilisateur devient
« pièces d’identité », credentials en anglais, qui
un principal (terme anglais qui signifie mandant,
prouvent son identité commettant) au nom duquel il effectuera des
‰ Le plus souvent la saisie d’un nom de login et d’un opérations dans l’application
mot de passe prouve l’identité d’un utilisateur ‰ Un principal peut être un utilisateur, un groupe
‰ L’utilisateur peut correspondre à une personne ou d’utilisateurs, ou autre, qui a été défini dans
à une (partie d’une) application informatique l’environnement opérationnel d’exécution

R. Grin Sécurité Java EE page 11 Richard Grin EJB page 12

2
Rôle Rôles d’un utilisateur
‰ La politique de sécurité des serveurs d’application
‰ C’est celui qui déploie l’application qui associe
repose sur la notion de rôle
ces rôles
‰ Exemples de rôle : administrateur, organisateur,
participant, chef de service ‰ La manière dont un rôle est associé à un

‰ Un principal / utilisateur peut avoir un ou plusieurs


utilisateur n’est pas standard et dépend du
rôles dans une application serveur d’application
‰ Un rôle donne des droits aux utilisateurs qui ont ‰ Tomcat et GlassFish définissent des groupes
ce rôle d’utilisateurs et il est possible de les configurer
‰ La notion de rôle augmente la portabilité de pour qu’un groupe corresponde à un rôle (voir
l’application puisqu’on ne fait aucune prévision section « Configuration GlassFish » plus loin
sur l’existence d’utilisateurs particuliers dans ce support)
R. Grin Sécurité Java EE page 13 R. Grin Sécurité Java EE page 14

Groupes d’utilisateurs Realm – domaine de sécurité


‰ Pour authentifier les utilisateurs, les serveurs
‰ Les utilisateurs sont souvent regroupés en d’application doivent conserver des informations
groupes qui ont les mêmes types d’autorisation, sur ces utilisateurs
ce qui facilite l’attribution de rôles aux utilisateurs ‰ Un domaine de sécurité (realm), identifié par son
(on peut donner en bloc un rôle à tous les nom, définit comment ces informations sont
membres d’un groupe) conservées, et comment on les utilise pour
‰ Par exemple, le groupe des utilisateurs l’authentification (voir balise <login-config> de
enregistrés, le groupe des visiteurs non web.xml) ; la définition d’un realm n’est pas
enregistrés, le groupe des administrateurs standardisée
‰ Exemples : domaine défini par un fichier des mots
de passe, par des tables relationnelles, par un
R. Grin Sécurité Java EE page 15
registre LDAP, par des
R. Grin
certificats informatiquespage 16
Sécurité Java EE

Intervenants dans le
processus de développement
‰ Le développeur écrit l’application et indique les
rôles nécessaires pour les ressources protégées
Présentation de la sécurité
‰ L’administrateur du serveur d’application gère les
utilisateurs et les groupes d’utilisateurs dans Java EE
‰ Celui qui déploie l’application dans le serveur
d’application indique la correspondance entre les
utilisateurs et groupe d’utilisateurs et les rôles
définis par l’application (le plus souvent en
utilisant les fichiers de déploiement)

R. Grin Sécurité Java EE page 17 R. Grin Sécurité Java EE page 18

3
Principe général Déclaration ou programmation
‰ Écrire du code pour la sécurité est très complexe ‰ Java EE permet d’implémenter une politique de
et il est préférable de s’appuyer le plus possible sécurité de façon déclarative ou par
sur les facilités offertes par les serveurs programmation Java
d’application ‰ Le plus simple est d’utiliser les déclarations
(annotations Java ou fichiers de déploiement
XML) pour indiquer comment les ressources
sont protégées
‰ Si la façon déclarative ne suffit pas, il est
possible de programmer les cas les plus
complexes en Java
Richard Grin EJB page 19 R. Grin Sécurité Java EE page 20

Déclaration Fichiers de déploiement


‰ Les annotations permettent d’écrire les ‰ Fichiers standards qui ne dépendent pas du serveur
informations sur la politique de sécurité directement d’application : web.xml (module Web),
dans le code Java des EJB ou des servlets ejb-jar.xml (module EJB), application.xml
‰ Il n’est pas toujours possible d’utiliser une (module application qui peut regrouper plusieurs
annotation ; en ce cas les informations de sécurité modules dans un fichier EAR)
sont décrites dans des balises des fichiers de ‰ Chaque serveur d’application peut aussi avoir ses
déploiement propres fichiers de déploiement pour les informations
‰ Toutes les annotations ont leur pendant sous forme non standardisées ; pour GlassFish,
de balise XML ; en cas de contradiction, une glassfish-web.xml, glassfish-ejb-jar.xml,
information dans un fichier de déploiement glassfish-application-web.xml
l’emporte sur une annotation
R. Grin Sécurité Java EE page 21 R. Grin Sécurité Java EE page 22

Types de déclarations JAAS


‰ La sécurité en Java EE est basé sur Java
‰ Java EE permet de déclarer Authentication and Authorization Service (JAAS)
n les rôles utilisés par l’application qui est inclus dans Java SE (voir cours sur la
n la façon d’authentifier les utilisateurs sécurité en Java pour plus de détails)
n les pages Web protégées et les rôles qui y ont ‰ JAAS est centré sur l’utilisateur : il permet de
accès donner des permissions en se basant sur
n les classes ou méthodes Java protégées et les l’utilisateur qui exécute le code
rôles qui y ont accès ‰ JAAS s’appuie sur la notion de modules de login
qui permettent d’authentifier l’utilisateur en
utilisant un certain mode (par exemple en
consultant une base de données)
R. Grin Sécurité Java EE page 23 R. Grin Sécurité Java EE page 24

4
‰ Nous allons tout d’abord étudier comment définir
les rôles puis comment authentifier un utilisateur
‰ Nous verrons enfin comment protéger des pages
Web, puis comment restreindre l’accès à des Déclaration des rôles
méthodes Java
‰ L’attribution de rôles à un utilisateur n’est pas
standardisée ; elle sera étudiée pour le cas de
GlassFish

R. Grin Sécurité Java EE page 25 R. Grin Sécurité Java EE page 26

Déclaration des rôles Annotations pour les rôles


‰ Un rôle doit être déclaré avant d’être utilisé ‰ On verra les annotations @RolesAllowed,
‰ On peut le faire avec une annotation ou dans un @PermitAll et @DenyAll pour protéger l’accès
fichier de déploiement XML à des méthodes
‰ @RolesAllowed déclare automatiquement les
rôles concernés
‰ Dans des cas complexes, l’annotation
@DeclareRoles peut être utile pour utiliser le
nom d’un rôle dans une classe, sans que le rôle
ne soit déclaré par ailleurs

R. Grin Sécurité Java EE page 27 R. Grin Sécurité Java EE page 28

Annotation pour déclarer des rôles Exemples


‰ L’annotation @DeclareRoles peut être mise sur ‰ @Stateless
un EJB ou un servlet, au niveau de la classe @DeclareRoles("admin")
public class MonBean { ... }
‰ Elle peut prendre en paramètre un nom de rôle ou
‰ @Stateless
une liste de noms de rôle (entourée par des @DeclareRoles({"admin", "membre", "visiteur"})
accolades) public class MonBean {
‰ La casse (majuscules – minuscules) est @Resource
private SessionContext sc;
significative dans les noms de rôle
public void m() {
if (sc.isCallerInRole("membre")
...
}
R. Grin Sécurité Java EE page 29 R. Grin Sécurité Java EE page 30

5
Balise pour déclarer des rôles Référence d’un rôle
‰ Plusieurs balises <security-role> peuvent ‰ Le développeur utilise des noms de rôle dans son
être mises directement sous la balise racine code lorsqu’il écrit un module Java EE
(web-app, ejb-jar ou application) ‰ S’il réutilise son module dans plusieurs
‰ Exemple : applications, un nom de rôle peut avoir un autre
<security-role> nom dans les autres modules
<description>Administrateur</description>
‰ Avec la balise <security-role-ref> il est
<role-name>admin</role-name>
</security-role> possible de définir un alias pour un nom de rôle,
<security-role> pour faire correspondre le rôle du module avec un
<role-name>membre</role-name> rôle de l’environnement d’exécution
</security-role>

R. Grin Sécurité Java EE page 31 R. Grin Sécurité Java EE page 32

Exemple d’alias pour un rôle


‰ Le responsable du déploiement indiquera le rôle
de l’environnement de déploiement
(Controleur) associé au rôle indiqué par le
développeur d’EJB (Admin) : Authentification
<security-role-ref>
<description> . . . </description>
<role-name>Admin</role-name>
<role-link>Controleur</role-link>
</security-role-ref>
‰ Si l’utilisateur a le rôle Controleur,
isUserInRole("Admin") retourne true
Richard Grin Sécurité Java EE page 33 R. Grin Sécurité Java EE page 34

Type d’authentification Déclaration du type d’authentification


‰ Si l’utilisateur veut accéder à une page Web ‰ Pas d’annotation, il faut configurer avec la balise
protégée et qu’il n’est pas déjà enregistré, le <login-config> sous la balise racine du fichier
container Web cherche à l’authentifier web.xml
‰ Le plus souvent l’utilisateur s’authentifie en tapant ‰ 2 sous-balises :
son login et son mot de passe pour l’application n <auth-method> définit le mode d’authentification
dans un formulaire n <realm-name> indique le domaine de sécurité
‰ Un certificat peut aussi être utilisé pour dans lequel les informations pour l’authentification
l’authentification (mode CLIENT-CERT), à la seront cherchées ; il peut y en avoir plusieurs
place du login/mot de passe dans une application

R. Grin Sécurité Java EE page 35 R. Grin Sécurité Java EE page 36

6
Exemple Valeurs par défaut
<login-config> ‰ Par défaut, le mode d’authentification est le mode
<auth-method>BASIC</auth-method> BASIC : le login et le mot de passe sont demandés
<realm-name>candidatures</realm-name> à l’utilisateur par un formulaire affiché par le
</login-config> navigateur (ils transitent en clair sur le réseau)
‰ La valeur par défaut pour <realm-name> dépend
du serveur d’application
‰ Ce type risque de poser des problèmes car le
navigateur garde souvent des informations sur
l’utilisateur qui vient de se connecter ; préférer le
mode FORM
R. Grin Sécurité Java EE page 37 R. Grin Sécurité Java EE page 38

Autres modes d’authentification Exemple


‰ Plusieurs autres modes d’authentification, en plus <login-config>
du mode par défaut BASIC : <auth-method>FORM</auth-method>
n FORM : utilisation d’un formulaire écrit par le
<realm-name>candidatures</realm-name>
développeur dans une page Web pour obtenir <form-login-config>
le login et le mot de passe <form-login-page>/faces/login.xhtml</form-
login-page>
n DIGEST : utilisation d’un hachage pour le
<form-error-page>/faces/noaut.xhtml</form-
transport du mot de passe (MD5 par exemple) error-page>
n CLIENT-CERT : utilisation d’un certificat </form-login-config>
</login-config>

R. Grin Sécurité Java EE page 39 R. Grin Sécurité Java EE page 40

Mode FORM - pages Mode FORM - formulaire de login


‰ <form-login-config> ne sert que si ‰ Si on choisit le mode FORM, le formulaire écrit
<auth-method> a la valeur FORM, pour indiquer la par le développeur a des contraintes de nom pour
page qui contient le formulaire de login et celle qui n l’action exécutée lorsque le formulaire est
est affichée si le login et le mot de passe saisis ne soumis (j_security_check)
sont pas bons n les noms des champs qui contiennent le login
(j_username) et le mot de passe
(j_password)
‰ Ces contraintes vont permettre au container de
vérifier le login et le mot de passe suivant le
domaine de sécurité choisi par le développeur
R. Grin Sécurité Java EE page 41 R. Grin Sécurité Java EE page 42

7
Exemple de formulaire HTML Exemple de formulaire JSF
<form method="post" action="j_security_check">
<form method="POST" action="j_security_check"> <h:panelGrid columns="2">
Login : <h:outputLabel for="j_username"
<input type="text" name="j_username"/> value="Login" />
Mot de passe : <h:input id="j_username" />
<input type="password" name="j_password"/> <h:outputLabel for="j_password"
<input type="submit" value="Login"/> value="Mot de passe" />
</form> <h:inputSecret id="j_password"/>
<h:commandButton id="submit"
value="Login" />
</h:panelGrid>
</form>
R. Grin Sécurité Java EE page 43 R. Grin Sécurité Java EE page 44

Exemple de page d’erreur


<html> ‰ La méthode que l’on vient de voir est la façon la
<head> plus simple de filtrer les accès à une application
<title>Echec de l'authentification</title> ‰ Elle convient le plus souvent mais elle a des
</head> contraintes importantes (les action et propriétés
<body> pour enregistrer les login et mots de passe sont
<p>Désolé, vous n'avez pas tapé des bons imposés)
login et mot de passe. Essayez à nouveau.
</p> ‰ Depuis JSF 2.0, le développeur peut choisir une
</body> autre solution plus souple mais plus complexe à
</html> programmer

R. Grin Sécurité Java EE page 45 R. Grin Sécurité Java EE page 46

Méthode HttpServletRequest.login() Utilisation login – formulaire


‰ Depuis JSF 2.0, il est possible de récupérer le <h:form>
Login :
nom et le mot de passe comme on le souhaite et <h:inputText value="#{login.login}"
de passer les valeurs à la méthode required="true" /> <p/>
Mot de passe :
login(String nom, String mdp) de la <h:inputSecret value="#{login.mdp}"
classe HttpServletRequest pour s’authentifier required="true" /> <p/>
auprès du container (lance une <h:commandButton value="Connexion"
action="#{login.submit}">
ServletException si déjà connecté ou <f:ajax execute="@form" render="@form" />
mauvais login/mot de passe). </h:commandButton>
<h:messages globalOnly="true" />
</h:form>

R. Grin Sécurité Java EE page 47 R. Grin Sécurité Java EE page 48

8
Remarque sur le code Utilisation login – backing bean
‰ Le code du backing bean de la solution avec la @ManagedBean
@ViewScoped
méthode login est un peu complexe ; il tire parti
public class Login {
du fait que le container utilise un forward pour private String login, mdp;
faire afficher la page qui contient le formulaire de private String uri;
login
@PostConstruct
‰ Pour avoir l’URI de la page que voulait
public void init() {
l’utilisateur, il faut utiliser l’attribut de la requête uri = (String) FacesContext.getCurrentInstance()
RequestDispatcher.FORWARD_REQUEST_URI .getExternalContext().getRequestMap()
.get(RequestDispatcher.FORWARD_REQUEST_URI);
‰ Merci à BalusC (expert JSF) pour l’information
}

R. Grin Sécurité Java EE page 49 R. Grin Sécurité Java EE page 50

Utilisation login – backing bean Déconnexion


‰ L’authentification de l’utilisateur est valable pour
public void submit() throws IOException {
toute la session de travail HTTP
FacesContext context =
FacesContext.getCurrentInstance(); ‰ Avec le mode d’authentification FORM, il est
HttpServletRequest request = (HttpServletRequest) possible de faire sortir l’utilisateur de la session de
context.getExternalContext().getRequest();
travail avec la méthode logout() de la classe
try {
request.login(login, mdp); HttpServletRequest
context.redirect(uri); ‰ Cette méthode peut être appelée, par exemple,
} catch (ServletException e) {
facesContext.addMessage(...);
dans la méthode action d’un bouton sur lequel
} l’utilisateur peut cliquer pour se déconnecter
}
‰ Un exemple d’utilisation est donné dans la section
« Code Java pour la sécurité » de ce support
R. Grin Sécurité Java EE page 51 R. Grin Sécurité Java EE page 52

SSL Gestion des utilisateurs


‰ Les login et mot de passe seront passés en clair ‰ La gestion des utilisateurs (ajout d’un nouvel
sur le réseau utilisateur, modification,…) et la conservation des
‰ Il est possible d’utiliser SSL pour les protéger informations sur les utilisateurs dépend du
‰ Voir la section « Protection des pages Web »
serveur d’application
‰ La section « Sécurité avec GlassFish » donne un
exemple d’utilisation du serveur GlassFish

R. Grin Sécurité Java EE page 53 R. Grin Sécurité Java EE page 54

9
Changer l’id d’une session
‰ Pour éviter certaines formes de piratage, il peut ‰ Les sections suivantes montrent comment
être nécessaire de changer l’id d’une session en réserver l’accès des pages Web et des méthodes
cours de session Java des EJB ou des servlets aux utilisateurs qui
‰ Servlet 3.1 facilite ce changement de id avec : ont un certain rôle
n la méthode String changeSessionId() ‰ Ensuite, il est montré comment configurer
dans HttpServletRequest retourne le GlassFish pour les parties qui dépendent du
nouvel id de la session serveur d’application
n une interface écouteur
HttpSessionIdListener qui est prévenue
quand l’id de la session change
R. Grin Sécurité Java EE page 55 R. Grin Sécurité Java EE page 56

Utilité
‰ Le plus souvent des pages Web (définies par des
URL) ne doivent être accessibles que par certains
utilisateurs ou dans certaines circonstances
Protection des pages Web ‰ Cette section explique comment restreindre l’accès
d’une partie des pages d’une application à certains
utilisateurs

R. Grin Sécurité Java EE page 57 R. Grin Sécurité Java EE page 58

Erreurs HTTP pour la sécurité Schéma de protection


‰ Lorsqu’un utilisateur veut accéder à une page ‰ Le plus simple est d’utiliser le système de
protégée, il peut arriver les erreurs suivantes : sécurité offert par les containers de page Web
n erreur HTTP 401, Unauthorized, si l’utilisateur des serveurs d’application
ne fournit pas les credentials (le plus souvent ‰ Il est simple de grouper les pages à protéger
le bon mot de passe) dans un ou plusieurs répertoires et de filtrer
n erreur HTTP 403, Forbidden, si l’utilisateur a l’accès à ces répertoires
fournit les bons credentials mais n’a pas ‰ Pour les cas plus complexes de filtrage, il est
l’autorisation d’accéder à la page possible de coder le filtrage directement dans le
code Java de l’application

R. Grin Sécurité Java EE page 59 R. Grin Sécurité Java EE page 60

10
Déclaration des protections Notions utilisées
‰ La protection est déclarée dans le fichier web.xml ‰ L’application peut définir des contraintes de
par des contraintes de sécurité déclarées sur des sécurité (<security-constraint>)
ressources (les pages Web désignées par des ‰ Elles restreignent l’accès à des ressources (page
modèles d’URL) Web définies par leur URL) aux seuls utilisateurs
‰ Il est aussi possible de déclarer des contraintes de qui ont un certain rôle (plusieurs rôles peuvent être
sécurité dans un servlet (si l’application en a un) indiqués)
avec l’annotation @HttpConstraint contenue ‰ Lorsqu’un utilisateur veut accéder à une ressource
dans une annotation @ServletSecurity protégée, il doit être authentifié et il peut accéder à
la ressource s’il a les rôles requis par la ressource

R. Grin Sécurité Java EE page 61 R. Grin Sécurité Java EE page 62

Contraintes de sécurité Exemple


<security-constraint>
‰ Les sous balises de <security-constraint> : <web-resource-collection>
<web-resource-name>r1</web-resource-name>
n <web-resource-collection> indique les
<url-pattern>/liste.xhtml</url-pattern>
URLs des pages (<url-pattern>) et les </web-resource-collection>
méthodes HTTP protégées (<http-method>) <auth-constraint>
n <auth-constraint> indique les rôles qui <role-name>employe<role-name>
permettent d’accéder aux pages <role-name>drh<role-name>
</auth-constraint>
n <user-data-constraint> indique comment </security-constraint>
sont protégées les données échangées entre le
client et le serveur (aucune protection par défaut)

R. Grin Sécurité Java EE page 63 R. Grin Sécurité Java EE page 64

<url-pattern> Exemple - JSF


<security-constraint>
‰ Les pages protégées sont désignées par la sous-
<web-resource-collection>
balise <url-pattern> qui donne un chemin qui <web-resource-name>p1</web-resource-name>
peut comporter le joker * <url-pattern>/faces/candids/*</url-pattern>
‰ 3 Formats possibles pour un url-pattern : <url-pattern>/candids/*</url-pattern>
n commence par / et se termine par /* (toute page </web-resource-collection>
située sous le répertoire qui précède « /* », à <auth-constraint>
n’importe quelle profondeur <role-name>admin</role-name>
n commence avec *. et se termine par un <role-name>rsr</role-name>
caractère (par exemple *.jsf) </auth-constraint>
</security-constraint>
n commence par / et ne comporte pas de *
R. Grin Sécurité Java EE page 65 R. Grin Sécurité Java EE page 66

11
<http-method> Exemple
<security-constraint>
‰ L’accès est protégé pour toutes les méthodes <web-resource-collection>
HTTP si cette balise est omise <web-resource-name>r1</web-resource-name>
<url-pattern>/liste.xhtml</url-pattern>
‰ Si cette balise est présente, la protection ne <http-method>GET</http-method>
concerne que la méthode indiquée (GET et POST <http-method>POST</http-method>
pour l’exemple suivant) </web-resource-collection>
<auth-constraint>
<role-name>employe<role-name>
</auth-constraint>
</security-constraint>

R. Grin Sécurité Java EE page 67 R. Grin Sécurité Java EE page 68

<http-method> - erreur à éviter Exemple – avant Servlet 3.1


‰ Si une balise est présente, la protection ne ‰ Il faut ajouter la contrainte suivante :
concerne que la méthode indiquée (ici GET) <security-constraint>
<web-resource-collection>
‰ Une erreur serait de croire que l’accès est <web-resource-name>r1</web-resource-name>
<url-pattern>/liste.xhtml</url-pattern>
protégé pour les autres méthodes ; il faut donc <http-method-omission>GET</http-method-omission>
écrire une autre contrainte de sécurité qui interdit <http-method-omission>POST</http-method-omission>
les autres méthodes en utilisant éventuellement </web-resource-collection>
<auth-constraint/>
la balise <http-method-omission> </security-constraint>
‰ Servlet 3.1 facilite ceci avec
<deny-uncovered-http-methods/>

R. Grin Sécurité Java EE page 69 R. Grin Sécurité Java EE page 70

Exemple – depuis Servlet 3.1 Lien vers une page protégée


‰ Il suffit de modifier la 1ère contrainte ainsi : ‰ C’est l’URL de la page que l’on veut afficher qui
<deny-uncovered-http-methods/> est comparé aux patterns des pages protégées
<security-constraint>
<web-resource-collection> ‰ Si une page contient un lien vers une page
<web-resource-name>r1</web-resource-name> protégée, il faut écrire ce lien avec les composants
<url-pattern>/liste.xhtml</url-pattern>
<http-method>GET</http-method> <h:outputLink>, <h:button> ou <h:link>,
<http-method>POST</http-method> ou ajouter une redirection à un un lien avec un
</web-resource-collection>
<auth-constraint>
composant <h:commandButton> ou
<role-name>employe<role-name> <h:commandLink>
</auth-constraint>
</security-constraint>

R. Grin Sécurité Java EE page 71 R. Grin Sécurité Java EE page 72

12
Attention, pas de forward interne ! <auth-constraint>
‰ Un forward interne au serveur (méthode forward ‰ L’autorisation sera accordée si l’utilisateur a un
de RequestDispatcher) ne déclenche pas une des rôles indiqués
vérification des contraintes de sécurité puisque ‰ « * » indique que tous les rôles sont acceptés
l’URL n’est pas modifié ‰ « ** » indique que tous les utilisateurs authentifiés
‰ Ce qui signifie qu’un <h:commandButton> ou un sont acceptés (ajouté par Java EE 7)
<h:commandLink> (sans redirection) vers une ‰ S’il y a une balise <auth-constraint> mais
page protégée donnera accès à la page, même si aucune sous-balise <role-name>, les pages ne
l’utilisateur n’a pas l’autorisation d’accès à cette pourront être accédée par aucun utilisateur
page

R. Grin Sécurité Java EE page 73 R. Grin Sécurité Java EE page 74

Exemple <user-data-constraint>
<security-constraint> ‰ La balise <user-data-constraint> peut être
<web-resource-collection> ajoutée dans une balise <security-constraint>
<web-resource-name>r1</web-resource-name>
<url-pattern>/liste.xhtml</url-pattern>
pour indiquer que la connexion avec les pages
</web-resource-collection> protégées utilisera le protocole HTTPS
<auth-constraint> ‰ Elle contient une balise <transport-garantee>
<role-name>**<role-name> dont la valeur peut être égale à NONE (valeur par
</auth-constraint> défaut), CONFIDENTIAL ou INTEGRAL
</security-constraint>

R. Grin Sécurité Java EE page 75 R. Grin Sécurité Java EE page 76

Valeurs pour <transport-garantee> Exemple


‰ CONFIDENTIAL : les données transmises ne <security-constraint>
peuvent être vues par des tiers <web-resource-collection>
<web-resource-name>r1</web-resource-name>
‰ INTEGRAL : les données transmises ne peuvent être <url-pattern>/faces/restr/*</url-pattern>
modifiées par des tiers </web-resource-collection>
‰ NONE : pas de protection particulière <auth-constraint>
<role-name>employe<role-name>
‰ En pratique, les 2 modes CONFIDENTIAL et </auth-constraint>
INTEGRAL sont traités de la même façon par les <user-data-constraint>
serveurs d’application (utilisation de HTTPS) <transport-guarantee>
CONFIDENTIAL</transport-guarantee>
‰ Il est déconseillé de repasser en mode « normal »
</user-data-constraint>
après être passé en mode « SSL » ; si on veut le </security-constraint>
faire tout de même, il est nécessaire d’écrire du code
R. Grin Sécurité Java EE page 77 R. Grin Sécurité Java EE page 78

13
Avec les servlets Exemple 1
@WebServlet("/monurl")
‰ Dans le cas des applications qui n’utilisent pas @ServletSecurity(
les EJB, on peut utiliser les fichiers de @HttpConstraint(rolesAllowed={"r1", "r2"}))
configuration mais il est aussi possible de public class MaServlet extends HttpServlet

configurer la sécurité avec l’annotation


@ServletSecurity
L’URL /monurl sera réservée aux
‰ Les transparents suivant donne des exemples utilisateurs qui ont le rôle « r1 » ou
le rôle « r2 »

R. Grin Sécurité Java EE page 79 R. Grin Sécurité Java EE page 80

Exemple 2
@WebServlet("/monurl")
@ServletSecurity(
value=@HttpConstraint(
transportGuarantee=
ServletSecurity.TransportGuarantee.CONFIDENTIAL),
httpMethodConstraints={ Protéger les méthodes des EJB
@HttpMethodConstraint(
value="TRACE",
transportGuarantee=
ServletSecurity.TransportGuarantee.NONE,
rolesAllowed={"r1"}) })
public class MaServlet extends HttpServlet

R. Grin Sécurité Java EE page 81 R. Grin Sécurité Java EE page 82

Par déclaration Annotation @RolesAllowed


‰ Par défaut, toutes les méthodes sont accessibles ‰ Annote une méthode ou une classe (concerne
à tous les utilisateurs alors toutes les méthodes de la classe) protégée
‰ Il est possible de restreindre l’accès ‰ En paramètre, un seul rôle ou plusieurs rôles de
n avec une annotation
type String entourés d’accolades (les
n avec les fichiers de déploiement XML
utilisateurs ayant un des rôles peuvent utiliser la
méthode ou la classe) :
‰ Les fichiers XML l’emportent sur les annotations @RolesAllowed("role1")
@RolesAllowed({ "role1", "role2" })

R. Grin Sécurité Java EE page 83 R. Grin Sécurité Java EE page 84

14
Annotation @PermitAll Annotation @DenyAll
‰ Peut annoter une classe ou une méthode ; elle ‰ Ne peut annoter qu’une méthode ; elle indique
indique que toutes les méthodes de la classe que la méthode annotée n’est accessible par
annotée, ou la méthode annotée, sont autorisées aucun utilisateur
à tous les utilisateurs ‰ Cette annotation est rarement utilisée car la
‰ Si la classe est protégée, cette annotation permet méthode annotée ne pourra pas être utilisée à
d’exclure une méthode de la protection : tous les l’intérieur d’un container Java EE
utilisateurs seront autorisés à utiliser la méthode
annotée par @PermitAll

R. Grin Sécurité Java EE page 85 R. Grin Sécurité Java EE page 86

Exemple de déclarations (1/2) Exemple de déclarations (2/2)


<method-permission>
<ejb-jar>
<role-name>Controleur</role-name>
<assembly-descriptor> <method>
<security-role> <ejb-name>Compte</ejb-name>
<description>Employés chargés des clients <method-name>getBalance</method-name>
</description> </method>
<role-name>Caissier</role-name> <method>
</security-role> <ejb-name>Compte</ejb-name>
<security-role> <method-name>setBalance</method-name>
<description>Contrôleur</description> </method>
</method-permission>
<role-name>Controleur</role-name>
</assembly-descriptor>
</security-role>
</ejb-jar>
R. Grin Sécurité Java EE page 87 R. Grin Sécurité Java EE page 88

Méthodes non protégées Méthodes non accessibles


‰ Certaines méthodes sont autorisées à tous ‰ Des méthodes peuvent ne pas être accessibles
(<unchecked/>): pour un déploiement :
<method-permission> <exclude-list>
<unchecked/> <description>Méthode m1 de Ejb1 interdite
<method> </description>
<method>
<ejb-name>Compte</ejb-name> <ejb-name>Ejb1</ejb-name>
<method-name>getNames</method-name> <method-name>m1</method-name>
</method> </method>
</exclude-list>

R. Grin Sécurité Java EE page 89 R. Grin Sécurité Java EE page 90

15
Annotation @RunAs Balise run-as
‰ Dans un fichier de configuration :
‰ Peut annoter une méthode d’un EJB (si la classe <session>
EJB est annotée, toutes les méthodes de la <ejb-name>. . . </ejb-name>
classe sont concernées) . . .
<security-identity>
‰ Le paramètre est le nom du rôle que l’utilisateur <run-as>
prendra pendant qu’il exécutera la méthode <role-name>admin</role-name>
</run-as>
‰ Exemple :
</security-identity>
@RunAs("admin") . . .
‰ Même utilité que le « suid » d’Unix : donner </session>
temporairement une autorisation à un utilisateur

R. Grin Sécurité Java EE page 91 R. Grin Sécurité Java EE page 92

use-caller-identity AccessLocalException
‰ Pour être certain qu’on utilisera le principal et pas ‰ Cette exception du paquetage javax.ejb est levée
un rôle donné par une méthode EJB « run-as », si une méthode est appelée alors que les
on peut indiquer use-caller-identity pour autorisations ne sont pas suffisantes
un EJB ; en ce cas, les rôles transmis seront les
rôles liés à la vraie identité de l’utilisateur (sinon
ça serait le rôle donné par « run-as ») :
<security-identity>
<use-caller-identity/>
</security-identity>

R. Grin Sécurité Java EE page 93 R. Grin Sécurité Java EE page 94

Sécurité par programmation


‰ Dans certains cas la déclaration des autorisations
dans les fichiers de déploiement ou par des
Code Java pour la sécurité annotations n’est pas assez souple
‰ Dans ces cas, on peut écrire du code Java qui
prend en compte les cas particuliers
‰ L’exemple suivant montre comment distinguer
des utilisateurs qui ont le même rôle dans une
application JSF

R. Grin Sécurité Java EE page 95 R. Grin Sécurité Java EE page 96

16
Cas d’utilisation
‰ Dans une application qui gère des formations, les ‰ Les transparents suivants étudient le cas d’une
utilisateurs doivent ouvrir un compte application JSF, avec le code qu’un backing bean
‰ Ce compte leur donne le rôle « etudiant » qui leur peut contenir
permet de s’inscrire à des cours et de participer à ‰ On verra ensuite comment obtenir les mêmes
des forums informations dans une méthode d’un EJB session
‰ Cependant ces étudiants ne peuvent voir et modifier
que leurs données personnelles, ce qui impose une
programmation en Java

R. Grin Sécurité Java EE page 97 R. Grin Sécurité Java EE page 98

Nom de l’utilisateur connecté Nom de l’utilisateur connecté avec CDI


‰ CDI fournit un bean de type java.security.Principal ;
‰ Il est possible de récupérer le nom de l’utilisateur
avec le code suivant : il suffit de l’injecter dans un backing bean (ou ailleurs)
FacesContext context = pour récupérer le nom de l’utilisateur connecté
FacesContext.getCurrentInstance(); (ANONYMOUS si l’utilisateur ne s’est pas authentifié)
HttpServletRequest request = ‰ Exemple :
(HttpServletRequest) @Named @RequestScoped
context.getExternalContext().getRequest(); public class Bean {
String login = request.getRemoteUser(); @Inject
private Principal principal;
public String getNomUtilisateur() {
return principal.getName();
}
R. Grin Sécurité Java EE page 99 R. Grin Sécurité Java EE page 100

Classe ExternalContext Méthodes de ExternalContext


‰ Cette classe du paquetage ‰ boolean isUserInRole(String nomRole)
javax.faces.context permet d’obtenir des retourne true si celui qui appelle la méthode
informations sur l’environnement d’exécution ; remplit bien le rôle passé en paramètre
elle contient en particulier des méthodes utiles ‰ java.security.Principal
pour la sécurité getUserPrincipal() permet d’avoir le principal
‰ Une instance peut être obtenue par de celui qui appelle la méthode, ce qui permet de
FacesContext.getCurrentInstance() distinguer des utilisateurs qui ont le même rôle
.getExternalContext() ‰ Object getRequest() récupère la requête en
cours (caster en
javax.servlet.http.HttpServletRequest)
R. Grin Sécurité Java EE page 101 R. Grin Sécurité Java EE page 102

17
Exemple avec JSF Sortir d’une application JSF
... ‰ Après ce code (qu’on peut mettre, par exemple,
String login = request.getRemoteUser(); dans l’action d’un bouton), l’utilisateur devra à
if (<condition sur login>) { nouveau s’authentifier pour les fonctionnalités qui
FacesContext.getCurrentInstance() nécessite une authentification :
.getExternalContext() try {
.redirect(autrePage); ((HttpServletRequest)FacesContext
} .getCurrentInstance()
... .getExternalContext()
.getRequest()).logout();
} catch (ServletException ex) {

}
R. Grin Sécurité Java EE page 103 R. Grin Sécurité Java EE page 104

Dans un EJB Méthodes de EJBContext


‰ Pour filtrer les accès aux méthodes des EJB dans ‰ EJBContext contient des méthodes liées à
le cas où la granularité de protection offerte par les l’authentification des utilisateurs :
rôles ne suffit pas, il est possible d’utiliser les n Principal getCallerPrincipal()
méthodes de l’interface javax.ejb.EJBContext n boolean isCallerInRole(String role)
‰ Cette interface est implémentée par la classe ‰ Elles jouent le même rôle que les méthodes de
javax.ejb.SessionContext l’interface ExternalContext (avec « User » à
‰ On peut obtenir une instance de SessionContext la place de « Caller »)
en l’injectant dans un EJB session :
@Resource
private SessionContext contexte;
R. Grin Sécurité Java EE page 105 R. Grin Sécurité Java EE page 106

Exemple
// Méthode interdite à certains utilisateurs
String login =
contexte.getCallerPrincipal().getName();

Configuration de GlassFish
if (condition sur login) {
// l’utilisateur n’a pas le droit
// de faire exécuter ce traitement
throw new TrucException(...);
}
// Traitement métier effectué par la méthode
...

R. Grin Sécurité Java EE page 107 R. Grin Sécurité Java EE page 108

18
Mode de configuration Console d’administration de GlassFish
‰ GlassFish peut être configuré ‰ Elle s’affiche dans un navigateur en tapant
n du côté du serveur : avec la console l’adresse du serveur, suffixé avec « :4848 » (port
d’administration ou avec la commande d’écoute)
asadmin ‰ Exemple :
n en ajoutant dans l’application des fichiers de http://localhost:4848
configuration de déploiement particuliers à
GlassFish ; ces fichiers seront pris en compte
par GlassFish quand l’application sera
déployée sur le serveur

R. Grin Sécurité Java EE page 109 R. Grin Sécurité Java EE page 110

Commande asadmin (1/2) Commande asadmin (2/2)


‰ Cette commande est située dans le répertoire bin du ‰ On peut travailler avec asadmin en mode interactif
répertoire d’installation de GlassFish (répertoire en tapant « asadmin multimode » ; un prompt
affiché dans la console d’administration de « asadmin> » apparaît et on peut taper plusieurs
GlassFish) commandes ; taper « exit » pour sortir
‰ La commande asadmin prend en paramètre des ‰ On peut aussi lancer un script qui contient des
commandes qui permettent de configurer le serveur commandes par « asadmin multimode --file
(« asadmin --help » affiche une aide ; « asadmin script.txt »
commande --help » affiche une aide sur une
commande)

R. Grin Sécurité Java EE page 111 R. Grin Sécurité Java EE page 112

Si GlassFish ne veut plus démarrer Fichiers de déploiement GlassFish


‰ Il peut s’agir d’un problème de configuration ‰ Ils ont les mêmes noms que les fichiers de
‰ A essayer : déploiement standard, préfixés par « glassfish- » :
n Aller dans le répertoire qui contient domain.xml ; il glassfish-application.xml, glassfish-ejb-jar.xml,
contient aussi un fichier domain.xml.bak qui est la glassfish-web.xml
l’avant-dernière version de domain.xml
n Conserver les 2 fichiers et ensuite renommer
domain.xml.bak en domain.xml et essayer de
redémarrer GlassFish
n Si GlassFish redémarre, essayer de comprendre le
problème en faisant un « diff » des 2 fichiers (peut
venir, par exemple, de caractères particuliers, accents
ou autres, dans les chemins des fichiers désignés)
R. Grin Sécurité Java EE page 113 R. Grin Sécurité Java EE page 114

19
Affecter les rôles avec GlassFish Indiquer une correspondance avec un rôle
‰ Pour indiquer la correspondance entre les groupes
‰ La manière dont un rôle est associé à un utilisateur
dépend du serveur d’application (ou les utilisateurs) et les rôles, 2 possibilités :
n utiliser un fichier de déploiement de l’application
‰ GlassFish (et Tomcat) définit des groupes
d’utilisateurs particulier à GlassFish pour donner les
correspondances entre groupes et rôles
‰ On peut affecter un ou plusieurs rôles à un groupe
n utiliser la console d’administration de GlassFish
ou à un utilisateur
ou la commande asadmin pour indiquer que les
‰ Pour simplifier, il est aussi possible de configurer
rôles correspondent aux groupes d’utilisateurs
GlassFish pour que les groupes ou les utilisateurs
ou utilisateurs de même nom de GlassFish
correspondent aux rôles de même noms
(s’applique à toutes les applications qui
n’utilisent pas la 1ère possibilité)
R. Grin Sécurité Java EE page 115 R. Grin Sécurité Java EE page 116

Avec un fichier de déploiement Exemple


‰ Pour indiquer une correspondance entre un <?xml version="1.0" encoding="UTF-8"?>
groupe (group-name) ou un utilisateur <!DOCTYPE glassfish-web-app PUBLIC "…"
"http://glassfish.org/…">
(principal-name) et un rôle (role-name) il
<glassfish-web-app>
suffit d’ajouter une balise ... Dans glassfish-web.xml
<security-role-mapping> sous la balise <security-role-mapping>
racine du fichier <role-name>admin</role-name>
<principal-name>root</principal-name>
<principal-name>bob</principal-name>
<group-name>administrateur</group-name>
</security-role-mapping>
...
R. Grin Sécurité Java EE page 117 R. Grin Sécurité Java EE page 118

Par défaut, principal = rôle Par défaut, principal = rôle


‰ Pour simplifier, il est possible d’indiquer à GlassFish ‰ Avec la commande asadmin :
que les groupes ou utilisateurs correspondent aux asadmin set server-config.security-service.activate-default-
rôles de même nom (sauf si une correspondance principal-to-role-mapping=true
asadmin set server-config.security-service.mapped-
explicite d’un rôle et d’un principal est donnée)
principal-class=CustomPrincipalImplClass
‰ Les applications déjà déployées ne sont pas
‰ Avec le menu de la console d’administration :
affectées par une modification de l’activation du
Configuration > server-config > Securité > Cocher
mapping par défaut des principaux avec des rôles
la case Default Principal To Role Mapping (en
‰ Pendant le développement il ne faut donc pas français : Mise en correspondance par défaut des
oublier de redéployer l’application après un principaux avec des rôles)
changement de statut de cette activation
R. Grin Sécurité Java EE page 119 R. Grin Sécurité Java EE page 120

20
Gestion des utilisateurs Domaine de sécurité
‰ La manière de conserver les informations sur ‰ Dans GlassFish il y a les types de realms suivants :
l’identité de l’utilisateur, telles que les logins et n file (informations dans un simple fichier ;

mots de passe, n’est pas standard domaine par défaut)


‰ GlassFish et Tomcat utilisent pour cela la notion n jdbc (dans des tables d’un SGBDR)

de domaine (realm en anglais) qui correspond au n ldap (utilise un registre LDAP)


domaine utilisée dans la balise <realm-name> n certificate (utilise des certificats)
de la balise <login-config>
‰ Il est aussi possible de créer son propre type de
realm (pas étudié dans ce cours)

R. Grin Sécurité Java EE page 121 R. Grin Sécurité Java EE page 122

Créer un domaine de sécurité


‰ asadmin create-auth-realm ‰ Les transparents suivants étudient le type de
permet de créer un realm domaine JDBC qui est souvent utilisé car il
‰ On peut aussi passer par les menus de la permet d’ajouter simplement de nouveaux
console d’administration (voir exemple à suivre utilisateurs (des utilisateurs peuvent ainsi, par
pour un domaine de type JDBC) exemple, créer leur propre « espace membre »
pour l’application)

R. Grin Sécurité Java EE page 123 R. Grin Sécurité Java EE page 124

Étapes pour créer un domaine JDBC Structure des tables


1. Créer les tables qui contiennent les informations ‰ La table des utilisateurs doit avoir
sur les utilisateurs n une colonne qui contient le nom de login
2. Définir une source de données liée à la base de n une colonne qui contient le mot de passe (en clair ou
données qui contient ces tables crypté) ; de type chaîne de caractères dont la longueur
dépend du codage du mot de passe
3. Créer le domaine JDBC
‰ La table des groupes (en fait la table qui fait
correspondre un groupe et un utilisateur) doit avoir
n une colonne qui contient le nom d’un groupe
n une colonne qui contient un nom de login
‰ Ces tables peuvent avoir d’autres colonnes
R. Grin Sécurité Java EE page 125 R. Grin Sécurité Java EE page 126

21
Exemple de création des tables Exemple de données
‰ Table des utilisateurs (mot de passe crypté en ‰ Dans la table des groupes :
SHA256 avec codage Hex ; il faut donc 64 toto, groupe1
caractères) : toto, groupe2
create table utilisateur ( admin, admin
login varchar(20) primary key, pour indiquer que toto appartient aux groupes
mot_de_passe varchar(64)) groupe1 et groupe 2 et admin appartient au
‰ Table des groupes : groupe admin
create table groupe (
nom_groupe varchar(20),
login varchar(20))
R. Grin Sécurité Java EE page 127 R. Grin JSF page 128

Vues au-dessus des tables Exemple de vue pour les groupes


‰ Si ces informations (login et groupe) sont dans ‰ Table utilisateur(login, mot_de_passe, email)
des tables qui n’ont pas exactement le format ‰ Table groupe(id_groupe, nom_groupe)
voulu, il est possible d’utiliser des vues et non pas ‰ Table groupe_utilisateur(id_groupe, login) ; le
des tables dans la définition des domaines problème est que id_groupe est utilisé et pas
‰ L’exemple suivant est le cas fréquent où un nom-groupe
groupe est identifié par un id non significatif et où ‰ Vue v_groupe_utilisateur qui va servir comme
la correspondance entre un groupe et un login « table » des groupes :
utilise cet id et pas le nom du groupe ; il faut créer create view v_groupe_utilisateur as
une vue qui fera correspondre un login et un nom select login, nom_groupe
de groupe, et qui sera utilisée pour la définition du from groupe join groupe_utilisateur
domaine de sécurité on groupe.id_groupe = groupe_utilisateur.id_groupe
R. Grin Sécurité Java EE page 129 R. Grin Sécurité Java EE page 130

Définition de la source de données Pool de connexions


‰ Il faut maintenant créer une source de données ‰ Il décrit l’accès à la base de données (machine
dont une référence sera rangée dans l’annuaire serveur, nom de la base, port d’écoute,..)
JNDI de GlassFish utilisable par l’application ‰ Avec les menus de la console d’administration :
‰ Il faut commencer par créer un pool de Ressources > JDBC > Pool de connexions JDBC
connexions JDBC puis créer la source de données ‰ Avec asadmin create-jdbc-connection
en utilisant ce pool de connexions ‰ Exemple asadmin :
‰ 2 possibilités : asadmin create-jdbc-connection-pool --
n avec la console d’administration de GlassFish
datasourceclassname oracle.jdbc.pool.OracleDataSource --
restype javax.sql.DataSource --property
n avec la commande asadmin
user=dbuser:password=mdpdb:url="jdbc:oracle\:thin\:@loca
lhost\:1521\:ORCL" monpool
R. Grin Sécurité Java EE page 131 R. Grin Sécurité Java EE page 132

22
Ressource JDBC Création d’un realm JDBC (1/4)
‰ Il faut ensuite créer une ressource JDBC en ‰ Console d’administration de GlassFish
utilisant le pool de connexions ; on lui donnera le ‰ Configurations > server-config > Sécurité >
nom JNDI jdbc/candidatures pour l’utiliser dans Domaines
les transparents suivants ‰ Cliquer Nouveau
‰ Avec les menus de la console d’administration :
‰ Nom : candidatures
Ressources > JDBC > Resources JDBC
‰ Nom de classe : celle qui se nomme JDBCRealm
‰ Avec asadmin create-jdbc-resource
‰ Il s’affiche des propriétés qu’il faut renseigner
‰ Exemple :
(éviter de taper des lettres accentuées ;
asadmin create-jdbc-resource --connectionpoolid monpool
jdbc/masource problèmes possibles)

R. Grin Sécurité Java EE page 133 R. Grin JSF page 134

Création d’un realm JDBC (2/4) Création d’un realm JDBC (3/4)
‰ Contexte de JAAS : jdbcRealm ‰ Algorithme condensé : algorithme de hachage
‰ JNDI : jdbc/candidatures (nom de la source de utilisé pour condenser le mot de passe ; SHA256
données qui contient les tables) par défaut (MD5 dans les anciennes versions de
‰ Table d’utilisateurs : PERSONNE (attention à
GlassFish)
respecter la casse des tables de la BD si MySQL) ‰ Codage : indique comment le mot de passe

‰ Colonne de nom d’utilisateur : LOGIN


condensé (suite d’octets) sera enregistré sous la
forme d’une chaîne de caractères dans la base
‰ Colonne de mot de passe : MOT_DE_PASSE
de données (Hex ou Base64) ; pour Hex qui est
‰ Table de groupes : GROUPE la valeur par défaut, la chaîne de caractères sera
‰ Colonne de nom de groupe : NOM_GROUPE de longueur 32 pour MD5 et de longueur 64 pour
SHA256
R. Grin JSF page 135 R. Grin JSF page 136

Création d’un realm JDBC (4/4) Modification d’un domaine de sécurité


‰ Le charset indique quel codage des caractères ‰ Il faut relancer GlassFish pour qu’il tienne compte
est utilisé pour convertir en byte[] un mot de des modifications (à vérifier…)
passe tapé par l’utilisateur, pour lui appliquer
ensuite la fonction de hachage ; par défaut c’est
le codage par défaut du système (UTF-8 le plus
souvent)

R. Grin JSF page 137 R. Grin Sécurité Java EE page 138

23
En cas d’erreur Commandes asadmin en batch
‰ Il est possible d’écrire un script (fichier texte) qui
‰ Attention, si le domaine de sécurité n’est pas
défini, le message d’erreur de GlassFish ne contient plusieurs commandes de asadmin et de
l’indique pas ; pour tous les login / mot de passe, lancer son exécution en « batch » par
il dit seulement que le login a échoué asadmin multimode --file script.txt
‰ Le transparent suivant contient un exemple de
script avec 3 commandes pour créer un domaine
de sécurité JDBC ; il faudra remplacer les 12
« variables » (dans 15 emplacements) par de
valeurs car il n’y a pas de notion de variable avec
les scripts asadmin ; ne pas passer à la ligne à
l’intérieur de chaque commande asadmin
R. Grin Sécurité Java EE page 139 R. Grin Sécurité Java EE page 140

Exemple Exemple qui utilise Java DB (Derby)


asadmin create-jdbc-connection-pool --datasourceclassname asadmin create-jdbc-connection-pool --datasourceclassname
org.apache.derby.jdbc.ClientDataSource --restype javax.sql.DataSource org.apache.derby.jdbc.ClientDataSource --restype javax.sql.DataSource
--property PortNumber=${DATABASE_PORT}: --property
Password=${DATABASE_PASSWORD}:User=${DATABASE_USER}:Se PortNumber=1527:Password=toto:User=toto:ServerName=localhost:Dat
rverName=localhost:DatabaseName=${DATABASE_NAME} abaseName=base1 derbyPool
${CONNECTION_POOL_NAME} asadmin create-jdbc-resource --connectionpoolid derbyPool jdbc/db
asadmin create-jdbc-resource --connectionpoolid asadmin create-auth-realm --classname
${CONNECTION_POOL_NAME} ${JNDI_NAME} com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property user-
asadmin create-auth-realm --classname name-column=LOGIN:password-column=MOT_DE_PASSE:group-
com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property user- name-column=NOM_GROUPE:jaas-context=jdbcRealm:datasource-
name-column=${USER_NAME}:password- jndi="jdbc/db":group-table=GROUPE:user-table=PERSONNE realm1
column=${PASSWORD}:group-name-column=${GROUP_NAME}:jaas-
context=jdbcRealm:datasource-jndi="${JNDI_NAME}":group-
table=${GROUP_TABLE}:user-table=${USER_TABLE}
${REALM_NAME}
R. Grin Sécurité Java EE page 141 R. Grin Sécurité Java EE page 142

Modifier le fichier web.xml Extrait de web.xml


‰ Il faut maintenant indiquer que ce realm devra <login-config>
être utilisé lors de l’identification des utilisateurs <auth-method>FORM</auth-method>
‰ Un exemple d’utilisation du realm <realm-name>candidatures</realm-name>
« candidatures » est donné dans le transparent <form-login-config>
suivant <form-login-page>/faces/login.xhtml
</form-login-page>
<form-error-page>/faces/noauth.xhtml
</form-error-page>
</form-login-config>
</login-config>

R. Grin JSF page 143 R. Grin JSF page 144

24
‰ Cet exemple va utiliser une authentification avec
le domaine JDBC et un formulaire écrit par le
Un exemple avec template développeur (type FORM)

R. Grin Sécurité Java EE page 145 R. Grin Sécurité Java EE page 146

Modèle de page Exemple de template (1/3)


‰ Si on veut que toutes les pages de l’application <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-...N" ...>
indiquent le nom de l’utilisateur et permettent de
<html xmlns="http://www.w3.org/1999/xhtml"
se déconnecter de l’application, il faut prévoir un xmlns:ui="http://java.sun.com/jsf/facelets"
template qui contient ces fonctionnalités xmlns:h="http://java.sun.com/jsf/html"
‰ Les transparents suivant donnent un exemple xmlns:f="http://java.sun.com/jsf/core">

d’un tel template


<f:event type="preRenderView"
‰ Les détails sont donnés dans la section « Code listener="#{bean.infosUser}" />
Java pour la sécurité » de ce cours et dans le
cours JSF sur les templates <ui:insert name="metadata"/> Pour retrouver les
informations sur l’utilisateur

R. Grin Sécurité Java EE page 147 R. Grin Sécurité Java EE page 148

Exemple de template (2/3) Exemple de template (3/3)


<h:head> <h:body>
<meta http-equiv="Content-Type" <div id="top" class="top">
content="text/html; charset=UTF-8" /> <ui:insert name="top">
<h:outputStylesheet library="css" #{bundle.titreGeneral} -
name="cssLayout.css" /> <h:outputText value="#{bean.login.login}"
<title>#{bundle.titreGeneral}</title> rendered="#{bean.login.login} != ''"/> -
</h:head> <h:outputText value="#{bean.login.nom}"
Pour internationaliser ; dans faces-config.xml : rendered="#{bean.login.nom} != ''"/>
<resource-bundle> </ui:insert>
<base-name>/Bundle</base-name> </div>
<var>bundle</var> ...
</resource-bundle>
</body>

R. Grin Sécurité Java EE page 149 R. Grin Sécurité Java EE page 150

25
Code bean session - getLogin Code bean session - infosUser
public Login getLogin() { public void infosUser(ComponentSystemEvent event) {
// login contient la personne connectée if (login != null) { // infos déjà obtenues
if (login == null) { return;
String nomUtilisateur = }
FacesContext.getCurrentInstance() String loginUtilisateur =
.getExternalContext().getRemoteUser(); ((HttpServletRequest)
if (nomUtilisateur != null) { FacesContext.getCurrentInstance()
login = loginFacade.find(nomUtilisateur); .getExternalContext().getRequest())
.getRemoteUser();
}
if (loginUtilisateur != null) {
}
login = loginFacade.find(loginUtilisateur);
return login;
}
}
}
R. Grin Sécurité Java EE page 151 R. Grin Sécurité Java EE page 152

Déconnexion Code bean session - logout


‰ Il faut permettre à l’utilisateur de se déconnecter public String logout() {
login = null;
‰ Le plus simple est d’ajouter un bouton pour cela try {
qui appelle une méthode du backing bean qui ((HttpServletRequest)
appelle la méthode logout() de la classe FacesContext.getCurrentInstance()
.getExternalContext().getRequest()).logout();
HttpServletRequest
} catch (ServletException ex) {
Logger.getLogger(Bean.class.getName())
.log(Level.SEVERE, null, ex);
}
return "/index";
}

R. Grin Sécurité Java EE page 153 R. Grin Sécurité Java EE page 154

Écrire dans les fichiers de logs


‰ Dans du code Java, System.out.println
Logs dans GlassFish - envoie dans les logs de GlassFish au niveau
INFO
Mise au point ‰ System.err.println envoie dans les logs de
GlassFish au niveau SEVERE
‰ Il est aussi possible d’écrire à d’autres niveau en
utilisant explicitement l’API de logging du JDK

R. Grin Sécurité Java EE page 155 R. Grin Sécurité Java EE page 156

26
Exemple Afficher les logs
import java.util.logging.Logger; ‰ Les derniers logs s’affichent avec la console
... d’administration de GlassFish : serveur, onglet
private Logger log =
Logger.getLogger(MaClass.class.getName());
« Général », bouton « Afficher les fichiers
... journaux »
log.warning("Mon message."); ‰ On peut aussi aller directement voir le contenu
des fichiers

R. Grin Sécurité Java EE page 157 R. Grin Sécurité Java EE page 158

Où se trouvent les logs Configuration des logs


‰ Les fichiers de logs se trouvent par défaut dans le ‰ Dans la console d’administration, Configurations,
répertoire glassfish/domains/domain1/logs du « Paramètres du journaliseur » (Logger Settings
répertoire d’installation de GlassFish (si on an anglais)
travaille avec le domaine domain1), par exemple
dans
C:\Program Files\glassfish-3.1.2
\glassfish\domains\domain1\logs
‰ Attention, sous Windows, ces fichiers peuvent
être ailleurs (voir les propriétés du serveur sous
NetBeans, champ « Domains folder »)
R. Grin Sécurité Java EE page 159 R. Grin Sécurité Java EE page 160

Pour la mise au point avec GlassFish


‰ Configurer le niveau du logger de GlassFish
javax.enterprise.system.core.security à FINEST
avec la console d’administration de GlassFish Gérer les mots de passe
(Configurations, server-config, Paramètres du
logger/journaliseur en français, onglet Niveaux de
journalisation)
‰ Des informations intéressantes pour résoudre des
problèmes de sécurité sont alors affichées dans
les logs de GlassFish

R. Grin Sécurité Java EE page 161 R. Grin Sécurité Java EE page 162

27
Conserver les mots de passe
‰ Cette section expose quelques généralités sur la ‰ Pour authentifier les utilisateurs, 2 solutions :
gestion des login / mots de passe n s’appuyer sur un système d’authentification
externe, tel LDAP
n gérer les mots de passe dans l’application

‰ Nous allons étudier le 2ème cas

R. Grin Sécurité Java EE page 163 R. Grin Sécurité Java EE page 164

A ne pas faire ! Saler !


‰ Ne jamais conserver les mots de passe en clair ‰ Les mots de passe doivent donc être conservés
dans l’application cryptés dans l’application
‰ Ne pas utiliser des algorithmes de cryptage ou de ‰ Pour compliquer la recherche d’une série de mots
hashage faciles à déjouer de passe, il faut ajouter une valeur aléatoire, le
‰ Par exemple, ne pas utiliser MD5 (aller par sel, différente pour tous les utilisateurs, qui sera
exemple sur le site http://www.md5hacker.com/ ajoutée au mot de passe de chaque utilisateur
qui permet de trouver rapidement un mot de ‰ Le sel peut être conservé en clair avec le mot de
passe qui correspond à une valeur MD5) passe crypté

R. Grin Sécurité Java EE page 165 R. Grin Sécurité Java EE page 166

Utilisation du sel Mots de passe avec GlassFish


‰ Les dernières versions de GlassFish utilisent par
‰ L’application récupère le mot de passe tapé par défaut le codage SHA-256 pour hacher les mots
l’utilisateur, elle concatène le sel au mot de passe et de passe (on peut choisir lorsqu’on définit un
elle crypte le tout en une valeur v1 domaine de sécurité)
‰ L’application vérifie que la valeur v0 qu’elle conserve
‰ GlassFish récupère le mot de passe par un
(le mot de passe de l’utilisateur, concaténé au sel et getString alors que les algorithmes de hashage
crypté au moment de l’enregistrement du mot de fournissent un tableau d’octets ; la façon de
passe) est bien égale à v1 ; si ça n’est pas le cas, passer du tableau d’octets à une String doit être
c’est que le mot de passe tapé n’était pas le bon indiquée dans la définition du domaine
‰ En standard GlassFish ne permet pas de saler
les mots de passe
R. Grin Sécurité Java EE page 167 R. Grin Sécurité Java EE page 168

28
Enregistrer un mot de passe Exemple de code
‰ On peut l’enregistrer sous la forme de byte[] ou ‰ L’exemple suivant peut être utilisé tel quel dans
de String une application qui voudrait gérer elle-même
‰ Hex est le codage utilisé par défaut par GlassFish l’authentification en utilisant du sel
(écriture en hexadécimal de chaque octet et ‰ Il est extrait et adapté du code de Jerry Orr donné
concaténation de tous les octets ; 2 caractères dans un article qui traite de la façon de conserver
par octet) les mots de passe, trouvé à l’adresse
‰ Base64 peut aussi être utilisé pour la http://jerryorr.blogspot.fr/2012_05_01_archive.html
transformation de byte[] en String

R. Grin Sécurité Java EE page 169 R. Grin Sécurité Java EE page 170

Exemple de code (1/4) Exemple de code (2/4)


import java.security.NoSuchAlgorithmException; public boolean authenticate(
import java.security.SecureRandom; String attemptedPassword, byte[] encryptedPassword,
import java.security.spec.InvalidKeySpecException; byte[] salt)
import java.security.spec.KeySpec; throws NoSuchAlgorithmException,
import java.util.Arrays; InvalidKeySpecException {
import javax.crypto.SecretKeyFactory; byte[] encryptedAttemptedPassword =
import javax.crypto.spec.PBEKeySpec; getEncryptedPassword(attemptedPassword, salt);
return Arrays.equals(
encryptedPassword, encryptedAttemptedPassword);
public class PasswordEncryptionService {
}

D’après code de Jerry Orr ;


http://jerryorr.blogspot.fr/2012_05_01_archive.html

R. Grin Sécurité Java EE page 171 R. Grin Sécurité Java EE page 172

Exemple de code (3/4) Exemple de code (4/4)


public byte[] getEncryptedPassword( // Utilisé la 1ère fois pour générer un sel.
String password, byte[] sel) // On peut garder le même si le mot de passe change
throws NoSuchAlgorithmException, public byte[] generateSalt()
InvalidKeySpecException {
throws NoSuchAlgorithmException {
// Nom algorithme (PBKDF2 avec SHA-1)
SecureRandom random =
String algo = "PBKDF2WithHmacSHA1"; SecureRandom.getInstance("SHA1PRNG");
int longueurCle = 160; // SHA-1 génère 160 bits // Genère un sel de 8 octets (64 bits)
int iterations = 20000; // Au moins 1000 byte[] sel = new byte[8];
KeySpec spec = new PBEKeySpec( random.nextBytes(sel);
password.toCharArray(), sel, iterations, longueurCle);
return sel;
SecretKeyFactory f = SecretKeyFactory.getInstance(algo);
}
return f.generateSecret(spec).getEncoded();
}

R. Grin Sécurité Java EE page 173 R. Grin Sécurité Java EE page 174

29
Attention à l’injection de code SQL Résumé sur les fonctions de hachage
et les codages
‰ Si l’application écrit son propre code SQL pour
vérifier un couple login/mot de passe enregistré ‰ On l’a vu avec GlassFish, la manipulation des
dans une base de données, attention à l’injection mots de passe et leur enregistrement peuvent
de code SQL (voir cours sur la sécurité en Java utiliser des fonctions de hachage (pour crypter les
http://deptinfo.unice.fr/~grin/messupports/java/Se mots de passe) et des codages (pour passer d’un
curite6.pdf) tableau de char à un tableau de byte)
‰ Pas de crainte avec la façon standard de vérifier ‰ Les transparents suivants font quelques rappels
un mot de passe dans une base utilisée par sur ces 2 points
GlassFish

R. Grin Sécurité Java EE page 175 R. Grin Sécurité Java EE page 176

Résumé sur les fonctions de hachage Exemple (1/2)


static byte[] crypter(char[] source,
‰ Fonctions de hachage pour hacher un tableau String nomMessageDigest,
String nomCharset)
d’octets de taille quelconque en un tableau
throws NoSuchAlgorithmException,
d’octets de taille constante :
CharacterCodingException {
n MD5 produit 128 bits ou 16 octets
MessageDigest md =
n SHA-256 produit 256 bits ou 32 octets MessageDigest.getInstance(nomMessageDigest);
‰ Pour avoir une liste des noms d’algorithme pour return md.digest(charToByte(source,
la sécurité : nomCharset));
http://docs.oracle.com/javase/7/docs/technotes/ }
guides/security/StandardNames.html
Par exemple, crypter(source, "SHA-256", "UTF-8")
R. Grin Sécurité Java EE page 177 R. Grin Sécurité Java EE page 178

Exemple (2/2) Résumé sur les codages


static byte[] charToByte(char[] tc,
String nomCharset) ‰ Le codage est utilisé pour transformer un tableau
throws CharacterCodingException { d’octets en tableau de char et réciproquement
Charset cs = Charset.forName(nomCharset); ‰ Les 2 codages utilisés Hex et Base64 ont
CharsetEncoder encoder = cs.newEncoder(); l’avantage de fournir des tableaux de char de
ByteBuffer bbuf = tailles constantes pour un tableau d’octets d’une
encoder.encode(CharBuffer.wrap(tc)); taille fixée
return bbuf.array();
}

R. Grin Sécurité Java EE page 179 R. Grin Sécurité Java EE page 180

30
Base64 (1/2) Base64 (2/2)
‰ Codage qui utilise 64 caractères (codés sur 6
‰ Avant le JDK 8 : utiliser la classe
bits) pour coder des octets : les lettres
org.apache.commons.codec.binary.Base64
majuscules et minuscules (52), les chiffres (10),
« + » et « / » ; « = » est aussi utilisé en de la librairie « Apache Commons » ou, mieux (pas
compléments dans les cas où le nombre total de librairie externe), la classe
javax.xml.bind.DatatypeConverter qui a les
d’octets n’est pas divisible par 3
méthodes static
‰ 24 bits consécutifs (donc 3 octets) sont codés par
byte[] parseBase64Binary(String) pour
une chaîne de 4 caractères (3 x 8 = 4 x 6 = 24) décoder une String supposée encoder des octets,
‰ Classe java.util.Base64 du JDK 8 qui fournit et String printBase64Binary(byte[]) pour
un décodeur (String Æ byte[]) et un encodeur coder un tableau d’octets en String
(byte[] Æ String)
R. Grin Sécurité Java EE page 181 R. Grin Sécurité Java EE page 182

Hex Tailles dans une base de données


‰ Chaque octet est codé avec 2 caractères ; c’est ‰ Que le mot de passe utilise la fonction de
donc moins efficace que Base64 (mais plus facile hachage MD5 ou SHA-256 et le codage Hex ou
à décoder « à la main » pour les mises au point) Base64, le type de la colonne qui contient le mot
‰ DatatypeConverter a aussi les méthodes de passe doit être VARCHAR
byte[] parseHexBinary(String s) et ‰ La longueur du VARCHAR :
String printHexBinary(byte[] val) n 64 pour SHA-256 et Hex (32 x 2)
‰ Aussi : n 44 pour SHA-256 et Base64
static String hexToBin(String s) { n 32 pour MD5 et Hex (16 x 2)
return new BigInteger(s, 16).toString(2); n 24 pour MD5 et Base64
}

R. Grin Sécurité Java EE page 183 R. Grin Sécurité Java EE page 184

31

Vous aimerez peut-être aussi