MS Certificering: AZ-204, overnieuw beginnen, deel 06

Ingediend door Dirk Hornstra op 21-dec-2021 15:25

Na het 1e blok: Azure App Service web apps (link), het 2e blok: Implement Azure Functions (link), het 3e blok: Develop solutions that use Blob Storage (link) en het 4e blok: Develop solutions that use Azure Cosmos DB (link), het 5e blok: Implement infrastructure as a service solutions: link is het nu tijd voor het 6e learning-block: Implement user authentication and authorization, link.

Module 1: Explore the Microsoft identity platform, link.

Het Microsoft identity platform is een aantal tools voor developers, welke een authenticatie service bevat, open-source codebibliotheken en applicatie management tools.

Er zijn een aantal componenten:

OAuth 2.0 en OpenID Connect wordt ondersteund waardoor je werk- en schoolaccounts via Azure Active Directory kunt authenticeren, persoonlijke Microsoft accounts zoals Skype, Xbox en Outlook.com en ook sociale of lokale accounts door Azure Active Directory B2C.

Open source bibliotheken, MSAL (Microsoft Authentication Libraries) en andere codebibliotheken die aan de standaard voldoen.

Application Management Portal: in de Azure Portal kun je zaken instellen.

Applicatie configuratie API en PowerShell: via code kun je via de Microsoft Graph API en Powershell je DevOps taken automatiseren.

Om Identity en Access Management functies te delegeren naar Azure Active Directory, daarvoor moet een applicatie geregistreerd zijn bij een Azure Active Directory Tenant. Je moet de keuze maken of dit een single tenant is: alleen beschikbaar in jouw tenant of multi-tenant, beschikbaar in andere tenants.

Je kunt deze ook aanmaken met Azure PowerShell, Azure CLI, Microsoft Graph en andere tools.

Een Azure Active Directory applicatie is gedefinieerd door het application object, wat binnen de tenant zit waar de app geregistreerd is.

Het applicatie object beschrijft hoe een service tokens kan uitgeven, welke resources beschikbaar moeten zijn en de acties die uitgevoerd kunnen worden.

Microsoft Graph Application entity levert hier een schema voor aan: link.

Een security principal is de representatie voor een user (user principal) en applicatie (service principal).

  • Application: de lokale representatie in een enkele tenant of directory. Definieert wat de app kan doen, wie de app kan gebruiken en welke resources voor de app beschikbaar zijn.
  • Managed Identity: de service principal die dit representeert kan toegang en bevoegdheden krijgen, maar kan niet rechtstreeks bijgewerkt worden, link.
  • Legacy: een "oude" app. Een legacy service principal kan credentials, service principal names, reply URL's en andere eigenschappen hebben die een geautoriseerde gebruiker kan aanpassen, maar heeft geen gekoppelde app registratie. Kan alleen in de tenant gebruikt worden waar deze aangemaakt is.


Het applicatie object is de globale weergave van je applicatie, de service principal de lokale weergave binnen een specifieke tenant.
Een applicatie object is 1-1 gekoppeld met de software applicatie en 1:N relatie met het service object

Microsoft Identity Platform implementeert OAuth 2.0, link.
 

Diensten die je kunt gebruiken:

Met scope geef je de rechten aan. Het ondersteunt een flink aantal OpenID scopes: link.

Sommige zaken moeten extra door een Administrator bevestigd worden. Dat gaat via het administrator consent endpoint: link.

Als de resource niet in de scope zit (bijvoorbeeld User.Read), dan is het altijd de Microsoft Graph scope.

Je hebt delegated permissions, de app die aan jou gekoppeld zit, mag een actie doen "alsof de app jou is". En je hebt application permissions, dit zijn apps die niet aan een ingelogde user gekoppeld zitten, zoals een background service of daemon. Die kan alleen door de consent van de Administrator rechten krijgen.

Er zijn 4 consent types, static user consent, incremental user consent, dynamic user consent en admin consent.

Met static user consent moet je vooraf goedkeuring geven aan alles wat je nodig hebt. Het houdt je code "schoon", maar kan mensen tegenhouden (wat, willen ze die hele lijst?) en de app moet van tevoren weten wat nodig is. Als later blijkt dat je nog iets nodig hebt, dan zit je in de problemen.

Met incremental en dynamic user consent kun je in een call voor het authenticatie-token de nieuwe scope parameter toevoegen waar je nu consent voor nodig hebt. Als het akkoord er nog niet is, krijg de user een prompt om akkoord te geven.
Wel het nadeel dat als voor iets administrative consent nodig is, je deze al moet registreren via de portal, zodat de admin dit van tevoren voor alle users kan goedkeuren.

