Dynamic Dimension Security et Parent Child avec UserName() ou CustomData()

La sécurisation dynamique des dimensions est un mécanisme un tantinet plus fin que la sécurité par rôles de SSAS. Son principe est d’aller appliquer la sécurité, c’est à dire les membres d’une dimension qu’un utilisateur peut voir ou ne pas voir non pas en fonction de droits posés sur des rôles de manière fixe et externe aux données, mais de les stocker dans la base.

Teo Lachev en particulier a pas mal écrit sur le sujet, ainsi que Nick Barclay et bien sur Mosha. Le soucis c’est qu’ils ont adressé chacun à leur manière une partie du problème.

J’ai donc essayé de vous expliquer ce concept dans un post unique et en l’illustrant d’un petit exemple avec Adventure Works DW.

Principe

Quand ce genre de sécurité devient-il nécessaire?Lorsque les droits des utilisateurs sont aisément exprimables en termes métiers mais que leur expression en terme de rôles devient fastidieuse.

Une règlerencontrée récemment: « chaque employé du call-center a le droit de voir les données ouvertes par les autres employés ayant le même manager et le même grade. » est très simple à implémenter en SQL, mais infiniement plus fastidieuse avec des rôles SSAS: elle oblige a créer un rôle pour chaque Business Unit, et à changer les utilisateurs de BU à chaque changement RH: ce type de sécurité est par essence dynamique.

Pour faire l’exemple simple énoncé ci-dessus avec AdventureWorks DW, je me suis rajouté moi dans la table Employee d’AWDW. J’ai un manager et un login, WW-VMFJ-01\Administrator.

En SQL je récupère mes « collègues » de cette manière:

SELECT Collegues.*
FROM DimEmployee Emp
INNER JOIN DimEmployee Collegues
ON Emp.ParentEmployeeKey=Collegues.ParentEmployeeKey
WHERE Emp.LastName=‘Jehl’

Application des règles de sécurité: UserName

On le comprend rapidement, les formules de calcul MDX vont avoir pour but de récupérer les informations de l’utilisateur connecté et de les corréler à une hiérarchie Login. C’est ensuite dans l’onglet Dimension Data / Advanced du Role designer que l’on va appliquer cette formule.

Quant à la formule elle-même… La récupération de l’utilisateur courant en MDX est une affaire relativement simple: la fonction UserName vous permet de récupérer son nom au format Domaine\Utilisateur. Ensuite cela se passe de cette façon (cf Adventure Works DW) et c’est cette expression que je vais utiliser pour filtrer les membres auquels j’ai accès:

–3) Je récupère sa position dans la ParentChild grâce à la clé de Dimension
LinkMember
(
2) Je le rattache à la clé de Dimension correspondante
Exists
(
[Employee].[Employee].Members,
— 1) Je recherche le membre ayant le login correspondant à UserName
Filter
(
[Employee].[Employee].[Employee],
[Employee].[Employee].CurrentMember.Properties(« Login ID ») = UserName
)

).Item(0),
Employee.Employees
)
–4) Enfin je récupère ses collègues (membres de même niveau dans la ParentChild)
.Siblings

 

Une fois l’expression collée dans l’onglet advanced je vois immédiatement le résultat en browsant dans l’OWC de BIDS:


Alternative sans domaine: CustomData

Ceci dit cette stratégie ne marche que dans un contexte d’authentification intégrée sur un domaine. Si l’on a mis en place une authentification anonyme avec le Middle Tier msmdpump.dll (cf mes posts précédents sur le sujet) il faut faire autrement.

Dans la plupart des architectures de ce type, la stratégie avancée est d’utiliser la node Role de la ConnectionString pour spécifier les rôles auquel l’utilisateur est mappé (la sécurité est cumulative dans SSAS). Mais on peut aussi faire de la sécurité au niveau utilisateur: en passant par la forge d’une chaine de connexion spécifique qui passe le login à travers le noeud CustomData.

Qu’est ce que le noeud CustomData? C’est un attribut de la chaine de connexion à travers lequel on peut passer ce que l’on souhaite et dont on peut récupérer la valeur via la fonction MDX CustomData().

On va donc créer un Rôle spécifique à l’utilisateur anonyme exécutant l’application pool hostant msmdpump.dll. Dans mon cas l’utilisateur est AnalysisServicesHTTP et le rôle s’appelle… HTTP.
Il faut juste modifier l’expression au dessus pour prendre en compte CustomData, mais aussi en gérant le cas ou cette valeur n’est pas renseignée (Merci à Chris Webb pour cette précision d’ailleurs, sans qui je serais resté bloqué🙂 )

