Duplication of data in explicit authorization - permissions

Our current authorization strategy on our site is very tightly coupled to our RDB's schema - which in some ways is a good thing, since it means the permissions available to a user exactly match what he should have, assuming a correct interpretation of the data. So when we query for authorization, we're asking about foreign key/m2m relationships.
I see two main problems with this: first, interpreting relational data is much more difficult to get right than reading explicit permissions from a separate table. The bigger problem I see is that this does not scale. As the app has grown, our permissions checks have gone from a single query across three tables to multiple queries across ten or more tables.
The strategy I've seen in a lot of places that solves this problem is explicit authorization (roles- or claims-based for example). Because this kind of thing is simple enough to just stick in a single table, it seems simpler, faster, and more scalable. The thing that bothers me about it is this: how do you avoid duplication of data?
For example, I have a User that owns a Design. That's currently accomplished with a foreign key. In switching to explicit authorization, I would add the user's id to a table containing the design's id and type. Should I remove the foreign key as well? Should permissions-relevant relationships always be mediated by the permissions table, or should I duplicate the data between the relational representation and the permissions table?
It seems like one the downsides of moving to explicit authorization could include performance, especially if a service call or something was required to fully discover permissions.

I think you're on the right track with roles.
When logging in, you should request your roles as scopes. It's not a terrible idea to namespace them by API and maybe group ids, if they apply.
scopes: ['forum:admin:somegroupid']
The login service could then validate that role by asking the service associated with the namespace.
GET https://forum-api.company.tld/grant_scope/[user_id]?scope=forum:admin:somegroupid
Which then returns whether that user can have that scope and the description of thats scope. Then the login service may include that scope in the generated jwt for that request.
Non subselected scopes should be validated at the route level (say if it were a role that wasn't specific to any group or item).
Otherwise, you'll have to do a query to see if that service says that the userid or one of the included scopes is allowed to do the thing. Redis SETs might be nice for this if you didn't want it to be a foreign table.
I think for object-level permissions, joining to a an access table makes sense, but use it as sparingly as possible. For example, in a forum-setting, object-level permissions should be on the forum, not at the threads or post level (except for owners, that are just included in row with the data). Then you can join from post->thread->forum_access to see whether they can write a new object.
TLDR; Use roles when possible and include as scopes that are validated at a route level. Use group level roles as scopes if necessary. Minimally use object-level permissions only when necessary, only on the objects absolutely necessary.
Edit: This is just one of many possible ways to solve your problem.

Related

REST API optional path elements

I am in the process of designing a new API and am trying to make it as simple as possible. For the intended system most API consumers will be referencing objects that belong to them alone however a few other accounts will "own" objects in other peoples accounts. The questions is whether account becomes a required part of the path or an optional inclusion for these special super-accounts.
Here is an example spec and works fine in the single user context (Account ID "basic1"):
# return person "s4t4s2" for account "basic1"
GET /v1/person/s4t4s2
# return team "g3a35a" for account "basic1"
GET /v1/team/g3a35a
For super-accounts they have their own objects where the above implementation works, however they also require access to the properties of accounts they effectively own (Account ID "super1"):
# return person "s4t4s2" for account "super1"
GET /v1/person/s4t4s2
# get team "g399a2" for account "super1"
GET /v1/team/g399a2
# return person "s4t4s2" for account "basic1"
GET /v1/accounts/basic1/person/s4t4s2
Because most of my consumers will be dealing with the single account view is it best practice to use the second format for all accounts or is it entirely valid to use both formats with automatic scoping via authentication credientials when the account is omitted?
If I understand correctly, those are the same "person" resources, but they have multiple URIs? I would probably prefer having one URI for a single instance of a resource. Even if it has different "views". Different views can still be solved by either having different media-types, or just filling out fields differently on the same media-type depending on the user's permissions.
The advantage of having a single URI for a single instance is that it can be bookmarked, cached, etc. For example if a user's team/account view changes, it can't reuse its links to persons because the URIs change. I think that is not a good design.
If my understanding is wrong, and /v1/accounts/basic1/person/s4t4s2 is not the same person as /v1/person/s4t4s2 then disregard my comment. :)

Routing based on logged in user type

Not sure if I'm going about this the "right" way.
In my application, I have recently had the requirement added for a second "type" of user. This means realistically I will need to route this user to a different controller than the primary type.
As a more concrete example:
The primary user of the application will be staff members. They will need to see company wide information.
Now, clients of the company will need to be able to log into the application, and see information specific to their needs (and no more).
Furthermore, there are likely to be more types of user in the future.
What is the "correct" way of designing/implementing this?
I think that, if you control the users role in the TWIG templates and showing them the only links that they could access (and, of course, protecting the routes with firewalls in the security.yml) may work.

