Live Security

Última modificación por Aurelie Bertrand el 2023/11/22 18:29

 


Preámbulo

Live Security es una forma adicional de asegurar la información contenida en los cubos de datos. Generalmente se denomina Seguridad a Nivel de Fila (« Row Level Security »). También nos referimos a esto como "personalización" de cubos y flujos.

Este documento resume las técnicas tradicionales de personalización de datos e introduce una nueva técnica avanzada de personalización denominada "Live Security".

Mecanismos tradicionales de personalización de DigDash Enteprise

Inicialmente, la seguridad a nivel de línea se resuelve bien personalizando los cubos, bien personalizando los flujos mediante el uso de variables de usuario (${user.<nombre_variable>}). A continuación recordamos estos métodos tradicionales de personalización.

Personalización del modelo de datos (cubo)

La seguridad a nivel de línea se resuelve en la generación del cubo de datos mediante el uso de variables de usuario (${user.<nombre_variable>}) en la definición de la fuente de datos y el modelo de datos. Por ejemplo en SQL SELECT * FROM UneTable WHERE country='${user.country}' AND service in '${user.services}'.

En este ejemplo, cada usuario tiene una variable de país igual a su país, y una variable de servicios que es una lista separada por comas de nombres de departamentos (Marketing,Ventas,Logística) a los que el usuario tiene derechos de acceso.

De este modo, para los distintos usuarios se genera un cubo diferente (uno para cada combinación de valores de las variables) que contiene únicamente los datos correspondientes al "perfil de personalización" de cada usuario. Si varios usuarios tienen los mismos valores para estas variables, se dice que tienen el mismo perfil, por lo que comparten el mismo cubo.

Este mecanismo es muy sencillo de poner en marcha y, en general, permite segmentar el volumen de datos y, por tanto, la carga de memoria del servidor durante la consulta. Los usuarios raramente se conectan todos al servidor al mismo tiempo, por lo que el servidor no necesita almacenar todos los cubos en memoria en todo momento.

Otra ventaja es que, dependiendo del tipo de fuente de datos, la regla de seguridad puede ser muy avanzada. Nuestro sencillo ejemplo de filtrado sobre dos columnas, países y servicios, puede tener en cuenta otros criterios, procedentes de otras tablas (que no queremos integrar en el cubo), o incluso de la propia fuente de datos.

Por otro lado, este mecanismo multiplica el número de cubos a generar y, por tanto, el número de peticiones a la fuente de datos.

Por último, la regla de seguridad puede generar redundancia de datos entre diferentes cubos, representando la parte común de los datos que varios usuarios pueden ver, aunque no compartan exactamente el mismo perfil. Esta parte común se duplica en varios cubos.

  • Ventajas: Fuerte seguridad, fácil de implementar, alta flexibilidad (la complejidad de asegurar depende de las capacidades de la fuente de datos).
  • Desventajas: Más consultas para generar cubos, riesgo de redundancia de datos en varios cubos.

live_security_fr_html_6eaa6052687470b4.gif
Schéma de personnalisation au niveau du cube

Personalización a nivel de flujo

Otro enfoque más dinámico consiste en utilizar estas variables de usuario en el valor de los filtros de cada gráfico que utilice el cubo. Volviendo al ejemplo anterior, el cubo toma sus datos de una fuente SQL: SELECT * FROM UneTable. Es única (no personalizada) para todos los usuarios, y por tanto de gran tamaño. En todos los feeds que utilicen este cubo, se puede añadir un filtro sobre la dimensión País (regla "igual a" ${user.country}) y sobre la dimensión Servicio (regla "está contenido en" ${user.services}). Cada vez que se muestre un feed, el filtro se aplicará al cubo de datos para que sólo se conserven las líneas a las que el usuario tiene acceso. Por supuesto, la navegación por estas dimensiones debe estar prohibida al usuario para que quede restringida a este perímetro.

La ventaja es que sólo hay que generar un cubo y, por tanto, una única solicitud a la fuente de datos.

Por otro lado, como el filtrado lo controlan las propias fuentes cuando se consultan los cuadros de mando, existe el riesgo de permitir que los usuarios accedan a datos que no les conciernen. Esto podría deberse a un fallo de diseño en las páginas de los cuadros de mando (por ejemplo, se ha omitido la prohibición de navegación en una dimensión), o a la manipulación (por un usuario experto) de las solicitudes de visualización enviadas al servidor.