–1) Si CustomData est vide, je renvoie un Set vide
IIF ( IsEmpty(CustomData()) ,{} ,
–4) Je récupère sa position dans la ParentChild grâce à la clé de Dimension

LinkMember
(
3) Je le rattache à la clé de Dimension correspondante
Exists
(
[Employee].[Employee].Members,
— 2) Sinon je recherche le membre ayant le login correspondant à CustomData
Filter
(
[Employee].[Employee].[Employee],
[Employee].[Employee].CurrentMember.Properties(« Login ID ») = CustomData()
)

).Item(0),
Employee.Employees
)
–5) Enfin je récupère ses collègues (membres de même niveau dans la ParentChild)
.Siblings
)

Dans les frontaux, on peut donc utiliser cette node pour passer le Login de l’utilisateur, en forgeant cette chaîne dans les SSRS. (Bien sûr dans le scénario, SSRS est sur le domaine et joint un cube non présent sur le domaine).

RS possède en effet la possibilité de générer dynamiquement les ConnectionStrings (attention pas sur les DataSources partagées!) et dispose de la propriété User!UserId qui renvoie… l’utilisateur exécutant le rapport sous la forme DOMAIN\User. Pile ce qui nous intéresse.
Il va donc falloir utiliser CustomData pour passer la valeur de UserId comme visible ci dessous (notez au passage l’adresse du middle tier HTTP):


Ensuite il ne reste qu’à faire un rapport simple, et vérifier que l’on ne voit que ses collègues (et les membres supérieurs mais avec la valeur de la mesure pour All pour ceux composés d’au moins un membre sur lequel je n’ai pas les droits).


Voilà, en espérant que cela vous ait donné des idées de scenarii de sécurité alternatifs intéressants, à bientôt!

3 réflexions sur “Dynamic Dimension Security et Parent Child avec UserName() ou CustomData()

  1. Bonjour,
    J'ai deux hiearchies employés et Dossiers. les deux Hiearchie sont des hiearchies parent-child.

    Dossiers-Sous dossier
    Manager–Employe

    La régle de sécurité stipule que le manager ne peux voir que les employés qui sont sous ses ordres et ne consulter que son dossier et les sous dossiers inhérents.

    Donc si l'un des membres de son équipe s'occupe d'un sous-dossier mais que ce sous-dossier ne fait pas parti du dossier don't il s'occupe il doit pas pouvoir le consulter.

    La table bridge est composé de la clé suivante( Id_User_Connecte,Id_Employe,Id_Dossier) La question est comment l'application de la sécurité parent-enfant je sais faire. Mais le lien entre les deux sécurités (un manager ne doit voir que les sous dossiers qui sont fils de sont dossier) j'y arrive pas pouvez vous m'aider svp

    Tarik

  2. François, quel plaisir de te lire à nouveau après tout ce temps!

    Par contre, et comme à chaque fois, tu traites d’un sujet dont je pensais avoir fait le tour et je découvre qu’en fait je n’en savais rien. Un peu rageant à force🙂

    Merci (ou pas)!

  3. Bonjour,

    merci pour vos articles j’en ai lu plusieurs en essayant de résoudre le problème suivant :
    J’ai le livre SQL Server 2008 MDX et j’ai implémenté une relation Parent/Enfant et une sécurité dynamique.

    Elle n’est pas exactement pareille que la vôtre puisque ça donne :

    Filter(
    {[Employee].[Employees].Members},
    [Employee].[Employees].CurrentMember.Properties(« User »)=
    VBAMDX!Right(
    UserName(),
    VBAMDX!Len(UserName()) –
    VBAMDX!Instr(UserName(), »\ »)
    )
    )

    Toujours est il que ça fonctionne mais contrairement à tous les articles ou posts que j’ai pu trouver et qui proposent de changer cela, par défaut, mon utilisateur manager n’apparaît pas dans la liste de ses subordonnés.

    J’obtiens :
    Manager
    Employé1
    Employé2

    Au lieu de :
    Manager
    Manager
    Employé1
    Employé2

    J’ai vérifié les paramètres que changent ceux qui ne souhaitent pas voir le manager dans sa liste de subordonnés et je ne vois pas ce qui cloche. Auriez vous une idée?
    J’avoue que là je suis coincé.

    Cordialement,

    Matthieu.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s