Modifié par Aurelie Bertrand le 2025/07/01 11:39

Afficher les derniers auteurs
1 {{ddtoc/}}
2
3 ----
4
5 = Définir la fonction Live Security =
6
7 (% class="box" %)
8 (((
9 💡 Consultez le paragraphe [[Sécurisation via Live Security>>doc:Digdash.user_guide.tutorials.live_security.WebHome||anchor="live_security"]] pour plus de détails sur le fonctionnement et la mise en place de Live Security.
10 )))
11
12 La fonction Live security, aussi appelée fonction de transformation de la sélection peut être configurée durant l'édition d'un modèle de données, au niveau de l'étape de configuration avancée du modèle de données, dans l'onglet **Avancé**. Vous pouvez choisir une fonction de transformation de sélection existante, ou en créer une nouvelle, manuellement, pour des fonctions utilisant du code javascript, ou via un assistant.
13
14 L'utilisation de l'assistant permet d'associer des dimensions à des paramètre de l'utilisateur qui fera en sorte que toute sélection sur un cube forcera les dimensions configurées à être filtrées en fonction des valeurs des paramètres utilisateurs.
15
16 L'approche manuelle, par utilisation d'un script javascript permet d'aller plus loin. L'exemple suivant est la création d'une fonction avancée de transformation de sélection qui peut être changer pour ajouter des dimensions sécurisées (modifier entre (% style="color:#e67e22" %)**/* START CONFIG */**(%%) et (% style="color:#e67e22" %)**/* END CONFIG */**(%%)) :
17
18 {{code language="js"}}
19 /* START CONFIG */
20 var securedDims = {};
21 securedDims["DIMENSION_NAME_1"] = getUserAttribute("USER_PARAM_1");
22
23 /* Ajouter ici les autres dimensions sur lequel du live security doit s’appliquer */
24 /*
25 securedDims["DIMENSION_NAME_2"] = getUserAttribute("USER_PARAM_2");
26 */
27
28 /* END CONFIG */
29
30 /* MODIFY THE SCRIPT BELOW WITH CAUTION */
31 var sLogPrefix = "[LIVE_SECURITY] [live-sec-thread-" + Math.floor(Math.random()*16777215).toString(16) + "]"; /* 16777215 is FFFFFF in decimal */
32
33 for (var dimId in securedDims)
34 {
35 var dim = selection.dm.objName[dimId];
36 var persoVal = securedDims[dimId];
37
38 //Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + "Applying user filters on: " + dimId + ", persoVal:" + persoVal);
39 if (dim)
40 {
41 if (persoVal == null || persoVal.length == 0)
42 {
43 // user must no see any value
44 var persoValuesTab = ["-noval-"];
45 var filt = new FilterSelection(dim, -1, -1, [], persoValuesTab);
46 selection.setFilter(filt);
47 Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + " Filters (members) on " + dimId + ": [" + persoValuesTab + "]");
48 }
49 else if (persoVal && persoVal != ".*")
50 {
51 //user is limited to some value(s)
52 var persoValuesTab = persoVal.split("|");
53 Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + " Applying user filters on " + dimId + ": [" + persoValuesTab + "]");
54 var exFilter = selection.filterByDimName[dimId];
55 if (!exFilter)
56 {
57 //there is no exisitng filter on that dimension => create a new one
58 var filt = new FilterSelection(dim, -1, -1, [], persoValuesTab);
59 selection.setFilter(filt);
60 Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + " Resolved filters (members) on " + dimId + ": [" + persoValuesTab + "]");
61 }
62 else
63 {
64 //there is already a filter on that dimension => merge (intersect) into a new one
65 var filt = new FilterSelection(dim, -1, -1, [], persoValuesTab);
66 filt.recalcIds();
67 exFilter.recalcIds();
68 exFilter = mergeFilters(exFilter, filt);
69 origIdsTab = exFilter.origIds;
70 selection.setFilter(exFilter);
71 Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + " Resolved filters (origIds) on " + dimId + ": [" + exFilter.origIds + "]");
72 }
73 }
74 else // perso value is .*
75 {
76 // do nothing, user can see everything
77 Packages.com.digdash.utils.MessageStack.getInstance().addDebug(sLogPrefix + " Resolved filters on " + dimId + ": All (.*)");
78 }
79 }
80 else
81 {
82 Packages.com.digdash.utils.MessageStack.getInstance().addError(sLogPrefix + " Dimension " + dimId + "not found");
83 }
84 }
85 {{/code}}
86
87 == Attribut Utilisateur ==
88
89 Prendre le soin de créer le paramètre utilisateur **USER_PARAM_1** et de l’avoir renseigné pour les utilisateurs concernés (Saisie “.*” pour les autres).
90 Dans l’exemple ci-dessous, admin aura le droit de voir les lignes de la dimension **DIMENSION_NAME_1** ou les valeurs **A, B ou C** apparaissent.
91
92 [[image:User_parameter_FR.png]]
93
94 = Live Security pour interdire l’affichage d’une mesure =
95
96 Une utilisation avancée du Live Security permet de cacher des mesures en fonction du profil de l'utilisateur. Dans l'exemple suivant, les utilisateurs ont un paramètre **show_measure** qui peut avoir une valeur **oui **ou **non** :
97
98 {{code language="js"}}
99 var show_measure = getUserAttribute('show_measure');
100 var measureId = 'CA'; // id of the measure to hide
101
102 if (show_measure == 'non')
103 {
104 var measIndex = selection.indexOfMeasure(measureId);
105 if (measIndex != -1)
106 selection.removeMeasure(measIndex);
107 }
108 {{/code}}
109
110 = Live Security à appliquer à un graphique précis =
111
112 On peut aussi spécialiser le Live Security en fonction du graphique :
113
114 {{code language="js"}}
115 if (flowId != null && flowId.indexOf("mon_flow_id") > -1)
116 {
117 //Ajouter le code ici pour transformer la sélection de manière spécifique au flux
118 }
119 else
120 {
121 //Ajouter le code ici pour tous les autres flux
122 }
123 {{/code}}
124
125 = Live Security utilisant un autre cube =
126
127 L'exemple le plus avancé est d'aller chercher les valeurs de filtrage dans un autre cube plutôt que dans les paramètres utilisateurs stockés dans le LDAP.
128
129 == Explication du cas ==
130
131 La données « de base » est une table de transactions de flux monétaire.
132 Il existe un champ « SECURITY_CODE » qui sert à savoir au final si un utilisateur connecté à le droit de voir la transaction ou pas.
133 Il existe une autre table dite de confidentialité où l’on trouve les utilisateurs LOGIN, appartenant à des groupes GROUP_ID (relation n-n). Et les « SECURITY_CODE » rattachés à plusieurs groupes.
134 On ne peut pas déclarer ces SECURITY_CODE dans une variable utilisateur du LDAP car il y beaucoup de valeurs possibles et cette information doit rester en base car très changeante.
135
136 == Solution Live Security ==
137
138 La solution est donc de ne pas faire la jointure mais de simplement ajouter une fonction Live Security au cube transactions qui va en temps réel aller « chercher » les « SECURITY_CODE » par rapport à l’utilisateur connecté dans le cube confidentialité et les imposer comme filtre.
139 De cette manière, la volumétrie du cube final n’augmente pas, on est sur des aplatissements très rapide et on à besoin que de 8GB de RAM sur le serveur alors qu’il en fallait au moins 32GB à Tableau pour des chargements lents.
140
141 Voici le code du script Live Security pour cet exemple (à adapter selon votre cas, entre **/* START CONFIG */** et **/* END CONFIG */**) :
142
143 {{code cssClass="notranslate" language="javascript"}}
144 /* START CONFIG */
145 var cubeId = "id_cube_authorisations";
146 var userAttr = getUserAttribute("USER_LOGIN_SSO");
147 var dimSecurityCode = "SECURITY_CODE";
148 var dimUser = "LOGIN";
149 /* END CONFIG */
150
151 var sLogPrefix = "[SECURITY] [live-sec-thread-" + Math.floor(Math.random()*16777215).toString(16) + "]";
152 Packages.com.digdash.utils.MessageStack.getInstance().addText(sLogPrefix + " start...");
153 DimBean = function(id)
154 {
155 this.id = id;
156 this.members = [];
157 }
158
159 DimBean.prototype.toJSON = function()
160 {
161 return this.id;
162 }
163
164 Packages.com.digdash.utils.MessageStack.getInstance().addText(sLogPrefix + " user is " + userAttr);
165 var sel = new DataModelSelection();
166 sel.dm = { "variables":{} };
167 sel.pivot = 0;
168 sel.addBrowse(1, new DimBean(dimSecurityCode), -1, -1, null);
169 sel.addFilter(new FilterSelection(new DimBean(dimUser), -1, -1, [], [userAttr]));
170 var resultJSON = Packages.com.digdash.utils.ResultCubeToJavascript.getResultCubeLiveJSON(sessionId, JSON.stringify(sel), cubeId, null);
171 var cubRes = null;
172 eval("cubRes = " + resultJSON);
173 var resAxis = cubRes.axis[1];
174 var mbr = [];
175 for (var i = 0; i < resAxis.length; ++i)
176 {
177 mbr.push(resAxis[i].i);
178 }
179 if (mbr.length > 0)
180 {
181 var dim = selection.dm.getDimensionById(dimSecurityCode);
182 var filt = new FilterSelection(dim, -1, -1, [], mbr);
183 selection.setFilter(filt);
184 Packages.com.digdash.utils.MessageStack.getInstance().addText(sLogPrefix + " Dimension " + dimSecurityCode + " filtered on " + mbr);
185 }
186 else
187 {
188 Packages.com.digdash.utils.MessageStack.getInstance().addText(sLogPrefix + " No " + dimSecurityCode + " found for user " + userAttr);
189 }
190 {{/code}}
191
192 = Vérifier l'existence d'une dimension dans un modèle de données =
193
194 Dans certains cas il peut être intéressant de vérifier qu'une dimension est présente dans le modèle de données, par exemple si le script de Live Security doit être réutilisé dans un modèle dépendant (union, transformateur de colonnes, etc.)
195
196 {{code cssClass="notranslate" language="javascript"}}
197 if (!selection.dm.getDimensionById("LaDimensionObligatoire"))
198 {
199 Packages.com.digdash.utils.MessageStack.getInstance().addError("LaDimensionObligatoire n'est pas dans le modèle de données");
200 //dans cet exemple on choisit de faire échouer le Live Security si la dimension est absente du modèle
201 throw new Error("LaDimensionObligatoire n'est pas dans le modèle de données");
202 }
203
204 //ajouter un filtre sur LaDimensionObligatoire...
205 {{/code}}
206
207 = Pour en savoir plus... =
208
209 * [[Sécuriser un modèle de données>>doc:Digdash.user_guide.tutorials.live_security.WebHome]]