Quand on déploie des cubes Mondrian dans Pentaho, on est bien souvent amené à gérer des droits d’accès sur une ou plusieurs dimensions d’un cube : par exemple pour un cube des ventes, ne permettre aux responsables commerciaux de visualiser uniquement les chiffres d’affaires concernant les zones dont ils ont la charge.
Cette opération de sécurisation d’accès aux données s’effectue assez simplement, via l’ajout d’attributs dans le schéma XML du cube, et ceci pour chaque rôle à filtrer, par exemple :
1 2 3 4 5 6 7 8 9 10 11 |
<Role name="California manager"> <SchemaGrant access="none"> <CubeGrant cube="Sales" access="all"> <DimensionGrant hierarchy="[Measures]" access="all"/> <HierarchyGrant hierarchy="[Store]" access="custom" topLevel="[Store].[Store Country]"> <MemberGrant member="[Store].[USA].[CA]" access="all"/> <MemberGrant member="[Store].[USA].[CA].[Los Angeles]" access="none"/> </HierarchyGrant> </CubeGrant> </SchemaGrant> </Role> |
Cette sécurisation d’accès aux données fonctionne bien, mais montre rapidement ses limites dès que :
- le nombre de rôles devient important
- l’affectation des utilisateurs à ces rôles évolue souvent
Dans ces 2 cas, il devient alors très contraignant d’appliquer la sécurité car celle-ci nécessite obligatoirement une définition en dur dans le schéma XML
Comment donc procéder dans ce type de situation ?
Réponse : grâce à la sécurisation dynamique du schéma Mondrian offerte par le « Dynamic Schema Processor » (DSP)
# Sécurisation dynamique du cube SteelWheels
Nous prendrons comme exemple l’adaptation du cube « SteelWheels » fourni dans la plate-forme Pentaho de démo (pré-requis : Pentaho 4.8 CE + plugin Saiku).
L’objectif est de pouvoir sécuriser dynamiquement les pays en fonction de qui se connecte.
Dans mon exemple, on sécurise les pays pour Joe, Suzy, Pat et Tiffany comme indiqué dans les codes couleurs ci-dessous :
# Etape 1 – Stockage des habilitations
La façon la plus souple de conserver les droits d’accès, c’est encore une base de données. Ainsi les liens Utilisateur <=> Pays sont stockés dans une table « USER_FILTER » créée spécifiquement dans la base SampleData et chargée avec le traitement Kettle ci-dessous :
# Etape 2 – Chargement des pays autorisés pour l’utilisateur
Une Xaction « set_session_vars.xaction » est créée, celle-ci permet de charger dans la session utilisateur la liste des pays autorisés. Cette Xaction charge en session (lors de la connexion de l’utilisateur à la PUC) la variable USER_COUNTRY, à savoir une chaine de caractère correspondant à la concaténation des pays accessibles et qui sera utilisée ultérieurement dans la clause « WHERE COUNTRY IN » d’un ordre SQL.
Ci-dessous la requête SQL sur la table user_filter permettant de récupérer la liste des pays autorisés en fonction de l’identifiant utilisateur (via le paramètre {login}) :
Une fonction javascript permet d’instancier la variable USER_COUNTRY, via la concaténation de tous les pays retournés :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function getCountry(){ var chaine=""; var nbRecords = query_result.getRowCount(); for (var j = 0; j< nbRecords ; j++) { var value = query_result.getValueAt(j, 1); if (j == nbRecords-1) { chaine = chaine + "'" + value + "'"; } else { chaine = chaine + "'" + value + "',"; } } return chaine; } |
# Etape 3 – Activation automatique de « set_session_vars.xaction »
Afin que cette Xaction soit déclenchée automatiquement à la connexion, il faut ajouter les lignes ci-dessous dans le fichier /pentaho-solutions/system/sessionStartupActions.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!– Start of PentahoHttpSession startup actions. –> <bean class="org.pentaho.platform.engine.core.system.SessionStartupAction"> <property name="sessionType" value="org.pentaho.platform.web.http.session.PentahoHttpSession"/> <property name="actionPath" value="bi-developers/rules/session-region-list.xaction"/> <property name="actionOutputScope" value="session"/> </bean> <!–LIGNES A AJOUTER –> <bean class="org.pentaho.platform.engine.core.system.SessionStartupAction"> <property name="sessionType" value="org.pentaho.platform.web.http.session.PentahoHttpSession"/> <property name="actionPath" value="DSP/set_session_vars.xaction"/> <property name="actionOutputScope" value="session"/> </bean> <!–FIN des LIGNES A AJOUTER –> |
L’Xaction « get_session_vars.xaction » permet de vérifier la valeur de USER_COUNTRY après la connexion de chaque utilisateur.
- pour Joe :
- pour Pat :
# Etape 4 – Adaptation du schéma XML Mondrian
Une partie du schéma XML Mondrian doit être adaptée (/pentaho-solutions/steel-wheels/analysis/steelwheels.mondrian.xml)
On remplaçe ainsi la définition en dur de la table CUSTOMER_W_TER :
1 2 |
<Table name="CUSTOMER_W_TER"> </Table> |
par un ordre SQL prenant dans sa clause WHERE … IN le paramètre %USER_COUNTRY % :
1 2 3 4 5 |
<View alias="CUSTOMERS"> <SQL dialect="generic"> <![CDATA[SELECT TERRITORY, COUNTRY, STATE, CITY FROM CUSTOMER_W_TER where COUNTRY in (%USER_COUNTRY%)]]> </SQL> </View> |
# Etape 5 – Création d’une classe Java pour la mise à jour dynamique du schéma Mondrian
Un code Java permet de remplacer dynamiquement dans le schéma les informations contenues dans USER_COUNTRY. Celui-ci implémente la classe DynamicSchemaProcessor et doit être compilé puis exporté sous forme de jar dans le répertoire biserver-cepentaho-solutionssystemsaikulib
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.atolcd; import mondrian.i18n.LocalizingDynamicSchemaProcessor; import mondrian.olap.Util; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.engine.core.system.PentahoSessionHolder; import java.io.InputStream; import java.util.regex.PatternSyntaxException; public class CountryDynamicSchemaProcessor extends LocalizingDynamicSchemaProcessor implements mondrian.spi.DynamicSchemaProcessor { public CountryDynamicSchemaProcessor() { super(); System.out.println("DSP: Création du DSP"); } @Override public String filter(String schemaUrl, Util.PropertyList connectInfo, InputStream stream) throws Exception { String schema = super.filter(schemaUrl, connectInfo, stream); IPentahoSession session = PentahoSessionHolder.getSession(); String country = (String)session.getAttribute("USER_COUNTRY"); if (country == null) { System.out.println("DSP: ATTENTION - Pas de country en session"); } else { try { // remplacement à la volée de la chaîne %USER_COUNTRY% dans le schéma XML Mondrian schema = schema.replaceAll("%USER_COUNTRY%", country); } catch (PatternSyntaxException pse) { pse.printStackTrace(); } } return schema; } } |
# Etape 6 – Configuration Saiku
Afin que Saiku affecte bien un cache dédié à chaque utilisateur, la modification suivante doit être effectuée.
Mettre la valeur true pour le paramètre userAware dans le fichier plugin.spring.xml
1 2 3 4 5 |
<bean id="connectionManager" class="org.saiku.plugin.PentahoSecurityAwareConnectionManager" init-method="init"> <property name="dataSourceManager" ref="pentahoDsManager" /> <property name="userAware" value="true" /> <property name="connectionPooling" value="true" /> </bean> |
# Etape 7 – Mise à jour du catalogue
Configurer la datasource dans le fichier /system/olap/datasources.xml comme suit, afin de spécifier l’utilisation d’un DSP :
1 2 3 4 |
<Catalog name="SteelWheels"> <DataSourceInfo>Provider=mondrian;DataSource=SampleData;DynamicSchemaProcessor=com.atolcd.CountryDynamicSchemaProcessor;</DataSourceInfo> <Definition>solution:steel-wheels/analysis/steelwheels.mondrian.xml</Definition> </Catalog> |
# Télécharger l’exemple :
Cet exemple est issu d’une configuration dynamique effectuée chez un de nos clients (Ministère de l’Agriculture) sur plus d’une centaine de rôles.
Vous pouvez télécharger l’ensemble des fichiers décrits ci-dessus dans cette archive.
Pour encore plus de souplesse, vous pouvez aussi vous appuyer sur les rôles Pentaho (au lieu des identifiants utilisateurs) à l’aide de la variable PrincipalRoles !
Laisser un commentaire