Admin consent is al een aantal keren benoemd en is nu wel duidelijk.

Voorbeeld van een user consent:


GET https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=
https%3A%2F%2Fgraph.microsoft.com%2Fcalendars.read%20
https%3A%2F%2Fgraph.microsoft.com%2Fmail.send
&state=12345

Conditionele toegang is een feature (van vele) waarmee je jouw app en je services kunt beveiligen. Via multifactor authenticatie (link), alleen devices die via Intune binnen komen of filteren op basis van locatie en IP-ranges
In de meeste gevallen heeft het geen invloed op het gedrag van de app of heeft het aanpassingen van de ontwikkelaar nodig.
Deze scenario's vereisen dat code conditional access challenges kan afhandelen:

  • de app doet iets met een flow waarbij deze acteert als "iemand"
  • de app roept meerdere services en resources aan
  • een single page app die MSAL.js gebruikt
  • web-apps die een resource aanroepen


Module 2: Implement authentication by using the Microsoft Authentication Library, link.

De Microsoft Authentication Library (MSAL) kun je gebruiken om veilig toegang te krijgen tot Microsoft Graph, andere API's van Microsoft, 3rd party web apps of je eigen web API. Zowel .NET als Javascript, Java, Python, Android en iOS worden ondersteund.

Waarom zou je het gebruiken?

  • Je hoeft geen OAuth codebibliotheken in jouw code toe te voegen
  • Je krijgt een token voor een user of voor een applicatie
  • het behoudt de token cache en ververst je tokens als ze op het punt staan om te verlopen, dat hoef je niet zelf te implementeren
  • helpt jou om aan te geven voor welke gebruiker wel (en welke niet) met jou applicatie in mag loggen
  • helpt je om je applicatie in te richten met configuratiebestanden
  • helpt je om te troubleshooten door het zichtbaar maken van excepties, logging en telemetrie


Overzicht van de codebibliotheken:

Library Supported platforms and frameworks
MSAL for Android Android
MSAL Angular Single-page apps with Angular and Angular.js frameworks
MSAL for iOS and macOS iOS and macOS
MSAL Go (Preview) Windows, macOS, Linux
MSAL Java Windows, macOS, Linux
MSAL.js JavaScript/TypeScript frameworks such as Vue.js, Ember.js, or Durandal.js
MSAL.NET .NET Framework, .NET Core, Xamarin Android, Xamarin iOS, Universal Windows Platform
MSAL Node Web apps with Express, desktop apps with Electron, Cross-platform console apps
MSAL Python Windows, macOS, Linux
MSAL React Single-page apps with React and React-based libraries (Next.js, Gatsby.js)


Overzicht van de authenticatie-flows:

Flow Description
Authorization code Native and web apps securely obtain tokens in the name of the user
Client credentials Service applications run without user interaction
On-behalf-of The application calls a service/web API, which in turns calls Microsoft Graph
Implicit Used in browser-based applications
Device code Enables sign-in to a device by using another device that has a browser
Integrated Windows Windows computers silently acquire an access token when they are domain joined
Interactive Mobile and desktops applications call Microsoft Graph in the name of a user
Username/password The application signs in a user by using their username and password

Er zijn verschillende type applicaties die een security token kunnen gebruiken;

  • Single-page applications, SPA: via Javascript of Typescript wordt het token opgevraagd, vaak met Angular, React of Vue. MSAL.js is de enige codebibliotheek van Microsoft die dit ondersteunt.
  • Public client applications: apps die op devices of desktop pc's in een browser uitgevoerd worden. Kunnen/mogen geen application secrets bewaren (want ze zijn niet vertrouwd), dus hebben alleen toegang tot web API's met de rechten van de huidige gebruiker (alleen public client flow). Kunnen geen configuration-time secrets hebben, dus hebben geen client-secrets.
  • Confidential client applications: apps de op servers uitgevoerd worden (web apps, web API apps, service/daemon apps). Moeilijk te bereiken, dus mogen/kunnen een application secret bevatten. Elke instantie heeft een eigen configuratie (client ID en client secret).


Het initialiseren van een client doe je met de PublicClientApplicationBuilder of ConfidentialClientApplicationBuilder.