Otra desventaja es que la regla de seguridad es menos flexible. En este enfoque, depende directamente de lo que se haya almacenado en el cubo y se basa únicamente en el filtrado de dimensiones.

  • Ventajas: Una única solicitud para la generación de un único cubo.
  • Inconvenientes: Tedioso de implementar (preconfigurar el filtrado en todos los flujos), seguridad débil, regla de seguridad limitada.

live_security_fr_html_db1cee0c8234453e.gif
Schéma de personnalisation au niveau du flux

A continuación se presenta una tabla comparativa de estos dos enfoques de la personalización:

 Personalización de cubosPersonalización de flujos
SeguridadForteFaible
Generación de cubos

N cubos generados (1 por "perfil de personalización")

=> N consultas

1 cubo generado

=> 1 única consulta

ImplementaciónSencillaTediosa
FlexibilidadEn función de la fuente de datos (por ejemplo, SQL)Filtrar sólo en los datos del cubo

Live Security

Concept

Cette nouvelle approche, introduite dans la version 2017R1 vise à ne garder que les avantages des deux mécanismes de personnalisation précédents. A savoir une sécurisation forte, un nombre de requêtes nécessaires minimum pour la génération du cube, une mise en place aussi simple que possible tout en conservant un niveau de flexibilité suffisamment élevé.

Elle permet d’ajouter des règles de sécurisation au niveau du modèle de données lui-même, sans démultiplier le nombre de cubes générés et sans obliger à gérer la sécurité au niveau ligne dans les flux.

La sécurisation est exprimée aux travers de règles de filtrage simples mises en place grâce à un assistant pour couvrir les besoins les plus courants de restriction de navigation à de membres d'une ou plusieurs dimensions, en fonction des variables d'un utilisateur.

Pour les besoins avancés on peut avoir recours à un script Javascript qui sera exécuté à chaque interrogation du cube sur la sélection entrante. Dans ce cas c’est véritablement une transformation de la sélection qui peut être faite. Aussi bien du filtrage simple analogue à l’approche « personnalisation de flux » que de la transformation plus complexe en fonction du profil de l’utilisateur. Par exemple, changer un niveau d’exploration, supprimer un axe, une ou plusieurs mesure, etc.

Quelques exemples de transformations avancées de sélection (des exemples avancés de Live Security sont détaillés dans notre base de connaissance) :

  • Filtrer une dimension ou une autre en fonction de la valeur d'une variable utilisateur.
  • Faire des règles de filtrage "OU" entre dimensions.
  • Interroger un autre cube pour en extraire un périmètre de sécurisation dynamique, en fonction de la sélection actuelle...

Coté sécurisation, cette transformation, qu'elle soit simple ou avancée, est appliquée avant le traitement de la sélection coté serveur et ne dépend que du profil de l’utilisateur. Il n’y a aucun moyen pour un utilisateur, même expert, d’altérer ce processus comme pour la personnalisation des flux.

  • Avantages : Une seule requête pour la génération d’un seul cube, sécurisation forte, grande flexibilité (transformation potentiellement totale de la sélection du flux)
  • Inconvénients : Mise en place potentiellement compliquée (Javascript) pour les besoins complexes. Mais il existe une interface assistant l'utilisateur à créer des filtres de Live Security simples, sans Javascript.

live_security_fr_html_b6bea0d8a0772539.gif
Schéma de personnalisation « Live Security »

Voici un tableau comparatif reprenant cette nouvelle approche avec les deux précédentes approches de personnalisation :

 Personnalisation des cubesPersonnalisation des fluxPersonnalisation « Live Security »
SécurisationForteFaibleForte
Génération des cubes

X cubes générés (1 par « profil de personnalisation »)

=> X requêtes

1 cube généré

=> 1 seule requête

1 cube généré

=> 1 seule requête

Mise en placeSimpleFastidieuse (par flux)Par assistant / Par script
FlexibilitéEn fonction de la source de données (ex : SQL)Filtrage sur les données du cube uniquementTransformation de la sélection

Mise en place

Ce chapitre décrit comment mettre en place le mécanisme Live Security au travers d’un exemple standard de filtrage de dimension.

L’exemple se base sur une source de données qui contient au moins deux colonnes pays et service et des colonnes de valeurs (mesures). Chaque utilisateur est assigné à un pays et à un ou plusieurs services et ne verra donc que les chiffres qui s’y rapportent. Certains utilisateur peuvent avoir le droit de voir tous les pays et/ou tous les services.

Prérequis

Chaque utilisateur a deux variables dans le LDAP : pays et services qui définissent son périmètre de sécurité. Chacune des deux variables peut être vide, cela signifie que l’utilisateur peut voir tous les pays et/ou services. La variable services peut être une liste de noms de services séparés par des virgules (pas d’espace après les virgules).

