In un articolo precedente abbiamo visto Arricchire token JWT emessi da Azure Active Directory B2C.

In quell’articolo abbiamo parlato di come sia possibile aggiungere ad un JWT informazioni esterne a Microsoft Graph mediante l’uso di una Logic App ed un Blob Storage.

In questo invece vedremo come sia possibile creare una soluzioni che integri Azure Active Directory B2C.

Seguendo la traccia di quanto trattato nel precedente articolo vedremo come salvare su Blob Storage dati fittizi alla registrazione di un utente.

Note Nel resto dell’articolo ci sono riferimenti a risorse e concetti trattati nel precedente articolo al quale si rimanda.

Panoramica della soluzione.

La soluzione è cosi composta:

Composizione della soluzione

Composizione della soluzione

  • read-customer-details-identity-la: rappresenta l’api il cui scopo è reperire il contenuto del blob da customersstgacc (lo storage account)
  • customer-register-tpc: è il topic nel quale sono collezionati gli eventi di creazione di un nuovo utente
  • customer-identity-details-filler-la: rappresenta l’api al quale spetta l’onere di generare dati fittizi che poi saranno salvati all’interno di un blob sullo customersstgacc
    Definizione della logic app
  • contoso-b2c: è il servizio di gestione degli accessi e delle identità offerto da Azure

Introduzione ad Azure Event Grid.

In Azure esiste un’implementazione del pattern publish/subscribe concepita per agevolare l’integrazione e la gestione delle risorse mediante un paradigma di sviluppo ad eventi.

Mediante Event Grid sarà quindi possibile sottoscriversi a sorgenti di messaggi built-in attraverso una serie di gestori.

Qual’ora questo non fosse sufficiente è comunque possibile creare dei topic personalizzati ai quali sarà possibile sottoscriversi per riceverne gli eventi.

Creazione di un topic personalizzato.

Per la creazione di un topic è possibile fare riferimento a questa guida.

Una scelta da fare al momento della creazione del topic riguarda lo schema del contenuto della richiesta HTTP utilizzato. Gli schemi supportati al momento sono:

Il messaggio usato in questo caso ha la seguente struttura

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[
    {
        "data": {
            "objectId": "25100647-****-4571-****-b03e4ce72d02" // l'identificativo utile ad identificare l'utente
        },
        "id": "25100647-****-4571-****-b03e4ce72d02", // l'identificativo univoco del messaggio, lo stesso di `data.objectId` in qesto caso
        "eventType": "Microsoft.ActiveDirectory", 
        "subject": "*.onmicrosoft.com",
        "dataVersion": "1.0",
        "metadataVersion": "1",
        "eventTime": "2021-12-03T21:04:03.8504745Z",
        "topic": "/subscriptions/{your-subscription-id}/resourceGroups/{your-resource-group}/providers/Microsoft.EventGrid/topics/{your-event-grid-topic}"
    }
]

Emissione dell’evento di registrazione.

L’invio degli eventi verso il topic avviene utilizzando un RESTful technical profile.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<TechnicalProfile Id="AAD-UserEmitRegistrationEvent">
    <DisplayName>Emit user registration event to Event Grid.</DisplayName>
    <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <Metadata>
        <Item Key="ServiceUrl">{Settings:CustomerRegisteredTopicUrl}</Item>
        <Item Key="AuthenticationType">ApiKeyHeader</Item>
        <Item Key="SendClaimsIn">Body</Item>
        <Item Key="ClaimUsedForRequestPayload">userRegisterEvent</Item>
        <Item Key="DefaultUserMessageIfRequestFailed">Cannot process your request right now, please try again later.</Item>
    </Metadata>
    <CryptographicKeys>
        <Key Id="aeg-sas-key" StorageReferenceId="B2C_1A_CustomerRegisteredTopicSas" />
    </CryptographicKeys>
    <InputClaimsTransformations>
        <InputClaimsTransformation ReferenceId="GetSystemDateTime" />
        <InputClaimsTransformation ReferenceId="GenerateRegistrationEventRequest" />
    </InputClaimsTransformations>
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="userRegisterEvent" />
    </InputClaims>
    <PersistedClaims>
        <PersistedClaim ClaimTypeReferenceId="systemDateTime" />
    </PersistedClaims>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

