From aa44afe8adf1f2e7617330e2ed4d03800480a1a8 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 17:16:33 +0100 Subject: [PATCH 01/15] Add solution file to the project --- src/b2c-ms-graph.sln | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/b2c-ms-graph.sln diff --git a/src/b2c-ms-graph.sln b/src/b2c-ms-graph.sln new file mode 100644 index 0000000..eb017f2 --- /dev/null +++ b/src/b2c-ms-graph.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "b2c-ms-graph", "b2c-ms-graph.csproj", "{9AA1B89E-B2D7-4391-803B-1654F96379A5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FDF38FBE-8929-4734-903C-AB429F42D7BA} + EndGlobalSection +EndGlobal From a0da63eaba1774c461ebcb5917c86053e22ddcd3 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 20:02:21 +0100 Subject: [PATCH 02/15] Add helpers --- src/Helpers/B2cCustomAttributeHelper.cs | 22 +++++++++++++++ src/Helpers/PasswordHelper.cs | 37 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/Helpers/B2cCustomAttributeHelper.cs create mode 100644 src/Helpers/PasswordHelper.cs diff --git a/src/Helpers/B2cCustomAttributeHelper.cs b/src/Helpers/B2cCustomAttributeHelper.cs new file mode 100644 index 0000000..ee19a9e --- /dev/null +++ b/src/Helpers/B2cCustomAttributeHelper.cs @@ -0,0 +1,22 @@ +namespace b2c_ms_graph.Helpers +{ + internal class B2cCustomAttributeHelper + { + internal readonly string _b2cExtensionAppClientId; + + internal B2cCustomAttributeHelper(string b2cExtensionAppClientId) + { + _b2cExtensionAppClientId = b2cExtensionAppClientId.Replace("-", ""); + } + + internal string GetCompleteAttributeName(string attributeName) + { + if (string.IsNullOrWhiteSpace(attributeName)) + { + throw new System.ArgumentException("Is mandatory", nameof(attributeName)); + } + + return $"extension_{_b2cExtensionAppClientId}_{attributeName}"; + } + } +} diff --git a/src/Helpers/PasswordHelper.cs b/src/Helpers/PasswordHelper.cs new file mode 100644 index 0000000..89aa932 --- /dev/null +++ b/src/Helpers/PasswordHelper.cs @@ -0,0 +1,37 @@ +using System; + +namespace b2c_ms_graph.Helpers +{ + public static class PasswordHelper + { + public static string GenerateNewPassword(int lowercase, int uppercase, int numerics) + { + string lowers = "abcdefghijklmnopqrstuvwxyz"; + string uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + string number = "0123456789"; + + Random random = new Random(); + + string generated = "!"; + for (int i = 1; i <= lowercase; i++) + generated = generated.Insert( + random.Next(generated.Length), + lowers[random.Next(lowers.Length - 1)].ToString() + ); + + for (int i = 1; i <= uppercase; i++) + generated = generated.Insert( + random.Next(generated.Length), + uppers[random.Next(uppers.Length - 1)].ToString() + ); + + for (int i = 1; i <= numerics; i++) + generated = generated.Insert( + random.Next(generated.Length), + number[random.Next(number.Length - 1)].ToString() + ); + + return generated.Replace("!", string.Empty); + } + } +} From b5d94104d17464ef573637ccc48a28b7b0edf14b Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 20:02:41 +0100 Subject: [PATCH 03/15] Add extra appsetting --- src/Models/AppSettings.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Models/AppSettings.cs b/src/Models/AppSettings.cs index 091cfc6..15e3b04 100644 --- a/src/Models/AppSettings.cs +++ b/src/Models/AppSettings.cs @@ -35,6 +35,9 @@ public class AppSettings [JsonProperty(PropertyName = "ClientSecret")] public string ClientSecret { get; set; } + [JsonProperty(PropertyName = "B2cExtensionAppClientId")] + public string B2cExtensionAppClientId { get; set; } + [JsonProperty(PropertyName = "UsersFileName")] public string UsersFileName { get; set; } From fce0b6bec07ee5d054df9670caea99be56b0cb55 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 20:03:13 +0100 Subject: [PATCH 04/15] Extend userservice with multiple requests --- src/Services/UserService.cs | 126 +++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/src/Services/UserService.cs b/src/Services/UserService.cs index 9008433..c0f6aec 100644 --- a/src/Services/UserService.cs +++ b/src/Services/UserService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.Graph; @@ -32,6 +33,39 @@ public static async Task ListUsers(GraphServiceClient graphClient) } } + public static async Task ListUsersWithCustomAttribute(GraphServiceClient graphClient, string b2cExtensionAppClientId) + { + if (string.IsNullOrWhiteSpace(b2cExtensionAppClientId)) + { + throw new ArgumentException("B2C Extension App ClientId (ApplicationId) is missing in the appsettings.json. Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", nameof(b2cExtensionAppClientId)); + } + + // Declare the names of the custom attributes + const string favouriteSport = "FavouriteSport"; + const string isAwesome = "IsAwesome"; + + // Get the complete name of the custom attribute (Azure AD extension) + Helpers.B2cCustomAttributeHelper helper = new Helpers.B2cCustomAttributeHelper(b2cExtensionAppClientId); + string favouriteSportAttributeName = helper.GetCompleteAttributeName(favouriteSport); + string isAwesomeAttributeName = helper.GetCompleteAttributeName(isAwesome); + + Console.WriteLine($"Getting list of users with the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean)"); + + // Get all users (one page) + var result = await graphClient.Users + .Request() + .Select($"id,displayName,identities,{favouriteSportAttributeName},{isAwesomeAttributeName}") + .GetAsync(); + + foreach (var user in result.CurrentPage) + { + Console.WriteLine(JsonConvert.SerializeObject(user)); + + // Only output the custom attributes... + //Console.WriteLine(JsonConvert.SerializeObject(user.AdditionalData)); + } + } + public static async Task GetUserById(GraphServiceClient graphClient) { Console.Write("Enter user object ID: "); @@ -135,7 +169,7 @@ public static async Task SetPasswordByUserId(GraphServiceClient graphClient) var user = new User { - PasswordPolicies = "DisablePasswordExpiration,DisableStrongPassword", + PasswordPolicies = "DisablePasswordExpiration,DisableStrongPassword", PasswordProfile = new PasswordProfile { ForceChangePasswordNextSignIn = false, @@ -202,5 +236,95 @@ public static async Task BulkCreate(AppSettings config, GraphServiceClient graph } } } + + public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphClient, string b2cExtensionAppClientId, string tenantId) + { + if (string.IsNullOrWhiteSpace(b2cExtensionAppClientId)) + { + throw new ArgumentException("B2C Extension App ClientId (ApplicationId) is missing in the appsettings.json. Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", nameof(b2cExtensionAppClientId)); + } + + // Declare the names of the custom attributes + const string favouriteSport = "FavouriteSport"; + const string isAwesome = "IsAwesome"; + + // Get the complete name of the custom attribute (Azure AD extension) + Helpers.B2cCustomAttributeHelper helper = new Helpers.B2cCustomAttributeHelper(b2cExtensionAppClientId); + string favouriteSportAttributeName = helper.GetCompleteAttributeName(favouriteSport); + string isAwesomeAttributeName = helper.GetCompleteAttributeName(isAwesome); + + Console.WriteLine($"Create a user with the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean)"); + + // Fill custom attributes + IDictionary extensionInstance = new Dictionary(); + extensionInstance.Add(favouriteSportAttributeName, "Basketball"); + extensionInstance.Add(isAwesomeAttributeName, true); + + try + { + // Create user + var result = await graphClient.Users + .Request() + .AddAsync(new User + { + GivenName = "Kobe", + Surname = "Bryant", + DisplayName = "Kobe Bryant", + Identities = new List + { + new ObjectIdentity() + { + SignInType = "emailAddress", + Issuer = tenantId, + IssuerAssignedId = "kobe.bryant@example.com" + } + }, + PasswordProfile = new PasswordProfile() + { + Password = Helpers.PasswordHelper.GenerateNewPassword(4, 8, 4) + }, + PasswordPolicies = "DisablePasswordExpiration", + AdditionalData = extensionInstance + }); + + string userId = result.Id; + + Console.WriteLine($"Created the new user. Now get the created user with object ID '{userId}'..."); + + // Get created user by object ID + result = await graphClient.Users[userId] + .Request() + .Select($"id,givenName,surName,displayName,identities,{favouriteSportAttributeName},{isAwesomeAttributeName}") + .GetAsync(); + + if (result != null) + { + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine($"DisplayName: {result.DisplayName}"); + Console.WriteLine($"{favouriteSport}: {result.AdditionalData[favouriteSportAttributeName].ToString()}"); + Console.WriteLine($"{isAwesome}: {result.AdditionalData[isAwesomeAttributeName].ToString()}"); + Console.WriteLine(); + Console.ResetColor(); + Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented)); + } + } + catch (ServiceException ex) + { + if (ex.StatusCode == System.Net.HttpStatusCode.BadRequest) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Have you created the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean) in your tenant?"); + Console.WriteLine(); + Console.WriteLine(ex.Message); + Console.ResetColor(); + } + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(ex.Message); + Console.ResetColor(); + } + } } } \ No newline at end of file From 906e18d6a767e9c6864612956018467c804ba8b6 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 20:03:47 +0100 Subject: [PATCH 05/15] Extend program with the new operations --- src/Program.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Program.cs b/src/Program.cs index afe6b6a..a6ac9f3 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -52,13 +52,13 @@ private static async Task RunAsync() switch (decision.ToLower()) { case "1": - await UserService.ListUsers(graphClient); ; + await UserService.ListUsers(graphClient); break; case "2": - await UserService.GetUserById(graphClient); ; + await UserService.GetUserById(graphClient); break; case "3": - await UserService.GetUserBySignInName(config, graphClient); ; + await UserService.GetUserBySignInName(config, graphClient); break; case "4": await UserService.DeleteUserById(graphClient); @@ -69,6 +69,12 @@ private static async Task RunAsync() case "6": await UserService.BulkCreate(config, graphClient); break; + case "7": + await UserService.CreateUserWithCustomAttribute(graphClient, config.B2cExtensionAppClientId, config.TenantId); + break; + case "8": + await UserService.ListUsersWithCustomAttribute(graphClient, config.B2cExtensionAppClientId); + break; case "help": Program.PrintCommands(); break; @@ -122,6 +128,8 @@ private static void PrintCommands() Console.WriteLine("[4] Delete user by object ID"); Console.WriteLine("[5] Update user password"); Console.WriteLine("[6] Create users (bulk import)"); + Console.WriteLine("[7] Create user with custom attributes and show result"); + Console.WriteLine("[8] Get all users (one page) with custom attributes"); Console.WriteLine("[help] Show available commands"); Console.WriteLine("[exit] Exit the program"); Console.WriteLine("-------------------------"); From 4692068e1cbdd8e86ad1152e98c438692cc17e7a Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Thu, 5 Mar 2020 20:05:58 +0100 Subject: [PATCH 06/15] Add new setting with description --- src/appsettings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/appsettings.json b/src/appsettings.json index 87f98f2..cfa1dc6 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -3,6 +3,7 @@ "TenantId": "your-b2c-tenant.onmicrosoft.com", "AppId": "Application (client) ID", "ClientSecret": "Client secret", + "B2cExtensionAppClientId": "Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", "UsersFileName": "users.json" } } From 88ab7cd063ff1fd67bdc4d52a56392f1a0e37010 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:35:35 +0100 Subject: [PATCH 07/15] Update src/Helpers/B2cCustomAttributeHelper.cs Co-Authored-By: Marsh Macy --- src/Helpers/B2cCustomAttributeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Helpers/B2cCustomAttributeHelper.cs b/src/Helpers/B2cCustomAttributeHelper.cs index ee19a9e..245ed6f 100644 --- a/src/Helpers/B2cCustomAttributeHelper.cs +++ b/src/Helpers/B2cCustomAttributeHelper.cs @@ -13,7 +13,7 @@ internal string GetCompleteAttributeName(string attributeName) { if (string.IsNullOrWhiteSpace(attributeName)) { - throw new System.ArgumentException("Is mandatory", nameof(attributeName)); + throw new System.ArgumentException("Parameter cannot be null", nameof(attributeName)); } return $"extension_{_b2cExtensionAppClientId}_{attributeName}"; From a49c4aa534bf052b24dd7263818b44de763c3fc5 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:35:57 +0100 Subject: [PATCH 08/15] Update src/Services/UserService.cs Co-Authored-By: Marsh Macy --- src/Services/UserService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Services/UserService.cs b/src/Services/UserService.cs index c0f6aec..18e49b1 100644 --- a/src/Services/UserService.cs +++ b/src/Services/UserService.cs @@ -267,9 +267,9 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC .Request() .AddAsync(new User { - GivenName = "Kobe", - Surname = "Bryant", - DisplayName = "Kobe Bryant", + GivenName = "Casey", + Surname = "Jensen", + DisplayName = "Casey Jensen", Identities = new List { new ObjectIdentity() @@ -327,4 +327,4 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC } } } -} \ No newline at end of file +} From 6a846852ee9634737f5e7a623276602023c3f108 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:36:52 +0100 Subject: [PATCH 09/15] Update src/appsettings.json Co-Authored-By: Marsh Macy --- src/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/appsettings.json b/src/appsettings.json index cfa1dc6..915fe96 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -3,7 +3,7 @@ "TenantId": "your-b2c-tenant.onmicrosoft.com", "AppId": "Application (client) ID", "ClientSecret": "Client secret", - "B2cExtensionAppClientId": "Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", + "B2cExtensionAppClientId": "Find this Application (client) ID in the App registrations pane in the Azure portal. The app registration is named 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", "UsersFileName": "users.json" } } From 360ec8a3bd63a6c147fffa74be0962077aab9b9f Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:38:09 +0100 Subject: [PATCH 10/15] Update src/Services/UserService.cs Co-Authored-By: Marsh Macy --- src/Services/UserService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/UserService.cs b/src/Services/UserService.cs index 18e49b1..b878578 100644 --- a/src/Services/UserService.cs +++ b/src/Services/UserService.cs @@ -37,7 +37,7 @@ public static async Task ListUsersWithCustomAttribute(GraphServiceClient graphCl { if (string.IsNullOrWhiteSpace(b2cExtensionAppClientId)) { - throw new ArgumentException("B2C Extension App ClientId (ApplicationId) is missing in the appsettings.json. Get it from the App Registrations blade in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", nameof(b2cExtensionAppClientId)); + throw new ArgumentException("B2cExtensionAppClientId (its Application ID) is missing from appsettings.json. Find it in the App registrations pane in the Azure portal. The app registration has the name 'b2c-extensions-app. Do not modify. Used by AADB2C for storing user data.'.", nameof(b2cExtensionAppClientId)); } // Declare the names of the custom attributes From f3981c7c4ad600adaf0b6e63f8d3d78119276894 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:47:40 +0100 Subject: [PATCH 11/15] Change names of the attributes --- src/Services/UserService.cs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Services/UserService.cs b/src/Services/UserService.cs index b878578..553d997 100644 --- a/src/Services/UserService.cs +++ b/src/Services/UserService.cs @@ -41,20 +41,20 @@ public static async Task ListUsersWithCustomAttribute(GraphServiceClient graphCl } // Declare the names of the custom attributes - const string favouriteSport = "FavouriteSport"; - const string isAwesome = "IsAwesome"; + const string customAttributeName1 = "FavouriteSeason"; + const string customAttributeName2 = "LovesPets"; // Get the complete name of the custom attribute (Azure AD extension) Helpers.B2cCustomAttributeHelper helper = new Helpers.B2cCustomAttributeHelper(b2cExtensionAppClientId); - string favouriteSportAttributeName = helper.GetCompleteAttributeName(favouriteSport); - string isAwesomeAttributeName = helper.GetCompleteAttributeName(isAwesome); + string favouriteSeasonAttributeName = helper.GetCompleteAttributeName(customAttributeName1); + string lovesPetsAttributeName = helper.GetCompleteAttributeName(customAttributeName2); - Console.WriteLine($"Getting list of users with the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean)"); + Console.WriteLine($"Getting list of users with the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean)"); // Get all users (one page) var result = await graphClient.Users .Request() - .Select($"id,displayName,identities,{favouriteSportAttributeName},{isAwesomeAttributeName}") + .Select($"id,displayName,identities,{favouriteSeasonAttributeName},{lovesPetsAttributeName}") .GetAsync(); foreach (var user in result.CurrentPage) @@ -245,20 +245,20 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC } // Declare the names of the custom attributes - const string favouriteSport = "FavouriteSport"; - const string isAwesome = "IsAwesome"; + const string customAttributeName1 = "FavouriteSeason"; + const string customAttributeName2 = "LovesPets"; // Get the complete name of the custom attribute (Azure AD extension) Helpers.B2cCustomAttributeHelper helper = new Helpers.B2cCustomAttributeHelper(b2cExtensionAppClientId); - string favouriteSportAttributeName = helper.GetCompleteAttributeName(favouriteSport); - string isAwesomeAttributeName = helper.GetCompleteAttributeName(isAwesome); + string favouriteSeasonAttributeName = helper.GetCompleteAttributeName(customAttributeName1); + string lovesPetsAttributeName = helper.GetCompleteAttributeName(customAttributeName2); - Console.WriteLine($"Create a user with the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean)"); + Console.WriteLine($"Create a user with the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean)"); // Fill custom attributes IDictionary extensionInstance = new Dictionary(); - extensionInstance.Add(favouriteSportAttributeName, "Basketball"); - extensionInstance.Add(isAwesomeAttributeName, true); + extensionInstance.Add(favouriteSeasonAttributeName, "summer"); + extensionInstance.Add(lovesPetsAttributeName, true); try { @@ -294,15 +294,15 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC // Get created user by object ID result = await graphClient.Users[userId] .Request() - .Select($"id,givenName,surName,displayName,identities,{favouriteSportAttributeName},{isAwesomeAttributeName}") + .Select($"id,givenName,surName,displayName,identities,{favouriteSeasonAttributeName},{lovesPetsAttributeName}") .GetAsync(); if (result != null) { Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine($"DisplayName: {result.DisplayName}"); - Console.WriteLine($"{favouriteSport}: {result.AdditionalData[favouriteSportAttributeName].ToString()}"); - Console.WriteLine($"{isAwesome}: {result.AdditionalData[isAwesomeAttributeName].ToString()}"); + Console.WriteLine($"{customAttributeName1}: {result.AdditionalData[favouriteSeasonAttributeName].ToString()}"); + Console.WriteLine($"{customAttributeName2}: {result.AdditionalData[lovesPetsAttributeName].ToString()}"); Console.WriteLine(); Console.ResetColor(); Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented)); @@ -313,7 +313,7 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC if (ex.StatusCode == System.Net.HttpStatusCode.BadRequest) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"Have you created the custom attributes '{favouriteSport}' (string) and '{isAwesome}' (boolean) in your tenant?"); + Console.WriteLine($"Have you created the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean) in your tenant?"); Console.WriteLine(); Console.WriteLine(ex.Message); Console.ResetColor(); From 32e7c3012c294be733287076e666240847544d19 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 15:57:00 +0100 Subject: [PATCH 12/15] Update readme --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6727a1b..3ff8e7f 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,11 @@ The code in this sample backs the [Manage Azure AD B2C user accounts with Micros ## Setup 1. Clone the repo or download and extract the [ZIP archive](https://github.com/Azure-Samples/ms-identity-dotnetcore-b2c-account-management/archive/master.zip) -1. Modify `./src/appsettings.json` with values appropriate for your environment: +2. Modify `./src/appsettings.json` with values appropriate for your environment: - Azure AD B2C **tenant ID** - Registered application's **Application (client) ID** - Registered application's **Client secret** -1. Build the application with `dotnet build`: +3. Build the application with `dotnet build`: ```console azureuser@machine:~/ms-identity-dotnetcore-b2c-account-management$ cd src @@ -61,6 +61,10 @@ The code in this sample backs the [Manage Azure AD B2C user accounts with Micros Time Elapsed 00:00:02.62 ``` +4. Add 2 custom attributes to your B2C instance in order to run all the sample operations with custom attributes involved. + Attributes to add: + - FavouriteSeason (string) + - LovesPets (boolean) ## Running the sample @@ -79,6 +83,8 @@ Command Description [4] Delete user by object ID [5] Update user password [6] Create users (bulk import) +[7] Create user with custom attributes and show result +[8] Get all users (one page) with custom attributes [help] Show available commands [exit] Exit the program ------------------------- From 0decf7340f61e0804d561478c63306326fd0bc08 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 16:07:36 +0100 Subject: [PATCH 13/15] Rename email --- src/Services/UserService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Services/UserService.cs b/src/Services/UserService.cs index 553d997..9aa1162 100644 --- a/src/Services/UserService.cs +++ b/src/Services/UserService.cs @@ -50,6 +50,7 @@ public static async Task ListUsersWithCustomAttribute(GraphServiceClient graphCl string lovesPetsAttributeName = helper.GetCompleteAttributeName(customAttributeName2); Console.WriteLine($"Getting list of users with the custom attributes '{customAttributeName1}' (string) and '{customAttributeName2}' (boolean)"); + Console.WriteLine(); // Get all users (one page) var result = await graphClient.Users @@ -276,7 +277,7 @@ public static async Task CreateUserWithCustomAttribute(GraphServiceClient graphC { SignInType = "emailAddress", Issuer = tenantId, - IssuerAssignedId = "kobe.bryant@example.com" + IssuerAssignedId = "casey.jensen@example.com" } }, PasswordProfile = new PasswordProfile() From b20718598f4d55c7b3d8bf60a05541bf4be26a27 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 16:09:06 +0100 Subject: [PATCH 14/15] Upgrade project to latest version of core and nuget packages --- src/b2c-ms-graph.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/b2c-ms-graph.csproj b/src/b2c-ms-graph.csproj index 2c0274a..c0e2b9a 100644 --- a/src/b2c-ms-graph.csproj +++ b/src/b2c-ms-graph.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.0 + netcoreapp3.1 b2c_ms_graph @@ -13,7 +13,7 @@ - + From 48fc307b72688040b6a1e14954899ad65ec6d5a2 Mon Sep 17 00:00:00 2001 From: Ralph Jansen Date: Tue, 10 Mar 2020 16:42:19 +0100 Subject: [PATCH 15/15] Remove solution because is just added in another PR --- src/b2c-ms-graph.sln | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/b2c-ms-graph.sln diff --git a/src/b2c-ms-graph.sln b/src/b2c-ms-graph.sln deleted file mode 100644 index eb017f2..0000000 --- a/src/b2c-ms-graph.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29806.167 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "b2c-ms-graph", "b2c-ms-graph.csproj", "{9AA1B89E-B2D7-4391-803B-1654F96379A5}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9AA1B89E-B2D7-4391-803B-1654F96379A5}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FDF38FBE-8929-4734-903C-AB429F42D7BA} - EndGlobalSection -EndGlobal