BookmarkSubscribeRSS Feed

A CAS Authorization Decision Flowchart for row-level security in SAS Viya

Started ‎09-06-2019 by
Modified ‎09-06-2019 by
Views 2,849

Back in February this year, I wrote here describing examples of row-level security in SAS Viya, illustrating row-level grants for groups, the most common way row-level grants are used.

 

A recent conversation with a SAS colleague highlighted that there are important aspects of CAS row-level security which I did not cover in that post. We also need to know how row-level grants for Authenticated Users, groups or the user behave when other access controls are also present. In other words, how does precedence work in the CAS authorization system, and in particular how does it work for row-level security?

 

In this post we will see how precedence works when there is a combination of row-level grants, and ordinary grants and denies, when there are access controls applied at several different levels of the user hierarchy. This post also presents a proposed Authorization Decision Flowchart for CAS permissions.

 

Because we are mainly thinking about row-level grants in this post, our attention will focus mainly on the Select permission, which controls whether the user is allowed to see data in the table (and for a row-level grant, which rows in the table they can see). When designing a security model, you will also need to consider other permissions, especially the ReadInfo permission on both the table and its parent CAS library. The way that ReadInfo and other permissions work is more straightforward, and easier to understand. Row-level grants on the Select permission are the most complex, and deserve a bit of extra attention.

Why the CAS object hierarchy is not usually very important for row-level security

CAS access controls can be applied to any of these objects, which form a simple object hierarchy:

  1. A CAS library (caslib) – this is the very top-level object in the CAS object hierarchy, there is nothing higher
  2. A CAS table
  3. Rows or columns in the CAS table (important for row-level security).

    Note: while the CAS engine supports column-level access controls, set via CAS actions called from CASL or another supported programming language, they are not (at least, not widely) supported in SAS Viya visual interfaces, and as I understand it are only usable in programming-only usage scenarios. Row-level grants work well throughout SAS Viya.

In general, it is important to understand and use the CAS object hierarchy listed above when designing your CAS security model, to secure your data. However, because this post is concerned with row-level security, that object hierarchy will not be very important to this discussion. As the documentation under Security > Authorization > CAS Authorization > Concepts > Authorization Decisions in the SAS Viya Administration Guide explains:

In the CAS authorization system, precedence is determined by where an access control is set and who an access control is assigned to.

  • Direct access controls have precedence over inherited settings.
  • The principal precedence hierarchy is relatively flat. It consists of only the following three levels: 1) individual users, 2) user groups, and 3) the construct Authenticated Users.

    Note: All user group memberships are at the same level of precedence, even if groups are nested.

Direct access controls have precedence over inherited access controls, regardless of who the principal is.

We will not spend much time in this post considering whether the user inherits a grant or a deny of the select permission from the parent CAS library. If the select permission is set on the CAS library for the user, or for a group to which the user belongs, and no direct access control for the user or one of their groups is set on the CAS table, then yes of course that inherited permission will determine whether the user sees all rows or no rows in the table.

 

But in this post we are considering row-level security, and the situation described in the previous paragraph is one in which you have not defined any table-level access controls at all for the user. That puts such a scenario a little outside the scope of this post. As we read above ‘Direct access controls have precedence over inherited access controls, regardless of who the principal is’, so any access control set directly on the table (even one for Authenticated Users) will have precedence over any inherited access control (even one for the user). We can therefore keep things simple when thinking about row-level security by focussing only on direct access controls applied to the table, for Authenticated Users, groups or the individual user.

Where in the object hierarchy access controls are applied

