IDENTITY GOVERNANCE · LAB
Ask your tenant's SCIM service what it supports, and read exactly what you need
Read SCIM discovery, change a tenant setting and watch discovery follow it, read users and groups attribute by attribute, and add a site extension whose value appears only when asked for.
ReadyUses your lab tenant
The lesson
Builds on: Sources of truth.
New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.
Your progress
Press Start before you begin. Only events your tenant records after that count, in the order below. Checking reads your tenant's Audit, so you need Audit read access in it.
Sign in to start this lab and check your progress. Log in or create an account.
Read the service's configuration
Recorded as
scim.discovery.readsucceeded forlab-provisioning.Change a provisioning setting that discovery reports
Recorded as
tenant.provisioning.updatesucceeded.Add the Site extension
Recorded as
tenant.schemas.createsucceeded.Give Ava a site through the extension
Recorded as
scim.user.patchsucceeded forlab-provisioningabout[email protected].A user that names an unknown schema is refused
Recorded as
scim.user.createrejected (invalid_value) forlab-provisioning.
Request console
Requests in this lab can be sent from this page to your tenant: open one and choose Send. Fill in the values below first. They stay in this page's memory and are gone when you leave; secrets are never stored or sent anywhere except the request you send.
Setup
Open a bash shell and set the variables and helpers from the directory lab, and look up Ava:
export AVA=$(scim -G "$SCIM/Users" --data-urlencode 'filter=userName eq "[email protected]"' | jq -r '.Resources[0].id').Press Start on the lab page.
Walkthrough
ServiceProviderConfig. Ask what the service offers.
GET$ISSUER/scim/v2/ServiceProviderConfig
Open in console
GET $ISSUER/scim/v2/ServiceProviderConfig HTTP/1.1
Authorization: Bearer $TOKEN
Accept: application/scim+jsonPatch is supported; bulk is supported with maxOperations: 100 and maxPayloadSize: 1048576; filter is supported with maxResults: 200; sort and etag are supported; changePassword reflects your tenant; authenticationSchemes says OAuth bearer token.
Why it matters: this is "Asking what a service supports". Each value changes how a client behaves, such as the largest page it should ask for and whether it may send one Bulk request instead of many.
A setting changes discovery. In User Management > Provisioning, turn Accept passwords over SCIM off and save. Read
scim "$SCIM/ServiceProviderConfig" | jq .changePassword:supportedis nowfalse.
Restore: turn Accept passwords over SCIM back on and save. The HR Simulator's runs with initial passwords need it.
Why it matters: discovery describes this tenant's runtime, not a static brochure, so a client that reads it adapts to the tenant's choices.
ResourceTypes.
scim "$SCIM/ResourceTypes/User" | jq '{endpoint, schema, schemaExtensions}'lists the enterprise extension and, if you did the contractors lab, theWorkforceextension, each withrequired: false.Attribute characteristics. Read the core user schema and pick out three attributes.
scim "$SCIM/Schemas/urn:ietf:params:scim:schemas:core:2.0:User" \
| jq '.attributes[] | select(.name=="password" or .name=="userName" or .name=="groups") | {name,mutability,returned,uniqueness,required}'
password is writeOnly and returned never. userName is required with uniqueness server. groups is readOnly.
Why it matters: these characteristics explain the mutability refusal from the directory lab, and why no response ever contains a password, even one the HR Simulator set.
Reading a user. Read Ava with
scim -i "$SCIM/Users/$AVA"and name each attribute's job:idbelongs to the service,userNamecan change,nameis complex,emailsis multi-valued,activeis the administrative status, andmeta.versionequals theETagheader. Ava has noexternalId, because no client created her. Then read a simulated person:externalId(HRSIM-...) is the HR client's own key, while the enterpriseemployeeNumber(0003, for example) is a business attribute.
Why it matters: this is "Reading a user". id is what a client stores to address the account later, and externalId is how the client finds it again if it loses the id.
Add the lesson's site extension. In User Management > Schemas, create a schema named
Sitewith the URNurn:example:labphotos:scim:schemas:extension:site:1.0:Userand one attributesite: text, allowed valuesMain,NorthandSouth, returned Only when requested. Give Ava a site, then read her twice.
export SITE=urn:example:labphotos:scim:schemas:extension:site:1.0:User
jq -n --arg p "$SITE:site" '{schemas:["urn:ietf:params:scim:api:messages:2.0:PatchOp"],Operations:[{op:"add",path:$p,value:"Main"}]}' \
| scim -X PATCH "$SCIM/Users/$AVA" --data-binary @- -o /dev/null -w '%{http_code}\n'
scim "$SCIM/Users/$AVA" | jq --arg s "$SITE" '.[$s]'
scim -G "$SCIM/Users/$AVA" --data-urlencode "attributes=$SITE:site" | jq --arg s "$SITE" '.[$s]'
The default read shows no site. The read that names the attribute shows {"site": "Main"}.
Why it matters: this is "Extensions". Extension attributes sit in their own object, named by the URN, so they never collide with core names, and returned: request keeps an attribute out of every default response.
Read only what you need.
scim -G "$SCIM/Users/$AVA" --data-urlencode 'attributes=userName,emails' | jq .returns those two, plusidandschemas, which always come back.--data-urlencode 'excludedAttributes=groups'returns everything except groups.Groups and members, cheaply. List group names without member lists, then read one group in full.
scim -G "$SCIM/Groups" --data-urlencode 'excludedAttributes=members' | jq -r '.Resources[] | [.displayName, .id] | @tsv'
scim -G "$SCIM/Groups" --data-urlencode 'filter=displayName eq "Photo moderation"' | jq '.Resources[0].members'
Each member has a value (the user's id), a $ref and a display name.
Why it matters: this is "Groups and members". Membership is stored on the group, and a client that needs only names should not pull every member list.
Break it
Filter a discovery endpoint:
scim -G "$SCIM/Schemas" --data-urlencode 'filter=id pr' | jq .. The answer is403with "Discovery endpoints do not support filters", as RFC 7644 recommends. Read the whole list instead.Create a user whose
schemasnamesurn:example:unknown:1.0:User. The answer is400 invalidValue: the request names a schema this service does not support.
Check your work
Press Check my progress. The checks look for, in order:
scim.discovery.readsucceeded bylab-provisioning(step 1)tenant.provisioning.updatesucceeded (step 2)tenant.schemas.createsucceeded (step 6)scim.user.patchsucceeded for Ava (step 6)scim.user.createrejected withinvalid_value(Break it)
Cleanup
Confirm Accept passwords over SCIM is on.
Keep the
Siteschema, or delete it. Deleting a schema removes its stored values, and Audit recordstenant.schemas.delete.