Exemple :

Utilisateur U1 :

  • pays = 'fr'
  • services = 'Marketing,Ventes'

Utilisateur U2 :

  • pays = 'de'
  • services = (chaîne vide)

Modèle de données

La source de données est une source SQL sur laquelle on exécute la requête suivante :

SELECT pays, service, val1, val2 FROM UneTable

On peut noter qu’il n’y a pas de clause WHERE dans cette requête car le but est de générer un cube unique contenant toutes les données pour tous les utilisateurs.

Le modèle de données contient donc deux dimensions et deux mesures.

Important : les variables utilisateur ${user.pays}, ${user.service} ne doivent pas être utilisées dans ce contexte, ni dans la source de données (clause WHERE), ni dans une formule de mesure dérivée ou n’importe où dans le modèle de données. Sinon cela impose au système d’utiliser la personnalisation par cubes, ce que l’on ne veut pas dans cette approche.

L’activation du Live Security se fait dans l’écran de configuration du modèle de données, onglet Avancé. Nous décrivons ici les deux façons de développer une fonction de Live Security, soit via notre assistant dédié aux fonctions simples, soit via la création d'un script Javascript.

Création avec l'assistant

  1. Pour créer une fonction de Live Security simple sans Javascript, vous pouvez cliquer sur le bouton Créer (assistant)... au niveau de la boite de sélection de la Fonction de transformation de sélection.
  2. Entrez un nom pour la fonction
  3. Choisissez la dimension Pays sur la première règle de filtrage. Cette règle n'a pas de hiérarchie ou niveau, laissez ces deux champs vides.
  4. Entrez ${user.pays} dans le champ des membres sélectionnés.
  5. Ajouter une nouvelle règle en cliquant sur l'icône +
  6. Choisissez la dimension Service sur la seconde règle de filtrage. Cette règle n'a pas de hiérarchie ou niveau, laissez ces deux champs vides.
  7. Entrez ${user.services} dans le champ des membres sélectionnés.
  8. Comme nous avons défini que la variable services de l'utilisateur peut avoir plusieurs valeurs séparées par des virgules, il faut saisir une virgule (,) dans le champ de séparateur de valeurs.
  9. Cliquez sur OK pour créer la nouvelle fonction de Live Security. Assistant fonction

Création d'un script

  1. Pour créer une fonction de Live Security avancée basée sur un script Javascript, cliquez sur le bouton Editer… au niveau de la boite de sélection de la Fonction de transformation de sélection.
  2. Choisissez Fonction pré-établie dans le Type de fonction.
  3. Ajouter une nouvelle fonction pré-établie en cliquant sur le bouton + dans la barre d'outil du gestionnaire de fonctions
  4. Entrez un nom pour la fonction

Vous pouvez maintenant saisir un script de transformation des sélections faites sur le cube correspondant à ce modèle de données. Ceci est décrit dans le paragraphe suivant.

Le script à écrire est le corps d’une fonction Javascript qui prend en paramètre un objet « selection ». Cet objet représente la description du résultat que l’on souhaite obtenir du cube (opération « d’aplatissement »). Cet objet complexe définit les axes souhaités, les dimensions, les filtres, les mesures et d’autres paramètres propres à chaque type de flux (graphique, tableaux…). Ce qui nous intéresse dans cet exemple ce sont les paramètres de filtrage de dimension. Le but est de transformer cette sélection afin d’y inclure deux filtres « forcés », un sur le pays de l’utilisateur et un sur ses services, si l’utilisateur a des variables définies (non vides) pour le pays et/ou les services.

Commençons par récupérer la valeur de la variable de l’utilisateur pays en utilisant la fonction getUserAttribute(‘<nomvariable>’) :

var pays = getUserAttribute('pays');

Ensuite, si la variable pays est définie et non vide, nous appliquons un filtre sur l’objet selection :

...

if (pays != null && pays != '')

{

var tabPays = [pays]; //création d'un tableau contenant le pays

var dim = selection.dm.getDimensionById('Pays');

var filt = new FilterSelection(dim, -1, -1, [], tabPays);

selection.setFilter(filt);

}

Explication : La construction du filtre se fait avec l’aide de l’instruction new FilterSelection(Dimension, nomHierarchie, nomNiveau, [ ], tableauMembres) :

  • Dimension : L’objet dimension peut-être récupéré directement dans le modèle de données accessible via selection.dm, grâce à la fonction getDimensionById(dimId).
  • nomHierarchie et nomNiveau : Ensuite, dans cet exemple, nous filtrons directement les membres racines de la dimension, il n’y a pas de hiérarchie ni de niveau à préciser (...-1, -1...).
  • [ ] (tableau vide) : Utilisé de manière interne, ne pas modifier.
  • TableauMembres : Enfin, un filtre sur une dimension peut avoir plusieurs membres sélectionnés, il faut donc lui passer un tableau de membres (ici tabPays). Pour le pays, comme l’utilisateur n’en a qu’un, le tableau ne contient qu’un élément.

