|
4 | 4 | - lock server
|
5 | 5 | ---
|
6 | 6 |
|
7 |
| -# Integrate Cedarling With Lock Server |
| 7 | +# Cedarling Lock Integration Setup Guide |
8 | 8 |
|
9 |
| -## This content is in progress |
| 9 | +For a Cedarling client to communicate with the Lock Server, it has to perform [Dynamic Client Registration **(DCR)**](https://datatracker.ietf.org/doc/html/rfc7591) with the Jans Auth Server. |
10 | 10 |
|
11 |
| -The Janssen Project documentation is currently in development. Topic pages are being created in order of broadest relevance, and this page is coming in the near future. |
| 11 | +By default, clients cannot obtain the necessary scopes to interact with the lock server. Additional configuration is required on both the Auth Server and the client. |
12 | 12 |
|
13 |
| -## Have questions in the meantime? |
| 13 | +This guide will walk you through the following setup processes: |
14 | 14 |
|
15 |
| -While this documentation is in progress, you can ask questions through [GitHub Discussions](https://github.com/JanssenProject/jans/discussions) or the [community chat on Gitter](https://gitter.im/JanssenProject/Lobby). Any questions you have will help determine what information our documentation should cover. |
| 15 | +- [Auth Server Setup](#auth-server-setup) |
| 16 | +- [Client Setup](#client-setup) |
16 | 17 |
|
17 |
| -## Want to contribute? |
| 18 | +--- |
| 19 | + |
| 20 | +## Auth Server Setup |
| 21 | + |
| 22 | +### 1. Creating an SSA JWT |
| 23 | + |
| 24 | +First, create a Software Statement Assertion (SSA) for your Cedarling client. |
| 25 | + |
| 26 | +The easiest way to do this is to use the Jans TUI: |
| 27 | + |
| 28 | +```sh |
| 29 | +jans tui |
| 30 | +``` |
| 31 | + |
| 32 | +Navigate to: |
| 33 | + `Auth Server` > `SSA` > `Add SSA` |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +When creating the SSA, ensure you: |
| 38 | + |
| 39 | +- Add the `Client Credentials` grant type |
| 40 | +- Include the following software roles: |
| 41 | + - `https://jans.io/oauth/lock/log.write` |
| 42 | + - `https://jans.io/oauth/lock/health.write` |
| 43 | + - `https://jans.io/oauth/lock/telemetry.write` |
| 44 | + |
| 45 | +After creation, **export the SSA token** and save it securely. |
| 46 | + |
| 47 | +### 2. Setting up the Interception Script |
| 48 | + |
| 49 | +Next, configure an [*interception script*](../janssen-server/developer/interception-scripts.md) to automatically add the required scopes when a Cedarling client registers. |
| 50 | + |
| 51 | +In your server, create a script file at `/opt/jans/jetty/jans-auth/custom/script/add_cedarling_scopes.py` with the following content: |
| 52 | + |
| 53 | +```py |
| 54 | +from io.jans.model.custom.script.type.client import ClientRegistrationType |
| 55 | +from io.jans.service.cdi.util import CdiUtil |
| 56 | +from io.jans.orm.util import ArrayHelper |
| 57 | +from io.jans.as.server.service import ScopeService |
| 58 | +from io.jans.as.model.util import JwtUtil |
| 59 | + |
| 60 | +class ClientRegistration(ClientRegistrationType): |
| 61 | + def __init__(self, currentTimeMillis): |
| 62 | + self.currentTimeMillis = currentTimeMillis |
| 63 | + |
| 64 | + def init(self, customScript, configurationAttributes): |
| 65 | + print "Cedarling Client registration. Initialization" |
| 66 | + |
| 67 | + if (not configurationAttributes.containsKey("jwks_uri")): |
| 68 | + print "Cedarling Client registration. Initialization failed. Property jwks_uri is not specified" |
| 69 | + return False |
| 70 | + else: |
| 71 | + self.jwks_uri = configurationAttributes.get("jwks_uri").getValue2() |
| 72 | + |
| 73 | + if (not configurationAttributes.containsKey("scope_list")): |
| 74 | + print "Cedarling Client registration. Initialization failed. Property scope_list is not specified" |
| 75 | + return False |
| 76 | + else: |
| 77 | + self.scope_list = configurationAttributes.get("scope_list").getValue2().split(" ") |
| 78 | + |
| 79 | + if (not configurationAttributes.containsKey("trigger_scope")): |
| 80 | + print "Cedarling Client registration. Initialization failed. Property trigger_scope is not specified" |
| 81 | + return False |
| 82 | + else: |
| 83 | + self.trigger_scope = configurationAttributes.get("trigger_scope").getValue2() |
| 84 | + |
| 85 | + # used to check if the scopes we're adding exists in the AS |
| 86 | + self.scopeService = CdiUtil.bean(ScopeService) |
| 87 | + |
| 88 | + print "Cedarling Client registration. Initialized successfully" |
| 89 | + return True |
| 90 | + |
| 91 | + def destroy(self, configurationAttributes): |
| 92 | + print "Cedarling Client registration. Destroy" |
| 93 | + print "Cedarling Client registration. Destroyed successfully" |
| 94 | + return True |
| 95 | + |
| 96 | + def createClient(self, context): |
| 97 | + print "Cedarling Client registration. createClient" |
| 98 | + |
| 99 | + # Check if the request has an SSA |
| 100 | + registerRequest = context.getRegisterRequest() |
| 101 | + ssa = registerRequest.getSoftwareStatement() |
| 102 | + if ssa == "": |
| 103 | + print "Cedarling Client registration. No SSA provided, defaulting" |
| 104 | + return True |
| 105 | + |
| 106 | + # Check if the request has a trigger_scope (this is set as 'cedarling' by default) in the request. |
| 107 | + # The trigger_scope is used to determine if we should add the scopes needed by Cedarling to the |
| 108 | + # registering client. |
| 109 | + # request_scopes = ArrayHelper.toString(registerRequest.getScope()) |
| 110 | + request_scopes = registerRequest.getScope() |
| 111 | + if self.trigger_scope not in request_scopes: |
| 112 | + print "Cedarling Client registration. the scope '%s' was not included in the request, defaulting" % self.trigger_scope |
| 113 | + return True |
| 114 | + |
| 115 | + # add cedarling scopes |
| 116 | + client = context.getClient() |
| 117 | + scopes = client.getScopes() |
| 118 | + for scope in self.scope_list: |
| 119 | + foundScope = self.scopeService.getScopeById(scope) |
| 120 | + if foundScope is None: |
| 121 | + print "did not find scope '%s' in the AS" % scope |
| 122 | + return False |
| 123 | + if len(scopes) == 0: |
| 124 | + scopes = [foundScope.getDn()] |
| 125 | + else: |
| 126 | + scopes = ArrayHelper.addItemToStringArray(scopes, foundScope.getDn()) |
| 127 | + |
| 128 | + client.setScopes(scopes) |
| 129 | + |
| 130 | + print "Cedarling Client registration. added Cedarling scopes" |
| 131 | + return True |
| 132 | + |
| 133 | + def updateClient(self, context): |
| 134 | + print "Cedarling Client registration. UpdateClient method" |
| 135 | + pass |
| 136 | + |
| 137 | + def getApiVersion(self): |
| 138 | + return 11 |
| 139 | + |
| 140 | + def getSoftwareStatementHmacSecret(self, context): |
| 141 | + return "" |
| 142 | + |
| 143 | + def getSoftwareStatementJwks(self, context): |
| 144 | + print "SSA Cedarling Client registration. getting jwks from '%s'" % self.jwks_uri |
| 145 | + jwks = JwtUtil.getJSONWebKeys(self.jwks_uri) |
| 146 | + if jwks is None: |
| 147 | + print "SSA Cedarling Client registration. jwks not found" |
| 148 | + return jwks.toString() |
| 149 | + |
| 150 | + def modifyPutResponse(self, responseAsJsonObject, executionContext): |
| 151 | + return False |
| 152 | + |
| 153 | + def modifyReadResponse(self, responseAsJsonObject, executionContext): |
| 154 | + return False |
| 155 | + |
| 156 | + def modifyPostResponse(self, responseAsJsonObject, executionContext): |
| 157 | + return False |
| 158 | +``` |
| 159 | + |
| 160 | +* *you can also find a copy of this script in [jans/jans-cedarling/lock-server-script/add_cedarling_scopes.py](../../jans-cedarling/lock-server-script/add_cedarling_scopes.py)*. |
| 161 | + |
| 162 | +Next, create a JSON file named `script_schema.json` with the following content: |
| 163 | + |
| 164 | +```json |
| 165 | +{ |
| 166 | + "name": "add_cedarling_scopes", |
| 167 | + "aliases": null, |
| 168 | + "description": "A DCR script that adds the required scopes by a client to interact with the lock server", |
| 169 | + "scriptType": "client_registration", |
| 170 | + "programmingLanguage": "python", |
| 171 | + "moduleProperties": [], |
| 172 | + "configurationProperties": [ |
| 173 | + { |
| 174 | + "value1": "jwks_uri", |
| 175 | + "value2": "https://demoexample.jans.io/jans-auth/restv1/jwks", |
| 176 | + "hide": false, |
| 177 | + "description": "JWKS URI used for the SSA validation" |
| 178 | + }, |
| 179 | + { |
| 180 | + "value1": "scope_list", |
| 181 | + "value2": "https://jans.io/oauth/lock/log.write https://jans.io/oauth/lock/health.write https://jans.io/oauth/lock/telemetry.write", |
| 182 | + "hide": false, |
| 183 | + "description": "space-separated scopes that will be added by the script" |
| 184 | + }, |
| 185 | + { |
| 186 | + "value1": "trigger_scope", |
| 187 | + "value2": "cedarling", |
| 188 | + "hide": false, |
| 189 | + "description": "the scope that must be present for the script to run" |
| 190 | + } |
| 191 | + ], |
| 192 | + "level": 100, |
| 193 | + "revision": 0, |
| 194 | + "enabled": true, |
| 195 | + "scriptError": null, |
| 196 | + "modified": false, |
| 197 | + "internal": false, |
| 198 | + "locationType": "file", |
| 199 | + "locationPath": "add_cedarling_scopes.py" |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +* *you can also find a copy of this schema in [jans/jans-cedarling/lock-server-script/script_schema.json](../../jans-cedarling/lock-server-script/script_schema.json)*. |
| 204 | + |
| 205 | +> Note: |
| 206 | +> |
| 207 | +> Do not change the field ordering; The Jans server expects a specific structure. |
| 208 | +
|
| 209 | +Finally, register the script with the Auth Server: |
| 210 | + |
| 211 | +```sh |
| 212 | +jans cli --operation-id post-config-scripts --data ./script_schema.json |
| 213 | +``` |
| 214 | + |
| 215 | +### 3. Testing the Setup |
| 216 | + |
| 217 | +You can verify the setup by initializing a client registration with your SSA: |
| 218 | + |
| 219 | +```sh |
| 220 | +curl -kX POST https://demoexample.jans.io/jans-auth/restv1/register \ |
| 221 | + -H "Content-Type: application/json" \ |
| 222 | + -d '{ |
| 223 | + "token_endpoint_auth_method": "client_secret_basic", |
| 224 | + "grant_types": ["client_credentials"], |
| 225 | + "client_name": "cedarling-test", |
| 226 | + "access_token_as_jwt": true, |
| 227 | + "scope": "cedarling", |
| 228 | + "software_statement": "<YOUR_SSA_HERE>" |
| 229 | +}' |
| 230 | +``` |
| 231 | + |
| 232 | +A successful response will contain the following scopes: |
| 233 | + |
| 234 | +```json |
| 235 | +{ |
| 236 | + "scope": "https://jans.io/oauth/lock/log.write https://jans.io/oauth/lock/health.write https://jans.io/oauth/lock/telemetry.write" |
| 237 | +} |
| 238 | +``` |
| 239 | + |
| 240 | +> Note: |
| 241 | +> |
| 242 | +> If you want to learn more about configuring the example interception script, see the [reference](../janssen-server/developer/interception-scripts.md). |
| 243 | +
|
| 244 | +--- |
| 245 | + |
| 246 | +## Client Setup |
| 247 | + |
| 248 | +To enable Lock Server integration in the Cedarling client, configure the appropriate [bootstrap properties](./cedarling-properties.md). |
| 249 | + |
| 250 | +Here's a table of the available properties: |
18 | 251 |
|
19 |
| -If you have content you'd like to contribute to this page in the meantime, you can get started with our [Contribution guide](https://docs.jans.io/head/CONTRIBUTING/). |
| 252 | +| Property | Description | Allowed Values | Default | |
| 253 | +| --- | --- | --- | --- | |
| 254 | +| `CEDARLING_LOCK` | Toggles the all the Lock Server integration features. | `enabled`, `disabled` | `disabled` | |
| 255 | +| `CEDARLING_LOCK_SERVER_CONFIGURATION_URI` | URI to fetch Lock Server metadata (`.well-known/lock-master-configuration`). Required if `CEDARLING_LOCK` is `enabled`. | String | `""` | |
| 256 | +| `CEDARLING_LOCK_DYNAMIC_CONFIGURATION` (WIP) | Toggles listening for Server-Sent Events (SSE) config updates. | `enabled`, `disabled` | `disabled` | |
| 257 | +| `CEDARLING_LOCK_SSA_JWT` | SSA JWT used for DCR. This is required if you followed the [auth server setup](#auth-server-setup). | String | `""` | |
| 258 | +| `CEDARLING_LOCK_LOG_INTERVAL` | Frequency (in seconds) of sending log messages to the Lock Server. `0` disables transmission. | uint | `0` | |
| 259 | +| `CEDARLING_LOCK_HEALTH_INTERVAL` (WIP) | Frequency (in seconds) of sending health messages to the Lock Server. `0` disables transmission. | uint | `0` | |
| 260 | +| `CEDARLING_LOCK_TELEMETRY_INTERVAL` (WIP) | Frequency (in seconds) of sending telemetry messages to the Lock Server. `0` disables transmission. | uint | `0` | |
| 261 | +| `CEDARLING_LOCK_LISTEN_SSE` (WIP) | Toggles listening for updates from the Lock Server via SSE. | `enabled`, `disabled` | `disabled` | |
| 262 | +| `CEDARLING_LOCK_ACCEPT_INVALID_CERTS` | Allows connection to servers with invalid certificates (for testing purposes only; not available for WASM builds).| `enabled`, `disabled` | `disabled` | |
0 commit comments