To fully understand how CAS row-level security works, we need to consider where each row-level grant is applied, and how it behaves with other row level grants and other permissions applied elsewhere in the object hierarchy. Focussing on the select permission on a table, we can have the following, any combination:

  1. The user can have
    1. no access control set, or
    2. a direct deny or grant, or
    3. a direct row-level grant
    of the select permission on the table. The user cannot have more than one direct access control.

     

  2. Considering all the groups to which the user belongs, there may be:
    1. no access controls set, or
    2. only one group with a direct grant or deny
    3. only one group with a row-level grant
    4. one group with a grant and another group with a deny
    5. one or more groups with a row-level grant and one or more groups with a grant or a deny
    6. two or more groups which each have row-level grants, and no groups with a grant or a deny
    of the select permission on the table.

     

  3. Authenticated Users can have:
    1. no access control set, or
    2. a direct deny or grant, or
    3. a direct row-level grant
    of the select permission on the table. Authenticated Users cannot have more than one direct access control.

However complex the set of access controls which may apply to an individual user, it should in fact be quite straightforward to determine how the user's effective access to rows of data is evaluated using the Authorization Decision Flowchart for CAS permissions, focussing on the Select permission below.

How access controls are evaluated

My previous post focussed on simple row-level grants for groups only, and how they were applied cumulatively. As the documentation explains (the following is the Multiple Filters and Cumulative Access section in full):

If multiple row-level filters are applicable to a user, only the highest precedence filter provides access. If there is an identity precedence tie (the user is a member of multiple groups, each of which has a filter), the user can access any row that meets any of the filters.

 

Here are details:

 

The filters for multiple row-level grants provide cumulative access only if all of the following circumstances exist:

  • The requesting user does not have a direct access control for the Select permission.
  • None of the requesting user’s groups have a direct grant or denial for the Select permission.
  • Two or more of the requesting user’s groups have row-level grants.

Note: All custom and LDAP groups have equal precedence, regardless of any nested memberships.

Note: A filter for a row-level grant that is assigned to Authenticated Users is never cumulative (joined with other filters by OR). Authenticated Users is a construct that has lower precedence than any group.

This explanation is absolutely correct, but personally, I still managed to find it hard to visualise (and remember afterwards) how authorization decisions for row level security worked in more complex situations. In fact, when discussing one such complex situation with a SAS colleague, I am ashamed to admit I got it quite wrong. To learn from this experience, I felt that a diagram might help me understand it better, and I hope it will be helpful to you too.

 

The following diagram is my proposed Authorization Decision Flowchart for CAS permissions, focussing on the Select permission in the implementation of row-level security. It is inspired by the Authorization Decision Flow diagram in the SAS 9.2 documentation designed by Catherine Hitti.

 

Row-level-security-authorization-flow-diagram-4-1024x424.png

Select the image to see a larger version.
Mobile users: To view the image, select the "Full" version at the bottom of the page.

 

The diagram is rather complex. Here are some details that may help interpret it.

 

First, consider the outer green boxes labelled “On the table” and “On the table’s parent CAS library”. Remember that for row-level security, we focus on how the select permission is applied to the table itself. Inherited permissions are effective only if there are no direct access controls for the user, their groups, or for Authenticated Users on the table. If any of those principals has a direct access control on the CAS table, it will have precedence over whatever is inherited from the parent caslib. Also note that you cannot set row-level grants on the select permission for a caslib.

 

Second, consider the top blue box labelled “Does the user have a direct deny, grant or row-level grant of the select permission?”. Any access control set directly on the table for the user will have precedence over an access control for one of the groups to which the user belongs, or an access control for Authenticated Users. So:

  • If the access control for the user is a deny of the select permission, the select permission is Not Authorized and the user will see no rows.
  • If that access control is a grant, the select permission is Authorized and the user will see all rows in the table.
  • If that access control is a row-level grant, then the user will see those rows which match the row-level grant’s filter expression.