Als je een app geregistreerd heb, heb je mogelijk deze gegevens nodig:

  • client ID (een GUID waarde).
  • identity provider URL en de sign-in audience (gezamenlijk: authority).
  • tenant ID (als je code schrijft die alleen voor jouw bedrijf geldt, single-tenant app).
  • application secret (client secret string) of certificate (X509Certificate2) voor een confidential client app.
  • voor web apps en soms public client apps moet je de redirectUri instellen voor de callback van security tokens.


Voorbeeldcode C#


string redirectUri = "https://myapp.azurewebsites.net";
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
    .WithClientSecret(clientSecret)
    .WithRedirectUri(redirectUri )
    .Build();

Met WithAuthority kun je het type cloud en tenant instellen:

var clientApp = PublicClientApplicationBuilder.Create(client_id)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenant_id)
    .Build();

Met WithRedirectUri kun je een eigen redirect instellen:

var clientApp = PublicClientApplicationBuilder.Create(client_id)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenant_id)
    .WithRedirectUri("http://localhost")
    .Build();

Voor public en afgeschermde applicaties kun je deze gebruiken:

  • .WithAuthority(), stel de authority in op Azure Active Directory, met de optie om de cloud te kiezen, het publiek (audience), tenant (tenant ID of domeinnaam) of een rechstreekse URI voor de authority.
  • .WithTenantId(string tenantId), bepaal de tenant ID of tenant omschrijving.
  • .WithClientId(string), bepaal de client ID
  • .WithRedirectUri(string redirectUri), bepaal de redirect URI. Als het een publieke client applicatie is, is dit handig als er gebruik wordt gemaakt van een "broker"
  • .WithComponent(string), stel de naam van de bibliotheek in mbv MSAL.NET (voor telemetrie)
  • .WithDebugLoggingCallback(), als dit wordt aangeroepen, dan roept de app een Debug.Write aan om acties te traceren.
  • .WithLogging(), als dit wordt aangeroepen, dan voert de applicatie een callback uit met het debuggen van het tracelog.
  • .WithTelemetry(TelemetryCallback telemetryCallback), stel in namens wie de telemetrie wordt uitgevoerd.telemetry.


En bij afgeschermde applicates kun je nog deze zaken instellen:

  • .WithCertificate(X509Certificate2 certificate), stel het certificaat in wat gebruikt wordt om te identificeren bij Azure Active Directory.
  • .WithClientSecret(string clientSecret), stel het client secret (app password) in.


Hierna volgt een oefening. Je maakt in Azure eerst een applicatie aan. Daarna ga je de volgende zaken in Visual Studio Code uitvoeren:


md az204-auth
cd az204-auth
dotnet new console
code . -r

// voeg packages toe
dotnet add package Microsoft.Identity.Client

// voeg uses toe
using System.Threading.Tasks;
using Microsoft.Identity.Client;

// wijzig main om async te draaien
public static async Task Main(string[] args)

// voeg deze code toe

private const string _clientId = "APPLICATION_CLIENT_ID";
private const string _tenantId = "DIRECTORY_TENANT_ID";

var app = PublicClientApplicationBuilder
    .Create(_clientId)
    .WithAuthority(AzureCloudInstance.AzurePublic, _tenantId)
    .WithRedirectUri("http://localhost")
    .Build();

// voor ophalen token

string[] scopes = { "user.read" };

AuthenticationResult result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();

Console.WriteLine($"Token:\t{result.AccessToken}");


Als je in het scherm wat je ziet inlogt, krijg je vervolgens een token terug:

Token:  eyJ0eXAiOiJKV1QiLCJub25jZSI6IlVhU.....


Module 3: Implement shared access signatures, link.

Een SAS (Shared Access Signature) is en URI die je toegang geeft tot een bepaalde resource.

Er zijn 3 types:

User delegation SAS: deze is beveiligd met Azure Active Directory credentials en permissies voor de SAS. Deze werkt alleen op Blob storage.
Service SAS: deze is beveiligd met de storage account key. Hiermee krijg je toegang tot Blob storage, Queue storage, Table storage of Azure Files.
Account SAS: deze is beveiligd met de storage account key. Hiermee krijg je toegang tot resources in één of meer storage services. Alle acties via user of service SAS zijn ook hier beschikbaar.

Microsoft raadt aan om Azure Active Directory credentials te gebruiken, omdat een account key openbaar kan worden. Als je een SAS nodig hebt voor toegang tot Blob storage, gebruik Azure Active Directory credentials om een user delegation SAS aan te maken.

Om toegang te krijgen heb je een URI nodig (voor de resource) en een SAS token om je toegang te autoriseren.

Voorbeeld:


https://medicalrecords.blob.core.windows.net/patient-images/patient-116139-nq8z7f.jpg?sp=r&st=2020-01-20T11:42:32Z&se=2020-01-20T19:42:32Z&spr=https&sv=2019-02-02&sr=b&sig=SrW1HZ5Nb6MbRzTbXCaPm%2BJiSEn15tC91Y4umMPwVZs%3D

sp is voor rechten (a=add, c=create, d=delete, l=list, r=read, w=write), st is de startdatum, se is de einddatum, sv is de versie, sr is het type opslag wat je opvraagt (b=blob), sig is de cryptografische handtekening.

Om risico's zo laag mogelijk te maken, de tips van Microsoft:

  • Gebruik altijd HTTPS
  • Meest veilige SAS is user delegation SAS. Gebruik het wanneer mogelijk, hierdoor hoeft je key niet in code opgeslagen te worden.
  • Stel de expiration time op de zo laagst mogelijke waarde.
  • Geef de minimale rechten, dus als iemand alleen maar hoeft te lezen, alleen de r geven en niet een c, d en w.
  • In sommige gevallen is SAS niet de juiste oplossing. Als er een te groot risico is, maak een eigen middle-tier service om gebruikers en hun toegang tot opslag in te regelen.


De meest flexibele en veilige manier om een service of account SAS te gebruiken is om SAS tokens te koppelen aan een stored access policy.

Sommige oplossingen hebben een Front End Proxy Service. Die kan soms en SAS uitgeven om zo te zorgen dat langdurige, zware schrijf-acties rechtstreeks op de Azure Storage uitgevoerd worden en zo de proxy minder belasten.

Bij bepaalde kopie-acties is een SAS nodig. Als je een blob kopieert naar een ander storage account, dan heb je de SAS nodig.
Hetzelfde geldt voor een kopie van een file naar een ander storage account. En als je een blob naar een file kopieert, of een file naar een blob, dan moet je ook een SAS aanleveren, zelfs als bron en bestemming in hetzelfde storage account zitten.

Met een stored access policy kun je handige dingen doen, zoals de starttijd aanpassen, expiratietijd aanpassen, de permissies voor een handtekening of een revoke uitvoeren nadat het uitgegeven is (handig als iemand anders de URL in bezit heeft gekregen en slechte dingen wil doen).

Stored access policies wordt ondersteund door blob containers, file shares, queue's en tables.

Met een Set ACL actie op een resource kun je de policy instellen. Meer informatie is na te lezen voor Containers (link), Queue (link), Table (link), Share (link).

De unieke identifier mag maximaal 64 tekens zijn.

Voorbeeld:


BlobSignedIdentifier identifier = new BlobSignedIdentifier
{
    Id = "stored access policy identifier",
    AccessPolicy = new BlobAccessPolicy
    {
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(1),
        Permissions = "rw"
    }
};

blobContainer.SetAccessPolicy(permissions: new BlobSignedIdentifier[] { identifier });

az storage container policy create \
    --name <stored access policy identifier> \
    --container-name <container name> \
    --start <start time UTC datetime> \
    --expiry <expiry time UTC datetime> \
    --permissions <(a)dd, (c)reate, (d)elete, (l)ist, (r)ead, or (w)rite> \
    --account-key <storage account key> \
    --account-name <storage account name> \

Module 4: Explore Microsoft Graph, link.

Met Microsoft Graph kun je veel doen. Microsoft 365, Windows 10, Enterprise mobility en security.

Op het endpoint https://graph.microsoft.com kun je via REST API's en via code SDK's je acties uitvoeren.
Met veel connectors (link) kun je data binnen krijgen.
Met Microsoft Graph Data Connect (link) heb je tools om data uit Microsoft Graph naar andere data-stores over te zetten.

Veel van de namespaces van de Graph API zit in de eigen microsoft.graph, waaronder de metadata (link).

Een klein deel zit in sub-namespaces, zoals microsoft.graph.callRecords: link.

De basis van de API call is deze structuur:


{HTTP method} https://graph.microsoft.com/{version}/{resource}?{query-parameters}

Je krijgt na de call een status code, response message en soms een nextLink terug (als er paging uitgevoerd sowrdt, dus @odata.nextLink).

GET=read, POST=create, PATCH=update, PUT=replace, DELETE=delete
GET en DELETE heeft geen BODY nodig.

Er zijn 2 versies: v1.0 (productie) en beta (preview).

Je kunt parameters via de querystring meegeven:


GET https://graph.microsoft.com/v1.0/me/messages?filter=emailAddress eq 'jon@contoso.com'

