Policies
Each policy specifies how we want to allow/deny someone to access to some resources.
Policy decision
Each policy could be either positive or negative.
When a policy is positive, it means if the policy matches in you authorization request, we allow to do the operation.
If the policy is negative, it means we will deny user from doing the operation when the policy matches.
note
One negative policy could make result of authorization negative totally.
- To create/update a positive policy, set its
decisionvalue ot1 - To create/update a negative policy, set its
decisionvalue to2
Policy features
A policy Could be per specific user using
user_idfield in creation or update policy API.A policy Could be per specific role using
role_codefield.A policy Could be per resource type (e.g., all products) using
res_typefield.A policy Could be per specific resource (e.g., product with id:4) using
res_idfield.A policy can contain a tree, in this case, policy will be matched just when tree path in the request matches with the policy tree path.
Set a policy tree path using thetreeparam.A policy can contain a condition.
A condition could filter policies based on theuser's attrs,resource's attrsandcontext paramswhich we send in our authorization request. Condition should follow expr language definitionA policy can contain
user_scopesto deny access if the user's token does not contain either one of scopes which is specified in theuser_scopesfield. The user's token does not need to bejwtto support this feature. It supports every token that shield generates for users.
Examples
Note
You will learn about tree and condition evaluation in the next section.
The following examples could be used as payload of our requests to create or update a policy.
- Allow user with id
abcto write onproductwith id4
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "product",
"res_id": "4",
"user_id": "abc",
"scopes": [
"write"
],
"decision": 1
}
- Allow all reporters to read all project statuses.
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "project",
"role_code": "reporter",
"scopes": [
"read"
],
"decision": 1
}
- Allow all reporters to read all project statuses in their own cities using Tree:
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "project",
"role_code": "reporter",
"scopes": [
"read"
],
"decision": 1,
"tree": {
"key": "dc",
"values": [
"abc.com"
],
"branches": [
{
"key": "state",
"values": [
"{res.state}"
]
}
]
},
"is_resource_based": true
}
INFO
In this type of policies (which we have a tree), we need to send a path param in our Authorization requests too. The tree in the authorization request must match with the tree in the policy. Read more about it in the Tree evaluation section please.
- Allow all reporters to read all project statuses in their own cities using Condition:
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "project",
"role_code": "reporter",
"scopes": [
"read"
],
"decision": 1,
"condition": "res.attrs.state==user.attrs.state",
"is_resource_based": true
}
- Allow all product owners to see products
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "product",
"scopes": [
"read","write"
],
"decision": 1,
"condition": "res.attrs.owner_id==user.id",
"is_resource_based": true
}
- Allow all admins to read and write on all projects
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "project",
"role_code": "reporter",
"scopes": [
"read"
],
"decision": 1
}
- Deny if a user doesn't have
api_readuser scope, to access to every project with resource scope ofread.
WARNING
user's scope and resource scope are two different things.
- resource's scopes are the
scopesthat you define per your resource to specify the operations that user can do on the resource. - user scopes are the
scopesin the user's token (e.g., user's jwt token,...) that we granted at the client at token generation time (in any oauth2 flow which the client requests a user token)
Note
This is a good policy to evaluate client's granted scopes in addition to the user permissions.
{
"service_id": "{{ your service id}}",
"name": "my test policy",
"res_type": "project",
"scopes": [
"read"
],
"user_scopes": [
"api_read"
],
"decision": 2
}
Tree
A tree is a hierarchically structured object which we use in our policies to match the policy with a group of users under some categories. (e.g., to allow all users in specific city).
Each value in the tree could be dynamic. We can set resource's attribute, user's attribute or context params.
To set user attr as value, use
{user.attr_name}. Changeattr_nameto the real attr name.To set resource attr as value, use
{res.attr_name}.attr_nameshould be changed to the attribute's name.To set context param as value, use
{ctx.param_name}.param_nameshould be changed to the real parameter's name.
Each tree structure is as following:
{
"key": "{branch's key}",
"values": [
"{branch's value}"
],
"branches": [
{
"key": "{child branches' key}",
"values": [
"{child branches' value}"
],
"branches": []
}
]
}
For example:
{
"key": "dc",
"values": [
"abc.com"
],
"branches": [
{
"key": "state",
"values": [
"{res.state}"
]
}
]
}
Tree evaluation
if the path param (which is a tree-path) in the authorization request is a path of tree in the policy, so policy matches in the authorization request.
Examples
- path:
a=b,c=dis match with the following tree:
{
"key": "a",
"values": [
"b"
],
"branches": [
{
"key": "c",
"values": [
"d"
]
},
{
"key": "e",
"values": [
"f"
]
}
]
}
- path
a=b,c=disn't match with the following tree (because of thehikey):
{
"key": "hi",
"values": [
"b"
],
"branches": [
{
"key": "c",
"values": [
"d"
]
}
]
}
Tip
To allow a value in the policy tree match with any value in the tree-path of authorization request, set its value to *
- Path
state=fars,city=fasais match with all the following trees:
{
"key": "state",
"values": [
"*"
]
}
{
"key": "state",
"values": [
"fars"
]
}
{
"key": "state",
"values": [
"fars"
],
"branches": [
{
"key": "city",
"values": [
"fasa"
]
}
]
}
- Path
state=fars,city=fasais not match with none of the following trees:
{
"key": "state",
"values": [
"tehran"
]
}
{
"key": "state",
"values": [
"fars"
],
"branches": [
{
"key": "city",
"values": [
"shiraz"
]
}
]
}
Condition
The condition result specifies whether we should apply the policy or not. If the condition returns true, so we apply the policy (if other sections of policy are good too, e.g., the scope,...)
If it returns false, we skip the policy.
Condition syntax follows expr language
Condition context
The context that we provide to each condition it as following:
ctx: {your provided context data in authorization check}
user: {user_data}
res_type: {resource's type in authorization check}
res: {provided resource in authorization check}
- User: user data in the condition is as following:
id: {user_id}
roles: {array of user's roles}
scopes: {array of user's available scopes}
attrs: {map of user's attributes}
For example:
id: user-1
roles: ["admin","reporter"]
scopes: ["profile","api_read"]
attrs: {
"age":"20"
}
- Resource : It contains the resource's data that you want to check authorization on it. Its structure is as following:
id: {res_id}
type: {res_type},
attrs: {map of resource's attributes}
For example:
id: project-4
type: project
attrs: {
"owner_id":"user-1",
"status":"active"
}
Examples
- Condition to check if
a(string literal) is equal tob(string literal)
a==b
- Condition to check of
stateof the project(as our resource in the policy) is equal to user's state:
res.attrs.state==user.attrs.state
- Condition to check if
stateof the user is nottehran:
user.attrs.state==tehran
- Condition to check if user's state is
tehranorfars.
user.attrs.state in ['tehran','fars']