left-icon

External Collaboration with Azure AD B2B Succinctly®
by Sjoukje Zaal

Previous
Chapter

of
A
A
A

CHAPTER 5

Automating Adding Guest Users with Azure Functions

Automating Adding Guest Users with Azure Functions


In the previous chapter, we covered how you can add guest users to Azure AD using the Graph API and PowerShell. In this chapter, we are going to add external users using Azure Functions. For this, we are going to call the Graph API from an Azure function that is written in C#. Adding users via Azure Functions is slightly more complicated than adding users via PowerShell, but using Azure Functions gives you complete, fine-grained, programmatic control over the process.

Before we can call the Graph API, we need to register an application in Azure AD that has the right permissions to access the Graph API. We already did this in the previous chapter. We then set these permissions directly in the Graph Explorer.

In the next section, we are going to register the app in Azure AD.

Create an Azure AD app registration

  1. Navigate to the Azure portal by opening https://portal.azure.com/.
  2. In the left menu, select Azure Active Directory.
  3. The Azure AD overview blade is opened. In the left menu, select App registrations:

App registrations in Azure AD

Figure 32: App registrations in Azure AD

  1. Select + New registration in the top menu:

Create a new registration

Figure 33: Create a new registration

  1. Add the following values:
  1. Name: FunctionB2B
  2. Supported account types: Account in this organizational directory only (Single tenant):

App settings

Figure 34: App settings

  1. Click Register.
  2. Once the app is created, you will be redirected to the overview page of the app. We now need to set the required permissions. In the left menu, select API permissions.
  3. For this app, we need to set the same permissions as in the previous chapter when we added the required permissions to the Graph Explorer. In the top menu, select + Add a permission:

API permissions

Figure 35: API permissions

  1. In the next blade, select Microsoft Graph. We are again using Microsoft Graph for creating the guest user.
  2. Click Application permissions:

Application permissions

Figure 36: Application permissions

  1. Add the following permissions:
  1. User.ReadWrite.All
  2. Directory.ReadWrite.All
  1. Click Add permissions.
  2. Click Grant admin consent for the permissions:

Grant admin consent

Figure 37: Grant admin consent

  1. The last step is to create an app secret. We need this, together with the Azure AD tenant ID and the application ID, to make a request from our Azure Function that we are going to create in the next step. In the left menu, click Certificates & secrets.
  2. Under Client secrets, click + New client secret:

Add new client secret

Figure 38: Add new client secret

  1. Specify a name for the secret and set when you want it to expire:

Set client secret values

Figure 39: Set client secret values

  1. Click Add to create the secret.
  2. Copy the newly created secret’s Value field to Notepad after creation, because it is only going to be displayed to you once:

App secret value

Figure 40: App secret value

  1. Navigate to the overview page of the app registration and copy the app ID and the tenant ID to Notepad as well:

App ID and Azure AD tenant ID

Figure 41: App ID and Azure AD tenant ID

We now have registered an app in Azure AD that has permissions to call Microsoft Graph. This means that we can create the guest user from our Azure function through this registration.

In the next part, we are going to create the function.

Adding guest users using an Azure function

In this demonstration, we are going to create an Azure function to create the guest user in Azure AD. We are using Visual Studio Code in this example to create the function.

  1. Open Visual Studio Code. First, we need to install the Azure Functions extension. If you already have it installed, you can skip this step. Open the Extensions screen by clicking it in the left menu or by pressing Ctrl+Shift+X.
  2. Search for Azure Functions in the search box, select it, and then click Install:

Install the Azure Functions extensions

Figure 42: Install the Azure Functions extensions

  1. After installing the Azure Functions extension, open the Command Palette by pressing Ctrl+Shift+P.
  2. Search for Azure Functions Create and select Create Function from the list:

Create a new function

Figure 43: Create a new function

  1. You will be prompted to create a new project. Select Create new project. Choose a folder to create the project in.
  2. Select the language of the project:

Select the language

Figure 44: Select the language

  1. Select a trigger for the function. We are going to use the HTTPTrigger for this demo:

Select the trigger

Figure 45: Select the trigger

  1. Next, you need to specify a name for the trigger. You can also keep the default name and press Enter:

Specify a name for the trigger

Figure 46: Specify a name for the trigger

  1. Specify a name for the function, such as CreateGuestUserGraph, and press Enter:

Specify a name for the function

Figure 47: Specify a name for the function

  1. For the AccessRights, select Anonymous and press Enter:

