IDENTITY GOVERNANCE · LAB
Bring accounts into your tenant four different ways
Create accounts by hand, by pushed SCIM changes, from a nightly file and at first arrival, see which routes can ever hear about a leaver, catch a silent mapping error, and limit what provisioning clients may change.
ReadyUses your lab tenant
The lesson
Builds on: Searching a directory with LDAP.
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.
Create an account from a ticket, by hand
Recorded as
tenant.users.createsucceeded.Push a new account over SCIM
Recorded as
scim.user.createsucceeded forlab-provisioning.Load a file of accounts in one Bulk request
Recorded as
scim.bulksucceeded forlab-provisioning.An account is created when the person first arrives
Recorded as
account.registersucceeded (registration_completed).A read-only client cannot create accounts
Recorded as
scim.user.createrejected (insufficient_scope) forlab-scim-reader.Provisioning cannot change an administrator
Recorded as
scim.user.patchrejected (protected_user) forlab-provisioningabout[email protected].
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
In this lab your tenant plays the application receiving accounts, and you play each route that delivers them.
Open a bash shell and set the variables and helpers from the directory lab, plus
READER_IDandREADER_SECRET(read -rs) forlab-scim-readerfrom the LDAP lab. If you skipped that lab, createlab-scim-readernow: confidential,client_credentials, onlyscim-<id6>.read.Set
MIA_EMAILto your own plus-address for Mia. Step 4 registers her as a new arrival, so if a user with that address already exists on Users, delete it first.Press Start on the lab page.
Walkthrough
A ticket, done by hand. In the portal, create
[email protected](Nia Abara). Users shows SourceTenant, and Audit recordstenant.users.createby you.
Why it matters: this is the billing system in "Files and tickets". The only record that this account must be removed one day is whoever remembers the ticket.
Pushed changes. Create an account the way a provisioning service would.
POST$ISSUER/scim/v2/Users
Open in console
POST $ISSUER/scim/v2/Users HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: application/scim+json
{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"externalId":"E20001","userName":"[email protected]",
"name":{"givenName":"Omar","familyName":"Haddad"},"emails":[{"value":"[email protected]","type":"work","primary":true}],"active":true}The answer is 201 Created. Users shows Source Tenant (SCIM), and the details name the provisioning client.
Why it matters: this is "Pushing changes". The same client that pushed the joiner can push the deactivation within seconds.
A nightly file. Turn a small CSV into one Bulk request.
printf '%s\n' 'email,given_name,family_name,department,status' \
'[email protected],Rosa,Galloway,Support,active' '[email protected],Sven,Lindqvist,Support,inactive' > staff.csv
tail -n +2 staff.csv | jq -Rn --arg ent "$ENT" '{schemas:["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
Operations:[inputs | split(",") | {method:"POST", path:"/Users", bulkId:.[0],
data:{schemas:["urn:ietf:params:scim:schemas:core:2.0:User",$ent], userName:.[0], name:{givenName:.[1],familyName:.[2]},
emails:[{value:.[0],type:"work",primary:true}], active:(.[4]=="active"), ($ent):{department:.[3]}}}]}' > bulk.json
scim -X POST "$SCIM/Bulk" --data-binary @bulk.json | jq '.Operations[] | {bulkId, status}'
Both operations return 201, and Sven's inactive row arrives disabled. Now delete Rosa's line from staff.csv, as if she had left, and consider what an import that only adds and updates would do next night: nothing. Rosa stays active.
Why it matters: a file conveys a departure only if it says so explicitly, as Sven's status does, and only on the night it runs.
Created on arrival. In Authentication, turn on self-service registration and save. In a private window, register
$MIA_EMAILat$ISSUER/registerand complete the email verification. Users shows a newTenantuser with no external ID, created the moment Mia arrived.
Restore: turn self-service registration off again and save.
Now list the active accounts no source has claimed:
scim -G "$SCIM/Users" --data-urlencode 'filter=active eq true and not (externalId pr)' --data-urlencode 'attributes=userName' | jq -r '.Resources[].userName'
Mia, Nia, Ava, Ben and Cora appear.
Why it matters: this is "Creating accounts at sign-in". Your tenant is an identity provider, so the nearest thing it has to an account created on first arrival is self-registration. Like just-in-time provisioning, it learns about joiners only. Nothing will ever tell it that Mia left.
A mapping error that nobody rejects. Create
[email protected]the way a mapping that sent department to the wrong attribute would:"title":"Support"and no enterprise department. The answer is201. Find the damage withfilter=title eq "Support", then fix it with one PATCH that sets$ENT:departmenttoSupportandtitletoSupport Engineer.
Why it matters: this is "Mapping attributes". Valid data in the wrong place passes every check and quietly breaks whatever reads the department.
Only send what the target needs. Read
scim "$SCIM/Schemas/urn:ietf:params:scim:schemas:core:2.0:User" | jq -r '.attributes[].name'. There is no date of birth or salary. Adding one would be a recorded decision (tenant.schemas.attributes.create), and an attribute nobody adds stays at the source.Least privilege for a provisioning client. Switch to the read-only client and try both a read and a create.
READ_TOKEN=$(token_for "$READER_ID" "$READER_SECRET" "$SCIM_SCOPE.read")
curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $READ_TOKEN" "$SCIM/Users?count=1"
jq -n '{schemas:["urn:ietf:params:scim:schemas:core:2.0:User"],userName:"[email protected]",name:{givenName:"Reader",familyName:"Test"},
emails:[{value:"[email protected]",type:"work",primary:true}]}' \
| curl -s -i -X POST -H "Authorization: Bearer $READ_TOKEN" -H "Content-Type: application/scim+json" --data-binary @- "$SCIM/Users" | grep -i -E '^(HTTP|www-authenticate)'
The read returns 200. The create returns 403 with WWW-Authenticate: Bearer realm="SCIM", error="insufficient_scope".
Why it matters: this is "Authorizing the provisioning client". Each client holds only the scopes its job needs, so a leaked reader credential cannot create anyone.
Some users are out of provisioning's reach. As
lab-provisioning, replace Ben'stitlewithHelp desk lead. It succeeds, becauseHelp deskgrants nothing the full SCIM scope lacks. Now create a management rolelab-tmp-auditorwithtenant.audit.read, assign it to Ben, and send the same PATCH again. The answer is403withprotected_user.
Why it matters: like the group that grants EHR_ADMIN in the lesson, a user who holds management permissions beyond the provisioning client's reach can be changed only through the reviewed portal path, never by the feed.
Restore: remove lab-tmp-auditor from Ben, delete the role, and set Ben's title back to empty or its earlier value.
Break it
Send the step 3 Bulk request again, unchanged. Both creates return
409withuniqueness: an import that creates accounts is not safe to repeat blindly. The keeping systems in sync lab makes a repeated create safe withX-Correlation-ID.
Check your work
Press Check my progress. The checks look for, in order:
tenant.users.createsucceeded (step 1)scim.user.createsucceeded bylab-provisioning(step 2)scim.bulksucceeded bylab-provisioning(step 3)account.registersucceeded withregistration_completed(step 4)scim.user.createrejected withinsufficient_scopebylab-scim-reader(step 7)scim.user.patchrejected withprotected_userfor Ben (step 8)
On Users, Sources Tenant and Tenant (SCIM) now sit side by side. Audit also shows tenant.authentication.update twice, for registration on and off.
Cleanup
Confirm self-service registration is off.
Delete
lab-tmp-nia,lab-tmp-omar,lab-tmp-rosa,lab-tmp-svenandlab-tmp-uma, and deletestaff.csvandbulk.json.Keep Mia's account. She is part of the lab cast.
Missing infrastructure
G26: a federated first sign-in that creates a tenant account from another provider's claims would make step 4 the lesson's just-in-time provisioning exactly.
G33: the tenant cannot yet provision outward to another application over SCIM, so you play the provisioning service yourself instead of configuring one.