Our application uses multiple ways for authorizing access to a given resource. Although it's working, it's messy and... well, it doesn't seem right.
1) Role-based authorization
We have well defined roles where each role has access to a set of the resources and different roles can access the same resources.
Resources, as of now, are simply MVC actions mapped in a database table as module, controller and action.
This seems to be OK, but every time I need to add a new controller/action I have to map this resource to the database table.
2) User-based authorization
Besides role-based authorization, users can have more or less access to a subset of resources of another role. Eg.:
RoleA: resources a, b, c, d
RoleB: resources x, y, z
RoleC: resources 1, 2, 3
User1: has RoleA but needs to access resource y
User2: has RoleB and RoleC but does not have access to resource z
This is implemented as an user_resources table with entries for additional resources that the user has access or is denied (indicated by a flag).
I could create different roles with tailored access, treating roles as group of permissions, but that would lead to a roles explosion.
3) Model state authorization
If that's not enough, some actions can only be performed when the model is in a certain state (each model knows when something can be done). Eg.: an order can only be edited if the user has access to the edit resource (through steps #1 or #2) and the object Order can be edited.
Anoter example: an user can access a Customer if he has access to /customer/view resource and he owns that Customer (he is the contact info for that customer).
4) Display information in UI
A role, group of roles or individual users can see more or less information about a model, depending on it's state.
How can I simplify this authorization process without loosing flexibility in giving or restraining access to resources?
There is any pattern I'm missing here to unify all this authorization in a single place?
After a long time I finally found an answer that satisfies all my requirements:
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/.
His solution is to consider everything as an activity, the permission to execute/call/whatever an activity is given to a role and users can have multiple roles.
What shines in this approach is that the permission check is done on the activity itself, not on the roles.
I've implemented access control by using the specification pattern, which I find directly suited for this. A central method is isSatisfiedBy. X is allowed to do y if it is satisfied by z. Eg a user is allowed to view 'the admin page' if it is satisfied by 'has admin role'. See how isSatisfiedBy can be very generic (eg 'is user with id 324', 'has been logged in for 30 minutes', 'is member of group foo', ...). Rules then become of the following general form:
allow X to do Y if X satisfies Z
Related
Here is the scenario, I have a service containing many records. My service also has many users, each with the ability to create, read, update and delete records. The ability to perform these operations on each record must be controlled at the record level.
For example, user A can only read and update record 1 but user B can read, update and delete records 1, 2 and 3 and user C can perform all operations on all records.
How if at all, can this be done using Azure AD?
Obviously, using application roles is not sufficient because that gives the user uniform access rights to all records.
The tenant is also not useful because its the same for all users (in this example).
I definitely do not want to define access rights for every record individually, I would like to do something like assigning roles to a user group and then somehow assign records to the group.
Is there a standard way to deal with this type of resource based authorization?
As you correctly mention, role based access or authorization is very generic and using that, a user with specific role gets access (or gets denied access) to all resources. (If your sceanrio permits, you could make it a little better by dividing your resources into a few types and give access for 1 or more types of resources to 1 or more roles).
When trying to control access for each record individually, you will need to implement custom logic for resource based authorization. Typically applications utilize a mix of role-based and resource-based authorization driven by their requirements.
In the end it will boil down to a mapping that you need to maintain between 3 things
Resource (or a collection of resources)
Azure AD object (like role, group, individual user that is being given permission)
Permission that you're giving (understood and enforced by your application e.g. Blogs.Create permission for a Blogs application)
Relevant Documentation available on Microsoft Docs
Role-based and resource-based authorization
This documentation talks about similar concepts and shows a good example which makes use of both role based and resource based. CRUD operations on resources based on roles and then special privileges on specific resource for the owner of that resource (i.e. resource based)
Code Samples
Multi-tenant Survey Application Code
Code base for the documentation link above
Authorization in a web app using Azure AD groups & group claims
This one provides a sample task tracker application where users can share tasks with other users or Azure AD groups. Again you will see a mapping between resources (i.e. tasks in this case) and Azure AD objects (i.e. Users or Groups) is being maintained in sample database.
Assigning Application Roles for groups
Since you mentioned this as part of your question, just letting you know that this is possible from Azure Portal but only if you have Azure AD Premium license (I'm not sure which specific ones support it, but search on Group based assignments feature and you'll find it.)
Hello again every one,
I have a question: I successfully implemented django-auth-ldap, the LDAP users can request successfully my DRF API. But nows, for my projetc needs, I have to define permissions depending of the group.
Indeed, I will have like 12 groups in my app. Depending of the group, I will authorize or not the user to request a given route, BUT even if I defined the global var AUTH_LDAP_MIRROR_GROUPS = True, and saw in my database the are linked to a group (see capture):
Users in database
Groups from LDAP inserted in db thx to django-auth_ldap settings
User linked to the groups defined
But now, I have some other problems: I do not know how to implement permissions depending of the group the user belong. In fact, if a user belong to the group ServerAdministrator, I want to allow him to access to every route accessible, but I dont know where to see this in the received request in my view?
As I understood, I should implement custom permissions I should write programmatically in a User object (which should inherit from django AbstractUser)
If yes, How does it work? Should I empty my whole Database and then let django-auth-ldap insert users and it also will create the given permissions defined inside the database?
Maybe it is not clear, do not hesitate to ask questions if I can be more precise.
Kind regards.
Benjamin
I understand the usage of claims for things I would commonly refer to as "roles" or "permissions". I know that claims are more general, but from what I have seen in practice, it usually boils down to this: If user has this set of claims they can access certain areas, or perform certain functions.
Imagine a wiki application. You might have a content_contributor claim that would allow a user to add content, a content_admin claim that would allow a user to remove content, and a modify_user claim that would allow the granting of contributor rights to other user.
Taking this example a step farther, I may want to restrict users so that they can only see content created by themselves or their team.
If a user can only see content created by themselves, would we have a claim for each piece of content they created, or would we delegate that authorization to the application?
When you are talking about roles and permissions then you are talking about authorization.
Claims are typically not for authorization. (Identity)Claims are there to model the identity of the user: who is the user? The claims on itself do not tell anything about authorization. A user can have a role claim, but this doesn't tell the application what the user is allowed to do.
Authorization is done by the application, based on who the user is. Think of authorization as a set of rules, like:
18+: allow when user is older than 18 (DateOfBirth).
Use car: allow when user has a drivers license.
Or something like that.
Roles are a bit confusing, as they are often misused for authorization. Please read this article for some background information.
The problem with roles IMO is that these are not universal. I can be a Doctor in one hospital, while I'm a Patient in another. And I can be Admin for one tenant, but a User for another tenant. So they have only meaning within a certain context.
The only reason to include roles as claim is that you won't need to lookup this information as it is already present. But given the previous remark, you actually can't include this information. And it will only give you headaches when you do. Because you can't do simple things like update or change permissions or profile settings, until the user logs in again.
So as a rule of thumb: keep authorization close to the resource (api / website). Because that is the place where the business rules are implemented. And that's the place where you can store and update permissions, etc.
Keep a seperation of concerns when it comes to authentication and authorization. Authentication tells you who the user is, and authorization tells you what the user is allowed to do. Don't mix these two.
Translating this to your wiki application:
Create a seperate context where you store authorization information like roles and permissions. You can manage this in a central resource (for multiple applications) or use the context in your application. I would not mix this context with the business context.
Add a user in the authorization context and add a role content_contributor. Within the application read the permissions (from the central API, the local authorization context, a settings file, or anything that suits best) for that user (based on the sub claim). Cache it to speed up performance, and apply the rules to determine whether the user is allowed to access the resource.
You can extend this with resource-based authorization. Save the value of the sub claim in the content record to identify the owner. When the current user matches the sub claim value, then the current user is the owner.
You can use the same approach for teams. Add a teams table to the business context and link the user to one or more teams. Directly using the sub claim value or indirectly, using a Users table, also in the business context, where the user is linked to the sub claim value. You can add name, etc. in case you want to show this information (like in a report).
You can save team id and / or user id or sub claim value (owner is member of the same team as current user) in the content record in order to determine the allowed access for the user.
My setup would be like this:
Identity context: users + userclaims. For authentication only. Application independent.
Authorization context: users (id = sub claim) + per application: roles, permissions, etc. In seperate 'local' databases or in a central database. For authorization only.
Business context: users (Id, Name, 'foreign key' sub claim, without the actual database relation as the table is outside the context) + teams, profile, settings, etc. Linked to the sub claim value when users table is omitted.
In order to keep the users table in the business context up-to-date, periodically refresh the values. You can for instance update values when the user logs in after x time. Or once in a while query the Identity Context (using the API) to request user information (using the identities User Info endpoint).
In all contexts there can be a users table, but they all have a different meaning and contain other information. So there is no redundant information.
Authorization takes place inside the application and is based on the business rules (policies) and authorization information from the authorization context.
As a final remark, when the current system requires role claims (like for User.IsInRole() or [Authorize("role")]) then you can read (from cache) the role / permissions on each call and add these to the claims collection of the current user (claims transformation).
Background
I'm building a application where all users belongs to a Organization. I only want the user to be able to Create/Read/Update/Delete records in the Organization they belong to.
I'm using sails, but I'm looking for Connect/Express-based, or a standalone answer as sails-permissions node module is unmaintained.
Question
How can one implement a authorization that allow CRUD only for the organization the user belongs to?
We are also not relying on sails-permissions. In our app, users can be members of multiple orgs.
We are using auth0 for all authentication activities, i.e. every request must include a jwt that is included in the request header. The jwt includes userId, orgId and role.
Sails policies decode the jwt and attach userId, orgId and role the the req object for all later checks.
Every model has the property orgId - we are using MongoDB.
Every controller, db operation, etc. adds this verified orgId to the query. Actually we have a small pipeline preparing the query: we add the orgId, in update cases we filter out unwanted property updates, etc.
This approach does not require additional db calls for separation of tenants.
Some models have specific access requirements per individual RECORD. Here we store allowedUser properties (one for read, one for update, etc.) on exactly this record and we extend the query once more so that only records are returned or updated or Xyz where the current user is included in the applicable allowedUsers property.
This approach also does not require additional db calls. This leverages MongoDB-specific query features, though.
We currently do not have ACL-like requirements which would be right between the 2 approaches I described above (re access control granularity).
You'll need to intercept each request using middlewares
combine them with a role system by checking if a certain token is present on request headers and in a acl map and finally, if the token is present in the acl map, see which permissions are related with this token.
Does anyone have any tips as we develop an application that will require each user to be assigned a permission level. The permission level will determine what functionality is available to the user.
Any advice?
How would you (do you) employ such functionality in your application?
First you need to figure out what functionality you want to cover by your permission system, and in what detail:
Access to tables (List, CRUD)
Functions/Modules
Access on record level (=ACL)
Positive (grant) or Negative (revoke) semantics
What is the "admin" role allowed to do
If you want to restrict access to tables, you can easily set up an additional table containing all the table names, and grant select-list/select-record/insert/update/delete access to the roles/groups, as sketched by JV.
If you want to grant access to functions or modules, have a table of modules and grant execute to roles/groups.
Both functionality is equivalent to grants in SQL.
Access restriction on record level is much more complicated, as you need to model access rights on the status of a record (e.g. "public", "private", "released" in CMS apps), or have explicit permissions on each record.
If you want to implement a permission scheme equivalent to NTFS, you calculate the permission per record based on the group the user is assigned to, and have user-specific permissions that may override the group permissions, and revokes overriding grants.
My applications typically work on table+function / group level, which may be good enough, depending on your requirements.
This is the partial ER diagram for identity module in Turbogears, Python. It implements what you are looking forward to. Users are associated with groups and groups have associated permissions.
The two ways restricted feature availability can be implemented are:
(I prefer)In your controllers check the group to which the user belongs to and moderate your response to the View according to that. Thus View is just a renderer - no business logic.
The View gets the user details like groups and permissions and it decides what to display and what not to (MVC violated).
Read more about MVC (and Turbogears may be).
alt text http://jaivikram.verma.googlepages.com/temp.jpeg
It depends a lot of the language you use and the architecture of your application (web service ? client software ?).
For a server toy project, I though about assigning a minimum permission level to each command, and check it directly when a command network packet is received, triggering a permission error when the user hasn't a high enough level. I might not be suitable for another architecture.
It may be a bit of a dead end to pursue the concept of 'levels'. It may suit your current application, however a data model that consists of a mapping of roles to privileges is more general and suits most purposes.
Assign roles to users. A user may have more than one role, and their role(s) define the privileges they have. The concept is similar to groups, however 'role' is usually easily mapped directly to business logic (think of roles such as 'administrator', 'user', 'clerk', 'account manager', 'regional manager', etc). Privileges also map fairly directly to functions and data objects. You may also be able to map to implementations that use underlying platform access control (e.g. Java privileges).
In the controller code, you check (via their roles) that the user holds the required privilege to perform a function. It is also good practice to modify your views to hide functions that the user does not have the privileges to perform.
In your design you can visualise / document the access control system as a matrix (roles to privileges).