Skip to content

Commit

Permalink
feat(jans-auth-server): support for OAuth 2.0 Rich Authorization Requ…
Browse files Browse the repository at this point in the history
…ests (#7145)

* feat(jans-auth-server): rar - added authorizationDetailsTypesSupported

#6292
Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added supported authz details types to discovery #6933

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added authorization_details custom interception script and dynamic registration #6933

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): used in templates title jans instead of oxauth #6933

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): authorization_details authorization #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added authz details service with check/save ability #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added authz details support to token endpoint #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added authz details to PAR #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* feat(jans-auth-server): added authz details to introspection #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* chore(jans-auth-server): authz details related refactoring #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* chore(jans-auth-server): authz details related refactoring #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* test(jans-auth-server): added AuthzDetailsServiceTest #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* test(jans-auth-server): added integration test for Rich Authorization Requests #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

* doc(jans-auth-server): added documentation for rich authorization requests #6292

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>

---------

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>
Signed-off-by: Mustafa Baser <mbaser@mail.com>
  • Loading branch information
yuriyz authored and devrimyatar committed Dec 30, 2023
1 parent da445f4 commit e006e4c
Show file tree
Hide file tree
Showing 83 changed files with 2,351 additions and 57 deletions.
1 change: 1 addition & 0 deletions docs/admin/auth-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ FAPI-CIBA OpenID Providers for the latest results.
* [RFC 9126 OAuth 2.0 Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc9126.html)
* [Draft - OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP)](https://www.ietf.org/archive/id/draft-ietf-oauth-dpop-11.html)
* [Draft - JWT Response for OAuth Token Introspection](https://www.ietf.org/archive/id/draft-ietf-oauth-jwt-introspection-response-12.html)
* [OAuth 2.0 Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396)

** User Managed Access (UMA) **

Expand Down
181 changes: 181 additions & 0 deletions docs/admin/auth-server/authz-details/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
tags:
- administration
- auth-server
- scope
- authorization-details
---

## OAuth 2.0 Rich Authorization Requests

Rich Authorization Requests introduces new `authorization_details` parameter that is used to carry fine-grained authorization data in OAuth messages.

While `scope` is used for coarse-grained access, `authorization_details` is used for fine-grained access.

`authorization_details` are associated with authorization and thus with client to limit what authorization can be granted within given client.

`authorization_details` is JSON array, example:

```json
[
{
"type": "demo_authz_detail",
"actions": [
"list_accounts",
"read_balances"
],
"locations": [
"https://example.com/accounts"
],
"ui_representation": "Read balances and list accounts at https://example.com/accounts"
},
{
"type":"financial-transaction",
"actions":[
"withdraw"
],
"identifier":"account-14-32-32-3",
"currency":"USD"
}
]
```

### Authorization Details Types

`type` - is required element in single authorization detail and specifies the authorization details type as a string.
Type defines how single authorization detail is handled by both AS and RS.
Because "shape" and structure of single authorization detail can vary a lot, validation and representation logic is externalized to `AuthzDetailType` custom scripts.

`type` defines type of authorization detail. Each such type is represented by AS `AuthzDetailType` custom scripts.
It means that for example above administrator must define two `AuthzDetailType` custom scripts with names: `demo_authz_detail` and `financial-transaction`.

If `authorization_details` parameter is absent in request then `AuthzDetailType` custom scripts are not invoked.

`demo_authz_detail` and `financial-transaction` `AuthzDetailType` custom scripts must be provided by administrator.

- `demo_authz_detail` is called for all authorization details with `"type": "demo_authz_detail"`
- `financial-transaction` is called for all authorization details with `"type": "financial-transaction"`

Sample Authorization Request
```
POST /jans-auth/restv1/authorize HTTP/1.1
Host: yuriyz-fond-skink.gluu.info
response_type=code&client_id=7a29bf35-96ec-4bbd-a05c-15e1ff9f07cc&scope=openid+profile+address+email+phone+user_name&redirect_uri=https%3A%2F%2Fyuriyz-relaxed-jawfish.gluu.info%2Fjans-auth-rp%2Fhome.htm&state=6cdc7701-178c-4653-adac-5c1e9c6c4aba&nonce=b9a1ecc4-548e-475c-8b29-f019417e1aef&prompt=&ui_locales=&claims_locales=&acr_values=&request_session_id=false&authorization_details=%5B%0A++%7B%0A++++%22type%22%3A+%22demo_authz_detail%22%2C%0A++++%22actions%22%3A+%5B%0A++++++%22list_accounts%22%2C%0A++++++%22read_balances%22%0A++++%5D%2C%0A++++%22locations%22%3A+%5B%0A++++++%22https%3A%2F%2Fexample.com%2Faccounts%22%0A++++%5D%2C%0A++++%22ui_representation%22%3A+%22Read+balances+and+list+accounts+at+https%3A%2F%2Fexample.com%2Faccounts%22%0A++%7D%0A%5D
```

Request is rejected if request's `authorization_details` has types which does not have corresponding `AuthzDetailType` custom script.

Check more details about [`AuthzDetailType` custom scripts](../../developer/scripts/authz-detail.md)

### AS Metadata (Discovery)

Metadata endpoint has `authorization_details_types_supported` which shows supported authorization details types.
Value for `authorization_details_types_supported` is populated based on valid and enabled `AuthzDetailType` insterception scripts.

For `demo_authz_detail` and `financial-transaction` `AuthzDetailType` custom scripts enabled discovery response has:

```text
{
"authorization_details_types_supported" : [ "demo_authz_detail", "financial-transaction" ],
...
}
```

### Client Registration

Client registration request has new parameter `authorization_details_types` to limit authorization details types supported by client.
If request is made with `authorization_details` that has types that are not listed in client's `authorization_details_types` the request will be rejected.

Sample registration request and response
```text
-------------------------------------------------------
REQUEST:
-------------------------------------------------------
POST /jans-auth/restv1/register HTTP/1.1
Host: yuriyz-relaxed-jawfish.gluu.info
Content-Type: application/json
Accept: application/json
{
"grant_types" : [ "authorization_code", "implicit" ],
"subject_type" : "public",
"application_type" : "web",
"authorization_details_types" : [ "demo_authz_detail" ],
"scope" : "openid profile address email phone user_name",
"minimum_acr_priority_list" : [ ],
"redirect_uris" : [ "https://yuriyz-relaxed-jawfish.gluu.info/jans-auth-rp/home.htm", "https://client.example.com/cb", "https://client.example.com/cb1", "https://client.example.com/cb2" ],
"client_name" : "jans test app",
"additional_audience" : [ ],
"response_types" : [ "code" ]
}
-------------------------------------------------------
RESPONSE:
-------------------------------------------------------
HTTP/1.1 201
Cache-Control: no-store
Connection: Keep-Alive
Content-Length: 1653
Content-Type: application/json
Date: Mon, 18 Dec 2023 17:59:13 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Set-Cookie: X-Correlation-Id=7b231c8f-5b2e-445d-b5ea-0f693c1cd7f2; Secure; HttpOnly;HttpOnly
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Xss-Protection: 1; mode=block
{
"allow_spontaneous_scopes": false,
"application_type": "web",
"rpt_as_jwt": false,
"registration_client_uri": "https://yuriyz-relaxed-jawfish.gluu.info/jans-auth/restv1/register?client_id=7a29bf35-96ec-4bbd-a05c-15e1ff9f07cc",
"tls_client_auth_subject_dn": "",
"run_introspection_script_before_jwt_creation": false,
"registration_access_token": "92a40113-b27c-43b9-bf96-a222fcfe1c9c",
"client_id": "7a29bf35-96ec-4bbd-a05c-15e1ff9f07cc",
"token_endpoint_auth_method": "client_secret_basic",
"scope": "openid",
"client_secret": "1af17da1-57a3-416b-a358-c84bb0ef0fad",
"client_id_issued_at": 1702922353,
"backchannel_logout_uri": [],
"backchannel_logout_session_required": false,
"client_name": "jans test app",
"par_lifetime": 600,
"spontaneous_scopes": [],
"id_token_signed_response_alg": "RS256",
"access_token_as_jwt": false,
"grant_types": [
"authorization_code",
"implicit"
],
"subject_type": "public",
"authorization_details_types": ["demo_authz_detail"],
"additional_token_endpoint_auth_methods": [],
"keep_client_authorization_after_expiration": false,
"require_par": false,
"redirect_uris": [
"https://client.example.com/cb2",
"https://client.example.com/cb1",
"https://yuriyz-relaxed-jawfish.gluu.info/jans-auth-rp/home.htm",
"https://client.example.com/cb"
],
"redirect_uris_regex": "",
"additional_audience": [],
"frontchannel_logout_session_required": false,
"client_secret_expires_at": 0,
"access_token_signing_alg": "RS256",
"response_types": ["code"]
}
```








1 change: 1 addition & 0 deletions docs/admin/developer/interception-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ calling external APIs
1. [Introspection](./scripts/introspection.md) : Introspection scripts allows to modify response of Introspection Endpoint spec and present additional meta information surrounding the token.
1. [Post Authentication](./scripts/post-authentication.md)
1. [Authorization Challenge](./scripts/authorization-challenge.md)
1. [Authz Detail](./scripts/authz-detail.md)
1. [Select Account](./scripts/select-account.md)
1. Resource Owner Password Credentials
1. UMA 2 RPT Authorization Policies
Expand Down
185 changes: 185 additions & 0 deletions docs/admin/developer/scripts/authz-detail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
tags:
- administration
- developer
- scripts
---

# Authorization Detail Custom Script (AuthzDetail)

## Overview

The Jans-Auth server implements [OAuth 2.0 Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396).
This script is used to control/customize single authorization detail from `authorization_details` array.

## Behavior

In request to Authorization Endpoint and to Token Endpoint RP can specify `authorization_details` request parameter which specifies JSON array.

```json
[
{
"type": "demo_authz_detail",
"actions": [
"list_accounts",
"read_balances"
],
"locations": [
"https://example.com/accounts"
],
"ui_representation": "Read balances and list accounts at https://example.com/accounts"
},
{
"type":"financial-transaction",
"actions":[
"withdraw"
],
"identifier":"account-14-32-32-3",
"currency":"USD",
"ui_representation": "Withdraw money from account-14-32-32-3"
}
]
```

`type` defines type of authorization detail. Each such type is represented by AS `AuthzDetailType` custom scripts.
It means that for example above administrator must define two `AuthzDetailType` custom scripts with names: `demo_authz_detail` and `financial-transaction`.

If `authorization_details` parameter is absent in request then `AuthzDetailType` custom scripts are not invoked.

`demo_authz_detail` and `financial-transaction` `AuthzDetailType` custom scripts must be provided by administrator.

- `demo_authz_detail` is called for all authorization details with `"type": "demo_authz_detail"`
- `financial-transaction` is called for all authorization details with `"type": "financial-transaction"`

Sample Authorization Request
```
POST /jans-auth/restv1/authorize HTTP/1.1
Host: yuriyz-fond-skink.gluu.info
response_type=code&client_id=7a29bf35-96ec-4bbd-a05c-15e1ff9f07cc&scope=openid+profile+address+email+phone+user_name&redirect_uri=https%3A%2F%2Fyuriyz-relaxed-jawfish.gluu.info%2Fjans-auth-rp%2Fhome.htm&state=6cdc7701-178c-4653-adac-5c1e9c6c4aba&nonce=b9a1ecc4-548e-475c-8b29-f019417e1aef&prompt=&ui_locales=&claims_locales=&acr_values=&request_session_id=false&authorization_details=%5B%0A++%7B%0A++++%22type%22%3A+%22demo_authz_detail%22%2C%0A++++%22actions%22%3A+%5B%0A++++++%22list_accounts%22%2C%0A++++++%22read_balances%22%0A++++%5D%2C%0A++++%22locations%22%3A+%5B%0A++++++%22https%3A%2F%2Fexample.com%2Faccounts%22%0A++++%5D%2C%0A++++%22ui_representation%22%3A+%22Read+balances+and+list+accounts+at+https%3A%2F%2Fexample.com%2Faccounts%22%0A++%7D%0A%5D
```

## Interface
The Authorization Details script implements the [AuthzDetailType](https://github.com/JanssenProject/jans/blob/main/jans-core/script/src/main/java/io/jans/model/custom/script/type/authzdetails/AuthzDetailType.java) interface. This extends methods from the base script type in addition to adding new methods:

### Inherited Methods
| Method header | Method description |
|:-----|:------|
| `def init(self, customScript, configurationAttributes)` | This method is only called once during the script initialization. It can be used for global script initialization, initiate objects etc |
| `def destroy(self, configurationAttributes)` | This method is called once to destroy events. It can be used to free resource and objects created in the `init()` method |
| `def getApiVersion(self, configurationAttributes, customScript)` | The getApiVersion method allows API changes in order to do transparent migration from an old script to a new API. Only include the customScript variable if the value for getApiVersion is greater than 10 |

### New methods
| Method header | Method description |
|:-----|:------|
|`def validateDetail(self, context)`| Called when the request is received. Method validates single authorization detail from `authorization_details`. |
|`def getUiRepresentation(self, context)`| Called when single authorization detail from `authorization_details` has to be represented on UI as string. For example on authorization page. |

`validateDetail` method returns true/false which indicates to server whether the validation of single authorization detail (from `authorization_details` array) is passed or failed.
If at least one element from `authorization_details` array fails validation error is returned by AS.

`getUiRepresentation` method returns string and represents single authorization detail as string on UI. Authorization detail can have "ui_representation" json key which makes implementation as simple as following:

```java
@Override
public String getUiRepresentation(Object scriptContext) {
ExternalScriptContext context = (ExternalScriptContext) scriptContext;
return context.getAuthzDetail().getJsonObject().optString("ui_representation");
}
```


### Objects
| Object name | Object description |
|:-----|:------|
|`customScript`| The custom script object. [Reference](https://github.com/JanssenProject/jans/blob/main/jans-core/script/src/main/java/io/jans/model/custom/script/model/CustomScript.java) |
|`context`| [Reference](https://github.com/JanssenProject/jans/blob/main/jans-auth-server/server/src/main/java/io/jans/as/server/service/external/context/ExternalScriptContext.java) |

- Get Authz Detail - `context.getAuthzDetail()`
- Get Authz Detail Type - `context.getAuthzDetail().getType()`
- Get Authz Detail JSON Object (`org.json.JSONObject`) for manipulation - `context.getAuthzDetail().getJsonObject()`
- Get full HTTP Request - `context.getHttpRequest()`


## Simple Use Case: validate authz details is present and return string representation

### Script Type: Java

```java
/*
Copyright (c) 2023, Gluu
Author: Yuriy Z
*/

import io.jans.as.server.service.external.context.ExternalScriptContext;
import io.jans.model.SimpleCustomProperty;
import io.jans.model.custom.script.model.CustomScript;
import io.jans.model.custom.script.type.authzdetails.AuthzDetailType;
import io.jans.service.custom.script.CustomScriptManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

/**
* @author Yuriy Z
*/
public class AuthzDetail implements AuthzDetailType {

private static final Logger log = LoggerFactory.getLogger(AuthzDetail.class);
private static final Logger scriptLogger = LoggerFactory.getLogger(CustomScriptManager.class);

/**
* All validation logic of single authorization detail must take place in this method.
* If method returns "false" AS returns error to RP. If "true" processing of request goes on.
*
* @param scriptContext script context. Authz detail can be taken as "context.getAuthzDetail()".
* @return whether single authorization detail is valid or not
*/
@Override
public boolean validateDetail(Object scriptContext) {
ExternalScriptContext context = (ExternalScriptContext) scriptContext;
return context.getAuthzDetail() != null;
}

/**
* Method returns single authorization detail string representation which is shown on authorization page by AS.
*
* @param scriptContext script context. Authz detail can be taken as "context.getAuthzDetail()".
* @return returns single authorization details string representation which is shown on authorization page by AS.
*/
@Override
public String getUiRepresentation(Object scriptContext) {
ExternalScriptContext context = (ExternalScriptContext) scriptContext;
return context.getAuthzDetail().getJsonObject().optString("ui_representation");
}

@Override
public boolean init(Map<String, SimpleCustomProperty> configurationAttributes) {
scriptLogger.info("Initialized AuthzDetail Java custom script.");
return true;
}

@Override
public boolean init(CustomScript customScript, Map<String, SimpleCustomProperty> configurationAttributes) {
scriptLogger.info("Initialized AuthzDetail Java custom script.");
return true;
}

@Override
public boolean destroy(Map<String, SimpleCustomProperty> configurationAttributes) {
scriptLogger.info("Destroyed AuthzDetail Java custom script.");
return true;
}

@Override
public int getApiVersion() {
return 11;
}
}

```


## Sample Scripts
- [AuthzDetails](../../../script-catalog/authz_detail/AuthzDetail.java)
Loading

0 comments on commit e006e4c

Please sign in to comment.