Advertise with Googlier.com  Steve Spencer's Blog - C# Blogging on Azure Stuff http://blogs.recneps.net/ http://www.rssboard.org/rss-specification BlogEngine.NET 2.9.1.0 en-US http://blogs.recneps.net/opml.axd http://www.dotnetblogengine.net/syndication.axd Steve Spencer Steve Spencer's Blog 0.000000 0.000000 Custom Application Roles in Azure AD <p>Previously I’ve talked about how you can control access to your web applications in Azure AD (<a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-1" target="_blank">Part 1</a> &amp; <a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-2" target="_blank">Part 2</a>) and also how to use Role Based Access Control (<a href="http://blogs.recneps.net/post/Introduction-to-Azure-Role-Based-Access-Control-(RBAC)" target="_blank">RBAC</a>) to manage access to resources in Azure. This post will build on these previous posts and show you how you can create your own custom roles for use in your own web applications and how you can use these roles to control access to parts of your application.I’ll use the same example used in <a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-1" target="_blank">Part 1</a>.</p><p>Firstly you need to created the roles for your application to use, assign the roles to users and finally change your code to make it role aware.</p><p>To add roles to your application. Navigate to the Azure portal and click on Azure Active Directory and App Registrations. Select the Web App you created previously.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_190.png"><img width="744" height="401" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_190.png" border="0"></a></p><p>Click on “App roles | Preview” then “Create App Role”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_191.png"><img width="372" height="586" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_191.png" border="0"></a></p><p>Enter the role information and click Apply and repeat for all the roles you require.</p><p>You should now see your roles in the grid:</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_192.png"><img width="601" height="166" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_192.png" border="0"></a></p><p>I’ve added a standard user role and a test administrator role.</p><p>To assign these roles to users, Navigate to the Enterprise Applications blade and click your application. Then select “Users and groups”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_193.png"><img width="745" height="275" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_193.png" border="0"></a></p><p>To Add roles to an existing assigned user, tick the user and then click “Edit”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_194.png"><img width="584" height="410" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_194.png" border="0"></a></p><p>Select the role and click “Select”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_195.png"><img width="740" height="225" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_195.png" border="0"></a></p><p>You should now see the role is assigned to the user. Similarly to add a role to a new user click “Add user”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_196.png"><img width="740" height="225" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_196.png" border="0"></a></p><p>This time you need to select the new user and then the role:</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_197.png"><img width="748" height="525" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_197.png" border="0"></a></p><p>You can add multiple roles to a user by repeating the Add user process.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_198.png"><img width="750" height="290" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_198.png" border="0"></a></p><p>Here I’ve added both new roles to one user.</p><p>You are now ready to user these roles in your application.</p><p>The sample code already shows how to <a href="https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-DotNet/blob/fe61021b02414c8c97e46ded79ecc71de12cf4b8/AppModelv2-WebApp-OpenIDConnect-DotNet/Views/Claims/Index.cshtml#L23" target="_blank">view the claims</a> for a user. </p><p><a href="http://blogs.recneps.net/image.axd?picture=image_199.png"><img width="557" height="140" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_199.png" border="0"></a></p><p>When I sign in to the application with the user that has two roles I see the following entries in the claims table:</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_200.png"><img width="558" height="76" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_200.png" border="0"></a></p><p>Adding the roles to the application and the assigning the roles to a user is enough to make them appear as roles in your application when the user signs in. There is a limit to the number of roles that an application can have. These are stored in the manifest of the App Registration. There is a <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest#manifest-limits" target="_blank">limit of 1200</a> items in the App Registration Manifest and this includes all the configuration items not just roles. </p><p>There are a number of ways in which you can use Roles in code. Firstly in your views you can add conditional code to limit what a standard user can see</p><blockquote><p>@if (Request.IsAuthenticated &amp;&amp; User.IsInRole("Test.Admin"))<p>{<p>&lt;h2&gt;You Are An Admininstrator&lt;/h2&gt;<p>&lt;br /&gt;<p>}</p></blockquote><p>When you sign in with the Test,Admin role you will get this additional text which is not visible for the User role</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_201.png"><img width="418" height="154" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_201.png" border="0"></a></p><p>You can also control access at the controller and controller action levels by adding the Authorize attribute on the controller or controller action:</p><blockquote><p>[Authorize(Roles = "Test.Admin ")]<p>public class ClaimsController : Controller<p>{</p></blockquote><p>or for multiple roles<blockquote><p>[Authorize(Roles = "Test.Admin,User")]<p>public class ClaimsController : Controller<p>{</p></blockquote><p>at the action level:<blockquote><p>[Authorize(Roles = "Test.Admin")]<p>public async Task&lt;ActionResult&gt; Index()<p>{<p>}</p></blockquote><p>or both<blockquote><p>[Authorize(Roles = "Test.Admin,User")]<p>public class ClaimsController : Controller<p>{<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Authorize(Roles = "Test.Admin")]<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public async Task&lt;ActionResult&gt; Index()<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<p><br><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Authorize(Roles = "User")]<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public async Task&lt;ActionResult&gt; Index2()<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<p>}</p></blockquote><p>In this example the user needs either the User or Test.Admin role to access the controller but only the Test.Admin role can access the Index action and the User role can access the Index2 action. This allows you to put controls in at multiple levels and provide a more custom experience for your users.<p>App Roles makes it easy to add custom roles to your application. If you have a higher Azure AD subscription you can assign these roles to groups and assign the groups to the applications. This means that you can add users to groups to assign the roles rather than adding them to each individual user. I can have a Standard user group that has the User role assigned and all users in that group will have the User role passed through to the application. <p>You now have Role Based Access control in your Azure AD application and can start to build your application features out based on the roles you define. http://blogs.recneps.net/post/Custom-Application-Roles-in-Azure-AD http://blogs.recneps.net/post/Custom-Application-Roles-in-Azure-AD#comment http://blogs.recneps.net/post.aspx?id=334b0a22-6f2e-4b36-a60b-ba70adcb2beb Sun, 22 Nov 2020 10:33:55 +0000 ASP.NET Azure AD Azure App Service C# Security steve http://blogs.recneps.net/pingback.axd http://blogs.recneps.net/post.aspx?id=334b0a22-6f2e-4b36-a60b-ba70adcb2beb 3 http://blogs.recneps.net/trackback.axd?id=334b0a22-6f2e-4b36-a60b-ba70adcb2beb http://blogs.recneps.net/post/Custom-Application-Roles-in-Azure-AD#comment http://blogs.recneps.net/syndication.axd?post=334b0a22-6f2e-4b36-a60b-ba70adcb2beb Accessing secrets in Azure Key Vault using a Managed Identity <p>With any key/password store I always thought that the weak link was the credentials used to access it. If that single point of failure was compromised then all your secrets would be vulnerable. Microsoft have overcome this by creating the Managed Identity. A Managed Identity is generated by a resource within Azure and can be configured to access resources that use Azure AD for authentication. As the Managed Identity is generated by the resource there are no credentials to store anywhere and code running in the resource can use this built-in identity to access other resources. This is specifically useful for Key Vault because we can now give access to Key Vault to specific resources without the need to store any credentials anywhere. This post will show you how to access Azure Key vault from an App Service using a Managed Identity to retrieve a secret for use in accessing other services.</p><p>So I have a web site deployed to Azure App Service and in order to access Key Vault I need to create a Managed Identity for the App Service. In the <a href="https://portal.azure.com" target="_blank">Azure Portal</a> navigate to your App Service and click on the Identity blade</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_187.png"><img width="759" height="448" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_187.png" border="0"></a></p><p>Your Manages Identity status should be Off. Click it On and then hit Save. This has now enabled your Managed Identity. The App Service Identity now exists in your associated Azure AD tenant and can be assigned to resources. This means that any code I write and deploy to this App Service will be able to take advantage of this built in identity to access the resources I need. In this example I want to access Key Vault. I therefore need to enable this new user in Key Vault. To do this I need to create a new access policy in Key Vault for this user.</p><p>Navigate to your Key Vault and click “Access policies”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_188.png"><img width="754" height="342" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_188.png" border="0"></a></p><p>Click “Add Access policy”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_189.png"><img width="755" height="426" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_189.png" border="0"></a></p><p>I’m interesting in just secrets from this Key Vault so I’ve selected the Secret Management template then clicked “None selected”. You should now see a new Principal blade appear. Type the name of you App service in the search box and select the principal that appears. Now click the “Select” button followed by the “Add” button. If you have not done this stage then you will get an error like this, when trying to access the Key Vault:</p><blockquote><p>Service request failed. Status: 403 (Forbidden) The user, group or application 'appid=&lt;app id&gt;;oid=&lt;oid&gt;;iss=https://sts.windows.net/&lt;tenantid&gt;/' does not have secrets get permission on key vault 'yourkeyvault;location=westeurope'.</p></blockquote><p>You should be setup now to access the secrets from code. there is a <a href="https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net" target="_blank">quick start guide</a> produced by Microsoft to help with this.<p>Two packages are required to access Key Vault secrets. <p>Azure.Security.KeyVault.Secrets &amp; Azure.Identity<p>With the packages installed the code to access Key Vault is simple.<blockquote><p>var credential = new DefaultAzureCredential();<br> var client = new SecretClient(new Uri("<a href="https://yourkeyvault.vault.azure.net/&quot;)">https://yourkeyvault.vault.azure.net/")</a>, credential);<br> var secret = await client.GetSecretAsync("YourSecret");<br> string actualSecret = secret.Value.Value;<br> </p></blockquote><p> Once this code is deployed to your App Service, the DefaultAzureCredential will automatically pick up the Managed Identity and allow you to access the secrets stored in it. Create a SecretClient, point it at your Key Vault and add the Managed Identity credential. Now you can retrieve the secret and use it.</p><p>Managed Identity is another tool to help you make your applications more secure. There is now a reduced risk of compromise from a mishandled Key Vault credential that you’ve stored somewhere safe. The Managed Identity cannot be used from anywhere other than code running in your App Service.</p> http://blogs.recneps.net/post/Accessing-secrets-in-Azure-Key-Vault-using-a-Managed-Identity http://blogs.recneps.net/post/Accessing-secrets-in-Azure-Key-Vault-using-a-Managed-Identity#comment http://blogs.recneps.net/post.aspx?id=c9b0fbbd-cb0f-41d7-b222-fa0aa20bcdf4 Fri, 30 Oct 2020 20:49:16 +0000 Azure App Service Security C# Azure Key Vault steve http://blogs.recneps.net/pingback.axd http://blogs.recneps.net/post.aspx?id=c9b0fbbd-cb0f-41d7-b222-fa0aa20bcdf4 8 http://blogs.recneps.net/trackback.axd?id=c9b0fbbd-cb0f-41d7-b222-fa0aa20bcdf4 http://blogs.recneps.net/post/Accessing-secrets-in-Azure-Key-Vault-using-a-Managed-Identity#comment http://blogs.recneps.net/syndication.axd?post=c9b0fbbd-cb0f-41d7-b222-fa0aa20bcdf4 Using the Azure Graph API Beta to add an Application Role Assignment <p>In an <a href="http://blogs.recneps.net/post/Using-Graph-API-to-automate-Azure-AD">earlier post</a> I talked about using Graph API to invite users using B2B and add them to groups. In this post I am introducing the Beta version of the API. This has additional functionality that is currently not released. Microsoft have provided documentation for the Graph API which currently defaults to V1.0. See <a href="https://docs.microsoft.com/en-us/graph/api/overview">https://docs.microsoft.com/en-us/graph/api/overview</a><p>To see the Beta documentation there is a version drop down list which allows you to select either V1.0 or the Beta version. <p><a href="http://blogs.recneps.net/image.axd?picture=clip_image002_3.jpg"><img width="427" height="175" title="clip_image002" style="display: inline; background-image: none;" alt="clip_image002" src="http://blogs.recneps.net/image.axd?picture=clip_image002_thumb_3.jpg" border="0"></a><p>Just like the release version of Graph API you install the C# Graph API Beta using a nuget package: <a href="https://www.nuget.org/packages/Microsoft.Graph.Beta">Microsoft.Graph.Beta</a> <p>The code samples in here will work in both the Beta and released version but I wanted to show the difference between using the Beta API but also show you something you can use in production.<p>The scenario I am going to show is Adding a user to an Azure AD application. <p>First you will need a client to access the Beta Graph API. With the Beta API nuget package installed this automatically uses the Beta client.<blockquote><p>ConfidentialClientApplicationOptions _applicationOptions = new ConfidentialClientApplicationOptions<p>{<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClientId = ConfigurationManager.AppSettings["ClientId"],<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TenantId = ConfigurationManager.AppSettings["TenantId"],<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClientSecret = ConfigurationManager.AppSettings["AppSecret"]<p>};<p>var confidentialClientApp = ConfidentialClientApplicationBuilder<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CreateWithApplicationOptions(_applicationOptions)<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Build();<p>ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApp);<p>GraphServiceClient betaGraphClient = new GraphServiceClient(authProvider);</p></blockquote><p>This creates a Beta graph client with application scope. <p>To add an application role assignment to a user we need access to the Service Principles endpoint. Looking at the API documentation for List Service Principles we need an Application permission of Directory.ReadAll,<p><a href="http://blogs.recneps.net/image.axd?picture=clip_image004_3.jpg"><img width="588" height="374" title="clip_image004" style="display: inline; background-image: none;" alt="clip_image004" src="http://blogs.recneps.net/image.axd?picture=clip_image004_thumb_3.jpg" border="0"></a><p>Create and Update Service Principles requires Directory.ReadWriteAll<p><a href="http://blogs.recneps.net/image.axd?picture=clip_image006_1.jpg"><img width="598" height="454" title="clip_image006" style="display: inline; background-image: none;" alt="clip_image006" src="http://blogs.recneps.net/image.axd?picture=clip_image006_thumb_1.jpg" border="0"></a><p>We can to add the permission to the Graph API application of Directory.ReadWriteAll and Grant Admin consent to the permissions we set up in the <a href="http://blogs.recneps.net/post/Using-Graph-API-to-automate-Azure-AD">previous post</a>. This will also cover the List API call.<p><a href="http://blogs.recneps.net/image.axd?picture=clip_image008_1.jpg"><img width="732" height="256" title="clip_image008" style="display: inline; background-image: none;" alt="clip_image008" src="http://blogs.recneps.net/image.axd?picture=clip_image008_thumb_1.jpg" border="0"></a><p>Without these permissions adding any calls to the Service Principle endpoint would return unauthorised.<p>In order to add an application role assignment we need to first obtain the user:<blockquote><p>var user = (await betaGraphClient.Users.Request(options)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Filter($"mail eq '{testUserEmail}'")<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .GetAsync()).FirstOrDefault();</p></blockquote><p>Then find all the app role assignments for the application we are interested in to see if the user is already assigned. To get the role assignments we call the service principle endpoint and expand the approleassignedto property:<blockquote><p>var app1ServicePrincipals = await betaGraphClient.ServicePrincipals<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Filter($"appId eq '{testApp1}'")<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Expand("approleassignedto")<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .GetAsync();<p>var app1RoleAssignment = (from ra in app1ServicePrincipals[0].AppRoleAssignedTo<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where ra.PrincipalId.ToString() == user.Id<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select ra).FirstOrDefault();</p></blockquote><p>If we want to remove the role assignment then we call the DeleteAsync method.<blockquote><p>if (app1RoleAssignment != null)<p>{<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await betaGraphClient.ServicePrincipals[app1ServicePrincipals[0].Id]<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .AppRoleAssignedTo[app1RoleAssignment.Id]<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .DeleteAsync();<p>}</p></blockquote><p>To Add a role assignment to the application call the Add endpoint:<blockquote><p>app1RoleAssignment = new AppRoleAssignment<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CreationTimestamp = DateTimeOffset.Now,<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrincipalDisplayName = user.DisplayName,<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrincipalId = Guid.Parse(user.Id),<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrincipalType = user.UserType,<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResourceDisplayName = app1ServicePrincipals[0].DisplayName,<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResourceId = Guid.Parse(app1ServicePrincipals[0].Id),<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AppRoleId = Guid.Empty<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<p>await betaGraphClient.ServicePrincipals[app1ServicePrincipals[0].Id]<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .AppRoleAssignments<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .AddAsync(app1RoleAssignment);</p></blockquote><p>To see the role assignments that the user now has find all the appRoleAssignments that contain the users id:<blockquote><p>var roleAssignments = servicePrincipals.SelectMany(x =&gt; x.AppRoleAssignedTo).ToList();<p>var appRoleAssignments = from ra in roleAssignments<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where ra.PrincipalId.ToString() == user.Id<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select ra;<p>foreach (var ra in appRoleAssignments)<p>{<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine($"[{ra.PrincipalDisplayName}] [{ra.ResourceDisplayName}]");<p>}</p></blockquote><p>This should show the same information you can see when you look in Azure AD at the User’s applications:<p><a href="http://blogs.recneps.net/image.axd?picture=clip_image010.jpg"><img width="779" height="149" title="clip_image010" style="display: inline; background-image: none;" alt="clip_image010" src="http://blogs.recneps.net/image.axd?picture=clip_image010_thumb.jpg" border="0"></a><p>Features and tools may change between Beta and Production. The code above changed slightly when moving to productions but the easiest way to see is to remove the Beta nuget and add the production one. The only change I had to make was to change the CreationTimeStamp to CreatedDateTime = DateTime.Now.<p>Information about which features are in Beta and which are in production can be found here: <a href="https://docs.microsoft.com/en-us/graph/whats-new-overview">https://docs.microsoft.com/en-us/graph/whats-new-overview</a> http://blogs.recneps.net/post/Using-the-Azure-Graph-API-Beta-to-add-an-Application-Role-Assignment http://blogs.recneps.net/post/Using-the-Azure-Graph-API-Beta-to-add-an-Application-Role-Assignment#comment http://blogs.recneps.net/post.aspx?id=9a062e6a-fbc9-4c0e-8bf4-7c5aa6cad1ba Sun, 27 Sep 2020 10:05:56 +0000 Azure Graph API Azure AD C# Security Microsoft Azure steve http://blogs.recneps.net/pingback.axd http://blogs.recneps.net/post.aspx?id=9a062e6a-fbc9-4c0e-8bf4-7c5aa6cad1ba 4 http://blogs.recneps.net/trackback.axd?id=9a062e6a-fbc9-4c0e-8bf4-7c5aa6cad1ba http://blogs.recneps.net/post/Using-the-Azure-Graph-API-Beta-to-add-an-Application-Role-Assignment#comment http://blogs.recneps.net/syndication.axd?post=9a062e6a-fbc9-4c0e-8bf4-7c5aa6cad1ba Using Graph API to automate Azure AD <p>In my previous posts I discussed how you can manage access to applications (<a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-1">part 1</a>) using Azure AD and also how you can add users users from outside of your organisation (<a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-2">part 2</a>). Now we will look at how you can automate this using Graph API.</p><p>“The Microsoft Graph API offers a single endpoint, https://graph.microsoft.com, to provide access to rich, people-centric data and insights exposed as resources of Microsoft 365 services. You can use REST APIs or SDKs to access the endpoint and build apps that support scenarios spanning across productivity, collaboration, education, security, identity, access, device management, and much more.” - <a href="https://docs.microsoft.com/en-us/graph/overview">https://docs.microsoft.com/en-us/graph/overview</a></p><p>From the overview you can see that Graph API covers a large area of Microsoft 365 services. One of the services it covers is Azure AD. What I’ll show you today is how to invite users and then add/remove them to/from groups using Graph API. </p><p>There are two ways to access Graph API. A user centric approach (Delegated) that requires a user account and an application centric approach that uses an application key and secret. Accessing Azure AD for user invite and group management utilises the application centric approach. In order to get an application id and secret you will need to create an application in Azure AD. The <a href="http://blogs.recneps.net/post/Managing-Application-Access-with-Azure-AD-Part-1">first post</a> in the series talks about how to create an App Registration.</p><p>Once you have created your application, there are a couple of bits of information you require in order to get started. These are the tenantId and clientId. These can be found in the Azure portal. Navigate to your App Registration and the details can be found in the Overview blade.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_167.png"><img width="783" height="270" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_167.png" border="0"></a></p><p>If you hover over each of the Guids a copy icon appears to allow you to easily copy these values.</p><p>Next you will need a key generating. For this you click on the Certificates and secrets blade.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_168.png"><img width="775" height="393" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_168.png" border="0"></a></p><p>Then click “New client secret” and populate the form and click “Add”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_169.png"><img width="782" height="399" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_169.png" border="0"></a></p><p>Your key will now appear. </p><p><a href="http://blogs.recneps.net/image.axd?picture=image_170.png"><img width="785" height="147" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_170.png" border="0"></a></p><p>Make sure you copy this as it is not visible again once you navigate away and you will need to generate a new one.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_171.png"><img width="787" height="148" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_171.png" border="0"></a></p><p>We are now ready to start looking at Graph API. There is good documentation about each of the functions in Graph API including the permissions required to access and code samples in a variety of languages. If we look at the list User function:</p><p><a href="https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&amp;tabs=http">https://docs.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&amp;tabs=http</a></p><p><a href="http://blogs.recneps.net/image.axd?picture=image_172.png"><img width="799" height="315" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_172.png" border="0"></a></p><p>You can see the permissions needed to access this function. As we are using an Application permission type we need to set one of the permissions: User.Read.All, User.ReadWrite.All, Directory.Read.All or Directory.ReadWrite.All.</p><p>You can set the permissions required by going to your App Registration and clicking on the “API permissions”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_173.png"><img width="783" height="283" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_173.png" border="0"></a></p><p>The application by default requires a user login that can read their own user profile. We need to add some additional permissions to allow our application to list the users in AD.Click on “Add permission”</p><p>This shows the list of built-in API’s that you can access. We are only looking at Microsoft Graph today</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_174.png"><img width="474" height="541" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_174.png" border="0"></a></p><p>Click “Microsoft graph”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_175.png"><img width="544" height="164" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_175.png" border="0"></a></p><p>Then “Application permission” and scroll to the User section</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_176.png"><img width="485" height="526" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_176.png" border="0"></a></p><p>To list users we need the User.Read.All permission, but we’ll also add the User.Invite.All so that we can invite B2B users. click “Add permissions”.</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_177.png"><img width="847" height="369" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_177.png" border="0"></a></p><p>Although you have added the permissions you cannot currently access the Graph API as you will need to Grant admin consent in first. If we had&nbsp; added a Delegated permission then the user could try an access the Graph API but Admin consent would be required to stop anyone from accessing certain features. This can be done in a workflow with selected Admins being notified of access. Before the use can access an Administrator would need to approve each access. This process will not work for our application as it is an unattended application using the application permission type. We can however grant access to this application user by clicking “Grant admin consent …” button and clicking Yes to the message box that pops up. </p><p><a href="http://blogs.recneps.net/image.axd?picture=image_178.png"><img width="862" height="365" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_178.png" border="0"></a></p><p>Clicking the button adds admin consent to all permissions. If you want to remove it from any, click the ellipsis (…) at the end and click “Revoke admin consent”</p><p><a href="http://blogs.recneps.net/image.axd?picture=image_179.png"><img width="681" height="108" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_179.png" border="0"></a></p><p>You can also remove permissions from this menu.</p><p>Your user is now ready to go. I’m using the <a href="https://www.nuget.org/packages/Microsoft.Graph">C# SDK and this is available as a nuget package</a></p><p>Once the nuget package is installed. You will need to create an instance of the Graph API client:</p><blockquote><p>ConfidentialClientApplicationOptions _applicationOptions = new ConfidentialClientApplicationOptions<br> {<br>&nbsp;&nbsp;&nbsp;&nbsp; ClientId = ConfigurationManager.AppSettings["ClientId"],<br>&nbsp;&nbsp;&nbsp;&nbsp; TenantId = ConfigurationManager.AppSettings["TenantId"],<br>&nbsp;&nbsp;&nbsp;&nbsp; ClientSecret = ConfigurationManager.AppSettings["AppSecret"]<br> };<br> </p><p><br></p><p>// Build a client application.<br> IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CreateWithApplicationOptions(_applicationOptions)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Build();<br> </p><p><br></p><p>// Create an authentication provider by passing in a client application and graph scopes.<br> ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);<br> </p><p><br></p><p>// Create a new instance of GraphServiceClient with the authentication provider.<br> GraphServiceClient graphClient = new GraphServiceClient(authProvider);<br> </p></blockquote><p>You will need the ClientId, TenentId and Secret you copied earlier. Looking at the Graph API documentation there are example of how to use each of the functions. </p><p><a href="http://blogs.recneps.net/image.axd?picture=image_180.png"><img width="718" height="367" title="image" style="display: inline; background-image: none;" alt="image" src="http://blogs.recneps.net/image.axd?picture=image_thumb_180.png" border="0"></a></p><p>We want to see if a user existing in our AAD before we invite them, so we will use the filter option as above.</p><blockquote><p>var user = (await graphClient.Users<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request(options)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Filter($"mail eq '{testUserEmail}'")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .GetAsync()).FirstOrDefault();<br> </p><p>Console.WriteLine($"{testUserEmail} {user != null} {user?.Id} [{user?.DisplayName}] [{user?.Mail}]");</p> </blockquote><p>If user is null then is does not exist in your AzureAD tenant. Assuming that this is an external user then you will need to invite the user to be able to access your application. I created a method for this:</p><blockquote><p>private async Task&lt;Invitation&gt; InviteUser(IGraphServiceClient graphClient, string displayName, string emailAddress, string redirectUrl, bool wantCustomEmaiMessage, string emailMessage)<br> {<br>&nbsp;&nbsp;&nbsp;&nbsp; // Needs: User.InviteAll <br> </p><p>&nbsp;&nbsp;&nbsp; var invite = await graphClient.Invitations<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request().AddAsync(new Invitation<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvitedUserDisplayName = displayName, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvitedUserEmailAddress = emailAddress, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SendInvitationMessage = wantCustomEmaiMessage,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InviteRedirectUrl = redirectUrl, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvitedUserMessageInfo = wantCustomEmaiMessage ? new InvitedUserMessageInfo<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomizedMessageBody = emailMessage, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } : null<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<br> </p><p>&nbsp;&nbsp;&nbsp; return invite;<br> }</p></blockquote><p>Now you’ve just invited a B2B user into your Azure AD tenant. At the moment they do not have access to anything as you’ve not assigned them to any application. The Graph API for assigning users to applications uses the delegated permissions model which means you need to use an actual user account. The Graph API with the application permission model does not support adding users to applications. In order to use the same application client you used for inviting users, you could assign a group to your application and then use the Graph API to add/remove users to/from that group.</p><p>Adding/removing a user to/from a group requires one of the following permissions: GroupMember.ReadWrite.All, Group.ReadWrite.All and Directory.ReadWrite.All. This is set in the same way as for the user permissions in the App Registration/Api permission section mentioned earlier. Admin consent will also need to be granted for these permissions.</p><p>The code to add &amp; remove users is below:</p><blockquote><p>// find group<br> var groupFound = (await graphClient.Groups<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Filter($"displayName eq '{groupName}'")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Expand("members")<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .GetAsync()).FirstOrDefault();</p> <p>Console.WriteLine($"{groupName} {groupFound != null } [{groupFound?.Id}] [{groupFound?.DisplayName}] [{groupFound?.Members?.Count}]");</p> <p>if (groupFound != null)<br> {<br>&nbsp;&nbsp;&nbsp;&nbsp; // check is the user is already in the group<br>&nbsp;&nbsp;&nbsp;&nbsp; var user = (from u in groupFound.Members<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where u.Id == user.Id<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select u).FirstOrDefault();<br>&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine($"user Found {user != null}");</p> <p>&nbsp;&nbsp;&nbsp; if (user != null)<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine($"removing user {user.Id}");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // remove from group<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await graphClient.Groups[groupFound.Id].Members[user.Id].Reference<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .DeleteAsync();</p> <p>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine($"adding user {user.Id}");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // add to group<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await graphClient.Groups[groupFound.Id].Members.References<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Request()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .AddAsync(new DirectoryObject<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Id = user.Id<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br> }</p></blockquote><p>In the code above I wanted the Graph API to return me the list of users in the group. By default you do not see this data when retrieving group information. Adding the Expand method tells Graph API to extend the query and return the additional data. This is something to bear in mind when using Graph API. Just because the data is null does not mean that there is no data, you might need to expand the data set returned.</p><p>I hope you found this a useful introduction to Graph API, I will be posting more on Azure AD in the future including more on Graph API. </p> http://blogs.recneps.net/post/Using-Graph-API-to-automate-Azure-AD http://blogs.recneps.net/post/Using-Graph-API-to-automate-Azure-AD#comment http://blogs.recneps.net/post.aspx?id=724470f0-95be-421a-9140-ec15c094f871 Sun, 19 Jul 2020 09:29:06 +0000 Azure AD Microsoft Azure Security C# Azure Graph API steve http://blogs.recneps.net/pingback.axd http://blogs.recneps.net/post.aspx?id=724470f0-95be-421a-9140-ec15c094f871 7 http://blogs.recneps.net/trackback.axd?id=724470f0-95be-421a-9140-ec15c094f871 http://blogs.recneps.net/post/Using-Graph-API-to-automate-Azure-AD#comment http://blogs.recneps.net/syndication.axd?post=724470f0-95be-421a-9140-ec15c094f871