Can I use Shibboleth to present different attributes of other users to different users

OK, so it's a badly phrased question. But it's hard to explain in a single line.
I've tried to read the Shibboleth documentation and being a newbie got out of my depth fairly rapidly. I don't really want to spend days understanding it if an expert can take half a minute to say "no chance, that won't work".
I have many groups of users, lets say (for now) that groups are different companies.
What I'd like to do is only allow users to see some fields from other companies.
For example I'm Alice in Company A and I can see that Bob in Company B has an email address bob#b.com. He can see that I'm alice#a.com
However everyone else in Company B can see that Bob has a last name and a phone number etc.
And everyone else in Company A can see my details.
To make this more complicated, lets say that Bob and I become friends and decide we want to share our information then we create a "transient" group "alice&bob". Because we are both members of that group, we can both see each others full details. (But nobody else in A can see Bob's details unless they are also friends and vice versa)
I can sort all that out in application code by querying all attributes and relationships and only showing what's relevant but for extra security I'd like to limit the disclosure of information at source.
I think I need to use attribute filters but not sure if they are able to give me this level of control. With this flexibility of being able to form relationships, will I need to build filter files on the fly and then end up with thousands of filters that Shibboleth starts to choke on because the logic is so long.
Something like the "is requester in group" filter rule :
https://wiki.shibboleth.net/confluence/display/SHIB2/IdPFilterRequirementAttributeRequesterInEntityGroup
The answer above is quite good, but i believe that non shibboleth users will find it confusing.
The quick answer is You really don't want to do it this way, it may be possible to do but for 100% there are better tools to do it.
Ok, full version now (sorry for being too obvious i some places).
In shibboleth architecture we can distinguish two main components.
Identity Provider IdP- which holds information about users from specific organizations.
Service Provider SP - which are generally some service or protected resource, for which we can define some access rules
In your example credentials for Alice and Bob could be stored in different IdP, because they are member of different organizations/companies, or (which isn't exactly matching the whole pattern) you can have one IdP for all users, and "company" is just one of user attributes. IdP doesn't provide you any kind of api that will give you opportunity to access users attributes for any user, apart from the one that is being authenticated.
On the other hand you have your SP, which hold some super secret resources, for which you can define policies. And in which you would like to define polices for user information.
And here lays the problem, on SP side you don't have access to whole users database, that's the way Shibboleth works. You can of course treat all users information as a resource in your SP, but why in the hell would you like to use Shibboleth if you have clear access to all users credentials on you application side?
If you store all users information on you service side I believe that any well designed relational database with some kind of authentication for your service will be better than shibboleth for this job.
Hope that helped.
This is not a job for Shibboleth or for most SAML/SSO providers, for that matter. The attribute filtering you speak of is used for filtering those attributes between the IdP and SP ... which is basically saying : let service provider or "application" B see the following attributes from IdP A.
Once you transmit the attributes to the SP on the other end, Shibboleth does not (and indeed cannot) provide you with a mechanism to prevent users of application B from seeing any data that you present to them ... in fact, they really shouldnt be able to see any data transmitted by the IdP unless you are exposing it in someway via your application.

Designing a User Access/Permissions class

I'm working on a site, which will have several modules that either fully available to certain users, semi available to other users, and unavailable to the rest.
For example:
An 'employee' is able to respond to the customer support tickets assigned to him.
A 'Manager' is able to manage all employees and support tickets in his team, including viewing the tickets of a specific employee.
An 'Admin' is able to manage all managers, employees, and tickets in all teams, as well as some other core functionality.
In addition, on some pages there will be some additional fields shown if the current user is an admin or manager. (E.g links to delete/flag things). These won't be shown to employees.
I want to create one 'Permissions' model which will handle the logic for:
Determining if a user can access the current page or not.
Determining whether a particular part of a page should be displayed or not. (E.g special links for editing/deleting to be shown to admins and managers only).
I need some recommendations/advice for designing this class, particularly what methods it should have in order to accomplish the 2nd requirement.
The way I have approached this problem when it has come up is to give each action that can be taken or piece of information that can be shown it's own Permission. Each User then has a collection of Permissions. From this, you can add other layers of structure to help manage the huge number of permissions that will exist, such as hierarchies or categories of permissions.
Once that is in place, you can either have the various parts ask the User if they have the needed permission(s), or you can have a PermissionManager take a User and a set of Permissions and determine if the given user has the needed Permissions. Either way will work fine, but which one you choose has an impact on dependencies and the architecture of your system.
The PermissionManager approach has the advantage that your application pieces don't need to depend on a User, so you could use a different PermissionManager that always returns False if no permissions is appropriate, or True if all permissions is appropriate.
For simple situations, this approach can be overkill, and it often seems like it is at first, but I've gone the route of using basic hierarchical or coarse-grained Roles and fond that virtually every system I've worked on quickly got too complicated for most vanilla, pre-built Roles-based permission systems.
My approach to this problem from database point of view would be to have a user table which holds the list of users, a role table for the list of roles, e.g.: employee, manager, admin; and permission table which stores all of the values of every action/feature available in the system and its permission for a specific role, e.g.: say for admin, the values for actions/features like create, edit, delete, view are all true. The relationships can be seen below whereas (N) ---- (N) is a many-to-many relationship.
Users (N) ------- (N) Roles (N) -------- (N) Permission
My impression is that you would require to make use of roles e.g. employee, Manager, and Admin. So a roles table with these would do. Then for the particular actions/permisions you would have to make use of branching logic i.e. for example for the employee you will have
if User.IsInRole("employee")
// insert logic to deal with customer support tickets
else if User.IsInRole("manager")
// insert logic to deal with manager responsibilities
and finally logic to deal with admin responsibilities
So you need both the users table and the roles table to achieve this.
Hope it helps

Storing a Windows SID in a Database for Lookup

I have an ASP.NET MVC application where I need to allow to customers configure MembershipProviders based on their environment, but still be able to map that MembershipUser to a concrete User model in our database.
Membership.GetUser() will give me access to the logged-in user's Membership.ProviderUserKey. I can use this to relate to a User record. Our custom SQL provider will just return the User.Id, but AD is a different story. In that case, ProviderUserKey is an IdentityReference.
These lookups will happen very frequently, as you can imagine (although caching can assist in reducing the lookups at the database level).
I can't decide which route is better to go: Storing the SID as a varbinary or varchar column. This column would not be a primary key and would not have a clustered index. Knowing that I can index strings pretty well, and reading a SID in string format is certainly nicer than binary. Anyone willing to share how they solved such a situation?
Update
I don't know how I missed this SO question when I was searching before I posted, but it seems pretty clear that ActiveDirectoryMembershipProvider and ActiveDirectoryMembershipUser are not quite cut out for the task at hand, as they exist today.
An answer in that SO question linked the following article, where the following was stated:
The relative identifier portion of a
SID is unique relative to the domain,
so if the domain changes, the relative
identifier also changes.
Thus when a User object moves from one
domain to another, a new SID must be
generated for the user account and
stored in the Object-SID property.
However, each group and user has an Object-GUID, which will never change, even if the account is moved. Therefore, it would behoove me to use Object-GUID in my User class, and not Object-SID. Otherwise, someone's User record will be abandoned if they are moved and therefore breaking the relationship between their principal and the data they created.
Unfortunately, ActiveDirectoryMembershipUser doesn't let me get at Object-GUID. So, I'll either have to translate the SID to a GUID after ActiveDirectoryMembershipUser does its work, or create my own MembershipProvider that does everything I need on the spot. Unfortunately, this means I might have to duplicate effort already done for me by ActiveDirectoryMembershipProvider.
Microsoft stores SIDs as varbinary(85) in sys.server_principals
This is also a unique column, so it must have an index...
username is the LAST thing you want to index on.
SIDs only change in an AD when you change a user from one domain to another. RIDs are split into 2 groups - inbuilt (< 1000) and user RIDs. Pre-defined users such as Administrator, Guest etc always have the same RID.
If you want to handle movement of users etc, then GUID is the way to go.
username can be changed at any time in Users and Groups management.
this is different to the object name, which is invariant, but I don't believe is mandated unique across a forest. You can have any number of John Smith users.
I'd look into the ADSI objects. These are COM objects which should be accessible from ASP. MSDN explains pretty well. an ADSearch object can be used to return user attributes (e.g. including DN) from a GUID.
Sounds like you're making this a lot more difficult than it needs to be. What do you need a SID or GUID for? You already have a unique, perfectly readable identifier for the users account maintained in ActiveDirectory.
It's called "the username". Hopefully it's the same username as stored in your apps "user" table.
Your app just needs to know if that username successfully authenticated with ActiveDirectory. So if they successfully log in - you just store the fact that they are authenticated in your Session variables.
If they are configured to use the db user login, if successful set the same Session variable indicating that they successfully logged in.
No fancy GUIDs or SIDs ... simple.