'Row Level Security design for key value attributes

Background

I have a set of objects, called Protected Entities. These Protected Entities, have custom defined attributes attached to them (managed from an application (.NET)). Within the application we've also defined a set of Roles a user (or group of users) might have.

This will be running on Azure SQL by the way

What I want

Now I want to define a query, which I want to use with Row Level Security, to allow for application defined filtering on these protected entities.

Use case:

User1 with the role Regional User has only access to the protected entities where all the attributes of those entities are matching with the filtering defined on the Regional User role.

User2 with the role Regional User and Field 3 Expert role has only access to the protected entities matching the filtering on Regional User role OR matching the filtering on Field 3 expert role.

Why RLS? Because I want to building a guarantee that doing aggregate calculations and or other database operations are only done on the entities you have access to (needed requirement).

Example Dataset

Protected Entities

ID Protected Entity Name
1 First Entity
2 Second Entity

Entities attributes (key value)

ID Entity Key Value of attribute
1 MyField My Val
1 MyField1 My Val 2
2 MyField Some other val

Roles

ID Name
R1 Regional User
R2 Field 3 Expert
R3 Global Admin

Role filter table

(Which role has access to which protected entity based on the attribute values (AND filter)

Role ID Attribute Key Access when value is
R1 MyField1 MyRegional Value
R1 MyField2 Only when this second filter is also matching
R2 MyField3 Specific Field 3 value

What's the question?

I'm trying to explore 2 things. This example above is about applying an AND filter on a role. The next option I'm exploring in putting a filter object between Role and it's filtering, allowing for AND + OR combination of filtering. Where AND are inside a filter, the OR accross those filters.

I find it difficult to think on how to query this well. I started with the following query, however, I'm not sure how to approach it well. Especially with a performant query (i'm first going for a filtered view, before trying to translate it to a security predicate).

I know I need a count on how many filters I expect and how many filters are matched per role and filter.

DECLARE @username varchar(50);

SET @username = 'priority-nl';

SELECT tempRoleCount.AmountOfFiltersExpected, af.RoleId, af.SecurityFilterId, pa.EntityId, COUNT(pa.AttributeValue) AS a
FROM dbo.AttributeFilters af
LEFT JOIN (
    SELECT RoleId, SecurityFilterId, COUNT(1) AS AmountOfFiltersExpected FROM dbo.AttributeFilters
    GROUP BY RoleId, SecurityFilterId
) AS tempRoleCount ON (tempRoleCount.RoleId = af.RoleId AND tempRoleCount.SecurityFilterId = af.SecurityFilterId)
LEFT JOIN dbo.ProtectedEntityAttributes pa ON (af.AttributeKey = pa.AttributeKey AND af.ValueToFilter = pa.AttributeValue)
WHERE NOT(EntityId IS NULL)
GROUP BY af.RoleId, af.SecurityFilterId, pa.EntityId

Example SQL database code setup

https://gist.github.com/meghuizen/8021572216fe50958f2fca25e92fa6b0



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source