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.