Select the Access Rights

Figure 48: Select the Access Rights

  1. To choose how you would like to open the newly created project, select Add to workspace:

Open the project

Figure 49: Open the project

  1. The project is generated and added to the workspace in VS Code.
  2. We need to add two NuGet packages to the project to be able to call Microsoft Graph and use the Microsoft Authentication Library (MSAL) .NET SDK.

Tip: MSAL enables developers to acquire tokens from the Microsoft identity platform endpoint to access secured web APIs. For more information, you can refer to this website.

  1. Open a new terminal by pressing Ctrl+Shift+` and enter the following lines to add the required packages:

dotnet add package Microsoft.Graph

dotnet add package Microsoft.Identity.Client

  1. Now that the libraries are added to the project, we can add the Azure AD app registration configuration values to the local.settings.json file. Open the file from the project and add the following code below the Functions Worker Runtime line:

Code Listing 4

    "AzureADAppId": "YOUR_CLIENT_ID",

    "AzureADTenantId": "YOUR_TENANT_ID",

    "AzureADAppSecret": "YOUR_CLIENT_SECRET"

  1. Add the values that we have copied to Notepad here.
  2. Your file should now look like the following image:

Azure AD registration values

Figure 50: Azure AD registration values

  1. Add a new file to the project and name it AuthHandler.cs. Add the following code to it:

Code Listing 5

using System.Net.Http;

using System.Threading.Tasks;

using Microsoft.Graph;

using System.Threading;

namespace CreateGuestUserGraph

     public class AuthHandler : DelegatingHandler {

        private IAuthenticationProvider _authenticationProvider;

        public AuthHandler(IAuthenticationProvider authenticationProvider, HttpMessageHandler innerHandler) 

        {

            InnerHandler = innerHandler;

            _authenticationProvider = authenticationProvider;

        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 

        {

            await _authenticationProvider.AuthenticateRequestAsync(request);

            return await base.SendAsync(request,cancellationToken);

        }

}

}

  1. Add another new file to the project and name it MSALAuthenticationProvider.cs. Add the following code to it:

Code Listing 6

using System.Net.Http;

using System.Net.Http.Headers;

using System.Threading.Tasks;

using Microsoft.Identity.Client;

using Microsoft.Graph;

namespace CreateGuestUserGraph

{

     // This class encapsulates the details of getting a token from MSAL and exposes it via the 

    // IAuthenticationProvider interface so that GraphServiceClient or AuthHandler can use it.

    // A significantly enhanced version of this class will be available from the GraphSDK team

    // in the future. It will support all the types of

    //Client Application as defined by MSAL.

    public class MsalAuthenticationProvider : IAuthenticationProvider

    {

        private IConfidentialClientApplication _clientApplication;

        private string[] _scopes;

        public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes) {

            _clientApplication = clientApplication;

            _scopes = scopes;

        }

        /// <summary>

        /// Update HttpRequestMessage with credentials

        /// </summary>

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)

        {

            var token = await GetTokenAsync();

            request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);

        }

        /// <summary>

        /// Acquire Token 

        /// </summary>

        public async Task<string> GetTokenAsync()

        {

            AuthenticationResult authResult = null;

            authResult = await _clientApplication.AcquireTokenForClient(_scopes)

                                .ExecuteAsync();

            return authResult.AccessToken;

        }

    }

}

  1. Open the HTTPTriggerCSharp1.cs file and add the following code to it:

Code Listing 7

using System;

using System.IO;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

using Microsoft.Azure.WebJobs;

using Microsoft.Azure.WebJobs.Extensions.Http;

using Microsoft.AspNetCore.Http;

using Microsoft.Extensions.Logging;

using Newtonsoft.Json;

using Microsoft.Graph;

using System.Collections.Generic;

using Microsoft.Identity.Client;

namespace CreateGuestUserGraph

{

    public static class HttpTriggerCSharp1

    {

        private static GraphServiceClient _graphServiceClient;

        [FunctionName("HttpTriggerCSharp1")]

        public static async Task<IActionResult> Run(

            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,

            ILogger log)

        {

            log.LogInformation("C# HTTP trigger function processed a request.");

            string firstname = req.Query["firstname"];

            string lastname = req.Query["lastname"];

            string emailaddress = req.Query["emailaddress"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

            dynamic data = JsonConvert.DeserializeObject(requestBody);

           

            firstname = firstname ?? data?.firstname;

            lastname = lastname ?? data?.lastname;

            emailaddress = emailaddress ?? data?.emailaddress;

            var invitation = new Invitation 

            {

                InvitedUserDisplayName = $"{firstname} {lastname}",

                InvitedUserEmailAddress = emailaddress,

                InviteRedirectUrl= "https://myapplications.microsoft.com/",

                InvitedUserMessageInfo = new InvitedUserMessageInfo {

                    CustomizedMessageBody = "Hey there! Check this out. I created an invitation through an Azure Function!"

                },

                SendInvitationMessage = true

            };

            GraphServiceClient graphClient = GetAuthenticatedGraphClient();

            var graphResult = await graphClient.Invitations

                    .Request()

                    .AddAsync(invitation);

        return graphResult != null

        ? (ActionResult)new OkObjectResult($"Following user created: {firstname}, {lastname}, {emailaddress}")

        : new BadRequestObjectResult("Please provide guest user information details on the query string or in the request body."); 

        }

        private static GraphServiceClient GetAuthenticatedGraphClient()

        {

            var authenticationProvider = CreateAuthorizationProvider();

            _graphServiceClient = new GraphServiceClient(authenticationProvider);

            return _graphServiceClient;

        }

        private static IAuthenticationProvider CreateAuthorizationProvider()

        {

            var clientId = System.Environment.GetEnvironmentVariable("AzureADAppId", EnvironmentVariableTarget.Process);

            var clientSecret = System.Environment.GetEnvironmentVariable("AzureADAppSecret", EnvironmentVariableTarget.Process);

           // var redirectUri = System.Environment.GetEnvironmentVariable("AzureADAppRedirectUri", EnvironmentVariableTarget.Process);

            var tenantId = System.Environment.GetEnvironmentVariable("AzureADTenantId", EnvironmentVariableTarget.Process);

            var authority = $"https://login.microsoftonline.com/{tenantId}/v2.0";

            //this specific scope means that application will default to what is defined in the application registration rather than using dynamic scopes

            List<string> scopes = new List<string>();

            scopes.Add("https://graph.microsoft.com/.default");

            var cca = ConfidentialClientApplicationBuilder.Create(clientId)

                                              .WithAuthority(authority)

                                             // .WithRedirectUri(redirectUri)

                                              .WithClientSecret(clientSecret)

                                              .Build();

            return new MsalAuthenticationProvider(cca, scopes.ToArray());

        }

    }

}

  1. To test the Azure function, open a new terminal and run dotnet build.
  2. When the function is built successfully, you can press F5 to execute the function locally. This will result in the following output:

Debugging the function locally

Figure 51: Debugging the function locally

  1. The URL for the function is also displayed here. Copy the URL and add the query string to it to make a POST request to the Azure function. The URL will look like the following example:

    http://localhost:7071/api/HttpTriggerCSharp1?firstname=Sjoukje&lastname=Zaal&emailaddress=<your-email-address>

  2. Open a browser window and paste in the URL. This will result in the following outcome:

Output after creating the guest user

Figure 52: Output after creating the guest user

  1. Now that the function has executed without any errors, we can deploy it to Azure. We can do this directly from VS Code as well. Press Ctrl+Shift+P again and search for Azure Functions: Deploy, and select the following item:

Deploying the function from VS Code

Figure 53: Deploying the function from VS Code

  1. Next, you need to sign in to Azure with an administrator account:

Sign in to Azure

Figure 54: Sign in to Azure

  1. Select the subscription you want to deploy the function to.
  2. Create a new function app:

Create a new Function App

Figure 55: Create a new Function App

  1. Specify a unique name for the function and press Enter:

Specify a unique name

Figure 56: Specify a unique name

  1. Pick the region you want to deploy your app to:

Pick the region in Azure

Figure 57: Pick the region in Azure

The Function App will now be deployed to Azure. If you navigate to the Azure portal after deployment, you will see that the function is deployed:

Deployed Azure function

Figure 58: Deployed Azure function

We have now created a guest user in Azure AD using an Azure function written in C#. This function uses the Microsoft.Graph and the Microsoft.Identity.Client NuGet packages, and an Azure AD app registration to get access to the Azure AD tenant.

In this chapter, we have covered how you can add guest users to Azure AD B2B using an Azure AD app registration, an Azure function, and the Graph API. This Azure function was built in VS Code. In the next chapter, we are going to cover how you can manage access using Azure AD B2B entitlement management.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.