{"id":15915,"date":"2017-09-26T13:39:00","date_gmt":"2017-09-26T20:39:00","guid":{"rendered":"https:\/\/devwww.3cloudsolutions.com\/post\/using-dynamic-row-level-security-with-organizational-hierarchies-2\/"},"modified":"2023-07-28T12:26:05","modified_gmt":"2023-07-28T19:26:05","slug":"using-dynamic-row-level-security-with-organizational-hierarchies","status":"publish","type":"post","link":"https:\/\/3cloudsolutions.com\/resources\/using-dynamic-row-level-security-with-organizational-hierarchies\/","title":{"rendered":"Using Dynamic Row-Level Security with Organizational Hierarchies"},"content":{"rendered":"<p><span style=\"background-color: transparent;\">We recently discussed options for securing internal access to <\/span><a href=\"https:\/\/www.blue-granite.com\/blog\/understanding-power-bi-security-and-data-access\" target=\"_blank\" style=\"background-color: transparent;\" rel=\"noopener\">Power BI reports and dashboards<\/a><span style=\"background-color: transparent;\">. That post also explained how to apply role-based security filters to a dataset, ensuring users only see the information appropriate for their roles. Dynamic row-level security (DRLS) is one of the most effective and efficient ways to restrict data views across an organization. Using DAX functions, DRLS filters the dataset based on the Power BI service user\u2019s log-in credentials. This allows Power BI report authors to easily create filtered data views and skip the hassles of creating multiple security roles in the model and managing the assignment of users to these roles.<\/span><\/p>\n<p><!--more--><\/p>\n<div class=\"hs-embed-wrapper hs-fullwidth-embed\" data-service=\"youtube\" data-responsive=\"true\" style=\"position: relative; overflow: hidden; width: 100%; height: auto; padding: 0px; min-width: 256px; display: block; margin: auto;\">\n<div class=\"hs-embed-content-wrapper\">\n<div style=\"position: relative; overflow: hidden; max-width: 100%; padding-bottom: 56.25%; margin: 0px;\"><iframe loading=\"lazy\" width=\"480\" height=\"270\" src=\"https:\/\/www.youtube.com\/embed\/esM4uGoQ8tM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\" style=\"position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; border: none;\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<p>\u00a0<\/p>\n<p>However, using dynamic role-based security in dashboards and reports has some limitations. One is that the data will be filtered to show only the data associated with the login credentials of the user. In some scenarios, users may want access to data associated with different user credentials. Circumstances such as these require that a filter instead be applied to a hierarchy in the data model. As an example, let\u2019s look at a model with a security role based on geography.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"248\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-13.png\"><\/p>\n<p>This security role filters dataset to the North American continent. This means that report consumers assigned to the <strong>Geography Role<\/strong> can view North America continent data. These users can also view data for the countries within that continent.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"290\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 1.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-1-1.png\"><\/p>\n<p>The geography table below has columns for both continent and state, enabling users to crossfilter the data for that continent.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"827\" height=\"328\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 2.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-2-1.png\"><\/p>\n<p>There are often times when there isn\u2019t an option in the data model to crossfilter as shown above. Developers typically address this issue by creating additional dimension tables to support crossfiltering, then adding those tables to the data model. In the example below, we use a helper table to add categories to the product list. By creating a product subcategory table, and adding keys to the products table, we can define product groupings by subcategory.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"654\" height=\"253\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 3.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-3-1.png\"><\/p>\n<p>Additional dimension tables are often used to apply an organizational hierarchy to a fact table. Suppose that a company wants to look at sales based on organizational hierarchy. Ideally, they want to be able to drill up from an individual salesperson\u2019s results through the organization \u2013 sales manager, district manager, regional manager, country manager and so on. Creating additional dimensional tables is one way to accomplish this.<\/p>\n<p>Though this approach may enable users to drill up and down through organizational data, without security roles it may also give users access to all the company\u2019s sales data \u2013 information typically restricted to upper-level management and employees governed by insider trading restrictions.<\/p>\n<p>Creating security roles configured to limit access for groups of employees to specific data, then assigning users or security groups to those roles once the report has been published to the Power BI service, is one way to secure data access.<\/p>\n<p>However, you might be thinking that this approach sounds complicated, especially in a larger organization, or in one where the combination of employees, managers, and executives is not clearly hierarchical, and you would be correct. Maintaining the security roles, and users assigned to those roles, can be time consuming and error prone.<\/p>\n<p>Here\u2019s where we come back to dynamic row-level security. It\u2019s one of the most efficient ways to assign users or security groups to specific roles after publishing a report to the Power BI service. The process filters data based on the Power BI user\u2019s log-in credentials, passing those credentials to the data model through a DAX expression used in a security role. Let\u2019s see what that looks like:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"260\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 4.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-4-1.png\"><\/p>\n<p>When using this role in a published report, the Power BI service passes the user\u2019s email log-in address to the model, filtering the data accordingly. To test the functionality, we can manually substitute an employee email address in double quotations for USERPRINCIPALNAME, as shown below:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"252\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 5.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-5-1.png\"><\/p>\n<p>When viewing the report without the security role applied, we see the following data:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"479\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 6.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-6-1.png\"><\/p>\n<p>However, when we use the <strong>View as Roles<\/strong> function in the Security group on the toolbar, we see data filtered by that email address:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"335\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 7.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-7-1.png\"><\/p>\n<p>However, our fictional support organization has a hierarchy, and the user above (sanne@contoso.com) has a manager. When we change the hardcoded value to her manager (rpatrick@contoso.com), we see the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"345\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 8.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-8-1.png\"><\/p>\n<p>The dynamic row-level security role filtered the data to only show those tickets assigned to rpatrick@contoso.com. This is by design, as the USERPRINCIPALNAME function filters data to only show tickets assigned to that specific user.<\/p>\n<p>As discussed earlier, most organizations want to see a rollup of metrics by organizational hierarchy. In this case, the manager (rpatrick) has five employees that report to him. To accomplish this goal, and use dynamic row-level security in our report, we need to implement the PATH function in the model.<\/p>\n<p>The PATH function is used with parent-child hierarchies, like those typically found in organizational charts. When used in a calculated column, the function creates a delimited text string with the identifiers of all the parent values for each child value in the table. In our example, the user \u201csanne\u201d reports to the user \u201crpatrick\u201d, who then reports to another manager, and so on. The PATH function allows us to map the parent-child hierarchy from the lowest level to the highest level in the organization. The function automatically generates the complete hierarchy, even though each employee only has their direct manager\u2019s ID associated with their email address.<\/p>\n<p><img decoding=\"async\" width=\"517\" style=\"display: block; margin-left: auto; margin-right: auto; width: 517px;\" alt=\"Row-Level Security 9.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-9-1.png\"><\/p>\n<p>As you can see below, once we add the calculated column with the PATH function, the complete hierarchy for each employee is generated:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"661\" height=\"287\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 10.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-10-1.png\"><\/p>\n<p>The next step is to create an additional column in the model for each level in the organizational hierarchy, and to get the email address for the corresponding employee ID. This is necessary for the use of dynamic row-level security, since it needs the email address as the value for USERPRINCIPALNAME. Our example organization has four hierarchy levels, so we will create four additional calculated columns that capture the email address for each hierarchy level, and get the corresponding email address using the following function:<\/p>\n<p style=\"padding-left: 30px;\">Org Level 4 = LOOKUPVALUE (<br \/><span style=\"background-color: transparent;\">\u00a0 \u00a0 &#8216;Organization'[Email &#8211; Work],<br \/><\/span><span style=\"background-color: transparent;\">\u00a0 \u00a0 &#8216;Organization'[Employee ID],<br \/><\/span><span style=\"background-color: transparent;\">\u00a0 \u00a0 PATHITEM ( &#8216;Organization'[Organizational Hierarchy], 4, 1 )<br \/><\/span><span style=\"background-color: transparent;\">)<\/span><\/p>\n<p>The PATHITEM function determines which level in the PATH string should be retrieved. In the DAX example above, the 4th level in the hierarchy is being returned.\u00a0After we\u2019ve repeated the process for the other three levels in the hierarchy, we\u2019ll have a table that looks like the following:<\/p>\n<p><img decoding=\"async\" width=\"1069\" style=\"width: 1069px;\" alt=\"Row-Level Security 11.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-11-1.png\"><\/p>\n<p>Now that we have the parent-child hierarchy with email addresses implemented in the model, we can modify the role to use dynamic row-level security in the context of a hierarchy with the following expression:<\/p>\n<p style=\"padding-left: 30px;\">[Email &#8211; Work] = USERPRINCIPALNAME()<br \/><span style=\"background-color: transparent;\">|| [Org Level 4] = USERPRINCIPALNAME()<br \/><\/span><span style=\"background-color: transparent;\">|| [Org Level 3] = USERPRINCIPALNAME()<br \/><\/span><span style=\"background-color: transparent;\">|| [Org Level 2] = USERPRINCIPALNAME()<br \/><\/span><span style=\"background-color: transparent;\">|| [Org Level 1] = USERPRINCIPALNAME()<\/span><\/p>\n<p>Using the OR operator (II) in the expression means that the role will evaluate the user\u2019s email address against each level in the organizational hierarchy.<\/p>\n<p>We can again test the functionality by using the hardcoded email addresses in the role. For example, if we replace USERPRINCIPALNAME() with \u201csanne@contoso.com\u201d as shown below, we\u2019ll see all the data shown for her level in the hierarchy. As a member of the lowest level of the parent-child hierarchy, only the tickets assigned to her will be shown. However, if we use her manager\u2019s email address \u201crpatrick@contoso.com\u201d, the data is filtered to show all of the tickets assigned to him and any employee that reports to him:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"384\" style=\"display: block; margin-left: auto; margin-right: auto;\" alt=\"Row-Level Security 12.png\" src=\"https:\/\/3cloudsolutions.com\/wp-content\/uploads\/2022\/11\/Row-Level-Security-12-1.png\"><\/p>\n<p>This approach enables dynamically filtered data based on the email address of the user accessing the report, and limits the dataset to only that employee and his or her subordinates. This can greatly reduce the number of Power BI reports and security roles that an author needs to create, and can significantly simplify the management and governance of the groups assigned to security roles once the report is published to the Power BI service. In this example, a single report and a single role can be utilized to provide the appropriate filtering of data for anyone in the organization. In addition, if the employee data is being imported from an official HR source, whenever new employees are added or the organizational structure changes, the report will automatically be updated to filter the data correctly.<\/p>\n<p>Creating the correct level of access and security for your Power BI reports, dashboards, and datasets can be complicated. If you have a question or want to know more about how BlueGranite can help your organization with Power BI solutions,\u00a0<a href=\"https:\/\/www.blue-granite.com\/contact-us\" target=\"_blank\" rel=\"noopener\">contact us<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using dynamic row-level security, Power BI report authors can provide filtered views of data without numerous security roles to manage.<\/p>\n","protected":false},"author":21,"featured_media":14577,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"content-type":"","footnotes":""},"categories":[260],"tags":[305],"class_list":["post-15915","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-ai","tag-modern-bi","topics-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/15915","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/comments?post=15915"}],"version-history":[{"count":0,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/posts\/15915\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media\/14577"}],"wp:attachment":[{"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/media?parent=15915"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/categories?post=15915"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/3cloudsolutions.com\/wp-json\/wp\/v2\/tags?post=15915"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}