SCIM protected by UMA: simplified flow - GluuFederation/SCIM-Client GitHub Wiki
Config data required
config =
domainURL: oxtrust REST services base, eg "https://didp.gluu.org/identity/restv1"
tokenEndpoint: oxauth's token endpoint, eg https://didp.gluu.org/oxauth/restv1/token
keyStorePassword: the passwork of the scim-rp keystore file
clientId: the client ID of the SCIM requesting party (scim-rp) client, see oxtrust
keyId: one of the kids (eg. the first one) listed in the JWKS field of scim-rp client (see them in the encryption tab)
keyAlg: the algorithm associated to that key
privateKey: the private key associated to that key (see below)
Notes:
To extract the private key do the following (valid for 3.1.x):
-
login to chroot
-
cd /install/community-edition-setup/output/
-
/opt/jre/bin/java -cp '/home/jetty/lib/*' org.xdi.oxauth.util.KeyExporter -keystore scim-rp.jks -keypasswd keyStorePassword -alias keyId -exportfile private-key.pem
(replace keyStorePassword and keyId accordingly)
Send a tokenless request
From here on, I assume we are creating a user. For other operations, adjust payload as necessary.
Send a POST to domainURL/scim/v2/Users (eg. https://didp.gluu.org/identity/restv1/scim/v2/Users) with the contents of the user to add, for instance:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "Barbara",
"name": {
"familyName":"Jensen",
"givenName":"Barbara"
},
"emails": [
{
"value": "[email protected]",
"type": "work",
"primary": true
}
]
}
In the headers of the request include:
- Content-type: "application/scim+json"
Obtain a ticket
The request just sent will return a 401 response. Parse the header www-authenticate
, it will look like:
{ "ticket": ..., "as_uri": ..., "realm": ... }
grab the ticket
Generate a JWT
Create a JWT with payload like:
{
"iss": config.clientId,
"sub": config.clientId,
"aud": config.tokenEndpoint,
"jti": generate a unique identifier (eg. an UUID),
"exp": now / 1000 + 30,
"iat": now
}
(now means the current time expressed as milliseconds elapsed after UNIX epoch)
For its header use:
{
"typ": "JWT",
"alg": config.keyAlg,
"kid": config.keyId
}
Then sign the JWT using config.privateKey, use for algorithm config.keyAlg
Request a token
Send a POST to config.tokenEndpoint with header Content-type: "application/x-www-form-urlencoded", and params:
grant_type = "urn:ietf:params:oauth:grant-type:uma-ticket"
scope = "uma_authorization"
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
client_assertion = signed JWT previously generated
client_id = config.clientId
ticket = ticket (previously received)
As reponse, JSON data will be returned like:
{ "access_token" : "sadfas-1334-2341-blah", "pct" : "..." }
grab access_token and pct
Re-send request
Send the original request again, this time setting headers:
- Authorization = Bearer access_token (eg. Authorization: Bearer sadfas-1334-2341-blah )
- pct (eg. pct: value)
The response must be OK (200) with the actual SCIM output, like:
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"...",
"meta":{
"resourceType":"User",
"created":...,
"lastModified":...,
...
},
...
}
Send more requests
Continue sending SCIM requests as in the previous step. Since the access token has an expiration (1 hour or so), at some point, 401 will be received once more, in this case, start again at this point.