Puis nous appliquons ce filtre à la sélection par selection.setFilter(…).

Enfin, on fait la même chose pour la variable services qui représente une liste de services, qu’on traite spécifiquement grâce à la fonction Javascript split(). Elle découpe une chaîne de caractères en un tableau de chaînes de caractères selon un caractère séparateur (la virgule dans notre cas) :

...

var services = getUserAttribute('services');

if (services != null && services != '')

{

var tabServices = services.split(',');

var dim = selection.dm.getDimensionById('Service');

var filt = new FilterSelection(dim, -1, -1, [], tabServices);

selection.setFilter(filt);

}

Utilisation

Il ne reste plus qu’à créer un flux sur ce modèle de données et à le placer dans une page de tableau de bord.

Si on ne cache pas les dimensions pays et service dans le tableau de bord (ou dans le flux) il sera toujours possible de filtrer sur une de ces dimensions. Cependant le filtre sera écrasé par le script de Live Security si l’utilisateur a une valeur non vide pour sa variable pays ou services. Au final le filtrage sur ces dimensions dans le tableau de bord n’est utile que pour les utilisateurs ayant le droit de tout voir c’est à dire ceux qui ont une valeur vide dans leur variable pays et/ou services.

Référence API

Cette fonctionnalité est très récente, son API est susceptible d’évoluer dans de futures versions. Pour l’instant il n’y a que quelques méthodes recommandées pour manipuler une sélection. Ces méthodes sont décrites dans ce paragraphe.

Récupération d’informations utilisateurs

(Chaîne) getUserAttribute (attr)

Description : Retourne l'attribut LDAP attr de l'utilisateur. Aussi appelé « variable d’utilisateur ».

Exemple :

var userName = getUserAttribute('displayName');

Récupération d’informations de la session utilisateur

(Chaîne) getSessionAttribute (attr)

Description : Retourne l'attribut Session attr de l'utilisateur pour la session courante.

L’utilisation des variables de session est couverte dans le document Tutoriel variables de session.

Exemple :

var scenario = getUserAttribute('Scenario');

Récupération d’informations de la sélection ou du modèle de données courant

(Nombre) getDDVar(variable)

Description : Retourne la valeur de la variable du modèle (DDVar) correspondante. Ces variables sont définies dans le modèle de données et correspondent à un widget dans la page de tableau de bord.

Attention : ne pas confondre la DDVar avec la variable d’utilisateur (attribut LDAP).

Exemple :

var tauxEuroDollar = getDDVar('txEuroDollar');

(Dimension) selection.dm.getDimensionById(dimId)

Description : Retourne un objet Javascript correspondant à la dimension d’identifiant dimId. Retourne null si cette dimension n’est pas dans modèle courant. Cet objet est nécessaire à d’autres fonctions, par exemple pour la construction d’un filtre.

Exemple :

var dimPays = selection.dm.getDimensionById('Pays');

Transformation de la sélection

(Filtre) new FilterSelection(Dimension, nomHierarchie, nomNiveau, [ ], tableauMembres)

Description : Retourne un objet Javascript correspondant au filtre souhaité sur la dimension en paramètre, dans une hiérarchie et un niveau donné (-1 si pas de hiérarchie/niveau) et avec les membres spécifiés. Cet objet est nécessaire à d’autres fonctions, par exemple pour l’application du filtre sur la sélection.

Attention : le 4ème paramètre ([ ]) est un tableau vide utilisé de manière interne. Il ne faut pas modifier ce paramètre.

Exemple :

var filter = new FilterSelection(dim, -1, -1, [], new Array('fr','it','de'));

void selection.setFilter(filtre)

Description : Applique un filtre sur la sélection courante. Écrase le filtre existant sur cette dimension s’il y en avait un.

Exemple :

selection.setFilter(filter);

void setDDVar(variable, valeur)

Description : Modifie la valeur d’une variable de modèle (DDVar) pour la sélection courante. La valeur de la variable n’est pas modifiée de manière persistante, seulement pour cette sélection.

Attention : ne pas confondre la DDVar avec la variable d’utilisateur (attribut LDAP).

Exemple :

setDDVar('txEuroDollar', 1.06);