Third, if there are no access controls for the user which allowed us to reach an authorization decision in the previous step, consider the blue box labelled “Do the groups to which the user belongs have any direct denies, grants or row-level grants of the select permission?”. Any access controls set for groups to which the user belongs will have precedence over any access controls set for Authenticated Users. So:

  • If any group to which the user belongs is denied the select permission, the select permission is Not Authorized and the user will see no rows.
  • If no groups to which the user belongs are denied the select permission, but any group to which the user belongs is granted the select permission, the select permission is Authorized and the user will see all rows in the table. Row-level grants for other groups are not considered. Any access control set for Authenticated Users are also not considered.
  • If there are no grants or denies for any group to which the user belongs, but there is one row-level grant for a group to which the user belongs, then the filter expression in that access control determines which rows the user sees. Any access controls for Authenticated Users are not considered.
  • If there are no grants or denies for any group to which the user belongs, but there are two or more row-level grants for groups to which the user belongs, then the user will be able to see the union of all rows matching any of the filter expressions in those access controls. Any access controls for Authenticated Users are not considered.

Fourth, if there are no access controls set for the user, nor for any of the groups to which the user belongs, we consider the next blue box titled “Does Authenticated Users have a direct deny, grant or row-level grant of the select permission?”.

  • If AUs are denied the select permission, the user will see no rows.
  • If AUs are granted the select permission, the user will see all rows.
  • If a row-level grant is defined for AUs, the user will see only the rows that match the filter expression in that access control.

Lastly, only if there are no access controls for the user, any of their groups, or AUs set directly on the table itself, effective access inherited from the parent caslib is considered. This will not be a row-level grant, so we are not so interested in that situation in this post. If no access controls are set anywhere, access to data is denied and the user sees no rows.

Combining row-level filters for all users with row-level filters for groups

If you want a row-level filter to apply to all Authenticated Users and have it work cumulatively with other row-level filters for other groups, the way the rules are evaluated can make this seem a bit of a challenge.

 

Here is an example of such a requirement, based loosely on a real conversation with my SAS colleague. Suppose you have a table in a travel system CAS library, listing employee trips with columns for the traveller’s userID, the region the trip was from, the region it was to, and the region the traveller reports to, among many other columns. Then suppose that you want to create:

  1. a row-level grant for all Authenticated Users, to show each user their own rows which might be implemented with a row-level grant of the Select permission for Authenticated Users with a filter expression such as travellerId='SUB::SAS.Userid'

    and have that filter be cumulative with

  2. a number of group-based row-level filters, including one to also show members of the Asia Travel Approvers group all rows for trips to or from a location in Asia plus trips for employees who work for the Asia region. This requires a filter expression in a row-level grant for the Asia Travel Approvers group such as toRegion='Asia' OR fromRegion='Asia' OR reportingRegion='Asia'

The problem is that when CAS determines which rows the user in the Asia Travel Approvers group should see, the access controls for their groups take precedence over the access controls for Authenticated Users. Any access controls for Authenticated Users are simply not considered when evaluating which rows the user can see. So that user will see all trips to or from Asia or for employees who work for the Asia region, but if the user has trips themselves, which were not to or from an Asian location and they do not report to an Asian region themselves, the user does not see their own trips! This is not what was intended by the report designer.

 

But there is a solution, if your LDAP directory has an LDAP group which contains all users. If it does not, you may consider asking your LDAP administrator to create such a group!

 

You can replace the row-level grant for Authenticated Users with a row-level grant for the LDAP group which contains all users. When you have done that, the ‘all users’ group-level row-level grant will combine with other group-level row-level filters in a union join of rows that each user is allowed to see, producing the desired result.

 

With thanks to Richard Clowes and Teri Patsilaras for their efforts in understanding and explaining this.

 

I hope this helps if you ever need to design an approach to row-level security in the context of other permissions, especially when you have good reason to apply row-level grants at more than one level of the identity hierarchy. If it does, perhaps you would consider a thumbs-up below? And please do leave a reply if you have any questions or observations about this topic, or the content of this post.

 

See you next time!

Version history
Last update:
‎09-06-2019 04:48 AM
Updated by:
Contributors

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags