Power BI datasets and Analysis Services models share a common role-based security infrastructure. In Power BI Desktop you can only define row-level filter rules, whereas in Tabular Editor object-level security is accessible for both Power BI and Analysis Services models.
Put simply – in theory, you can apply security only to tables and columns, not to measures. Measures are hidden if they have a dependency on a column or table that is hidden because of a security role. However, there is a way to hide a measure without hiding any of the tables and columns of the model: just create a hidden empty table that is not really used in any calculation, but that is referenced in an unused variable of the measure you want to hide. Then, hide that table, and the measure will be hidden, too.
To be more technical, object-level security can be applied to tables and columns, but it cannot be applied to measures directly. If a measure – whether in a direct or indirect way – references a column or a table that is not accessible under the current security context, the measure becomes invisible as well. This way, it is guaranteed that if a column must be invisible to a group of users, its content cannot be inferred by looking at the result of measures based on said column.
Concretely, there may be cases where a measure should be hidden from a group of users without removing the visibility of existing data structures. Let us look at a simple example first. We define the Sales Amount measure as the product of Sales[Quantity] by Sales[Price]. You also have a Discounted Sales measure that applies a set discount Sales Amount; now how can you hide Discounted Sales from a group of users without hiding the initial Sales Amount measure? By hiding either Sales[Quantity] or Sales[Price], you would hide both measures. Because the discount is set inside the Discounted Sales measure and not stored in the model, it looks as though you cannot hide just the measure. However, it we create a dependency in Discounted Sales on an empty hidden table specifically created to generate that dependency, we can hide Discounted Sales by hiding that table.
With the basics presented to you, we now dive into the meat of our article. There are four measures visible to all users in the sample model used in this article:
- Sales Amount
- Total Cost
- Margin
- Margin %
We add another three measures that a group of users is restricted from seeing – i.e. the users that do not have access to information pertaining to resellers. We refer to these as the “reseller measures” later on:
Reseller Value := [Sales Amount] * .9
Reseller Margin := [Reseller Value] - [Total Cost]
Reseller Margin % := DIVIDE ( [Reseller Margin], [Reseller Value] )
The Reseller Value measure includes a constant value (0.9) which is part of the business logic that we do not want to make known. The reseller measures are considered sensitive information, and their access must be protected. Because both Reseller Margin and Reseller Margin % depend on Reseller Value, we can apply the security restriction to only Reseller Value, and the existing dependencies will propagate the security rule to the other reseller measures.
The most efficient way of hiding Reseller Value is to add in its DAX expression a dependency to a table (ResellerSecurity) that users belonging to the Reseller Disabled security role are restricted from seeing. By referencing the ResellerSecurity table in an unused variable, we create a semantic dependency that does not affect the execution plan, thus without any impact on performance. Here is the code we propose:
Reseller Value := VAR CheckSecurity = 'ResellerSecurity' RETURN [Sales Amount] * .9
The ResellerSecurity table can be defined as a calculated table using an empty table expression. This table should be made invisible to the users:
ResellerSecurity = FILTER ( { BLANK() }, FALSE )
In order to define the object-level security rule, we must first create the security role. In Power BI Desktop, you can go to Modeling / Manage roles / Create and define the Reseller Disabled security role. You do not have to assign a filter to this role in Power BI Desktop.
The next step requires Tabular Editor as an external tool connected to the model in Power BI Desktop. We assign “None” to the Reseller Disabled role in the Object Level Security property of the ResellerSecurity table.
Once we have saved the model back to Power BI Desktop, we can check that the administrator sees all the measures in the Fields Pane.
However, if we use the View As feature in Power BI Desktop and we choose the Reseller Disabled role, the Fields Pane does not show any of the reseller measures.
Because of the dependency between the hidden ResellerSecurity table and the Reseller Value measure, the latter is not visible to the users in the Reseller Disabled role. As a side effect, the Reseller Margin and Reseller Margin % measures are not visible because they depend on Reseller Value.
Before we move on to a concrete example, we strongly recommend the reader peruse a preliminary article about KPIs, KPIs in Tabular models for Power BI and Excel.
We can use the technique above to hide specific KPIs. For example, the Margin % measure includes a KPI definition that shows two KPIs: Goal and Status. As you see in the picture below, only Status is visible. The Goal KPI is hidden.
We assign a dependency to the expression of Goal, which then propagates to the expression of Status as well. Target Expression (corresponding to the Goal measure for the KPI) has a dependency on a hidden, empty KpiSecurity table we add to the data model just as we did for ResellerSecurity.
The definition of Status Expression in the next picture uses the _Margin % Goal measure, which corresponds to Target Expression in the previous picture under “Property”.
Similar to what we did for the reseller measures, we set to “None” the object-level security of the KpiSecurity table for a Kpi Disabled role we create in Power BI Desktop.
We make sure to save the model from Tabular Editor. The author of the model can then see in the Fields pane in Power BI Desktop, both the Goal and Status KPIs for the Margin % measure.
When we activate the View As feature in Power BI Desktop and we choose the Kpi Disabled role, the Goal and Status KPIs in Margin % are no longer visible nor available to the user.
Conclusions
The object-level security in a Tabular model does not make it possible to hide a measure or a KPI in a direct way. However, you can actually limit the access to measures and KPIs via object-level security by creating a dependency with a table or a column, to which you apply security restrictions for specific groups of users. By simply using a reference in a variable that is not used in the remaining DAX expression, you create the dependency for the security requirements without affecting query performance.