Questo frammento di markup tradotto in comando curl, per maggiore esplicabilità, risulterebbe cosi:

1
curl -X POST -H "aeg-sas-key: $key" -d "$event" $endpoint

dove i requisiti di autenticazione vengono soddisfatti dal metadato AuthenticationType al quale viene associata la chiave crittografica aeg-sas-key il cui valore viene recuperato dalla chiave B2C_1A_CustomerRegisteredTopicSas presente nella collezione delle chiavi dei criteri.

TL;DR La scelta dello schema del topic in questo esempio è stata guidata dalle limitazioni al momento imposte dal profilo tecnico RESTful riguardo alle possibilità di costruzione della richiesta HTTP, infatti per una combinazione di criteri non risulta possibile passare informazioni nelle intestazioni e nel corpo della richiesta allo stesso tempo.
Ciò rende impossibile inviare verso un topic schemi di tipo Cloud Event in quanto il protocollo, nella versione 1.0 richiede la presenza di un’intestazione obbligatoria.

Ben più complessa è la creazione del corpo della richiesta per la quale risultano necessario:

  • utilizzare le InputClaimsTransformation
  • aggiungere due attestazioni all’interno del bagaglio userRegisterEvent e systemDateTime entrambe di tipo stringa.

Infine il profilo tecnico è stato aggiunto fra i profili tecnici di validazione di LocalAccountSignUpWithLogonEmail in modo tale che l’evento venga emesso solamente in fase di registrazione di un’utente.

Utilizzo delle trasformazioni delle attestazioni.

Durante la creazione di criteri personalizzati potremmo avere la necessità di eseguire calcoli, come ad esempio il numero di tentativi di autenticazione, che seppur molto semplici risulterebbero impossibili senza l’esecuzioni di funzioni.

Questo requisito trova espressività tramite le ClaimsTransformation il cui riferimento delle trasformazioni delle attestazioni contiene la lista completa delle trasformazioni utilizabili.

Nell’esempio sono stati utilizzati i metodi GetCurrentDateTime e GenerateJson

1
2
3
4
5
<ClaimsTransformation Id="GetSystemDateTime" TransformationMethod="GetCurrentDateTime">
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="systemDateTime" TransformationClaimType="currentDateTime" />
    </OutputClaims>
</ClaimsTransformation>

GetSystemDateTime ha lo scopo di valorizzare l’attestazione systemDateTime

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<ClaimsTransformation Id="GenerateRegistrationEventRequest" TransformationMethod="GenerateJson">
    <InputClaims>
        <InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="0.data.objectId" />
        <InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="0.id" />
        <InputClaim ClaimTypeReferenceId="systemDateTime" TransformationClaimType="0.eventTime" />
    </InputClaims>
    <InputParameters>
        <InputParameter Id="0.dataVersion" DataType="string" Value="1.0" />
        <InputParameter Id="0.eventType" DataType="string" Value="Microsoft.ActiveDirectory" />
        <InputParameter Id="0.subject" DataType="string" Value="{Settings:Tenant}" />
    </InputParameters>
    <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="userRegisterEvent" TransformationClaimType="outputClaim" />
    </OutputClaims>
</ClaimsTransformation>

GenerateRegistrationEventRequest ha invece l’onere di costruire il JSON e valorizzare l’attestazione userRegisterEvent.

Conclusioni.

In questo articolo abbiamo visto come mediante Identity Experience Framework sia possibile integrare un tenant B2C con la nostra infrastruttura ed aprire eventuali scenari di sviluppo interessanti.
Per farlo abbiamo toccato Azure Event Grid e come creare un Event Grid Topic.

Infine come sia possibile manipolare delle attestazioni ed utilizzarle all’interno dei profili tecnici.

Se foste interessati all’esempio completo lo potrete trovare al seguente indirizzo https://github.com/binick/samples/tree/master/src/enrich-a-jwt-token-with-ief.