CodamAIDocs
Topicdone

Your own logic: hooks and events

Hooks run inside the registration and may reject it, events follow afterwards. All hook points and what a hook must not do.

Variants
Hook rejects → 422Hook changes tenantHook changes initial rolesHook with FROM_CALLER (not called)Events

What this is about

Every project has its own rules for registration: allow only addresses of certain companies, choose the tenant by domain, give a person extra roles. So that nobody has to change CIAS’s code for this, there are two kinds of extension points:

  • A hook runs inside the registration. It may change values or reject the registration.
  • An event is sent afterwards. Whoever receives it learns what happened, but can no longer change it.
Hook
inside the registration
  • Bean that implements RegistrationHook
  • may reject (RegistrationRejectedException → 422)
  • may change tenant, initial roles, email
  • order via getOrder(), lower first
Event
afterwards
  • Spring @EventListener on RegistrationEvent
  • can no longer prevent anything
  • never contains a token
  • sent right after saving

The hook points on the timeline

Where a hook can plug in
  1. 1
    Hook
    onResolveTenant(context, decision) – change the tenant, not with FROM_CALLER
  2. 2
    Hook
    beforeValidation(context) – before the fields are checked
  3. 3
    CIAS
    checks the fields
  4. 4
    Hook
    afterValidation(context) – the usual place for a veto
  5. 5
    Hook
    beforeIdentityProvisioning / afterIdentityProvisioning – only for a new account, around the creation in Keycloak
  6. 6
    Hook
    beforeNotification(mail, context) – before every email, may change the email
  7. 7
    User→CIAS
    clicks the link
  8. 8
    Hook
    onVerified(context) – after verification
  9. 9
    Hook
    onAssignInitialRoles(context, roles) – change the initial roles
  10. 10
    Hook
    onCompleted(context) – at the end of provisioning
  11. 11
    Hook
    onFailed(context, error) – when provisioning fails
  12. 12
    Hook
    onCompensate(context, accountRemoved) – when an administrator discards the failed registration; in reverse order, before CIAS takes back tenant, organization and account

All methods have an empty default implementation. A hook implements only the ones it needs.

The variants

What a hook can do

When: Only addresses of partner companies should be allowed to register.

The hook throws a RegistrationRejectedException with its own key in afterValidation. CIAS then creates no account and stores nothing.

Result: 422 { "error": "<own key>", "message": "the registration was refused" }

When: Addresses with @nordbau.example should always end up in nordbau.

onResolveTenant returns a new TenantDecision, for example JOIN_EXISTING with key nordbau, and a reason. null means: unchanged. Several hooks run one after another, and each sees the result of the previous one.

Result: See Where the tenant comes from.

When: People from a certain company should also get report-read.

onAssignInitialRoles gets the roles from the rule set and returns a new set. CIAS then checks that each role exists.

Result: See Initial roles as a rule set.

When: Invitation by a tenant administrator.

onResolveTenant is not called at all. The tenant from the inviting person's token cannot be redirected.

When: A record should be created in another system.

onCompleted still runs inside provisioning. If it throws an exception, the registration ends in FAILED, and retry runs it again. If an error there should not hold up the registration, an event is the better place.

The events

Eventis sent when
Initiated(id, flow)a registration was accepted and the email was sent
Verified(id)the address is verified, by click or by hand
Completed(id, externalUserId, tenantKey)provisioning is done
Rejected(id, reason)an administrator rejected it
Failed(id, reason)provisioning failed
Expired(id, state, identityRemoved)a registration expired, was replaced, or was discarded

Events are sent in the same thread, right after CIAS has saved the new state. A listener that takes long delays the response. CIAS’s audit listens to the same events, see One trail for everything.

Next

Sources in the code and the knowledge base
  • CIAS/cias-registration – RegistrationHook, RegistrationContext, RegistrationEvent, RegistrationRejectedException, RegistrationService (forEachHook, register, verify, provision)
  • CIAS/cias-spring-boot-starter – RegistrationUserHook, RegistrationDefaultGroupHook
  • hub-backend – AccessAttributeRegistrationHook
  • CIAS/cias-registration/docs/adr – ADR-013
Search