Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

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.

  1. Create an account from a ticket, by hand

    Recorded as tenant.users.create succeeded.

  2. Push a new account over SCIM

    Recorded as scim.user.create succeeded for lab-provisioning.

  3. Load a file of accounts in one Bulk request

    Recorded as scim.bulk succeeded for lab-provisioning.

  4. An account is created when the person first arrives

    Recorded as account.register succeeded (registration_completed).

  5. A read-only client cannot create accounts

    Recorded as scim.user.create rejected (insufficient_scope) for lab-scim-reader.

  6. Provisioning cannot change an administrator

    Recorded as scim.user.patch rejected (protected_user) for lab-provisioning about [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.

  1. Open a bash shell and set the variables and helpers from the directory lab, plus READER_ID and READER_SECRET (read -rs) for lab-scim-reader from the LDAP lab. If you skipped that lab, create lab-scim-reader now: confidential, client_credentials, only scim-<id6>.read.

  2. Set MIA_EMAIL to 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.

  3. Press Start on the lab page.

Walkthrough

  1. A ticket, done by hand. In the portal, create [email protected] (Nia Abara). Users shows Source Tenant, and Audit records tenant.users.create by 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.

  1. 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.

  1. 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.

  1. Created on arrival. In Authentication, turn on self-service registration and save. In a private window, register $MIA_EMAIL at $ISSUER/register and complete the email verification. Users shows a new Tenant user 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.

  1. 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 is 201. Find the damage with filter=title eq "Support", then fix it with one PATCH that sets $ENT:department to Support and title to Support Engineer.

Why it matters: this is "Mapping attributes". Valid data in the wrong place passes every check and quietly breaks whatever reads the department.

  1. 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.

  2. 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.

  1. Some users are out of provisioning's reach. As lab-provisioning, replace Ben's title with Help desk lead. It succeeds, because Help desk grants nothing the full SCIM scope lacks. Now create a management role lab-tmp-auditor with tenant.audit.read, assign it to Ben, and send the same PATCH again. The answer is 403 with protected_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

  1. Send the step 3 Bulk request again, unchanged. Both creates return 409 with uniqueness: an import that creates accounts is not safe to repeat blindly. The keeping systems in sync lab makes a repeated create safe with X-Correlation-ID.

Check your work

Press Check my progress. The checks look for, in order:

  • tenant.users.create succeeded (step 1)

  • scim.user.create succeeded by lab-provisioning (step 2)

  • scim.bulk succeeded by lab-provisioning (step 3)

  • account.register succeeded with registration_completed (step 4)

  • scim.user.create rejected with insufficient_scope by lab-scim-reader (step 7)

  • scim.user.patch rejected with protected_user for 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

  1. Confirm self-service registration is off.

  2. Delete lab-tmp-nia, lab-tmp-omar, lab-tmp-rosa, lab-tmp-sven and lab-tmp-uma, and delete staff.csv and bulk.json.

  3. 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.

Back to all labs

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

The Lab