Table of Contents
Introduction
Dans ce tutoriel, nous allons explorer la mise en œuvre d’une politique de refus dans Java. Une telle politique permet de définir des permissions qui sont explicitement refusées à un code source ou à une protection de domaine spécifique. Nous allons voir comment créer et utiliser une classe DenyingPolicy qui ajoute cette fonctionnalité au comportement par défaut de la politique.
Prérequis
Pour suivre ce tutoriel, vous devez avoir une bonne compréhension des concepts de sécurité Java, notamment les permissions, les protection de domaine et la politique. Vous devez également avoir installé un environnement de développement Java (par exemple Eclipse ou IntelliJ IDEA).
Création d’une classe DeniedPermission
La première étape consiste à créer une classe DeniedPermission qui représente une permission refusée.
public class DeniedPermission extends Permission {
private final Permission target;
public DeniedPermission(Permission target) {
this.target = target;
super(target.getName());
}
// Méthodes implémentées ci-dessous
}
Cette classe étend la classe Permission et stocke une référence à l’original permission refusée dans le champ target. Nous allons maintenant implémenter les méthodes nécessaires pour cette classe.
Implémentation des méthodes
@Override
public boolean implies(Permission p) {
if (p instanceof DeniedPermission) {
return target.implies(((DeniedPermission) p).target);
}
return target.implies(p);
}
public Permission getTargetPermission() {
return target;
}
La méthode implies() permet de vérifier si la permission en question est impliquée par la permission cible. Si la permission cible est également une instance de DeniedPermission, nous appelons la méthode implies() sur la permission cible pour obtenir le résultat final.
Création d’une classe DenyingPolicy
Maintenant que nous avons notre classe DeniedPermission, nous pouvons créer la classe DenyingPolicy qui ajoutera cette fonctionnalité à la politique par défaut.
public class DenyingPolicy extends Policy {
private final Policy defaultPolicy;
public DenyingPolicy() {
try {
defaultPolicy = Policy.getInstance("javaPolicy", null);
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("Could not acquire default Policy.", nsae);
}
}
// Méthodes implémentées ci-dessous
}
Cette classe étend la classe Policy et stocke une référence à la politique par défaut dans le champ defaultPolicy. Nous allons maintenant implémenter les méthodes nécessaires pour cette classe.
Implémentation des méthodes
@Override
public PermissionCollection getPermissions(CodeSource codesource) {
return defaultPolicy.getPermissions(codesource);
}
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
return defaultPolicy.getPermissions(domain);
}
Les deux méthodes ci-dessus sont simplement des appels directs à la méthode correspondante de la politique par défaut.
Méthode implies()
@Override
public boolean implies(ProtectionDomain domain, Permission permission) {
if (permission instanceof DeniedPermission) {
return false;
}
if (!defaultPolicy.implies(domain, permission)) {
return false;
}
Enumeration<Permission> perms = defaultPolicy.getPermissions(domain).elements();
while (perms.hasMoreElements()) {
Permission p = perms.nextElement();
if (p instanceof UnresolvedPermission && ((UnresolvedPermission) p).getUnresolvedType().equals(DeniedPermission.class.getName())) {
defaultPolicy.implies(domain, p);
p = new DeniedPermission(((UnresolvedPermission) p).getUnresolvedName());
}
if (p instanceof DeniedPermission && p.implies(permission)) {
return false;
}
}
return true;
}
Cette méthode est la plus complexe de l’ensemble. Elle vérifie si la permission en question est une instance de DeniedPermission, et si ce n’est pas le cas, elle appelle la méthode correspondante de la politique par défaut.
Si la permission cible est une instance de UnresolvedPermission avec un type égal à DeniedPermission.class.getName(), elle force la résolution de cette permission en créant un objet DeniedPermission.
Enfin, si elle trouve une permission refusée qui implique la permission en question, elle retourne false. Sinon, elle retourne true.
Conclusion
Dans cet article, nous avons vu comment créer et utiliser une classe DenyingPolicy pour ajouter des permissions de refus à la politique par défaut. Nous avons également implémenté les méthodes nécessaires pour cette classe.
Vous pouvez maintenant intégrer cette fonctionnalité dans votre application Java en créant un objet DenyingPolicy et en le configurant comme politique par défaut.
Exemple d’utilisation
public class Main {
public static void main(String... args) {
Policy.setPolicy(new DenyingPolicy());
// Utilisez la politique pour vérifier les permissions...
}
}
N’oubliez pas de configurer correctement la politique dans votre application.
QCM : Testez vos connaissances
Question 1 : Role de la classe DeniedPermission
Quel est le role principal de la classe DeniedPermission dans le systeme de securite Java ?
- A) Accorder des permissions supplementaires a un domaine de protection
- B) Representer une permission qui est explicitement refusee
- C) Remplacer completement le systeme de permissions Java
- D) Logger les tentatives d acces non autorisees
Voir la reponse
Reponse correcte : B) Representer une permission qui est explicitement refusee
La classe DeniedPermission encapsule une permission cible et indique que cette permission doit etre explicitement refusee. Elle etend la classe Permission standard de Java et utilise le pattern decorator pour envelopper la permission originale. Cela permet de creer des regles de refus explicites qui ont priorite sur les permissions accordees.
Pourquoi les autres reponses sont incorrectes :
- A) est faux car
DeniedPermissionfait exactement le contraire : elle refuse des permissions, elle ne les accorde pas. - C) est faux car
DeniedPermissions integre au systeme existant via la classeDenyingPolicy, elle ne le remplace pas. - D) est faux car la classe n a aucune fonctionnalite de logging ; son unique role est de representer un refus de permission.
Question 2 : Methode implies dans DeniedPermission
Dans la methode implies() de DeniedPermission, pourquoi verifie-t-on si le parametre est une instance de DeniedPermission ?
- A) Pour eviter une NullPointerException
- B) Pour gerer correctement la comparaison entre deux permissions refusees
- C) Pour convertir automatiquement la permission en permission accordee
- D) Pour declencher une SecurityException
Voir la reponse
Reponse correcte : B) Pour gerer correctement la comparaison entre deux permissions refusees
Lorsque deux DeniedPermission sont comparees, il faut comparer leurs permissions cibles respectives et non les objets DeniedPermission eux-memes. La methode extrait donc la permission cible via ((DeniedPermission) p).target pour effectuer une comparaison semantiquement correcte. Sans cette verification, la logique d implication ne fonctionnerait pas correctement entre permissions refusees.
Pourquoi les autres reponses sont incorrectes :
- A) est faux car la verification de type (
instanceof) ne protege pas contre les null ; une verificationp != nullserait necessaire pour cela. - C) est faux car aucune conversion n est effectuee ; les permissions restent des permissions refusees.
- D) est faux car la methode
implies()retourne un booleen et ne lance jamais deSecurityException.
Question 3 : Acquisition de la politique par defaut
Dans le constructeur de DenyingPolicy, quelle exception est capturee lors de l acquisition de la politique par defaut ?
- A) SecurityException
- B) PolicyException
- C) NoSuchAlgorithmException
- D) IllegalStateException
Voir la reponse
Reponse correcte : C) NoSuchAlgorithmException
La methode Policy.getInstance("javaPolicy", null) utilise le framework SPI (Service Provider Interface) de Java qui peut lancer une NoSuchAlgorithmException si le provider de politique specifie n est pas disponible. Dans notre implementation, cette exception est encapsulee dans une RuntimeException car l absence de politique par defaut est une erreur fatale qui empeche le fonctionnement du systeme de securite.
Pourquoi les autres reponses sont incorrectes :
- A)
SecurityExceptionpourrait etre lancee pour des problemes de droits, mais ce n est pas ce quePolicy.getInstance()declare. - B)
PolicyExceptionn existe pas dans l API standard de securite Java. - D)
IllegalStateExceptionn est pas lancee parPolicy.getInstance(); elle serait plus appropriee pour des erreurs d etat d objet.
Question 4 : Comportement de implies dans DenyingPolicy
Que retourne la methode implies() de DenyingPolicy si la permission demandee est elle-meme une instance de DeniedPermission ?
- A) true
- B) false
- C) Elle lance une exception
- D) Elle delegue a la politique par defaut
Voir la reponse
Reponse correcte : B) false
La premiere verification dans la methode implies() est if (permission instanceof DeniedPermission) return false;. Cela signifie qu on ne peut jamais obtenir une permission de type DeniedPermission directement. C est une mesure de securite logique : une permission refusee ne doit jamais etre accordee. Cela empeche egalement toute tentative de contourner le systeme en demandant explicitement une permission refusee.
Pourquoi les autres reponses sont incorrectes :
- A) Retourner
trueserait une faille de securite majeure car cela accorderait une permission explicitement refusee. - C) La methode ne lance pas d exception ; elle retourne simplement
falsepour refuser la permission. - D) La delegation a la politique par defaut n intervient que si la permission n est pas une
DeniedPermission.
Question 5 : UnresolvedPermission et resolution
Pourquoi le code verifie-t-il si une permission est une UnresolvedPermission avec un type DeniedPermission ?
- A) Pour ignorer les permissions non resolues
- B) Pour forcer la resolution des permissions refusees differees
- C) Pour convertir les permissions refusees en permissions accordees
- D) Pour supprimer les permissions invalides
Voir la reponse
Reponse correcte : B) Pour forcer la resolution des permissions refusees differees
Les UnresolvedPermission sont des permissions dont la classe n etait pas encore chargee au moment de la lecture du fichier de politique. Quand le code rencontre une UnresolvedPermission de type DeniedPermission, il force sa resolution en creant explicitement un objet DeniedPermission. Sans cette etape, les permissions refusees declarees dans le fichier de politique pourraient ne jamais etre appliquees, laissant des failles de securite.
Pourquoi les autres reponses sont incorrectes :
- A) est faux car le code ne les ignore pas ; au contraire, il les traite specifiquement.
- C) est faux car la resolution transforme une
UnresolvedPermissionenDeniedPermission, pas en permission accordee. - D) est faux car les permissions ne sont pas supprimees ; elles sont resolues et appliquees.
Question 6 : Integration de DenyingPolicy
Comment active-t-on la DenyingPolicy dans une application Java ?
- A) En ajoutant une annotation @Policy sur la classe main
- B) En appelant Policy.setPolicy(new DenyingPolicy())
- C) En modifiant le fichier java.security
- D) En heritant de SecurityManager
Voir la reponse
Reponse correcte : B) En appelant Policy.setPolicy(new DenyingPolicy())
La methode statique Policy.setPolicy() permet de definir la politique de securite active pour la JVM. En passant une instance de DenyingPolicy, on remplace la politique par defaut par notre implementation personnalisee. Cette approche programmatique est flexible et permet de changer la politique a l execution selon les besoins de l application.
Pourquoi les autres reponses sont incorrectes :
- A) Il n existe pas d annotation
@Policydans l API de securite Java standard. - C) Bien que java.security permette de configurer des policies, cela ne suffit pas pour activer une classe personnalisee sans code supplementaire.
- D)
SecurityManagerest un composant different qui utilise laPolicy; heriter de lui ne change pas la politique active.
Question 7 : Securite et design pattern
Quel design pattern est principalement utilise par la classe DeniedPermission ?
- A) Singleton
- B) Factory
- C) Decorator (ou Wrapper)
- D) Observer
Voir la reponse
Reponse correcte : C) Decorator (ou Wrapper)
DeniedPermission utilise le pattern Decorator car elle encapsule une permission existante (target) et modifie son comportement semantique. Au lieu d accorder la permission, elle indique qu elle doit etre refusee. Ce pattern permet d ajouter des fonctionnalites (ici, le concept de refus) sans modifier les classes de permission existantes, respectant ainsi le principe Open/Closed.
Pourquoi les autres reponses sont incorrectes :
- A) Singleton garantit une instance unique ;
DeniedPermissionpeut avoir plusieurs instances pour differentes permissions. - B) Factory cree des objets ;
DeniedPermissionencapsule un objet existant, elle ne le cree pas. - D) Observer gere les notifications entre objets ; ce n est pas le cas ici.
Question 8 : Ordre de verification des permissions
Dans la methode implies() de DenyingPolicy, quel est l ordre correct des verifications ?
- A) Verification politique par defaut, puis verification DeniedPermission
- B) Verification DeniedPermission directe, politique par defaut, puis iteration des permissions
- C) Iteration des permissions, puis verification politique par defaut
- D) Verification DeniedPermission directe, iteration des permissions, puis politique par defaut
Voir la reponse
Reponse correcte : B) Verification DeniedPermission directe, politique par defaut, puis iteration des permissions
L ordre est crucial pour la securite et la performance :
- D abord, on verifie si la permission demandee est elle-meme une
DeniedPermission(retour immediat false) - Ensuite, on verifie via la politique par defaut si la permission est accordee (si non, retour false)
- Enfin, on itere sur les permissions pour trouver d eventuelles
DeniedPermissionqui impliqueraient la permission demandee
Cet ordre garantit que les refus explicites sont toujours verifies apres l accord initial.
Pourquoi les autres reponses sont incorrectes :
- A) est incomplet et ne mentionne pas la verification initiale de
DeniedPermission. - C) inverserait la logique et serait inefficace (iteration avant verification rapide).
- D) place l iteration avant la politique par defaut, ce qui est incorrect.
Pour aller plus loin
Ressources recommandees
- Documentation Oracle : Java Security Architecture - La reference officielle sur l architecture de securite Java.
- Java SE Security : Permissions in the JDK - Liste complete des permissions standard.
Concepts connexes a explorer
- AccessController et doPrivileged : Comprendre comment executer du code avec des privileges eleves de maniere securisee.
- SecurityManager : Apprendre comment le SecurityManager utilise la Policy pour prendre des decisions de securite.
- JAAS (Java Authentication and Authorization Service) : Explorer l authentification et l autorisation basees sur les sujets.
- CodeSource et ProtectionDomain : Approfondir comment Java determine l origine du code et ses permissions.
Exercices pratiques
- Implementer un logger de permissions : Modifiez
DenyingPolicypour logger toutes les tentatives d acces refusees. - Permissions conditionnelles : Creez une
TimeBasedDeniedPermissionqui refuse une permission uniquement pendant certaines heures. - Tests unitaires : Ecrivez des tests JUnit pour verifier le comportement de
DeniedPermissionetDenyingPolicy.
Points cles a retenir
- Les permissions refusees ont priorite sur les permissions accordees grace a la verification dans
implies(). - Le pattern Decorator permet d etendre le systeme de permissions sans modifier les classes existantes.
- La resolution des
UnresolvedPermissionest necessaire pour que les permissions refusees fonctionnent correctement. - Toujours tester votre politique de securite dans un environnement isole avant la mise en production.
In-Article Ad
Dev Mode
Mahmoud DEVO
Senior Full-Stack Developer
I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.
Enjoyed this article?
Subscribe to get more tech content delivered to your inbox.
Related Articles
Reflexion Java : Manipuler Champs Prives et Finaux avec Precautions
Explorez la reflexion Java pour acceder aux champs prives et finaux. Decouvrez ses usages legitimes et les risques de securite a connaitre absolument.
Manipuler les classes Java avec ASM et Javassist : bytecode, instrumentation et fichiers JAR
Apprenez a manipuler les classes Java avec ASM et Javassist : chargement, modification du bytecode, instrumentation et creation de fichiers JAR.
Synchronisation Java avec AtomicInteger : eviter la contention et optimiser les performances
Decouvrez comment utiliser les types atomiques Java (AtomicInteger, AtomicLong, AtomicReference, AtomicBoolean) pour reduire la contention, eviter les blocages et ameliorer les performances.