1 Sécurité dans Java EE Présentation du cours Plan (1/2)

Transcription

1 Sécurité dans Java EE Présentation du cours Plan (1/2)
Présentation du cours
‰
Ce cours montre comment sécuriser une
application Java EE : réserver l’accès de pages
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
exemples de configuration sont donnés pour le
serveur d’application GlassFish
Sécurité dans Java EE
Université de Nice - Sophia Antipolis
Richard Grin
Version 0.12 – 12/4/13
R. Grin
Plan (1/2)
‰
‰
‰
Généralités sur la sécurité
Présentation de la sécurité dans Java EE et fichiers
de configuration
‰ Rôles et identité des utilisateurs – Authentification
‰ Protection des pages Web
‰ Protéger les méthodes des EJB
‰ Code Java pour la sécurité
‰ Configuration de GlassFish
Sécurité Java EE
page 3
Un exemple
Logs dans GlassFish
‰ Gérer les mots de passe
R. Grin
‰
Généralités sur la sécurité
R. Grin
Sécurité Java EE
page 2
Plan (2/2)
‰
R. Grin
Sécurité Java EE
page 5
Sécurité Java EE
page 4
Réserver des parties d’une application à certains
utilisateurs implique de gérer
n l’authentification des utilisateurs
n la vérification des autorisations
R. Grin
Sécurité Java EE
page 6
1
Authentification
Autorisation
‰
Obtenir l’identité des utilisateurs et vérifier qu’un
utilisateur est bien celui qu’il prétend être
‰ Le plus souvent, il s’agit de demander le nom et
le mot de passe de l’utilisateur
‰
R. Grin
R. Grin
Sécurité Java EE
page 7
Lorsqu’un utilisateur est entré dans l’application,
vérifier qu’il a bien le droit
n d’accéder aux ressources (pages Web, base
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
Sécurité Java EE
page 8
Transport des informations
‰
‰
Protéger les informations qui transitent sur le
réseau contre des personnes non autorisés :
n empêcher la lecture des données
confidentielles
n repérer qu’une information transmise a été
modifiée par une tierce personne avant
d’arriver à destination
R. Grin
Sécurité Java EE
Ce support n’abordera que l’authentification par
mot de passe et les autorisations
‰ Il n’abordera pas, par exemple, l’étude des
certificats et de la signature des documents
‰ Les transparents suivants donnent la terminologie
habituelle liée à la sécurité
page 9
R. Grin
Utilisateur
L’utilisateur d’une application est identifié par des
« pièces d’identité », credentials en anglais, qui
prouvent son identité
‰ Le plus souvent la saisie d’un nom de login et d’un
mot de passe prouve l’identité d’un utilisateur
‰ L’utilisateur peut correspondre à une personne ou
à une (partie d’une) application informatique
Sécurité Java EE
page 10
Principal
‰
R. Grin
Sécurité Java EE
page 11
‰
Une fois qu’il est authentifié, l’utilisateur devient
un principal (terme anglais qui signifie mandant,
commettant) au nom duquel il effectuera des
opérations dans l’application
‰ Un Principal peut être un utilisateur, un groupe
d’utilisateurs, ou autre, qui a été défini dans
l’environnement opérationnel d’exécution
Richard Grin
EJB
page 12
2
Rôle
Rôles d’un utilisateur
‰
La politique de sécurité des serveurs d’application
repose sur la notion de rôle
‰ Exemples de rôle : administrateur, organisateur,
participant, chef de service
‰ Un principal / utilisateur peut avoir un ou plusieurs
rôles dans une application
‰ Un rôle donne des droits aux utilisateurs qui ont
ce rôle
‰ La notion de rôle augmente la portabilité de
l’application puisqu’on ne fait aucune prévision
sur l’existence d’utilisateurs particuliers
R. Grin
Sécurité Java EE
page 13
‰
C’est celui qui déploie l’application qui associe
ces rôles
‰ La manière dont un rôle est associé à un
utilisateur n’est pas standard et dépend du
serveur d’applications
‰ Tomcat et GlassFish définissent des groupes
d’utilisateurs et il est possible de les configurer
pour qu’un groupe corresponde à un rôle (voir
section « Configuration GlassFish » plus loin
dans ce support)
R. Grin
Sécurité Java EE
page 14
Realm – domaine de sécurité
Groupes d’utilisateurs
‰
‰
Les utilisateurs sont souvent regroupés en
groupes qui ont les mêmes types d’autorisation,
ce qui facilite l’attribution de rôles aux utilisateurs
(on peut donner en bloc un rôle à tous les
membres d’un groupe)
‰ Par exemple, le groupe des utilisateurs
enregistrés, le groupe des visiteurs non
enregistrés, le groupe des administrateurs
R. Grin
Sécurité Java EE
page 15
Pour authentifier les utilisateurs, les serveurs
d’application doivent conserver des informations
sur ces utilisateurs
‰ Un domaine de sécurité (realm), identifié par son
nom, définit comment ces informations sont
conservées, et comment on les utilise pour
l’authentification (voir balise <login-config> de
web.xml) ; la définition d’un realm n’est pas
standardisée
‰ Exemples : domaine défini par un fichier des mots
de passe, par des tables relationnelles, par un
registre LDAP, par des
certificats informatiquespage 16
R. Grin
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
‰ L’administrateur du serveur d’application gère les
utilisateurs et les groupes d’utilisateurs
‰ 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
Présentation de la sécurité
dans Java EE
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
et il est préférable de s’appuyer le plus possible
sur les facilités offertes par les serveurs
d’application
Richard Grin
EJB
page 19
‰
Java EE permet d’implémenter une politique de
sécurité de façon déclarative ou par
programmation Java
‰ 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
R. Grin
Déclaration
Les annotations permettent d’écrire les
informations sur la politique de sécurité directement
dans le code Java des EJB ou des servlets
‰ Il n’est pas toujours possible d’utiliser une
annotation ; en ce cas les informations de sécurité
sont décrites dans des balises des fichiers de
déploiement
‰ Toutes les annotations ont leur pendant sous forme
de balise XML ; en cas de contradiction, une
information dans un fichier de déploiement
l’emporte sur une annotation
Sécurité Java EE
page 20
Fichiers de déploiement
‰
R. Grin
Sécurité Java EE
page 21
‰
Fichiers standards qui ne dépendent pas du serveur
d’application : web.xml (module Web),
ejb-jar.xml (module EJB), application.xml
(module application qui peut regrouper plusieurs
modules dans un fichier EAR)
‰ Chaque serveur d’application peut aussi avoir ses
propres fichiers de déploiement pour les informations
non standardisées ; pour GlassFish,
glassfish-web.xml, glassfish-ejb-jar.xml,
glassfish-application-web.xml
R. Grin
Sécurité Java EE
page 22
Types de déclarations
‰
Java EE permet de déclarer
n les rôles utilisés par l’application
n la façon d’authentifier les utilisateurs
n les pages Web protégées et les rôles qui y ont
accès
n les classes ou méthodes Java protégées et les
rôles qui y ont accès
R. Grin
Sécurité Java EE
page 23
‰
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
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 24
4
Déclaration des rôles
‰
Un rôle doit être déclaré avant d’être utilisé
‰ On peut le faire avec une annotation ou dans un
fichier de déploiement XML
Définition des rôles
R. Grin
Sécurité Java EE
page 25
R. Grin
Annotation pour déclarer des rôles
‰
L’annotation @DeclareRoles peut être mise sur
les EJB ou les servlets
‰ La casse (majuscules – minuscules) est
significative dans les noms de rôle
‰ Exemple :
Sécurité Java EE
page 27
‰
Plusieurs balises <security-role> peuvent
être mises directement sous la balise racine
(web-app, ejb-jar ou application)
‰
Exemple :
<security-role>
<description>Administrateur</description>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>membre</role-name>
</security-role>
R. Grin
‰
Le développeur utilise des noms de rôle dans son
code lorsqu’il écrit un module Java EE
‰ S’il réutilise son module dans plusieurs
applications, un nom de rôle peut avoir un autre
nom dans les autres modules
‰ Avec la balise <security-role-ref> il est
possible de définir un alias pour un nom de rôle,
pour faire correspondre le rôle du module avec un
rôle de l’environnement d’exécution
Sécurité Java EE
Sécurité Java EE
page 28
Exemple d’alias pour un rôle
Référence d’un rôle
R. Grin
page 26
Balise pour déclarer des rôles
@Stateless
@DeclareRoles("admin", "membre", "visiteur")
public class MonBean { ... }
R. Grin
Sécurité Java EE
page 29
‰
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) :
<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 30
5
Type d’authentification
‰
Si l’utilisateur veut accéder à une page Web
protégée et qu’il n’est pas déjà enregistré, le
container Web cherche à l’authentifier
‰ Le plus souvent l’utilisateur s’authentifie en tapant
son login et son mot de passe pour l’application
dans un formulaire
‰ Un certificat peut aussi être utilisé pour
l’authentification (mode CLIENT-CERT), à la
place du login/mot de passe
Authentification
R. Grin
Sécurité Java EE
page 31
R. Grin
Déclaration du type d’authentification
‰
Pas d’annotation, il faut configurer avec la balise
<login-config> sous la balise racine du fichier
web.xml
‰
2 sous-balises :
n <auth-method> définit le mode d’authentification
n <realm-name> indique le domaine de sécurité
dans lequel les informations pour l’authentification
seront cherchées ; il peut y en avoir plusieurs
dans une application
R. Grin
Sécurité Java EE
page 33
page 32
Exemple
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>candidatures</realm-name>
</login-config>
R. Grin
Valeurs par défaut
Sécurité Java EE
page 34
Autres modes d’authentification
‰
Par défaut, le mode d’authentification est le mode
BASIC : le login et le mot de passe sont demandés
à l’utilisateur par un formulaire affiché par le
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
R. Grin
Sécurité Java EE
Sécurité Java EE
page 35
Plusieurs autres modes d’authentification, en plus
du mode par défaut BASIC :
n FORM : utilisation d’un formulaire écrit par le
développeur dans une page Web pour obtenir
le login et le mot de passe
n DIGEST : utilisation d’un hachage pour le
transport du mot de passe (MD5 par exemple)
n CLIENT-CERT : utilisation d’un certificat
Sécurité Java EE
page 36
6
Exemple
Mode FORM - pages
<login-config>
<auth-method>FORM</auth-method>
<realm-name>candidatures</realm-name>
<form-login-config>
<form-login-page>/faces/login.xhtml</formlogin-page>
<form-error-page>/faces/noaut.xhtml</formerror-page>
</form-login-config>
</login-config>
‰
R. Grin
R. Grin
Sécurité Java EE
page 37
<form-login-config> ne sert que si
<auth-method> a la valeur FORM, pour indiquer la
page qui contient le formulaire de login et celle qui
est affichée si le login et le mot de passe saisis ne
sont pas bons
Mode FORM - formulaire de login
‰
Si on choisit le mode FORM, le formulaire écrit
par le développeur a des contraintes de nom pour
n l’action exécutée lorsque le formulaire est
soumis (j_security_check)
n
‰
les noms des champs qui contiennent le login
(j_username) et le mot de passe
(j_password)
Sécurité Java EE
page 38
Exemple de formulaire HTML
<form method="POST" action="j_security_check">
Login :
<input type="text" name="j_username"/>
Mot de passe :
<input type="password" name="j_password"/>
<input type="submit" value="Login"/>
</form>
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 39
R. Grin
Exemple de formulaire JSF
Sécurité Java EE
page 40
Exemple de page d’erreur
<form method="post" action="j_security_check">
<h:panelGrid columns="2">
<h:outputLabel for="j_username"
value="Login" />
<h:input id="j_username" />
<h:outputLabel for="j_password"
value="Mot de passe" />
<h:inputSecret id="j_password"/>
<h:commandButton id="submit"
value="Login" />
</h:panelGrid>
</form>
R. Grin
Sécurité Java EE
page 41
<html>
<head>
<title>Echec de l'authentification</title>
</head>
<body>
<p>Désolé, vous n'avez pas tapé des bons
login et mot de passe. Essayez à nouveau.
</p>
</body>
</html>
R. Grin
Sécurité Java EE
page 42
7
Méthode HttpServletRequest.login()
‰
La méthode que l’on vient de voir est la façon la
plus simple de filtrer les accès à une application
‰ Elle convient le plus souvent mais elle a des
contraintes importantes (les action et propriétés
pour enregistrer les login et mots de passe sont
imposés)
‰ Depuis JSF 2.0, le développeur peut choisir une
autre solution plus souple mais plus complexe à
programmer
‰
R. Grin
R. Grin
Sécurité Java EE
page 43
Depuis JSF 2.0, il est possible de récupérer le
nom et le mot de passe comme on le souhaite et
de passer les valeurs à la méthode
login(String nom, String mdp) de la
classe HttpServletRequest pour s’authentifier
auprès du container (lance une
ServletException si déjà connecté ou
mauvais login/mot de passe).
Utilisation login – formulaire
Sécurité Java EE
‰
Le code du backing bean de la solution avec la
méthode login est un peu complexe ; il tire parti
du fait que le container utilise un forward pour
faire afficher la page qui contient le formulaire de
login
‰ Pour avoir l’URI de la page que voulait
l’utilisateur, il faut utiliser l’attribut de la requête
RequestDispatcher.FORWARD_REQUEST_URI
‰ Merci à BalusC (expert JSF) pour l’information
page 45
R. Grin
Utilisation login – backing bean
@PostConstruct
public void init() {
uri = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestMap()
.get(RequestDispatcher.FORWARD_REQUEST_URI);
}
Sécurité Java EE
Sécurité Java EE
page 46
Utilisation login – backing bean
@ManagedBean
@ViewScoped
public class Login {
private String login, mdp;
private String uri;
R. Grin
page 44
Remarque sur le code
<h:form>
Login :
<h:inputText value="#{login.login}"
required="true" /> <p/>
Mot de passe :
<h:inputSecret value="#{login.mdp}"
required="true" /> <p/>
<h:commandButton value="Connexion"
action="#{login.submit}">
<f:ajax execute="@form" render="@form" />
</h:commandButton>
<h:messages globalOnly="true" />
</h:form>
R. Grin
Sécurité Java EE
page 47
public void submit() throws IOException {
FacesContext context =
FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)
context.getExternalContext().getRequest();
try {
request.login(login, mdp);
context.redirect(uri);
} catch (ServletException e) {
facesContext.addMessage(...);
}
}
R. Grin
Sécurité Java EE
page 48
8
Déconnexion
SSL
‰
L’authentification de l’utilisateur est valable pour
toute la session de travail HTTP
‰ Il est possible de faire sortir l’utilisateur de la
session de travail avec la méthode logout() de la
classe HttpServletRequest
‰
Cette méthode peut être appelée, par exemple,
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 49
‰
Les login et mot de passe seront passés en clair
sur le réseau
‰ Il est possible d’utiliser SSL pour les protéger ; la
façon de le faire dépend du serveur d’application
et ne sera pas étudié dans ce support
‰ Voir aussi la section « Protection des pages Web »
R. Grin
Sécurité Java EE
page 50
Gestion des utilisateurs
‰
La gestion des utilisateurs (ajout d’un nouvel
utilisateur, modification,…) et la conservation des
informations sur les utilisateurs dépend du
serveur d’application
‰ La section « Sécurité avec GlassFish » donne un
exemple d’utilisation du serveur GlassFish
‰
R. Grin
R. Grin
Sécurité Java EE
page 51
Les sections suivantes montrent comment
réserver l’accès des pages Web et des méthodes
Java des EJB ou des servlets aux utilisateurs qui
ont un certain rôle
‰ Ensuite, il est montré comment configurer
GlassFish pour les parties qui dépendent du
serveur d’application
Sécurité Java EE
page 52
Utilité
‰
Le plus souvent des pages Web (définies par des
URL) ne doivent être accessibles que par certains
utilisateurs ou dans certaines circonstances
‰ Cette section explique comment restreindre l’accès
d’une partie des pages d’une application à certains
utilisateurs
Protection des pages Web
R. Grin
Sécurité Java EE
page 53
R. Grin
Sécurité Java EE
page 54
9
Erreurs HTTP pour la sécurité
‰
Schéma de protection
Lorsqu’un utilisateur veut accéder à une page
protégée,
n erreur HTTP 401, Unauthorized, si l’utilisateur
ne fournit pas les credentials (le plus souvent
le bon mot de passe)
n erreur HTTP 403, Forbidden, si l’utilisateur a
fournit les bons credentials mais n’a pas
l’autorisation d’accéder à la page
R. Grin
Sécurité Java EE
page 55
‰
Le plus simple est d’utiliser le système de
sécurité offert par les containers de page Web
des serveurs d’application
‰ Il est simple de grouper les pages à protéger
dans un ou plusieurs répertoires et de filtrer
l’accès à ces répertoires
‰ Pour les cas plus complexes de filtrage, il est
possible de coder le filtrage directement dans le
code Java de l’application
R. Grin
Déclaration des protections
La protection est déclarée dans le fichier web.xml
par des contraintes de sécurité déclarées sur des
ressources (les pages Web désignées par des
modèles d’URL)
‰ Il est aussi possible de déclarer des contraintes de
sécurité dans un servlet (si l’application en a un)
avec l’annotation @HttpConstraint contenue
dans une annotation @ServletSecurity
‰
R. Grin
R. Grin
page 57
L’application peut définir des contraintes de
sécurité (<security-constraint>)
‰ Elles restreignent l’accès à des ressources (page
Web définies par leur URL) aux seuls utilisateurs
qui ont un certain rôle (plusieurs rôles peuvent être
indiqués)
‰ Lorsqu’un utilisateur veut accéder à une ressource
protégée, il doit être authentifié et il peut accéder à
la ressource s’il a les rôles requis par la ressource
Contraintes de sécurité
‰
Sécurité Java EE
Sécurité Java EE
page 58
Exemple
Les sous balises de <security-constraint> :
n <web-resource-collection> indique les
URLs des pages (<url-pattern>) et les
méthodes HTTP protégées (<http-method>)
n <auth-constraint> indique les rôles qui
permettent d’accéder aux pages
n <user-data-constraint> indique comment
sont protégées les données échangées entre le
client et le serveur (aucune protection par défaut)
R. Grin
page 56
Notions utilisées
‰
Sécurité Java EE
Sécurité Java EE
page 59
<security-constraint>
<web-resource-collection>
<web-resource-name>r1</web-resource-name>
<url-pattern>/liste.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>employe<role-name>
<role-name>drh<role-name>
</auth-constraint>
</security-constraint>
R. Grin
Sécurité Java EE
page 60
10
Exemple - JSF
<url-pattern>
‰
Les pages protégées sont désignées par la sousbalise <url-pattern> qui donne un chemin qui
peut comporter le joker *
‰ 3 Formats possibles pour un url-pattern :
n commence par / et se termine par /* (toute page
située sous le répertoire qui précède « /* », à
n’importe quelle profondeur
n commence avec *. et se termine par un
caractère (par exemple *.jsf)
n commence par / et ne comporte pas de *
R. Grin
Sécurité Java EE
page 61
<security-constraint>
<web-resource-collection>
<web-resource-name>p1</web-resource-name>
<url-pattern>/faces/candids/*</url-pattern>
<url-pattern>/candids/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>rsr</role-name>
</auth-constraint>
</security-constraint>
R. Grin
<security-constraint>
<web-resource-collection>
<web-resource-name>r1</web-resource-name>
<url-pattern>/liste.xhtml</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>employe<role-name>
</auth-constraint>
</security-constraint>
L’accès est protégé pour toutes les méthodes
HTTP si cette balise est omise
R. Grin
Sécurité Java EE
page 63
Lien vers une page protégée
R. Grin
Sécurité Java EE
page 64
Attention, pas de forward interne !
C’est l’URL de la page que l’on veut afficher qui
est comparé aux patterns des pages protégées
‰ Si une page contient un lien vers une page
protégée, il faut écrire ce lien avec les composants
<h:outputLink>, <h:button> ou <h:link>,
ou ajouter une redirection à un un lien avec un
composant <h:commandButton> ou
<h:commandLink>
‰
R. Grin
R. Grin
‰
Sécurité Java EE
page 62
Exemple
<http-method>
‰
Sécurité Java EE
page 65
Un forward interne au serveur (méthode forward
de RequestDispatcher) ne déclenche pas une
vérification des contraintes de sécurité puisque
l’URL n’est pas modifié
‰ Ce qui signifie qu’un <h:commandButton> ou un
<h:commandLink> (sans redirection) vers une
page protégée donnera accès à la page, même si
l’utilisateur n’a pas l’autorisation d’accès à cette
page
Sécurité Java EE
page 66
11
<auth-constraint>
<user-data-constraint>
‰
L’autorisation sera accordée si l’utilisateur a un
des rôles indiqués
‰ « * » indique que tous les rôles sont acceptés
‰ S’il y a une balise <auth-constraint> mais
aucune sous-balise <role-name>, les pages ne
pourront être accédée par aucun utilisateur
R. Grin
Sécurité Java EE
page 67
‰
La balise <user-data-constraint> peut être
ajoutée dans une balise <security-constraint>
pour indiquer que la connexion avec les pages
protégées utilisera le protocole HTTPS
‰ Elle contient une balise <transport-garantee>
dont la valeur peut être égale à NONE (valeur par
défaut), CONFIDENTIAL ou INTEGRAL
R. Grin
Valeurs pour <transport-garantee>
‰
CONFIDENTIAL : les données transmises ne
peuvent être vues par des tiers
‰ INTEGRAL : les données transmises ne peuvent
être modifiées par des tiers
‰ NONE : pas de protection particulière
‰ En pratique, les 2 modes CONFIDENTIAL et
INTEGRAL sont traités de la même façon par les
serveurs d’application (utilisation de HTTPS)
R. Grin
Sécurité Java EE
page 69
Exemple
R. Grin
Sécurité Java EE
page 70
Exemple 1
‰
Dans le cas des applications qui n’utilisent pas
les EJB, on peut utiliser les fichiers de
configuration mais il est aussi possible de
configurer la sécurité avec l’annotation
@ServletSecurity
‰
Les transparents suivant donne des exemples
Sécurité Java EE
page 68
<security-constraint>
<web-resource-collection>
<web-resource-name>r1</web-resource-name>
<url-pattern>/faces/restr/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>employe<role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>
CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Avec les servlets
R. Grin
Sécurité Java EE
page 71
@WebServlet("/monurl")
@ServletSecurity(
@HttpConstraint(rolesAllowed={"r1", "r2"}))
public class MaServlet extends HttpServlet
L’URL /monurl sera réservée aux
utilisateurs qui ont le rôle « r1 » ou
le rôle « r2 »
R. Grin
Sécurité Java EE
page 72
12
Exemple 2
@WebServlet("/monurl")
@ServletSecurity(
value=@HttpConstraint(
transportGuarantee=
ServletSecurity.TransportGuarantee.CONFIDENTIAL),
httpMethodConstraints={
@HttpMethodConstraint(
value="TRACE",
transportGuarantee=
ServletSecurity.TransportGuarantee.NONE,
rolesAllowed={"r1"}) })
public class MaServlet extends HttpServlet
R. Grin
Sécurité Java EE
page 73
Protéger les méthodes des EJB
R. Grin
‰
Avec une annotation
‰ Avec les fichiers de déploiement XML
‰ Les fichiers XML l’emportent sur les annotations
‰
R. Grin
R. Grin
page 75
Annote une méthode ou une classe (concerne
alors toutes les méthodes de la classe) protégée
‰ En paramètre, un seul rôle ou plusieurs rôles de
type String entourés d’accolades (les utilisateurs
ayant un des rôles peuvent utiliser la méthode ou
la classe) :
@RolesAllowed("role1")
@RolesAllowed({ "role1", "role2" })
Annotation @PermitAll
‰
Sécurité Java EE
Sécurité Java EE
page 76
Exemple de déclarations (1/2)
Si la classe est protégée, cette annotation permet
d’exclure une méthode de la protection : tous les
utilisateurs seront autorisés à utiliser la méthode
annotée par @PermitAll
R. Grin
page 74
Annotation @RolesAllowed
Par déclaration
Sécurité Java EE
Sécurité Java EE
page 77
<ejb-jar>
<assembly-descriptor>
<security-role>
<description>Employés chargés des clients
</description>
<role-name>Caissier</role-name>
</security-role>
<security-role>
<description>Contrôleur</description>
<role-name>Controleur</role-name>
</security-role>
R. Grin
Sécurité Java EE
page 78
13
Exemple de déclarations (2/2)
Méthodes non protégées
<method-permission>
<role-name>Controleur</role-name>
<method>
<ejb-name>Compte</ejb-name>
<method-name>getBalance</method-name>
</method>
<method>
<ejb-name>Compte</ejb-name>
<method-name>setBalance</method-name>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>
R. Grin
Sécurité Java EE
page 79
‰
Certaines méthodes sont autorisées à tous
(unchecked):
<method-permission>
<role-name>unchecked</role-name>
<method>
<ejb-name>Compte</ejb-name>
<method-name>getNames</method-name>
</method>
R. Grin
Des méthodes peuvent ne pas être accessibles
pour un déploiement :
<exclude-list>
<description>Méthode m1 de Ejb1 interdite
</description>
<method>
<ejb-name>Ejb1</ejb-name>
<method-name>m1</method-name>
</method>
</exclude-list>
R. Grin
Sécurité Java EE
page 81
‰
Peut annoter une méthode d’un EJB (si la classe
EJB est annotée, toutes les méthodes de la
classe sont concernées)
‰ Le paramètre est le nom du rôle que l’utilisateur
prendra pendant qu’il exécutera la méthode
‰ Exemple :
@RunAs("admin")
R. Grin
Balise run-as
‰
‰
<session>
<ejb-name>. . . </ejb-name>
. . .
<security-identity>
<run-as>
<role-name>admin</role-name>
</run-as>
</security-identity>
. . .
</session>
Sécurité Java EE
Sécurité Java EE
page 82
use-caller-identity
Dans un fichier de configuration :
R. Grin
page 80
Annotation @RunAs
Méthodes non accessibles
‰
Sécurité Java EE
Pour être certain qu’on utilisera le principal et pas
un rôle donné par une méthode EJB « run-as »,
on peut indiquer use-caller-identity pour
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>
page 83
R. Grin
Sécurité Java EE
page 84
14
Sécurité par programmation
‰
Dans certains cas la déclaration des autorisations
dans les fichiers de déploiement ou par des
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
Code Java pour la sécurité
R. Grin
Sécurité Java EE
page 85
R. Grin
Sécurité Java EE
page 86
Cas d’utilisation
‰
Dans une application qui gère des formations, les
utilisateurs doivent ouvrir un compte
‰ Ce compte leur donne le rôle « etudiant » qui leur
permet de s’inscrire à des cours et de participer à
des forums
‰ 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 87
‰
Les transparents suivants étudient le cas d’une
application JSF, avec le code qu’un backing bean
peut contenir
‰ On verra ensuite comment obtenir les mêmes
informations dans une méthode d’un EJB session
R. Grin
Il est possible de récupérer le nom de l’utilisateur
avec le code suivant :
FacesContext context =
FacesContext.getCurrentInstance();
HttpServletRequest request =
(HttpServletRequest)
context.getExternalContext().getRequest();
String login = request.getRemoteUser();
R. Grin
Sécurité Java EE
page 88
Classe ExternalContext
Dans un backing bean JSF
‰
Sécurité Java EE
page 89
‰
Cette classe du paquetage
javax.faces.context permet d’obtenir des
informations sur l’environnement d’exécution ;
elle contient en particulier des méthodes utiles
pour la sécurité
‰ Une instance peut être obtenue par
FacesContext.getCurrentInstance()
.getExternalContext()
R. Grin
Sécurité Java EE
page 90
15
Méthodes de ExternalContext
‰
boolean isUserInRole(String nomRole)
retourne true si celui qui appelle la méthode
remplit bien le rôle passé en paramètre
‰ java.security.Principal
getUserPrincipal() permet d’avoir le principal
de celui qui appelle la méthode, ce qui permet de
distinguer des utilisateurs qui ont le même rôle
‰ Object getRequest() récupère la requête en
cours (caster en
javax.servlet.http.HttpServletRequest)
R. Grin
Sécurité Java EE
page 91
Exemple avec JSF
...
String login = request.getRemoteUser();
if (<condition sur login>) {
FacesContext.getCurrentInstance()
.getExternalContext()
.redirect(autrePage);
}
...
R. Grin
Sortir d’une application JSF
‰
‰
try {
((HttpServletRequest)FacesContext
.getCurrentInstance()
.getExternalContext()
.getRequest()).logout();
} catch (ServletException ex) {
…
}
‰
Sécurité Java EE
Pour filtrer les accès aux méthodes des EJB dans
le cas où la granularité de protection offerte par les
rôles ne suffit pas, il est possible d’utiliser les
méthodes de l’interface javax.ejb.EJBContext
Cette interface est implémentée par la classe
javax.ejb.SessionContext
‰ On peut obtenir une instance de SessionContext
en l’injectant dans un EJB session :
@Resource
private SessionContext contexte;
page 93
R. Grin
Méthodes de EJBContext
EJBContext contient des méthodes liées à
l’authentification des utilisateurs :
n Principal getCallerPrincipal()
n boolean isCallerInRole(String role)
‰
Elles jouent le même rôle que les méthodes de
l’interface ExternalContext (avec User à la
place de Caller)
Sécurité Java EE
Sécurité Java EE
page 94
Exemple
‰
R. Grin
page 92
Dans un EJB
Après ce code (qu’on peut mettre, par exemple,
dans l’action d’un bouton), l’utilisateur devra à
nouveau s’authentifier pour les fonctionnalités qui
nécessite une authentification :
R. Grin
Sécurité Java EE
page 95
// Méthode interdite à certains utilisateurs
String login =
contexte.getCallerPrincipal().getName();
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 96
16
Mode de configuration
‰
Configuration de GlassFish
R. Grin
Sécurité Java EE
page 97
GlassFish peut être configuré
n du côté du serveur : avec la console
d’administration ou avec la commande
asadmin
n en ajoutant dans l’application des fichiers de
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
Console d’administration de GlassFish
‰
Elle s’affiche dans un navigateur en tapant
l’adresse du serveur, suffixé avec « :4848 » (port
d’écoute)
R. Grin
Sécurité Java EE
page 99
Commande asadmin (2/2)
On peut travailler avec asadmin en mode interactif
en tapant « asadmin multimode » ; un prompt
« asadmin> » apparaît et on peut taper plusieurs
commandes ; taper « exit » pour sortir
‰ On peut aussi lancer un script qui contient des
commandes par « asadmin multimode --file
script.txt »
Commande asadmin (1/2)
‰
Cette commande est située dans le répertoire bin du
répertoire d’installation de GlassFish (répertoire
affiché dans la console d’administration de
GlassFish)
‰ La commande asadmin prend en paramètre des
commandes qui permettent de configurer le serveur
(« asadmin --help » affiche une aide ; « asadmin
commande --help » affiche une aide sur une
commande)
R. Grin
Sécurité Java EE
page 100
‰
Il peut s’agir d’un problème de configuration
‰ A essayer :
n
n
n
Sécurité Java EE
page 98
Si GlassFish ne veut plus démarrer
‰
R. Grin
Sécurité Java EE
page 101
R. Grin
Aller dans le répertoire qui contient domain.xml ; il
contient aussi un fichier domain.xml.bak qui est la
l’avant-dernière version de domain.xml
Conserver les 2 fichiers et ensuite renommer
domain.xml.bak en domain.xml et essayer de
redémarrer GlassFish
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)
Sécurité Java EE
page 102
17
Fichiers de déploiement GlassFish
‰
Ils ont les mêmes noms que les fichiers de
déploiement standard, préfixés par glassfish- :
glassfish-application.xml, glassfish-ejb-jar.xml,
glassfish-web.xml
R. Grin
Sécurité Java EE
page 103
Affecter les rôles avec GlassFish
‰
La manière dont un rôle est associé à un utilisateur
dépend du serveur d’application
‰ GlassFish (et Tomcat) définit des groupes
d’utilisateurs
‰ On peut affecter un ou plusieurs rôles à un groupe
ou à un utilisateur
‰ Pour simplifier, il est aussi possible de configurer
GlassFish pour que les groupes ou les utilisateurs
correspondent aux rôles de même noms
R. Grin
Indiquer une correspondance avec un rôle
‰
Pour indiquer la correspondance entre les groupes
(ou les utilisateurs) et les rôles, 2 possibilités :
n utiliser un fichier de déploiement de l’application
particulier à GlassFish pour donner les
correspondances entre groupes et rôles
n utiliser la console d’administration de GlassFish
ou la commande asadmin pour indiquer que les
rôles correspondent aux groupes d’utilisateurs
ou utilisateurs de même nom de GlassFish
(s’applique à toutes les applications qui
n’utilisent pas la 1ère possibilité)
R. Grin
Sécurité Java EE
page 105
page 104
Avec un fichier de déploiement
‰
Pour indiquer une correspondance entre un
groupe (group-name) ou un utilisateur
(principal-name) et un rôle (role-name) il
suffit d’ajouter une balise
<security-role-mapping> sous la balise
racine du fichier
R. Grin
Exemple
Sécurité Java EE
page 106
Par défaut, principal = rôle
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "…"
"http://glassfish.org/…">
<glassfish-web-app>
Dans glassfish-web.xml
...
<security-role-mapping>
<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
R. Grin
Sécurité Java EE
Sécurité Java EE
page 107
Pour simplifier, il est possible d’indiquer à GlassFish
que les groupes ou utilisateurs correspondent aux
rôles de même nom (sauf si une correspondance
explicite d’un rôle et d’un principal est donnée)
‰ Les applications déjà déployées ne sont pas
affectées par une modification de l’activation du
mapping par défaut des principaux avec des rôles
‰ Pendant le développement il ne faut donc pas
oublier de redéployer l’application après un
changement de statut de cette activation
Sécurité Java EE
page 108
18
Par défaut, principal = rôle
‰
Gestion des utilisateurs
Avec la commande asadmin :
‰
asadmin set server-config.security-service.activate-defaultprincipal-to-role-mapping=true
asadmin set server-config.security-service.mappedprincipal-class=CustomPrincipalImplClass
‰
Avec le menu de la console d’administration :
Configuration > server-config > Securité > Cocher
la case Default Principal To Role Mapping (en
français : Mise en correspondance par défaut des
principaux avec des rôles)
R. Grin
Sécurité Java EE
page 109
La manière de conserver les informations sur
l’identité de l’utilisateur, telles que les logins et
mots de passe, n’est pas standard
‰ GlassFish et Tomcat utilisent pour cela la notion
de domaine (realm en anglais) qui correspond au
domaine utilisée dans la balise <realm-name>
de la balise <login-config>
R. Grin
Domaine de sécurité
page 110
Créer un domaine de sécurité
‰
Dans GlassFish il y a les types de realms suivants :
n file (informations dans un simple fichier ;
domaine par défaut)
n jdbc (dans des tables d’un SGBDR)
n ldap (utilise un registre LDAP)
n certificate (utilise des certificats)
‰ Il est aussi possible de créer son propre type de
realm (pas étudié dans ce cours)
‰
R. Grin
R. Grin
Sécurité Java EE
Sécurité Java EE
page 111
asadmin create-auth-realm
permet de créer un realm
‰ On peut aussi passer par les menus de la
console d’administration (voir exemple à suivre
pour un domaine de type JDBC)
Sécurité Java EE
page 112
Étapes pour créer un domaine JDBC
‰
Les transparents suivants étudient le type de
domaine JDBC qui est souvent utilisé car il
permet d’ajouter simplement de nouveaux
utilisateurs (des utilisateurs peuvent ainsi, par
exemple, créer leur propre « espace membre »
pour l’application)
R. Grin
Sécurité Java EE
page 113
Créer les tables qui contiennent les informations
sur les utilisateurs
2. Définir une source de données liée à la base de
données qui contient ces tables
3. Créer le domaine JDBC
1.
R. Grin
Sécurité Java EE
page 114
19
Structure des tables
‰
n
une colonne qui contient le nom de login
une colonne qui contient le mot de passe (en clair ou
crypté) ; de type chaîne de caractères dont la longueur
dépend du codage du mot de passe
La table des groupes (en fait la table qui fait
correspondre un groupe et un utilisateur) doit avoir
n
n
‰
‰
La table des utilisateurs doit avoir
n
‰
Exemple de création des tables
une colonne qui contient le nom d’un groupe
une colonne qui contient un nom de login
Ces tables peuvent avoir d’autres colonnes
R. Grin
Sécurité Java EE
page 115
Table des utilisateurs (mot de passe crypté en
SHA256 avec codage Hex ; il faut donc 64
caractères) :
create table utilisateur (
login varchar(20) primary key,
mot_de_passe varchar(64))
‰ Table des groupes :
create table groupe (
nom_groupe varchar(20),
login varchar(20))
R. Grin
Exemple de données
‰
JSF
‰
page 117
Exemple de vue pour les groupes
‰
Table utilisateur (login, mot_de_passe, email)
Table groupe(id_groupe, nom_groupe)
‰ Table groupe_utilisateur(id_groupe, login) ; le
problème est que id_groupe est utilisé et pas
nom-groupe
‰ Vue v_groupe_utilisateur qui va servir comme
« table » des groupes :
create view v_groupe_utilisateur as
select login, nom_groupe
from groupe join groupe_utilisateur
on groupe.id_groupe = groupe_utilisateur.id_groupe
Sécurité Java EE
Si ces informations (login et groupe) sont dans
des tables qui n’ont pas exactement le format
voulu, il est possible d’utiliser des vues et non pas
des tables dans la définition des domaines
R. Grin
Sécurité Java EE
page 118
Définition de la source de données
‰
‰
R. Grin
page 116
Vues au-dessus des tables
Dans la table des groupes :
toto, groupe1
toto, groupe2
admin, admin
pour indiquer que toto appartient aux groupes
groupe1 et groupe 2 et admin appartient au
groupe admin
R. Grin
Sécurité Java EE
page 119
Il faut maintenant créer une source de données
dont une référence sera rangée dans l’annuaire
JNDI de GlassFish utilisable par l’application
‰ Il faut commencer par créer un pool de
connexions JDBC puis créer la source de données
en utilisant ce pool de connexions
‰ 2 possibilités :
n avec la console d’administration de GlassFish
n avec la commande asadmin
R. Grin
Sécurité Java EE
page 120
20
Pool de connexions
Ressource JDBC
‰
Il décrit l’accès à la base de données (machine
serveur, nom de la base, port d’écoute,..)
‰ Avec les menus de la console d’administration :
Ressources > JDBC > Pool de connexions JDBC
‰ Avec asadmin create-jdbc-connection
‰ Exemple asadmin :
asadmin create-jdbc-connection-pool -datasourceclassname oracle.jdbc.pool.OracleDataSource -restype javax.sql.DataSource --property
user=dbuser:password=mdpdb:url="jdbc:oracle\:thin\:@loca
lhost\:1521\:ORCL" monpool
R. Grin
Sécurité Java EE
page 121
‰
Il faut ensuite créer une ressource JDBC en
utilisant le pool de connexions ; on lui donnera le
nom JNDI jdbc/candidatures pour l’utiliser dans
les transparents suivants
‰ Avec les menus de la console d’administration :
Ressources > JDBC > Resources JDBC
‰ Avec asadmin create-jdbc-resource
‰ Exemple :
asadmin create-jdbc-resource --connectionpoolid monpool
jdbc/masource
R. Grin
Console d’administration de GlassFish
‰ Configurations > server-config > Sécurité >
Domaines
‰ Cliquer Nouveau
‰ Nom : candidatures
‰ Nom de classe : celle qui se nomme JDBCRealm
‰ Il s’affiche des propriétés qu’il faut renseigner
(éviter de taper des lettres accentuées ;
problèmes possibles)
‰
R. Grin
R. Grin
JSF
page 123
Création d’un realm JDBC (3/3)
‰
Contexte de JAAS : jdbcRealm
JNDI : jdbc/candidatures (nom de la source de
données qui contient les tables)
‰ Table d’utilisateurs : PERSONNE (attention à
respecter la casse des tables de la BD si MySQL)
‰ Colonne de nom d’utilisateur : LOGIN
‰ Colonne de mot de passe : MOT_DE_PASSE
‰ Table de groupes : GROUPE
‰ Colonne de nom de groupe : NOM_GROUPE
‰
‰
R. Grin
R. Grin
page 125
JSF
page 124
Modification d’un domaine de sécurité
Algorithme condensé : algorithme de hachage
utilisé pour condenser le mot de passe ; SHA256
par défaut (MD5 dans les anciennes versions de
GlassFish)
‰ Codage : indique comment le mot de passe
condensé (suite d’octets) sera enregistré sous la
forme d’une chaîne de caractères dans la base
de données (Hex ou Base64) ; la chaîne de
caractères sera de longueur 32 pour MD5 et de
longueur 64 pour SHA256
JSF
page 122
Création d’un realm JDBC (2/3)
Création d’un realm JDBC (1/3)
‰
Sécurité Java EE
Il faut relancer GlassFish pour qu’il tienne compte
des modifications (à vérifier…)
Sécurité Java EE
page 126
21
En cas d’erreur
‰
Commandes asadmin en batch
Attention, si le domaine de sécurité n’est pas
défini, le message d’erreur de GlassFish ne
l’indique pas ; pour tous les login / mot de passe,
il dit seulement que le login a échoué
R. Grin
Sécurité Java EE
page 127
‰
Il est possible d’écrire un script (fichier texte) qui
contient plusieurs commandes de asadmin et de
lancer son exécution en « batch » par
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 128
Exemple
Exemple qui utilise Java DB (Derby)
asadmin create-jdbc-connection-pool --datasourceclassname
org.apache.derby.jdbc.ClientDataSource --restype javax.sql.DataSource
--property PortNumber=${DATABASE_PORT}:
Password=${DATABASE_PASSWORD}:User=${DATABASE_USER}:Se
rverName=localhost:DatabaseName=${DATABASE_NAME}
${CONNECTION_POOL_NAME}
asadmin create-jdbc-resource --connectionpoolid
${CONNECTION_POOL_NAME} ${JNDI_NAME}
asadmin create-auth-realm --classname
com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property username-column=${USER_NAME}:passwordcolumn=${PASSWORD}:group-name-column=${GROUP_NAME}:jaascontext=jdbcRealm:datasource-jndi="${JNDI_NAME}":grouptable=${GROUP_TABLE}:user-table=${USER_TABLE}
${REALM_NAME}
asadmin create-jdbc-connection-pool --datasourceclassname
org.apache.derby.jdbc.ClientDataSource --restype javax.sql.DataSource
--property
PortNumber=1527:Password=toto:User=toto:ServerName=localhost:Dat
abaseName=base1 derbyPool
asadmin create-jdbc-resource --connectionpoolid derbyPool jdbc/db
asadmin create-auth-realm --classname
com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm --property username-column=LOGIN:password-column=MOT_DE_PASSE:groupname-column=NOM_GROUPE:jaas-context=jdbcRealm:datasourcejndi="jdbc/db":group-table=GROUPE:user-table=PERSONNE realm1
R. Grin
R. Grin
Sécurité Java EE
page 129
Modifier le fichier web.xml
Sécurité Java EE
Extrait de web.xml
Il faut maintenant indiquer que ce realm devra
être utilisé lors de l’identification des utilisateurs
‰ Un exemple d’utilisation du realm
« candidatures » est donné dans le transparent
suivant
<login-config>
<auth-method>FORM</auth-method>
<realm-name>candidatures</realm-name>
<form-login-config>
<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
R. Grin
‰
JSF
page 130
page 131
JSF
page 132
22
‰
Un exemple avec template
R. Grin
Sécurité Java EE
page 133
Cet exemple va utiliser une authentification avec
le domaine JDBC et un formulaire écrit par le
développeur (type FORM)
R. Grin
Modèle de page
Sécurité Java EE
page 134
Exemple de template (1/3)
Si on veut que toutes les pages de l’application
indiquent le nom de l’utilisateur et permettent de
se déconnecter de l’application, il faut prévoir un
template qui contient ces fonctionnalités
‰ Les transparents suivant donnent un exemple
d’un tel template
‰ Les détails sont donnés dans la section « Code
Java pour la sécurité » de ce cours et dans le
cours JSF sur les templates
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-...N" ...>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
R. Grin
R. Grin
‰
Sécurité Java EE
page 135
<f:event type="preRenderView"
listener="#{bean.infosUser}" />
<ui:insert name="metadata"/>
Exemple de template (2/3)
Pour internationaliser ; dans faces-config.xml :
<resource-bundle>
<base-name>/Bundle</base-name>
<var>bundle</var>
</resource-bundle>
Sécurité Java EE
Sécurité Java EE
page 136
Exemple de template (3/3)
<h:head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<h:outputStylesheet library="css"
name="cssLayout.css" />
<title>#{bundle.titreGeneral}</title>
</h:head>
R. Grin
Pour retrouver les
informations sur l’utilisateur
page 137
<h:body>
<div id="top" class="top">
<ui:insert name="top">
#{bundle.titreGeneral} <h:outputText value="#{bean.login.login}"
rendered="#{bean.login.login} != ''"/> <h:outputText value="#{bean.login.nom}"
rendered="#{bean.login.nom} != ''"/>
</ui:insert>
</div>
...
</body>
R. Grin
Sécurité Java EE
page 138
23
Code bean session - getLogin
Code bean session - infosUser
public Login getLogin() {
// login contient la personne connectée
if (login == null) {
String nomUtilisateur =
FacesContext.getCurrentInstance()
.getExternalContext().getRemoteUser();
if (nomUtilisateur != null) {
login = loginFacade.find(nomUtilisateur);
}
}
return login;
}
R. Grin
Sécurité Java EE
public void infosUser(ComponentSystemEvent event) {
if (login != null) { // infos déjà obtenues
return;
}
String loginUtilisateur =
((HttpServletRequest)
FacesContext.getCurrentInstance()
.getExternalContext().getRequest())
.getRemoteUser();
if (loginUtilisateur != null) {
login = loginFacade.find(loginUtilisateur);
}
}
page 139
R. Grin
Déconnexion
Sécurité Java EE
page 140
Code bean session - logout
Il faut permettre à l’utilisateur de se déconnecter
‰ Le plus simple est d’ajouter un bouton pour cela
qui appelle une méthode du backing bean qui
appelle la méthode logout() de la classe
HttpServletRequest
public String logout() {
login = null;
try {
((HttpServletRequest)
FacesContext.getCurrentInstance()
.getExternalContext().getRequest()).logout();
} catch (ServletException ex) {
Logger.getLogger(Bean.class.getName())
.log(Level.SEVERE, null, ex);
}
return "/index";
}
R. Grin
R. Grin
‰
Sécurité Java EE
page 141
Sécurité Java EE
page 142
Écrire dans les fichiers de logs
‰
Dans du code Java, System.out.println
envoie dans les logs de GlassFish au niveau
INFO
‰ System.err.println envoie dans les logs de
GlassFish au niveau SEVERE
Logs dans GlassFish Mise au point
‰
R. Grin
Sécurité Java EE
page 143
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 144
24
Exemple
Afficher les logs
import java.util.logging.Logger;
...
private Logger log =
Logger.getLogger(MaClass.class.getName());
...
log.warning("Mon message.");
‰
R. Grin
R. Grin
Sécurité Java EE
page 145
Les derniers logs s’affichent avec la console
d’administration de GlassFish : serveur, onglet
« Général », bouton « Afficher les fichiers
journaux »
‰ On peut aussi aller directement voir le contenu
des fichiers
Où se trouvent les logs
page 146
Configuration des logs
‰
Les fichiers de logs se trouvent par défaut dans le
répertoire glassfish/domains/domain1/logs du
répertoire d’installation de GlassFish (si on
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
R. Grin
Sécurité Java EE
Sécurité Java EE
page 147
Dans la console d’administration, Configurations,
« Paramètres du journaliseur » (Logger Settings
an anglais)
Sécurité Java EE
page 148
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
(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 149
Gérer les mots de passe
R. Grin
Sécurité Java EE
page 150
25
Conserver les mots de passe
‰
Cette section expose quelques généralités sur la
gestion des login / mots de passe
R. Grin
Sécurité Java EE
page 151
‰
Pour authentifier les utilisateurs, 2 solutions :
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
A ne pas faire !
Ne jamais conserver les mots de passe en clair
dans l’application
‰ Ne pas utiliser des algorithmes de cryptage ou de
hashage faciles à déjouer
‰ Par exemple, ne pas utiliser MD5 (aller par
exemple sur le site http://www.md5hacker.com/
qui permet de trouver rapidement un mot de
passe qui correspond à une valeur MD5)
‰
R. Grin
R. Grin
page 153
Les mots de passe doivent donc être conservés
cryptés dans l’application
‰ Pour compliquer la recherche d’une série de mots
de passe, il faut ajouter une valeur aléatoire, le
sel, différente pour tous les utilisateurs, qui sera
ajoutée au mot de passe de chaque utilisateur
‰ Le sel peut être conservé en clair avec le mot de
passe crypté
Utilisation du sel
L’application récupère le mot de passe tapé par
l’utilisateur, elle concatène le sel au mot de passe et
elle crypte le tout en une valeur v1
‰ L’application vérifie que la valeur v0 qu’elle conserve
(le mot de passe de l’utilisateur, concaténé au sel et
crypté au moment de l’enregistrement du mot de
passe) est bien égale à v1 ; si ça n’est pas le cas,
c’est que le mot de passe tapé n’était pas le bon
Sécurité Java EE
Sécurité Java EE
page 154
Mots de passe avec GlassFish
‰
R. Grin
page 152
Saler !
‰
Sécurité Java EE
Sécurité Java EE
page 155
‰
Les dernières versions de GlassFish utilisent par
défaut le codage SHA-256 pour hasher les mots
de passe (on peut choisir lorsqu’on définit un
domaine de sécurité)
‰ GlassFish récupère le mot de passe par un
getString alors que les algorithmes de hashage
fournissent un tableau d’octets ; la façon de
passer du tableau d’octets à une String doit être
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 156
26
Enregistrer un mot de passe
Exemple de code
‰
On peut l’enregistrer sous la forme de byte[] ou
de String
‰
Base64 est le plus souvent utilisé pour la
transformation de byte[] en String
‰
Hex peut aussi être utilisé (écriture en
hexadécimal de chaque octet et concaténation de
tous les octets ; 2 chiffres par octet)
‰ Si on ne précise rien dans la définition du
domaine, GlassFish va passer par un char[] en
utilisant un codage (UTF-8)
R. Grin
Sécurité Java EE
page 157
‰
L’exemple suivant peut être utilisé tel quel dans
une application qui voudrait gérer elle-même
l’authentification en utilisant du sel
‰ Il est extrait et adapté du code de Jerry Orr donné
dans un article qui traite de la façon de conserver
les mots de passe, trouvé à l’adresse
http://jerryorr.blogspot.fr/2012_05_01_archive.html
R. Grin
Exemple de code (1/4)
import
import
import
import
import
import
import
Sécurité Java EE
page 158
Exemple de code (2/4)
java.security.NoSuchAlgorithmException;
java.security.SecureRandom;
java.security.spec.InvalidKeySpecException;
java.security.spec.KeySpec;
java.util.Arrays;
javax.crypto.SecretKeyFactory;
javax.crypto.spec.PBEKeySpec;
public class PasswordEncryptionService {
public boolean authenticate(
String attemptedPassword, byte[] encryptedPassword,
byte[] salt)
throws NoSuchAlgorithmException,
InvalidKeySpecException {
byte[] encryptedAttemptedPassword =
getEncryptedPassword(attemptedPassword, salt);
return Arrays.equals(
encryptedPassword, encryptedAttemptedPassword);
}
D’après code de Jerry Orr ;
http://jerryorr.blogspot.fr/2012_05_01_archive.html
R. Grin
Sécurité Java EE
page 159
R. Grin
Exemple de code (3/4)
Sécurité Java EE
page 160
Exemple de code (4/4)
public byte[] getEncryptedPassword(
String password, byte[] sel)
throws NoSuchAlgorithmException,
InvalidKeySpecException {
// Nom algorithme (PBKDF2 avec SHA-1)
String algo = "PBKDF2WithHmacSHA1";
int longueurCle = 160; // SHA-1 génère 160 bits
int iterations = 20000; // Au moins 1000
KeySpec spec = new PBEKeySpec(
password.toCharArray(), sel, iterations, longueurCle);
SecretKeyFactory f = SecretKeyFactory.getInstance(algo);
return f.generateSecret(spec).getEncoded();
}
R. Grin
Sécurité Java EE
page 161
// Utilisé la 1ère fois pour générer un sel.
// On peut garder le même si le mot de passe change
public byte[] generateSalt()
throws NoSuchAlgorithmException {
SecureRandom random =
SecureRandom.getInstance("SHA1PRNG");
// Genère un sel de 8 octets (64 bits)
byte[] sel = new byte[8];
random.nextBytes(sel);
return sel;
}
R. Grin
Sécurité Java EE
page 162
27
Attention à l’injection de code SQL
‰
Si l’application écrit son propre code SQL pour
vérifier un couple login/mot de passe enregistré
dans une base de données, attention à l’injection
de code SQL (voir cours sur la sécurité en Java
http://deptinfo.unice.fr/~grin/messupports/java/Se
curite6.pdf)
‰ Pas de crainte avec la façon standard de vérifier
un mot de passe dans une base utilisée par
GlassFish
R. Grin
Sécurité Java EE
page 163
28