2016-11-29 15:30:53 +00:00
[[_policy_js]]
2017-10-09 06:38:46 +00:00
= JavaScript-Based Policy
2016-06-05 22:17:31 +00:00
2021-01-18 12:18:04 +00:00
WARNING: If your policy implementation is using Attribute based access control (ABAC) as in the examples below, then please make sure that
users are not able to edit the protected attributes and the corresponding attributes are read-only. See the details in the link:{adminguide_link}#_read_only_user_attributes[Threat model mitigation chapter].
2016-11-15 21:34:20 +00:00
You can use this type of policy to define conditions for your permissions using JavaScript. It is one of the rule-based policy types
2017-08-28 12:50:14 +00:00
supported by {project_name}, and provides flexibility to write any policy based on the <<_policy_evaluation_api, Evaluation API>>.
2016-06-05 22:17:31 +00:00
2017-04-25 22:52:57 +00:00
To create a new JavaScript-based policy, select *JavaScript* in the dropdown list in the upper right corner of the policy listing.
2016-06-14 23:50:50 +00:00
2019-11-01 12:09:56 +00:00
NOTE: By default, JavaScript Policies can not be uploaded to the server. You should prefer deploying your JS Policies directly to
the server as described in link:{developerguide_jsproviders_link}[{developerguide_jsproviders_name}]. If you still want to use the
{project_name} Administration Console to manage your JS policies you should enable the `Upload Scripts` feature.
2016-06-14 23:50:50 +00:00
.Add JavaScript Policy
2017-08-28 12:50:14 +00:00
image:{project_images}/policy/create-js.png[alt="Add JavaScript Policy"]
2016-06-14 23:50:50 +00:00
2017-10-09 06:38:46 +00:00
== Configuration
2016-06-05 22:17:31 +00:00
* *Name*
+
2016-11-15 21:34:20 +00:00
A human-readable and unique string describing the policy. A best practice is to use names that are closely related to your business and security requirements, so you
can identify them more easily.
2016-06-05 22:17:31 +00:00
+
* *Description*
+
2016-11-15 21:34:20 +00:00
A string containing details about this policy.
2016-06-05 22:17:31 +00:00
+
* *Code*
+
2016-09-09 03:53:39 +00:00
The JavaScript code providing the conditions for this policy.
2016-06-05 22:17:31 +00:00
+
* *Logic*
+
2017-08-28 12:50:14 +00:00
The <<_policy_logic, Logic>> of this policy to apply after the other conditions have been evaluated.
2016-06-05 22:17:31 +00:00
2019-11-01 12:09:56 +00:00
== Creating a JS Policy from a Deployed JAR File
{project_name} allows you to deploy a JAR file in order to deploy scripts to the server. Please, take a look at link:{developerguide_jsproviders_link}[{developerguide_jsproviders_name}]
for more details.
Once you have your scripts deployed, you should be able to select the scripts you deployed from the list of available policy providers.
2017-10-09 06:38:46 +00:00
== Examples
2016-06-05 22:17:31 +00:00
2018-06-12 02:16:55 +00:00
=== Checking for attributes from the evaluation context
2016-11-15 21:34:20 +00:00
Here is a simple example of a JavaScript-based policy that uses attribute-based access control (ABAC) to define a condition based on an attribute
2016-06-05 22:17:31 +00:00
obtained from the execution context:
```javascript
2022-03-13 11:41:25 +00:00
const context = $evaluation.getContext();
const contextAttributes = context.getAttributes();
2016-06-05 22:17:31 +00:00
2016-06-29 22:51:16 +00:00
if (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {
2016-06-05 22:17:31 +00:00
$evaluation.grant();
}
```
2018-06-12 02:16:55 +00:00
=== Checking for attributes from the current identity
Here is a simple example of a JavaScript-based policy that uses attribute-based access control (ABAC) to define a condition based on an attribute
obtained associated with the current identity:
```javascript
2022-03-13 11:41:25 +00:00
const context = $evaluation.getContext();
const identity = context.getIdentity();
const attributes = identity.getAttributes();
const email = attributes.getValue('email').asString(0);
2018-06-12 02:16:55 +00:00
if (email.endsWith('@keycloak.org')) {
$evaluation.grant();
}
```
Where these attributes are mapped from whatever claim is defined in the token that was used in the authorization request.
=== Checking for roles granted to the current identity
2018-02-28 07:53:43 +00:00
You can also use Role-Based Access Control (RBAC) in your policies. In the example below, we check if a user is granted with a `keycloak_user` *realm* role:
2016-06-05 22:17:31 +00:00
```javascript
2022-03-13 11:41:25 +00:00
const context = $evaluation.getContext();
const identity = context.getIdentity();
2016-06-05 22:17:31 +00:00
2017-12-04 12:59:48 +00:00
if (identity.hasRealmRole('keycloak_user')) {
2016-06-05 22:17:31 +00:00
$evaluation.grant();
}
```
2018-02-28 07:53:43 +00:00
Or you can check if a user is granted with a `my-client-role` *client* role, where `my-client` is the client id of the client application:
2017-12-04 12:59:48 +00:00
```javascript
2022-03-13 11:41:25 +00:00
const context = $evaluation.getContext();
const identity = context.getIdentity();
2017-12-04 12:59:48 +00:00
if (identity.hasClientRole('my-client', 'my-client-role')) {
$evaluation.grant();
}
```
2018-06-12 02:16:55 +00:00
=== Checking for roles granted to an user
To check for realm roles granted to an user:
```javascript
2022-03-13 11:41:25 +00:00
const realm = $evaluation.getRealm();
2018-06-12 02:16:55 +00:00
if (realm.isUserInRealmRole('marta', 'role-a')) {
$evaluation.grant();
}
```
Or for client roles granted to an user:
```javascript
2022-03-13 11:41:25 +00:00
const realm = $evaluation.getRealm();
2018-06-12 02:16:55 +00:00
if (realm.isUserInClientRole('marta', 'my-client', 'some-client-role')) {
$evaluation.grant();
}
```
=== Checking for roles granted to a group
To check for realm roles granted to a group:
```javascript
2022-03-13 11:41:25 +00:00
const realm = $evaluation.getRealm();
2018-06-12 02:16:55 +00:00
if (realm.isGroupInRole('/Group A/Group D', 'role-a')) {
$evaluation.grant();
}
```
=== Pushing arbitrary claims to the resource server
To push arbitrary claims to the resource server in order to provide additional information on how permissions should be
enforced:
```javascript
2022-03-13 11:41:25 +00:00
let permission = $evaluation.getPermission();
2018-06-12 02:16:55 +00:00
// decide if permission should be granted
if (granted) {
permission.addClaim('claim-a', 'claim-a');
permission.addClaim('claim-a', 'claim-a1');
permission.addClaim('claim-b', 'claim-b');
}
```
=== Checking for group membership
```javascript
2022-03-13 11:41:25 +00:00
const realm = $evaluation.getRealm();
2018-06-12 02:16:55 +00:00
if (realm.isUserInGroup('marta', '/Group A/Group B')) {
$evaluation.grant();
}
```
=== Mixing different access control mechanisms
2017-12-04 12:59:48 +00:00
You can also use a combination of several access control mechanisms. The example below shows how roles(RBAC) and
2017-12-07 11:15:02 +00:00
claims/attributes(ABAC) checks can be used within the same policy. In this case we check if user is granted with `admin` role
or has an e-mail from `keycloak.org` domain:
2016-06-14 23:50:50 +00:00
```javascript
2022-03-13 11:41:25 +00:00
const context = $evaluation.getContext();
const identity = context.getIdentity();
const attributes = identity.getAttributes();
const email = attributes.getValue('email').asString(0);
2016-06-14 23:50:50 +00:00
2017-12-04 12:59:48 +00:00
if (identity.hasRealmRole('admin') || email.endsWith('@keycloak.org')) {
2016-06-14 23:50:50 +00:00
$evaluation.grant();
}
```
2018-06-12 02:16:55 +00:00
2017-12-07 11:15:02 +00:00
NOTE: When writing your own rules, keep in mind that the *$evaluation* object is an object implementing *org.keycloak.authorization.policy.evaluation.Evaluation*. For more information about what you can access from this interface, see the <<_policy_evaluation_api, Evaluation API>>.