First of all my apologies for the late response. Here are my comments inline.
ACL, RBAC, ABAC
I am studying about various types of access control models and came
across to know that abac and rbac are the popular ones.
Historically access control has been tackled through access control lists (ACL), then role-based access control (RBAC) and lately attribute-based access control (ABAC). ACLs grew unwieldy and hard to manage which is why NIST came up with RBAC in 1992 (yep it's that old). RBAC is well-known, mature, and built into most IAM products and applications. For instance, a user directory (LDAP, AD...) maintains users and role assignements and provides applications with those roles which the app can then use to determine whether access should be granted. With RBAC, finer-grained access (e.g. access based on relationships as in your case whereby a user can only see their own data) is impossible so either (a) the application developer writes custom code to achieve the right access or (b) you use ABAC.
Why ABAC?
ABAC gives you the ability to define fine-grained access based on any kind of attribute (not just role and not just user attributes) by using policies to describe what can (or cannot) happen. ABAC is sometimes called PBAC (policy-based access control). You refer to XACML which is the language in which ABAC policies are implemented. You can also look into alfa (Wikipedia), a simpler language that maps directly into XACML.
ABAC also defines an architecture with the idea of a Policy Decision Point (PDP) which processes your authorization requests against the policies it's been configured with. The PDP (in your case WSO2 Balana part of WSO2 IS) is called from a Policy Enforcement Point (PEP) such as your app or something sitting in front of your app (e.g. an API gateway or interceptor in your case WSO2 API Manager).
Your use case
I've a basic scenario for one of my project and I couldn't understand
should I go with RBACor ABAC. Obviously RBAC is subset of ABACso
definitely I should go for ABAC but ABAC requires some experience to
write polices in xacml. We are using WSO IS and APIM.
I wouldn't say RBAC is a subset of ABAC. It is indeed from a functionality perspective. But it's not one vs. the other. ABAC will extend RBAC by introducing more attributes, policies, and the aforementioned architecture.
I have admin, owner and member roles in my identity server (IS).
- Admin can view, delete and update users.
- Owners can view and update.
- Members can view only.
This is great. What you are doing is defining your authorization requirements. These will map directly into your ALFA / XACML policies.
At a moment I am using HTTP verbs to achieve desire results i.e. owners can not access DELETE requests and members can't access PUT & DELETE.
In ABAC, we also use actions. These could be plain old human actions (view, edit, delete, approve...) which can then be mapped to the HTTP verbs.
Your challenge
In your text below, I marked in bold what I consider to be your additional authorization requirements.
I have a dashboard where I am displaying different sections like top-users, billing, services, top-consumers etc.
I need to populate nav-bar based on user role and attributes from server e.g. members should not have access to see other users (Add, List) in nav-bar. nav-bar items dependents on user role so we can manage them via RBAC?
This would be handled via an ABAC policy. See below
We've a plan to add roles like ops, marketing, support etc. Does this means we need to create a separate db-schema to maintain access rights for each role?
No! You should not have to create new DB schemas let alone maintain access rights in custom-built systems. Use the policies to do so.
In dashboard I need to hide/show view, update and delete buttons in users, services etc. Now members can see users but have no permission to update or delete them. They cannot view stats, billing and other private information.
Owners can see all users related to their departments/organization but Admin can see all the users for all departments/organization. Here we need to consume the same API for all consumers but api should respond differently for different roles. Roles can be 10s and 100s so ee can not create different apis for each role.
Question
We can implement all these scenarios via RBAC but for managing nav-bar and view related implementation we need to add business logic in our server instead of using WSO2-IS and WSO2-APIM. Is there any way to manage view permissions like hide/show buttons and sections and even consume same API but it should return different result for different api-consumers.
Yes, definitely. This is the purpose of using ABAC and policies. Given you are using WSO2 IS, look into Balana, the PDP inside of that product. There are other solutions e.g. AuthZForce (open source) or Axiomatics (where I work)
The solution
Here is a sample policy written in ALFA and the XACML translation below
namespace haris {
/**
* User Records
*/
policyset users {
target clause axiomatics.objectType == "user record"
apply firstApplicable
/**
* View user record
*/
policy viewUser {
target clause axiomatics.actionId == "view" // This can be the HTTP verb
apply firstApplicable
/**
* Administrators can view all users
*/
rule administrator{
target clause axiomatics.user.role == "administrator"
permit
}
/**
* Owners can view users in their department
*/
rule owners{
target clause axiomatics.user.role == "owner"
permit
condition axiomatics.user.department == axiomatics.record.department
}
/**
* Members can view their own user record only
*/
rule member{
permit
condition axiomatics.user.username == axiomatics.record.owner
}
}
/**
* Update user
*/
policy updateUser {
target clause axiomatics.actionId == "update" // This can be the HTTP verb
apply firstApplicable
/**
* Administrator can update any user
*/
rule administrator{
target clause axiomatics.user.role == "administrator"
permit
}
/**
* Owner can update any user
*/
rule owner{
target clause axiomatics.user.role == "owner"
permit
// TODO: determine what an owner can update
}
}
/**
* Delete user
*/
policy deleteUser {
target clause axiomatics.actionId == "delete" // This can be the HTTP verb
apply firstApplicable
/**
* Administrator can delete any user
*/
rule administrator{
target clause axiomatics.user.role == "administrator"
permit
}
}
}
}
And the XML version
<?xml version="1.0" encoding="UTF-8"?><!--This file was generated by the
ALFA Plugin for Eclipse from Axiomatics AB (http://www.axiomatics.com). --><!--Any modification to this file will
be lost upon recompilation of the source ALFA file -->
<xacml3:PolicySet
PolicyCombiningAlgId="urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable"
PolicySetId="http://axiomatics.com/alfa/identifier/haris.users"
Version="1.0"
xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17">
<xacml3:Description>User Records</xacml3:Description>
<xacml3:PolicySetDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicySetDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">user record</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.objectType"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Policy
PolicyId="http://axiomatics.com/alfa/identifier/haris.users.viewUser"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>View user record</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">view</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.actionId"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.viewUser.administrator">
<xacml3:Description>Administrators can view all users
</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">administrator</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.role"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
</xacml3:Rule>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.viewUser.owners">
<xacml3:Description>Owners can view users in their department
</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">owner</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.role"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Condition>
<xacml3:Apply
FunctionId="urn:oasis:names:tc:xacml:3.0:function:any-of-any">
<xacml3:Function
FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal" />
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.department"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
<xacml3:AttributeDesignator
AttributeId="axiomatics.record.department"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.viewUser.member">
<xacml3:Description>Members can view their own user record only
</xacml3:Description>
<xacml3:Target />
<xacml3:Condition>
<xacml3:Apply
FunctionId="urn:oasis:names:tc:xacml:3.0:function:any-of-any">
<xacml3:Function
FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal" />
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.username"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
<xacml3:AttributeDesignator
AttributeId="axiomatics.record.owner"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
</xacml3:Policy>
<xacml3:Policy
PolicyId="http://axiomatics.com/alfa/identifier/haris.users.updateUser"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>Update user</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">update</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.actionId"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.updateUser.administrator">
<xacml3:Description>Administrator can update any user
</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">administrator</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.role"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
</xacml3:Rule>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.updateUser.owner">
<xacml3:Description>Owner can update any user</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">owner</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.role"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
</xacml3:Rule>
</xacml3:Policy>
<xacml3:Policy
PolicyId="http://axiomatics.com/alfa/identifier/haris.users.deleteUser"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>Delete user</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">delete</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.actionId"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Rule Effect="Permit"
RuleId="haris.users.deleteUser.administrator">
<xacml3:Description>Administrator can delete any user
</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">administrator</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="axiomatics.user.role"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#string"
MustBePresent="false" />
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
</xacml3:Rule>
</xacml3:Policy>
</xacml3:PolicySet>
Enforcing the policies
How will I return different data for a single api but for different roles/users.
Let's assume you have an API e.g. /api/profiles/{profileID}
. There are 2 ways you could use the API:
- GET /api/profiles would return all the profiles the user is entitled to
- GET /api/profiles/123 would return profile 123 if the user is entitled to or HTTP 403 otherwise (or 404 - you could argue you do not want to even reveal that the said profile does exist).
To do so, you need to implement a Policy Enforcement Point (PEP). This could be WSO2's API Manager. The PEP is responsible for
- parsing the incoming API call (GET /api/profile/123)
- converting it into an authorization request e.g. Can Alice view profile 123?
- sending the request to the PDP
- processing the response received back from the PDP - and notably extracting the decision (e.g. Permit).
If the decision is a Permit then the call is forwarded to your backend API. If it isn't you can return HTTP 403 / 404 as discussed.
If it is a 403, then the call does go to the backend and eventually a response is turned from your backend and goes through the PEP where it can once again call the PDP, for instance to redact data.
Do I need to involve business logic in my server like getting nav-bar items, getting api-usage stats, full data access for admins and organization/department for owners and restricted data for members. How to perform these basic operations?
No you don't. When building menus or navigation items, you can also invoke the PDP and ask whether a given user can get access to a given set of functionality e.g. "Can Alice view nav-bar item #123?". You need minimal business logic to invoke the PDP.