Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
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
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
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
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)
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
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
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>
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
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
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
}
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
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
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>
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
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>
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
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
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
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
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>
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
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
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
R. Grin Sécurité Java EE page 111 R. Grin Sécurité Java EE page 112
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
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 ;
R. Grin Sécurité Java EE page 121 R. Grin Sécurité Java EE page 122
R. Grin Sécurité Java EE page 123 R. Grin Sécurité Java EE page 124
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
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)
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
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
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
R. Grin Sécurité Java EE page 147 R. Grin Sécurité Java EE page 148
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
R. Grin Sécurité Java EE page 153 R. Grin Sécurité Java EE page 154
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
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
R. Grin Sécurité Java EE page 163 R. Grin Sécurité Java EE page 164
R. Grin Sécurité Java EE page 165 R. Grin Sécurité Java EE page 166
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
R. Grin Sécurité Java EE page 171 R. Grin Sécurité Java EE page 172
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. 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
R. Grin Sécurité Java EE page 183 R. Grin Sécurité Java EE page 184
31