Check ook de Graph Explorer: link en Postman: link.

Maak het jezelf gemakkelijk, gebruik de SDK's. Deze bestaat uit een service library en een core library.

De service library biedt models en request builders om een uitgebreide interface te bieden voor het werken met de vele datasets.
De core library is een aantal features om het werken met alle services te ondersteunen. Retry handling, veilige redirects, transparante authenticatie.

Ik neem hier even de lijst over:

  • Microsoft.Graph - Contains the models and request builders for accessing the v1.0 endpoint with the fluent API. Microsoft.Graph has a dependency on Microsoft.Graph.Core.
  • Microsoft.Graph.Beta - Contains the models and request builders for accessing the beta endpoint with the fluent API. Microsoft.Graph.Beta has a dependency on Microsoft.Graph.Core.
  • Microsoft.Graph.Core - The core library for making calls to Microsoft Graph.
  • Microsoft.Graph.Auth - Provides an authentication scenario-based wrapper of the Microsoft Authentication Library (MSAL) for use with the Microsoft Graph SDK. Microsoft.Graph.Auth has a dependency on Microsoft.Graph.Core.


Vervolgens een aantal voorbeelden hoe we dit kunnen gebruiken.
Nog even een link voor de keuze van de authenticatie provider: link.
 


// maak een client aan

// Build a client application.
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
            .Create("INSERT-CLIENT-APP-ID")
            .Build();
// Create an authentication provider by passing in a client application and graph scopes.
DeviceCodeProvider authProvider = new DeviceCodeProvider(publicClientApplication, graphScopes);
// Create a new instance of GraphServiceClient with the authentication provider.
GraphServiceClient graphClient = new GraphServiceClient(authProvider);

// lees informatie

// GET https://graph.microsoft.com/v1.0/me

var user = await graphClient.Me
    .Request()
    .GetAsync();

// haal een lijst van entiteiten op

// GET https://graph.microsoft.com/v1.0/me/messages?$select=subject,sender&$filter=<some condition>&orderBy=receivedDateTime

var messages = await graphClient.Me.Messages
    .Request()
    .Select(m => new {
        m.Subject,
        m.Sender
    })
    .Filter("<filter condition>")
    .OrderBy("receivedDateTime")
    .GetAsync();

// verwijder een entiteit

// DELETE https://graph.microsoft.com/v1.0/me/messages/{message-id}

string messageId = "AQMkAGUy...";
var message = await graphClient.Me.Messages[messageId]
    .Request()
    .DeleteAsync();

// maak een nieuwe entiteit aan

// POST https://graph.microsoft.com/v1.0/me/calendars

var calendar = new Calendar
{
    Name = "Volunteer"
};

var newCalendar = await graphClient.Me.Calendars
    .Request()
    .AddAsync(calendar);

Meer informatie over de REST API: link.

Om data uit de Microsoft Graph op te halen heb je een OAuth 2.0 access token nodig. Deze gaat mee in de HTTP Authorization header als een Bearer token. Of in de graph client constructor (als je dit in code doet).

Ook hier een verwijzing naar MSAL om een token op te halen.

Least privilage: maak een user (link) en kies de laagst mogelijke bevoegdheden.

Kies de juiste rechten op basis van scenario's.

Bekijk wie met de applicatie meot werken, een end user of admin
Zorg op de juiste manier voor akkoord gaan met de rechten: link.
Snap het verschil tussen static, dynamic en incremental consent.

Overweeg multi-tenant applicaties, verwacht dat klanten andere applicatie en consent controls in verschillende staten hebben. Tenant administrators kunnen de mogelijkheid voor gebruikers om akkoord te gaan met voorwaarden uitschakelen. Daar moet een administrator altijd de goedkeuring uitvoeren.
Tenant administrators kunnen blokkades instellen, bijvoorbeeld dat gebruikers niet de profielen van andere gebruikers mogen zien, of self-service is slechts beperkt beschikbaar. Je applicatie moet dus met 403 fouten om kunnen gaan!

Je applicatie moet met responses om kunnen gaan. Pagination: verwacht dat er meer pagina's zijn, dus een @odata.nextLink: link.
Als je een item aan een enumeratie toevoegt die al bestaat, dan gaat de boel kapot. Als je ook onbekende waardes wilt kunnen afhandelen moet je een HTTP Prefer in de request header meesturen.

Het is de bedoeling dat je live gaat zoeken. Als je zelf data gaat cachen/opslaan, dan moet je wel voldoen aan de terms of use: link.