1. Gestion des droits dans JPlatform
JPlatform offre en standard une large palette de droits sur l'ensemble des fonctionnalités : droits de consultation, de contribution, de dépôt de fichier, d'administration, … Néanmoins, pour certains besoins il peut être nécessaire de spécialiser la gestion de droit. La spécialisation peut se faire soit en complément soit en remplacement de l'implémentation standard.
Dans JPlatform les droits sont affectés soit individuellement à des membres soit à des groupes. Un membre qui appartient à un sous-groupe appartient automatiquement à tous les groupes parents de ce groupe (et aux parents des parents). Ainsi en affectant un droit à un groupe c'est non seulement les membres de ce groupe qui en bénéficient mais aussi tous les membres des sous groupes de ce groupe.
Cet article présente l'ensemble des droits de JPlatform.
2. Les grandes familles de droits
2.1 Droits sur les publications
2.1.1 Droits de consultation des publications
Ce droit contrôle qui peut consulter un contenu ou visualiser une portlet. Ce droit est défini contenu par contenu en indiquant les groupes et les membres autorisés. Si aucun droit n'est défini, la publication est visible de tous. Il est possible d'affecter des droits de consultation par défaut (par type de publication ou par espace de travail).
Le droit de consultation est conditionné :
- à l'état du workflow dans lequel se trouve la publication : une publication hors de l'état publié n'est visible que dans le back-office de son espace de travail.
- au rédacteur : quelques soient les droits de consultation, un membre a toujours accès aux contenus dont il est le rédacteur.
2.1.2 Droits de contribution
Ce droit contrôle qui peut créer, modifier ou supprimer des publications. Ce droit est défini par type de publication. Il est affecté pour un groupe ou pour membre.
Il est possible de définir un droit spécifique d'édition pour un contenu. Ceci permet à certains membres ou groupes n'ayant pas ce droit d'en bénéficier pour ces contenus.
Le droit de contribution est conditionné :
- Au droit de consultation : un utilisateur ne peut pas éditer ni supprimer une publication à laquelle il n'a pas accès ;
- A l'espace de travail : le contributeur ne bénéficie de son droit de contribution sur le type T dans un espace de travail que si cet espace utilise le type T ;
- Au workflow :
- Un membre ne peut créer une publication que si il est autorisé à travailler dans l'état initial du workflow de la publication.
- Un membre ne peut éditer ou supprimer une publication que si elle se situe dans un état de workflow où le membre peut agir ; c'est-à-dire un état pour lequel le membre occupe au moins un rôle de l'une des transitions sortantes de cet état.
2.1.3 Droits de dépôt des fichiers
Ce droit contrôle qui peut déposer des fichiers sur le site. Il s'agit en fait d'un droit dérivé du droit de contribution sur le type Document. Le membre doit avoir le droit de contribution sur le type Document
En standard, JPlatform permet de contrôler le type et et la taille des fichiers déposés. Il est par exemple possible d'interdire le dépôt de fichiers vidéo ou de n'accepter que les fichiers PDF inférieurs à 10 Mo. Pour plus de détails, consulter la FAQ à ce sujet.
2.1.4 Droits d'accès aux fichiers
Le droit d'accès aux fichiers déposés est régi par les publications qui les pointent. Lorsqu'un utilisateur accède à l'un de ces fichiers, JPlatform vérifie qu'il peut accéder à au moins une des publications qui référence ce fichier (soit un FileDocument, soit une publication avec un champ de type chemin de fichier).
2.1.5 Profils de consultation (audiencement)
JPlatform propose également une autre approche pour la gestion des droits de consultation : les profils de consultation.
Le principe consiste à déterminer les droits de consultation en croisant les catégories d’un contenu et les catégories du membre qui accède au contenu. Pour cela, les membres doivent être catégorisés sur les mêmes branches que les contenus. Les rédacteurs n'ont plus à déclarer explicitement les droits de consultations mais simplement à quelles catégories sont rattachés les contenus.
Pour plus de détails, consulter l'article Profils de consultation (Audiencement)
2.2 Droits sur les catégories
2.2.1 Droits de consultation des catégories
Ce droit contrôle qui peut consulter une branche de catégories. Il est défini branche par branche pour un membre ou un groupe. Si un membre peut consulter la catégorie C, alors il peut aussi consulter toutes les sous-catégories de C.
Ce droit porte sur l'affichage des catégories (typiquement pour une Portlet Navigation). Il n'affecte pas les contenus situés sous ces catégories. En d'autres termes, un membre peut consulter les contenus référencés sous la catégorie C même si il n'a pas le droit de consulter C.
2.2.2 Droits d'usage des catégories
Ce droit contrôle qui peut référencer un contenu sous une branche de catégories. Il est défini branche par branche pour un membre ou un groupe. Si un membre peut référencer la catégorie C, alors il peut aussi référencer toutes les sous-catégories de C. Ce droit est conditionné au droit de contribution des publications.
2.2.3 Droits de gestion des catégories
Ce droit contrôle qui peut gérer une branche de catégories, c'est-à-dire créer, modifier, déplacer et supprimer des catégories. Il est défini branche par branche pour un membre ou un groupe. Si un membre peut gérer une catégorie C, alors il peut aussi gérer toutes les sous-catégories de C.
2.3 Droits d'administration
2.3.1 Droits d'administration d'un espace de travail
Ce droit contrôle qui peut administrer un espace de travail, c'est-à-dire :
- Gérer les groupes de l'espace de travail;
- Affecter les membres aux groupes ;
- Gérer les affectations des rôles des workflows ;
- Gérer les propriétés des types (workflows, droits par défaut, onglet affichés, …)
- Consulter, éditer et supprimer toutes les publications et les catégories de l'espace de travail quelques soient leurs droits.
Ce droit est nominatif. Il est donné espace par espace par l'administrateur du site.
2.3.2 Droit d'administration centrale
Ce droit donne accès à toutes les fonctionnalités de JPlatform. En plus des droits précédents, il permet de :
- Gérer les comptes utilisateurs ;
- Gérer les groupes ;
- Gérer les espaces de travail ;
- Gérer les modèles de workflow ;
- Gérer les types de publications ;
- Effectuer les tâches d'exploitation (configuration, indexation des publications, gestions des caches, …) ;
- Effectuer les tâches de développement (définition des types de publication, gestion des changements, profiling, …)
2.4 Matrice d'affectation des droits
La matrice suivante indique qui peut affecter les droits.
Contributeurs | Gestionnaire des catégories |
Administrateur d'espace de travail |
Administrateur central |
|
---|---|---|---|---|
Droits de consultation des publications (§2.1.1) | x |
x |
x |
|
Droits de contribution (§2.1.2) | x |
x |
x |
|
Droits de consultation des catégories (§2.2.1) | x |
x |
x |
|
Droits d'usage des catégories (§2.2.2) | x |
x |
||
Droits de gestion des catégories (§2.2.3) | x |
x |
||
Droits d'administration d'espace de travail (§2.3.1) | x |
|||
Droits d'administration centrale (§2.3.2) | x |
3. Spécialisation des droits avec les RightPolicyFilter
3.1 Principes
Il est possible d'adapter ou de modifier une partie du système de droits de JPlatform en ajoutant un module comportant des composants RightPolicyFilter
. Chacune des méthodes de cette interface permet de surcharger le comportement d'une famille de droit de JPlatform.
3.1.1 La classe RightPolicyFilter
La plupart des méthodes de l'interface RightPolicyFilter
renvoient un booléen qui indique si le droit est validé ou non. Pour certaines méthodes de la classe RightPolicy
, le premier argument de la méthode est un booléen, isAuthorized
, qui indique si, selon le système de droits standard de JPlatform, l'utilisateur peut accéder ou non à ce qu'il demande. Lorsqu'une de ces méthodes est modifiée, il est recommandé de rejeter l'accès si JPlatform l'a lui aussi rejeté. C'est-à-dire renvoyer false
si isAuthorized
est false. Mais il est possible de passer outre le système de droit par défaut de JPlatform en ignorant la position de JPlatform.
Le contrôle de droit est très fréquemment invoqué par JPlatform. Par exemple, lors du rendu d'une page portail, certaines méthodes de la classe RightPolicyFilter
peuvent être appelées des centaines de milliers de fois. Il faut donc veiller à ce que l'implémentation de ces méthodes soit performante.
La classe BasicRightPolicyFilter
implémente l'interface RightPolicyFilter
et fournit une implémentation neutre pour chacune des méthodes de RightPolicyFilter
. Sauf cas particulier, il est donc recommandé de dériver de BasicRightPolicyFilter
.
Pour être prise en charge par le gestionnaire des modules, la classe implémentant RightPolicyFilter
doit aussi implémenter l'interface PluginComponent
et sa méthode init()
.
Exemple de code :
public MyRightPolicy extends BasicRightPolicyFilter
implements PluginComponent {
public boolean init(Plugin plugin) {
return true;
}
public boolean canBeReadBy(boolean isAuthorized
Publication pub,
Member mbr,
boolean searchInGroups) {
if (!isAuthorized) {
return false;
}
// Custom conditions here
...
}
}
3.1.2 Ajout d'un RightPolicyFilter
L'ajout d'un RightPolicyFilter
se fait dans le fichier plugin.xml
du module via la balise <policyfilter>
.
Exemple de déclaration :
<plugin>
...
<plugincomponents>
<policyfilter class="org.demo.jcmsplugin.demo.MyRightPolicyFilter" />
...
</plugincomponents>
...
</plugin>
3.1.3 Accès aux informations contextuelles
Les méthodes de classe RightPolicyFilter
fournissent des informations qui permettent de déterminer le droit (p. ex. la publication concernée, le membre qu'il faut tester, …) Ces méthodes sont utilisés dans tous les cas de contrôle de droit et pas uniquement lorsque l'utilisateur accède depuis son navigateur à un page de JPlatform. Par exemple, elles sont aussi appelées lorsque les mails de validation doivent être envoyés suite à un changement d'état programmé. Ces méthodes ne reçoivent donc pas d'information sur la requête HTTP. Cependant, si le droit doit être conditionné à des informations contextuelles à l'accès web (p. ex. l'adresse IP, le type de navigateur, …), ces informations sont accessibles via les méthodes channel.getCurrentServletRequest()
et channel.getCurrentJcmsContext()
.
3.1.4 Alternative aux RightPolicyFilter
Une solution alternative à la spécialisation par les RightPolicyFilter
consiste à contrôler le système de droits programmatiquement via les APIs d'écriture. Ceci se fait typiquement en utilisant un DataController. Par exemple, pour affecter automatiquement un droit de consultation, il est possible à chaque enregistrement d'un contenu d'examiner les champs du contenu, d'en déduire le droit et d'affecter les membres ou groupes autorisés. Cette approche à l'avantage d'assurer de bonne performance lors du contrôle des droits mais ne permet pas de faire des droits contextuels (par exemple, basé sur l'adresse IP de provenance du membre).
3.2 Droit de consultation des publications
Le droit de consultation des publications peut être modifié par les méthodes :
public boolean canBeReadBy(boolean isAuthorized, Publication pub, Member mbr, boolean searchInGroups)
La première méthode est invoquée lorsque le contrôle doit être fait sur un membre et la seconde sur un groupe. Pour la première méthode le booléen searchInGroups
indique si le contrôle doit être fait uniquement avec les droits propres au membre ou en intégrant aussi les droits issus de ses groupes.
Note : la méthode suivante est dépréciée depuis JPlatform 10 SP5 (JCMS-8577 ) et n'est pas utilisée par le produit :
public boolean canBeReadBy(boolean isAuthorized, Publication pub, Group grp)
3.3 Droit de consultation des catégories
Le droit de consultation des publications peut être modifié par les méthodes :
public boolean canBeReadBy(boolean isAuthorized, Category cat, Member mbr, boolean searchInGroups, boolean checkAncestors)
La première méthode est invoquée lorsque le contrôle doit être fait sur un membre et la seconde sur un groupe. Pour la première méthode le booléen searchInGroups
indique si le contrôle doit être fait uniquement avec les droits propres au membre ou en intégrant aussi les droits issus de ses groupes.
L'attribut checkAncestors
indique si le contrôle porte sur la catégorie seule ou si il doit être étendu aux ancêtres de cette catégorie. Dans ce dernier cas, si le membre ou le groupe ne dispose pas du droit sur la catégorie, JPlatform teste sur le parent, puis sur le parent du parent, et ainsi de suite jusqu'à ce qu'une catégorie accessible soit trouvée. Si la racine des catégories est atteinte sans avoir trouvé une catégorie autorisée alors l'utilisateur n'a pas accès à cette catégorie.
Il n'est pour l'instant pas possible de surcharger les droits d'usage et de gestion des catégories.
Note : la méthode suivante est dépréciée depuis JPlatform 10 SP5 (JCMS-8579) et n'est pas utilisée par le produit :
public boolean canBeReadBy(boolean isAuthorized, Category cat, Group grp, boolean checkAncestors)
3.4 Droits de contribution
Les droits de contribution peuvent être modifié par les méthodes :
public boolean canPublish(boolean isAuthorized, final Member mbr, final Class clazz, final Set wsSet)
public boolean canUpdateOther(boolean isAuthorized, final Member mbr, final Class clazz, final Workspace ws)
public boolean canDeleteOther(boolean isAuthorized, final Member mbr, final Class clazz, final Workspace ws)
public boolean canWorkOn(boolean isAuthorized, Publication pub, Member mbr)
Les méthodes canPublish(), canUpdateOther(), canDeleteOther()
permettent de contrôler le droit qu'elle représente (contribuer, modifier/supprimer les contributions des autres).
La méthode canWorkOn()
est invoquée à chaque fois que l'on doit déterminer si un membre peut éditer ou supprimer une publication.
3.5 Droits de gestion et d'utilisation des catégories
Les droits de gestion et d'utilisation des catégories peuvent être modifiés par les méthodes :
public boolean canUseCategory(boolean isAuthorized, final Member mbr, final Category cat, final boolean searchInGroups, final boolean searchInParent)
public boolean canManageCategory(boolean isAuthorized, final Member mbr, final Category cat, final boolean searchInGroups, final boolean searchInParent
3.6 Droit de dépôt de fichier
Le droit de dépôt de fichier peut être contrôler par les méthodes :
public boolean checkBeforeUpload(String fieldName, String contentType, String fileName)
public boolean checkAfterUpload(DocUploadInfo info)
La méthode checkBeforeUpload()
est invoquée au début du transfert et permet de l'interrompre celui en se basant sur le nom du fichier (fileName
) ou le type de fichier (contentType
).
La méthode checkAfterUpload()
est invoquée une fois que le fichier a été déposé. L'attribut info
permet d'obtenir des informations sur le fichier. Si cette méthode renvoie true
, le fichier est déplacé de la zone temporaire de dépôt à son emplacement définitif. Sinon, le fichier est supprimé et l'utilisateur est prévenu du rejet.
3.7 Contrôle de contenu HTML
Lors de l'enregistrement d'une publication contenant des champs de type Texte Riche (avec un éditeur wysiwyg), le contenu de ces champs est
- d'abord nettoyé automatiquement selon les règles décrites dans la documentation Wysiwyg - Configuration du Nettoyage HTML
- puis vérifié selon les règle décrites ci-dessous.
La vérification permet d'éviter qu'un contributeur mal intentioné introduise par exemple du code Javascript pour faire du Cross Site Scripting. Par défaut JPlatform, passe une expression régulière définie par la propriété channel.forbidden-html
qui est déclarée dans le fichier WEB-INF/data/webapp.prop
.
Il est possible d'aller au-delà en modifiant la méthode :
public ControllerStatus checkHtml(String str, String field)
L'attribut str
contient le texte à vérifier
L'attribut field
contient le nom du champ contenant ce texte.
La méthode retourne un ControllerStatus qui, en cas de rejet, permet de préciser un message d'explication.
4. Exemples de spécialisation
4.1 Filtrage selon la provenance de l'utilisateur
Dans cet exemple, on interdit l'accès aux publications de type Article aux utilisateurs utilisant un navigateur embarqué sur un PDA ou un téléphone i-mode.
Pour cet exemple, la méthode canBeReadBy()
est surchargée. Le contrôle par défaut (isAuthorized
) est préservé. Ensuite, si il s'agit d'une Article on contrôle le type de navigateur. La classe Browser fournit des informations sur le navigateur. Il est possible d'obtenir une instance correspondant à l'utilisateur qui fait la requête via la classe JcmsContext que l'on récupère via la méthode channel.getCurrentJcmsContext()
. La méthode isSmallDevice() permet de tester si il s'agit d'un PDA ou d'un téléphone i-mode.
Pour tester cet exemple, il suffit de consulter la page custom/jcms/indexPDA.jsp
et de comparer le résultat lorsque l'on y accède avec un navigateur classique. Si vous ne disposez pas d'un PDA ou d'un téléphone i-mode, vous pouvez utiliser un simulateur comme par exemple Phone Simulator d'OpenWave.
public class BrowserFilter extends BasicRightPolicyFilter
implements PluginComponent {
public boolean init(Plugin plugin) {
return true;
}
public boolean canBeReadBy(boolean isAuthorized, Publication pub, Member mbr, boolean searchInGroups) {
// Check JPlatform status
if (!isAuthorized) {
return false;
}
// Only test Article
if (!(pub instanceof generated.Article)) {
return true;
}
// Check the Browser
Channel channel = Channel.getChannel();
JcmsContext ctxt = channel.getCurrentJcmsContext();
if (ctxt == null) {
return true;
}
Browser browser = ctxt.getBrowser();
return !browser.isSmallDevice();
}
4.2 Droit de validation conditionnel
Dans cet exemple, on met en place un système de distribution des contenus à valider selon une branche de catégories. Un validateur n'aura à valider que les contenus classés dans des catégories dont il a le droit de gestion.
Pour cet exemple, la méthode canWorkOn()
est surchargée. Si la publication est dans l'état Soumis (-80) alors on vérifie que le membre a le droit de gérer au moins une des catégories de la publication.
public class ValidatorFilter extends BasicRightPolicyFilter
implements PluginComponent {
static int SUBMITTED_PSTATUS = -80;
public boolean init(Plugin plugin) {
return true;
}
public boolean canWorkOn(boolean isAuthorized, Publication pub, Member member) {
// Check JPlatform status
if (!isAuthorized) {
return false;
}
// Check only publication in "submitted" state
if (pub.getPstatus() != SUBMITTED_PSTATUS) {
return true;
}
// Get the categories of the publication
Set catSet = pub.getCategorySet();
if (Util.isEmpty(catSet)) {
return true;
}
// Get the categories the member can manage
Set rootSet = member.getCategoryRootSet();
if (Util.isEmpty(rootSet)) {
return false;
}
// Check if the publication is under a category the member can manage
for(Iterator it1 = catSet.iterator(); it1.hasNext();) {
Category cat = (Category)it1.next();
for(Iterator it2 = rootSet.iterator(); it2.hasNext();) {
Category root = (Category)it2.next();
if (cat == root || cat.hasAncestor(root)) {
return true;
}
}
}
return false;
}
4.3 Contrôle antivirus des fichiers déposés
Dans cet exemple, on souhaite déclencher un contrôle antivirus à chaque fois qu'un fichier est déposé dans JPlatform. Si un virus est détecté, le fichier est supprimé et l'utilisateur est prévenu du rejet.
Pour analyser les fichiers, on utiliser l'antivirus AVG de Grisoft qui est disponible gratuitement pour Windows et Linux. Cette version est fonctionnelle mais limitée a un usage personnel ; ce qui convient pour illustrer cet exemple. Dans le cadre, d'un usage en entreprise il faudrait envisager l'achat d'une licence adaptée. Le code de l'exemple est conçu pour la version Windows.
Pour cet exemple, la méthode checkAfterUpload()
est modifiée. A chaque soumission, on lance l'exécutable avgscan.exe
sur le fichier déposé avec le paramètre /REPORT
afin qu'il génère un rapport d'analyse. Le rapport est ensuite lu ligne par ligne. Si le texte "No viruses found."
est trouvé, le fichier est accepté ; sinon il est rejeté.
Pour tester cet exemple, il faut disposer d'un fichier infecté. Pour cela, il est conseillé d'utiliser un virus inoffensif et spécialement conçu pour les tests comme par exemple celui de EICAR. Attention ! Si AVG est actif, lors du dépôt du fichier eicar.com
, il le neutralisera dès son enregistrement et JPlatform acceptera un fichier vide. Il faut donc désactiver le contrôle automatique (au moins lors du test) pour laisser JPlatform effectuer le contrôle et prévenir l'utilisateur.
public class AVGFilter extends BasicRightPolicyFilter
implements PluginComponent {
private static final Logger logger = Logger.getLogger(AVGFilter.class);
static String AVGSCAN = "\"C:\\Program Files\\Grisoft\\AVG Free\\avgscan.exe\"";
static String NO_VIRUS = "No viruses found.";
public boolean init(Plugin plugin) {
return true;
}
public boolean checkAfterUpload(DocUploadInfo info) {
File file = info.getFile();
if (isInfected(file)) {
JcmsUtil.logSecurityIssue("Virus found in file " + file.getName());
return false;
}
logger.info("No viruses found in " + file.getName());
return true;
}
boolean isInfected(File file) {
boolean isInfected = true;
File report = null;
// Run avgscan.exe
try {
report = File.createTempFile("avgreport", "txt");
report.deleteOnExit();
String cmdLine = AVGSCAN + " /REPORT " + report + " " + file;
Runtime.getRuntime().exec(cmdLine).waitFor();
}
catch (Throwable th){
logger.warn("Exception while running avgscan", th);
return true;
}
// Parse the report
try (BufferedReader br = new BufferedReader(new FileReader(report))) {
for(String line = br.readLine(); line != null; line = br.readLine()) {
if (NO_VIRUS.equals(line)) {
isInfected = false;
break;
}
logger.debug(line);
}
report.delete();
}
catch (IOException ex){
logger.warn("Exception while reading report " + file, ex);
}
return isInfected;
}
}