From c201fba4c4085ae574d06e2aa91e8d546e008ff1 Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Tue, 12 Jul 2022 10:53:34 -0700 Subject: [PATCH 1/9] Change logging --- .../Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs index 88b5d6845..e57c2207a 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs @@ -42,7 +42,7 @@ public class AppProvisioningTool : IMsAADTool private ProjectDescriptionReader? _projectDescriptionReader; private ProjectDescriptionReader ProjectDescriptionReader => _projectDescriptionReader ??= new ProjectDescriptionReader(FilePaths); - public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = false) // TODO silent is temporary + public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = true) // TODO silent is temporary { CommandName = commandName; ProvisioningToolOptions = provisioningToolOptions; @@ -304,7 +304,6 @@ private async Task UpdateAppRegistration(TokenCredential tokenCredential, Applic output.Append(jsonResponse.Output); var response = new JsonResponse(CommandName, jsonResponse.State, output: output.ToString()); - ConsoleLogger.LogJsonMessage(response); } /// From ecbb3cd2bae45c986304050553c68cad101fe129 Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Thu, 21 Jul 2022 14:21:15 -0700 Subject: [PATCH 2/9] Console logging updates --- .../Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs index e57c2207a..3f44844e8 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs @@ -42,7 +42,7 @@ public class AppProvisioningTool : IMsAADTool private ProjectDescriptionReader? _projectDescriptionReader; private ProjectDescriptionReader ProjectDescriptionReader => _projectDescriptionReader ??= new ProjectDescriptionReader(FilePaths); - public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = true) // TODO silent is temporary + public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = false) // TODO silent is temporary { CommandName = commandName; ProvisioningToolOptions = provisioningToolOptions; From 6074424a51753b80183cd95483dd950333bb3674 Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Thu, 21 Jul 2022 15:39:48 -0700 Subject: [PATCH 3/9] B2C Updates --- .../AzureAdProperties.cs | 52 +++- .../AppSettingsModifier.cs | 3 +- .../AppProvisioningToolTests.cs | 280 +++++++++++++++++- 3 files changed, 324 insertions(+), 11 deletions(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs index 83a5ce91f..91dc78c2d 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs @@ -18,6 +18,7 @@ public class PropertyNames public const string BaseUrl = nameof(BaseUrl); public const string Scopes = nameof(Scopes); + public const string SignUpSignInPolicyId = nameof(SignUpSignInPolicyId); } // getting default properties from @@ -29,9 +30,11 @@ public static class DefaultProperties public const string ClientId = "11111111-1111-1111-11111111111111111"; public const string Instance = "https://login.microsoftonline.com/"; public const string CallbackPath = "/signin-oidc"; + public const string SignUpSignInPolicyId = "b2c_1_susi"; public const string ClientSecret = "Client secret from app-registration. Check user secrets/azure portal."; - public const string Authority = "https://login.microsoftonline.com/22222222-2222-2222-2222-222222222222"; + public const string Authority = Instance + TenantId; + public const string B2CAuthority = Authority + "/" + SignUpSignInPolicyId; public const bool ValidateAuthority = true; public const string MicrosoftGraphBaseUrl = "https://graph.microsoft.com/v1.0"; @@ -43,6 +46,7 @@ public class AzureAdBlock { public bool IsBlazorWasm; public bool IsWebApi; + public bool IsB2C; public string? ClientId; public string? Instance = DefaultProperties.Instance; @@ -50,6 +54,10 @@ public class AzureAdBlock public string? TenantId; public string? Authority; public string? CallbackPath = DefaultProperties.CallbackPath; + public string? SignUpSignInPolicyId = DefaultProperties.SignUpSignInPolicyId; + public string? ResetPasswordPolicyId = "b2c_1_reset"; // TODO constants + public string? EditProfilePolicyId = "b2c_1_edit_profile"; + public string? SignedOutCallbackPath = "/signout/B2C_1_susi"; public string? Scopes; @@ -60,6 +68,7 @@ public AzureAdBlock(ApplicationParameters applicationParameters) { IsBlazorWasm = applicationParameters.IsBlazorWasm; IsWebApi = applicationParameters.IsWebApi.GetValueOrDefault(); + IsB2C = applicationParameters.IsB2C; Domain = !string.IsNullOrEmpty(applicationParameters.Domain) ? applicationParameters.Domain : null; TenantId = !string.IsNullOrEmpty(applicationParameters.TenantId) ? applicationParameters.TenantId : null; @@ -68,6 +77,7 @@ public AzureAdBlock(ApplicationParameters applicationParameters) Authority = !string.IsNullOrEmpty(applicationParameters.Authority) ? applicationParameters.Authority : null; CallbackPath = !string.IsNullOrEmpty(applicationParameters.CallbackPath) ? applicationParameters.CallbackPath : null; Scopes = !string.IsNullOrEmpty(applicationParameters.CalledApiScopes) ? applicationParameters.CalledApiScopes : null; + SignUpSignInPolicyId = !string.IsNullOrEmpty(applicationParameters.SusiPolicy) ? applicationParameters.SusiPolicy : null; } /// @@ -85,6 +95,7 @@ public AzureAdBlock UpdateFromJToken(JToken azureAdToken) Authority ??= azureAdObj.GetValue(PropertyNames.Authority)?.ToString(); CallbackPath ??= azureAdObj.GetValue(PropertyNames.CallbackPath)?.ToString(); Scopes ??= azureAdObj.GetValue(PropertyNames.Scopes)?.ToString(); + SignUpSignInPolicyId ??= azureAdObj.GetValue(PropertyNames.SignUpSignInPolicyId)?.ToString(); ClientSecret ??= azureAdObj.GetValue(PropertyNames.ClientSecret)?.ToString(); ClientCertificates ??= azureAdObj.GetValue(PropertyNames.ClientCertificates)?.ToObject(); @@ -94,17 +105,32 @@ public AzureAdBlock UpdateFromJToken(JToken azureAdToken) public dynamic BlazorSettings => new { ClientId = ClientId ?? DefaultProperties.ClientId, // here, if a value is null, we could use the default properties - Authority = Authority ?? (string.IsNullOrEmpty(Instance) || string.IsNullOrEmpty(TenantId) ? DefaultProperties.Authority : $"{Instance}{TenantId}"), - ValidateAuthority = true + Authority = GetAuthority(), + ValidateAuthority = !IsB2C }; + internal string GetAuthority() + { + string authority; + if (string.IsNullOrEmpty(Instance) || string.IsNullOrEmpty(TenantId)) + { + authority = IsB2C ? DefaultProperties.B2CAuthority : DefaultProperties.Authority; + } + else + { + authority = IsB2C ? $"{Instance}{TenantId}/{SignUpSignInPolicyId}" : $"{Instance}{TenantId}"; + } + + return authority; + } + public dynamic WebAppSettings => new { Instance = Instance ?? DefaultProperties.Instance, Domain = Domain ?? DefaultProperties.Domain, TenantId = TenantId ?? DefaultProperties.TenantId, ClientId = ClientId ?? DefaultProperties.ClientId, - CallbackPath = CallbackPath ?? DefaultProperties.CallbackPath + CallbackPath = CallbackPath ?? DefaultProperties.CallbackPath, }; public dynamic WebApiSettings => new @@ -119,18 +145,30 @@ public AzureAdBlock UpdateFromJToken(JToken azureAdToken) ClientCertificates = ClientCertificates ?? Array.Empty() }; + public dynamic B2CSettings => new + { + SignUpSignInPolicyId, + SignedOutCallbackPath, + ResetPasswordPolicyId, + EditProfilePolicyId, + EnablePiiLogging = true + }; + public JObject ToJObject() { if (IsBlazorWasm) { return JObject.FromObject(BlazorSettings); } - if (IsWebApi) + + var jObject = IsWebApi ? JObject.FromObject(WebApiSettings) : JObject.FromObject(WebAppSettings); + + if (IsB2C) // Add B2C appsettings properties { - return JObject.FromObject(WebApiSettings); + jObject = jObject.Merge(JObject.FromObject(B2CSettings)); } - return JObject.FromObject(WebAppSettings); + return jObject; } } diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs index eb2222938..a03f6a73b 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using Microsoft.DotNet.MSIdentity.AuthenticationParameters; @@ -61,7 +62,7 @@ public void ModifyAppSettings(ApplicationParameters applicationParameters, IEnum { appSettings = new JObject(); } - + Debugger.Launch(); var modifiedAppSettings = GetModifiedAppSettings(appSettings, applicationParameters); // TODO: save comments somehow, only write to appsettings.json if changes are made diff --git a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs index 6761be9c5..5528d435f 100644 --- a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs +++ b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs @@ -12,12 +12,14 @@ public class AppProvisioningToolTests const string existingClientId = "existing client Id"; const string existingInstance = "existing Instance"; const string existingCallbackPath = "existing Callback Path"; + const string existingSusi = "existing_signup_policy"; const string inputDomain = "input domain"; - const string inputTenantId = "input tenant Id"; - const string inputClientId = "input client Id"; + const string inputTenantId = "input_tenant_Id"; + const string inputClientId = "input_client_Id"; const string inputInstance = "http://inputInstance/"; const string inputCallbackPath = "input Callback Path"; + const string inputSusi = "input_signup_policy"; // TODO test input for susi for blazor and webapp [Fact] public void ModifyAppSettings_NoInput_DefaultOutput() @@ -39,6 +41,27 @@ public void ModifyAppSettings_NoInput_DefaultOutput() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_NoInput_DefaultOutput_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject(); + var parameters = new AuthenticationParameters.ApplicationParameters { IsB2C = true }; + + var expected = JToken.FromObject(new + { + DefaultProperties.Domain, + DefaultProperties.TenantId, + DefaultProperties.ClientId, + DefaultProperties.Instance, + DefaultProperties.CallbackPath, + DefaultProperties.SignUpSignInPolicyId + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_NoInput_Blazor_DefaultOutput() { @@ -57,6 +80,24 @@ public void ModifyAppSettings_NoInput_Blazor_DefaultOutput() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_NoInput_BlazorB2C_DefaultOutput() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject(); + var parameters = new AuthenticationParameters.ApplicationParameters { IsBlazorWasm = true, IsB2C = true }; + + var expected = JObject.FromObject(new + { + Authority = DefaultProperties.B2CAuthority, + DefaultProperties.ClientId, + ValidateAuthority = false + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_HasInput_NoExistingProperties() { @@ -85,6 +126,35 @@ public void ModifyAppSettings_HasInput_NoExistingProperties() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_HasInput_NoExistingProperties_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject(); + + var expected = JObject.FromObject(new + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = inputInstance, + CallbackPath = inputCallbackPath + }); + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = inputInstance, + CallbackPath = inputCallbackPath, + IsB2C = true + }; + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults() { @@ -122,6 +192,44 @@ public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject + { + { + "AzureAd", + JToken.FromObject(new + { + Domain = existingDomain, + TenantId = existingTenantId, + ClientId = existingClientId + }) + } + }; + + var expected = JObject.FromObject(new + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = DefaultProperties.Instance, + CallbackPath = DefaultProperties.CallbackPath + }); + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + IsB2C = true + }; + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer() { @@ -163,6 +271,51 @@ public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject + { + { + "AzureAd", + JToken.FromObject(new + { + Domain = existingDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath, + SignUpSignInPolicyId = existingSusi + }) + } + }; + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = inputInstance, + CallbackPath = inputCallbackPath, + SusiPolicy = inputSusi, + IsB2C = true + }; + + var expected = JObject.FromObject(new + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = inputInstance, + CallbackPath = inputCallbackPath, + SignUpSignInPolicyId = inputSusi + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer() { @@ -201,6 +354,45 @@ public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer() Assert.True(JToken.DeepEquals(expected, modifications)); } + [Fact] + public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + + var appSettings = new Newtonsoft.Json.Linq.JObject + { + { + "AzureAd", + JToken.FromObject(new + { + Domain = existingDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath + }) + } + }; + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + IsB2C = true + }; + + var expected = JObject.FromObject(new + { + Domain = inputDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Fact] public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModified() { @@ -224,7 +416,47 @@ public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModifi { Domain = inputDomain, TenantId = "", - ClientId = "" + ClientId = "", + }; + + var expected = JObject.FromObject(new + { + Domain = inputDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + + [Fact] + public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModified_B2C() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject + { + { + "AzureAd", + JToken.FromObject(new + { + Domain = existingDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath + }) + } + }; + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + TenantId = "", + ClientId = "", + IsB2C = true }; var expected = JObject.FromObject(new @@ -280,6 +512,48 @@ public void ModifyAppSettings_BlazorWasm_AuthorityIsCorrect() Assert.True(JToken.DeepEquals(expected, modifications)); } + + [Fact] + public void ModifyAppSettings_BlazorWasmB2C_AuthorityIsCorrect() + { + var modifier = new AppSettingsModifier(new Tool.ProvisioningToolOptions()); + var appSettings = new Newtonsoft.Json.Linq.JObject + { + { + "AzureAd", + JToken.FromObject(new + { + Domain = existingDomain, + TenantId = existingTenantId, + ClientId = existingClientId, + Instance = existingInstance, + CallbackPath = existingCallbackPath, + SignUpSignInPolicyId = existingSusi + }) + } + }; + + var parameters = new AuthenticationParameters.ApplicationParameters + { + Domain = inputDomain, + TenantId = inputTenantId, + ClientId = inputClientId, + Instance = inputInstance, + IsBlazorWasm = true, + IsB2C = true + }; + + var expected = JObject.FromObject(new + { + ClientId = inputClientId, + Authority = $"{inputInstance}{inputTenantId}/{existingSusi}", + ValidateAuthority = false + }); + + (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); + } + [Theory] [InlineData(PropertyNames.Domain, "", "newValue", "newValue")] [InlineData(PropertyNames.Domain, "ExistingDomain", "", null)] From 3a7196fbade41bc47cce98147dc48932be2ed9cc Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Mon, 25 Jul 2022 13:34:56 -0700 Subject: [PATCH 4/9] Refactor and fix tests --- .../AzureAdProperties.cs | 98 +++++++------------ .../AppSettingsModifier.cs | 30 +++--- .../AppProvisioningToolTests.cs | 49 +++++++--- 3 files changed, 84 insertions(+), 93 deletions(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs index 91dc78c2d..f837ba748 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs @@ -3,7 +3,7 @@ namespace Microsoft.DotNet.MSIdentity.AuthenticationParameters { - public class PropertyNames + public static class PropertyNames { public const string Domain = nameof(Domain); public const string TenantId = nameof(TenantId); @@ -12,13 +12,14 @@ public class PropertyNames public const string ClientCertificates = nameof(ClientCertificates); public const string CallbackPath = nameof(CallbackPath); public const string Instance = nameof(Instance); - public const string Authority = nameof(Authority); public const string ValidateAuthority = nameof(ValidateAuthority); - public const string BaseUrl = nameof(BaseUrl); public const string Scopes = nameof(Scopes); public const string SignUpSignInPolicyId = nameof(SignUpSignInPolicyId); + public const string ResetPasswordPolicyId = nameof(ResetPasswordPolicyId); + public const string EditProfilePolicyId = nameof(EditProfilePolicyId); + public const string SignedOutCallbackPath = nameof(SignedOutCallbackPath); } // getting default properties from @@ -30,13 +31,15 @@ public static class DefaultProperties public const string ClientId = "11111111-1111-1111-11111111111111111"; public const string Instance = "https://login.microsoftonline.com/"; public const string CallbackPath = "/signin-oidc"; - public const string SignUpSignInPolicyId = "b2c_1_susi"; public const string ClientSecret = "Client secret from app-registration. Check user secrets/azure portal."; - - public const string Authority = Instance + TenantId; - public const string B2CAuthority = Authority + "/" + SignUpSignInPolicyId; public const bool ValidateAuthority = true; + // B2C properties + public const string SignUpSignInPolicyId = "b2c_1_susi"; + public const string ResetPasswordPolicyId = "b2c_1_reset"; + public const string EditProfilePolicyId = "b2c_1_edit_profile"; + public const string SignedOutCallbackPath = "/signout/B2C_1_susi"; + public const string MicrosoftGraphBaseUrl = "https://graph.microsoft.com/v1.0"; public const string MicrosoftGraphScopes = "user.read"; public const string ApiScopes = "access_as_user"; @@ -55,75 +58,42 @@ public class AzureAdBlock public string? Authority; public string? CallbackPath = DefaultProperties.CallbackPath; public string? SignUpSignInPolicyId = DefaultProperties.SignUpSignInPolicyId; - public string? ResetPasswordPolicyId = "b2c_1_reset"; // TODO constants - public string? EditProfilePolicyId = "b2c_1_edit_profile"; - public string? SignedOutCallbackPath = "/signout/B2C_1_susi"; + public string? ResetPasswordPolicyId = DefaultProperties.ResetPasswordPolicyId; + public string? EditProfilePolicyId = DefaultProperties.EditProfilePolicyId; + public string? SignedOutCallbackPath = DefaultProperties.SignedOutCallbackPath; public string? Scopes; - public string? ClientSecret = DefaultProperties.ClientSecret; + public string? ClientSecret; public string[]? ClientCertificates; - public AzureAdBlock(ApplicationParameters applicationParameters) + public AzureAdBlock(ApplicationParameters applicationParameters, JObject? existingBlock = null) { IsBlazorWasm = applicationParameters.IsBlazorWasm; IsWebApi = applicationParameters.IsWebApi.GetValueOrDefault(); IsB2C = applicationParameters.IsB2C; - Domain = !string.IsNullOrEmpty(applicationParameters.Domain) ? applicationParameters.Domain : null; - TenantId = !string.IsNullOrEmpty(applicationParameters.TenantId) ? applicationParameters.TenantId : null; - ClientId = !string.IsNullOrEmpty(applicationParameters.ClientId) ? applicationParameters.ClientId : null; - Instance = !string.IsNullOrEmpty(applicationParameters.Instance) ? applicationParameters.Instance : null; - Authority = !string.IsNullOrEmpty(applicationParameters.Authority) ? applicationParameters.Authority : null; - CallbackPath = !string.IsNullOrEmpty(applicationParameters.CallbackPath) ? applicationParameters.CallbackPath : null; - Scopes = !string.IsNullOrEmpty(applicationParameters.CalledApiScopes) ? applicationParameters.CalledApiScopes : null; - SignUpSignInPolicyId = !string.IsNullOrEmpty(applicationParameters.SusiPolicy) ? applicationParameters.SusiPolicy : null; - } - - /// - /// Updates AzureAdBlock object from existing appSettings.json - /// - /// - public AzureAdBlock UpdateFromJToken(JToken azureAdToken) - { - JObject azureAdObj = JObject.FromObject(azureAdToken); - - ClientId ??= azureAdObj.GetValue(PropertyNames.ClientId)?.ToString(); // here, if the applicationparameters value is null, we use the existing app settings value - Instance ??= azureAdObj.GetValue(PropertyNames.Instance)?.ToString(); - Domain ??= azureAdObj.GetValue(PropertyNames.Domain)?.ToString(); - TenantId ??= azureAdObj.GetValue(PropertyNames.TenantId)?.ToString(); - Authority ??= azureAdObj.GetValue(PropertyNames.Authority)?.ToString(); - CallbackPath ??= azureAdObj.GetValue(PropertyNames.CallbackPath)?.ToString(); - Scopes ??= azureAdObj.GetValue(PropertyNames.Scopes)?.ToString(); - SignUpSignInPolicyId ??= azureAdObj.GetValue(PropertyNames.SignUpSignInPolicyId)?.ToString(); - ClientSecret ??= azureAdObj.GetValue(PropertyNames.ClientSecret)?.ToString(); - ClientCertificates ??= azureAdObj.GetValue(PropertyNames.ClientCertificates)?.ToObject(); - - return this; + Domain = !string.IsNullOrEmpty(applicationParameters.Domain) ? applicationParameters.Domain : existingBlock?.GetValue(PropertyNames.Domain)?.ToString() ?? DefaultProperties.Domain; + TenantId = !string.IsNullOrEmpty(applicationParameters.TenantId) ? applicationParameters.TenantId : existingBlock?.GetValue(PropertyNames.TenantId)?.ToString() ?? DefaultProperties.TenantId; + ClientId = !string.IsNullOrEmpty(applicationParameters.ClientId) ? applicationParameters.ClientId : existingBlock?.GetValue(PropertyNames.ClientId)?.ToString() ?? DefaultProperties.ClientId; + Instance = !string.IsNullOrEmpty(applicationParameters.Instance) ? applicationParameters.Instance : existingBlock?.GetValue(PropertyNames.Instance)?.ToString() ?? DefaultProperties.Instance; + CallbackPath = !string.IsNullOrEmpty(applicationParameters.CallbackPath) ? applicationParameters.CallbackPath : existingBlock?.GetValue(PropertyNames.CallbackPath)?.ToString() ?? DefaultProperties.CallbackPath; + Authority = !string.IsNullOrEmpty(applicationParameters.Authority) ? applicationParameters.Authority : existingBlock?.GetValue(PropertyNames.Authority)?.ToString(); + Scopes = !string.IsNullOrEmpty(applicationParameters.CalledApiScopes) ? applicationParameters.CalledApiScopes : existingBlock?.GetValue(PropertyNames.Scopes)?.ToString() + ?? (applicationParameters.CallsDownstreamApi ? DefaultProperties.ApiScopes : applicationParameters.CallsMicrosoftGraph ? DefaultProperties.MicrosoftGraphScopes : null); + SignUpSignInPolicyId = !string.IsNullOrEmpty(applicationParameters.SusiPolicy) ? applicationParameters.SusiPolicy : existingBlock?.GetValue(PropertyNames.SignUpSignInPolicyId)?.ToString() ?? DefaultProperties.SignUpSignInPolicyId; + + ClientSecret = existingBlock?.GetValue(PropertyNames.ClientSecret)?.ToString() ?? DefaultProperties.ClientSecret; + ClientCertificates = existingBlock?.GetValue(PropertyNames.ClientCertificates)?.ToObject(); } public dynamic BlazorSettings => new { ClientId = ClientId ?? DefaultProperties.ClientId, // here, if a value is null, we could use the default properties - Authority = GetAuthority(), + Authority = Authority ?? (IsB2C ? $"{Instance}{TenantId}/{SignUpSignInPolicyId}" : $"{Instance}{TenantId}"), ValidateAuthority = !IsB2C }; - internal string GetAuthority() - { - string authority; - if (string.IsNullOrEmpty(Instance) || string.IsNullOrEmpty(TenantId)) - { - authority = IsB2C ? DefaultProperties.B2CAuthority : DefaultProperties.Authority; - } - else - { - authority = IsB2C ? $"{Instance}{TenantId}/{SignUpSignInPolicyId}" : $"{Instance}{TenantId}"; - } - - return authority; - } - public dynamic WebAppSettings => new { Instance = Instance ?? DefaultProperties.Instance, @@ -147,10 +117,10 @@ internal string GetAuthority() public dynamic B2CSettings => new { - SignUpSignInPolicyId, - SignedOutCallbackPath, - ResetPasswordPolicyId, - EditProfilePolicyId, + SignUpSignInPolicyId = SignUpSignInPolicyId ?? DefaultProperties.SignUpSignInPolicyId, + SignedOutCallbackPath = SignedOutCallbackPath ?? DefaultProperties.SignedOutCallbackPath, + ResetPasswordPolicyId = ResetPasswordPolicyId ?? DefaultProperties.ResetPasswordPolicyId, + EditProfilePolicyId = EditProfilePolicyId ?? DefaultProperties.EditProfilePolicyId, EnablePiiLogging = true }; @@ -163,9 +133,9 @@ public JObject ToJObject() var jObject = IsWebApi ? JObject.FromObject(WebApiSettings) : JObject.FromObject(WebAppSettings); - if (IsB2C) // Add B2C appsettings properties + if (IsB2C) { - jObject = jObject.Merge(JObject.FromObject(B2CSettings)); + jObject.Merge(JObject.FromObject(B2CSettings)); } return jObject; diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs index a03f6a73b..9090ab987 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using Microsoft.DotNet.MSIdentity.AuthenticationParameters; @@ -62,7 +61,7 @@ public void ModifyAppSettings(ApplicationParameters applicationParameters, IEnum { appSettings = new JObject(); } - Debugger.Launch(); + var modifiedAppSettings = GetModifiedAppSettings(appSettings, applicationParameters); // TODO: save comments somehow, only write to appsettings.json if changes are made @@ -135,32 +134,27 @@ public void ModifyAppSettings(ApplicationParameters applicationParameters, IEnum /// (bool changesMade, JObject? updatedBlock) internal (bool changesMade, JObject? updatedBlock) GetModifiedAzureAdBlock(JObject appSettings, ApplicationParameters applicationParameters) { - var azureAdBlock = new AzureAdBlock(applicationParameters); - if (!appSettings.TryGetValue("AzureAd", out var azureAdToken)) + var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test AzureAdB2C + if (azAdToken is null) { - // Create and return AzureAd block if none exists, differs for Blazor apps - return (true, azureAdBlock.ToJObject()); + return (true, new AzureAdBlock(applicationParameters).ToJObject()); } - var existingBlock = JObject.FromObject(azureAdToken); - var updatedBlock = azureAdBlock.UpdateFromJToken(azureAdToken).ToJObject(); - if (NeedsUpdate(existingBlock, updatedBlock)) - { - return (true, updatedBlock); - } + var existingParameters = JObject.FromObject(azAdToken); + var newBlock = new AzureAdBlock(applicationParameters, existingParameters).ToJObject(); - return (false, null); // If no changes were made, return null + return (NeedsUpdate(existingParameters, newBlock), newBlock); } /// /// Checks all keys in updatedBlock, if any differ from existingBlock then update is necessary /// /// - /// + /// /// - internal bool NeedsUpdate(JObject existingBlock, JObject updatedBlock) + internal static bool NeedsUpdate(JObject existingBlock, JObject newBlock) { - foreach ((var key, var updatedValue) in updatedBlock) + foreach ((var key, var updatedValue) in newBlock) { if (existingBlock.GetValue(key) != updatedValue) { @@ -171,7 +165,7 @@ internal bool NeedsUpdate(JObject existingBlock, JObject updatedBlock) return false; } - private JObject? GetApiBlock(JObject appSettings, string key, string? scopes, string? baseUrl) + internal static JObject? GetApiBlock(JObject appSettings, string key, string? scopes, string? baseUrl) { var inputParameters = JObject.FromObject(new ApiSettingsBlock { @@ -190,7 +184,7 @@ internal bool NeedsUpdate(JObject existingBlock, JObject updatedBlock) return inputParameters; } - private bool ModifyAppSettingsObject(JObject existingSettings, JObject inputProperties) + internal static bool ModifyAppSettingsObject(JObject existingSettings, JObject inputProperties) { bool changesMade = false; foreach ((var propertyName, var newValue) in inputProperties) diff --git a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs index 5528d435f..baa318f06 100644 --- a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs +++ b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs @@ -55,7 +55,11 @@ public void ModifyAppSettings_NoInput_DefaultOutput_B2C() DefaultProperties.ClientId, DefaultProperties.Instance, DefaultProperties.CallbackPath, - DefaultProperties.SignUpSignInPolicyId + DefaultProperties.SignUpSignInPolicyId, + DefaultProperties.SignedOutCallbackPath, + DefaultProperties.ResetPasswordPolicyId, + DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true }); (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); @@ -71,7 +75,7 @@ public void ModifyAppSettings_NoInput_Blazor_DefaultOutput() var expected = JObject.FromObject(new { - DefaultProperties.Authority, + Authority = $"{DefaultProperties.Instance}{DefaultProperties.TenantId}", DefaultProperties.ClientId, DefaultProperties.ValidateAuthority }); @@ -89,7 +93,7 @@ public void ModifyAppSettings_NoInput_BlazorB2C_DefaultOutput() var expected = JObject.FromObject(new { - Authority = DefaultProperties.B2CAuthority, + Authority = $"{DefaultProperties.Instance}{DefaultProperties.TenantId}/{DefaultProperties.SignUpSignInPolicyId}", DefaultProperties.ClientId, ValidateAuthority = false }); @@ -138,7 +142,12 @@ public void ModifyAppSettings_HasInput_NoExistingProperties_B2C() TenantId = inputTenantId, ClientId = inputClientId, Instance = inputInstance, - CallbackPath = inputCallbackPath + CallbackPath = inputCallbackPath, + DefaultProperties.SignUpSignInPolicyId, + DefaultProperties.SignedOutCallbackPath, + DefaultProperties.ResetPasswordPolicyId, + DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true }); var parameters = new AuthenticationParameters.ApplicationParameters @@ -215,7 +224,12 @@ public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults_B2C( TenantId = inputTenantId, ClientId = inputClientId, Instance = DefaultProperties.Instance, - CallbackPath = DefaultProperties.CallbackPath + CallbackPath = DefaultProperties.CallbackPath, + DefaultProperties.SignUpSignInPolicyId, + DefaultProperties.SignedOutCallbackPath, + DefaultProperties.ResetPasswordPolicyId, + DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true }); var parameters = new AuthenticationParameters.ApplicationParameters @@ -309,10 +323,15 @@ public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer_B2C ClientId = inputClientId, Instance = inputInstance, CallbackPath = inputCallbackPath, - SignUpSignInPolicyId = inputSusi - }); + SignUpSignInPolicyId = inputSusi, + SignedOutCallbackPath = DefaultProperties.SignedOutCallbackPath, + ResetPasswordPolicyId = DefaultProperties.ResetPasswordPolicyId, + EditProfilePolicyId = DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true + }); (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -386,7 +405,12 @@ public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer_B2 TenantId = existingTenantId, ClientId = existingClientId, Instance = existingInstance, - CallbackPath = existingCallbackPath + CallbackPath = existingCallbackPath, + DefaultProperties.SignUpSignInPolicyId, + DefaultProperties.SignedOutCallbackPath, + DefaultProperties.ResetPasswordPolicyId, + DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true }); (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); @@ -465,14 +489,18 @@ public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModifi TenantId = existingTenantId, ClientId = existingClientId, Instance = existingInstance, - CallbackPath = existingCallbackPath + CallbackPath = existingCallbackPath, + DefaultProperties.SignUpSignInPolicyId, + DefaultProperties.SignedOutCallbackPath, + DefaultProperties.ResetPasswordPolicyId, + DefaultProperties.EditProfilePolicyId, + EnablePiiLogging = true }); (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } - [Fact] public void ModifyAppSettings_BlazorWasm_AuthorityIsCorrect() { @@ -512,7 +540,6 @@ public void ModifyAppSettings_BlazorWasm_AuthorityIsCorrect() Assert.True(JToken.DeepEquals(expected, modifications)); } - [Fact] public void ModifyAppSettings_BlazorWasmB2C_AuthorityIsCorrect() { From 985c025736bf76e51945ee03c8c558a86b87c62f Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Wed, 27 Jul 2022 14:22:53 -0700 Subject: [PATCH 5/9] Refactors --- ...ework,Version=v4.7.2.AssemblyAttributes.cs | 4 ++ .../AzureAdProperties.cs | 2 +- .../AppSettingsModifier.cs | 4 +- ...osoftIdentityPlatformApplicationManager.cs | 60 +++++++++++-------- .../AppProvisioningToolTests.cs | 32 +++++----- 5 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs diff --git a/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs new file mode 100644 index 000000000..3871b184d --- /dev/null +++ b/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs index f837ba748..e6f35ba43 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs @@ -100,7 +100,7 @@ public AzureAdBlock(ApplicationParameters applicationParameters, JObject? existi Domain = Domain ?? DefaultProperties.Domain, TenantId = TenantId ?? DefaultProperties.TenantId, ClientId = ClientId ?? DefaultProperties.ClientId, - CallbackPath = CallbackPath ?? DefaultProperties.CallbackPath, + CallbackPath = CallbackPath ?? DefaultProperties.CallbackPath }; public dynamic WebApiSettings => new diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs index 9090ab987..523c13a07 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs @@ -132,9 +132,9 @@ public void ModifyAppSettings(ApplicationParameters applicationParameters, IEnum /// /// /// (bool changesMade, JObject? updatedBlock) - internal (bool changesMade, JObject? updatedBlock) GetModifiedAzureAdBlock(JObject appSettings, ApplicationParameters applicationParameters) + internal static (bool changesMade, JObject? updatedBlock) GetModifiedAzureAdBlock(JObject appSettings, ApplicationParameters applicationParameters) { - var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test AzureAdB2C + var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test AzureAdB2C, make sure that blazor WASM works if (azAdToken is null) { return (true, new AzureAdBlock(applicationParameters).ToJObject()); diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs index 9c1df5cb1..298f4d1a9 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs @@ -352,32 +352,40 @@ internal static bool UpdateImplicitGrantSettings(Application app, ProvisioningTo bool needsUpdate = false; var currentSettings = app.Web.ImplicitGrantSettings; - if (toolOptions.IsBlazorWasm) // In the case of Blazor WASM, Access Tokens and Id Tokens must both be true. - { - if (currentSettings.EnableAccessTokenIssuance is true || currentSettings.EnableIdTokenIssuance is true) - { - app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = false; - app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = false; - - needsUpdate = true; - } - } - else // Otherwise we make changes only when the tool options differ from the existing settings. - { - if (toolOptions.EnableAccessToken.HasValue && - currentSettings.EnableAccessTokenIssuance != toolOptions.EnableAccessToken.Value) - { - app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = toolOptions.EnableAccessToken.Value; - needsUpdate = true; - } - - if (toolOptions.EnableIdToken.HasValue && - currentSettings.EnableIdTokenIssuance != toolOptions.EnableIdToken.Value) - { - app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = toolOptions.EnableIdToken.Value; - needsUpdate = true; - } - } + if (currentSettings.EnableAccessTokenIssuance is false || currentSettings.EnableIdTokenIssuance is false) + { + app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = true; + app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = true; + + needsUpdate = true; + } + + //if (toolOptions.IsBlazorWasm) // In the case of Blazor WASM, Access Tokens and Id Tokens must both be true. + //{ + // if (currentSettings.EnableAccessTokenIssuance is false || currentSettings.EnableIdTokenIssuance is false) + // { + // app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = true; + // app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = true; + + // needsUpdate = true; + // } + //} + //else // Otherwise we make changes only when the tool options differ from the existing settings. + //{ + // if (toolOptions.EnableAccessToken.HasValue && + // currentSettings.EnableAccessTokenIssuance != toolOptions.EnableAccessToken.Value) + // { + // app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = toolOptions.EnableAccessToken.Value; + // needsUpdate = true; + // } + + // if (toolOptions.EnableIdToken.HasValue && + // currentSettings.EnableIdTokenIssuance != toolOptions.EnableIdToken.Value) + // { + // app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = toolOptions.EnableIdToken.Value; + // needsUpdate = true; + // } + //} return needsUpdate; } diff --git a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs index baa318f06..443c3e55a 100644 --- a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs +++ b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs @@ -37,7 +37,7 @@ public void ModifyAppSettings_NoInput_DefaultOutput() DefaultProperties.CallbackPath }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -62,7 +62,7 @@ public void ModifyAppSettings_NoInput_DefaultOutput_B2C() EnablePiiLogging = true }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -80,7 +80,7 @@ public void ModifyAppSettings_NoInput_Blazor_DefaultOutput() DefaultProperties.ValidateAuthority }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -98,7 +98,7 @@ public void ModifyAppSettings_NoInput_BlazorB2C_DefaultOutput() ValidateAuthority = false }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -126,7 +126,7 @@ public void ModifyAppSettings_HasInput_NoExistingProperties() CallbackPath = inputCallbackPath }; - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -160,7 +160,7 @@ public void ModifyAppSettings_HasInput_NoExistingProperties_B2C() IsB2C = true }; - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -197,7 +197,7 @@ public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults() ClientId = inputClientId }; - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -240,7 +240,7 @@ public void ModifyAppSettings_HasInput_SomePropertiesMissing_InsertDefaults_B2C( IsB2C = true }; - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -281,7 +281,7 @@ public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer() CallbackPath = inputCallbackPath }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -330,7 +330,7 @@ public void ModifyAppSettings_HasAllInputParameters_ExistingPropertiesDiffer_B2C EnablePiiLogging = true }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -369,7 +369,7 @@ public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer() CallbackPath = existingCallbackPath }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -413,7 +413,7 @@ public void ModifyAppSettings_HasSomeInputParameters_ExistingPropertiesDiffer_B2 EnablePiiLogging = true }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -452,7 +452,7 @@ public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModifi CallbackPath = existingCallbackPath }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -497,7 +497,7 @@ public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModifi EnablePiiLogging = true }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -536,7 +536,7 @@ public void ModifyAppSettings_BlazorWasm_AuthorityIsCorrect() ValidateAuthority = true }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } @@ -577,7 +577,7 @@ public void ModifyAppSettings_BlazorWasmB2C_AuthorityIsCorrect() ValidateAuthority = false }); - (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters); + (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters); Assert.True(JToken.DeepEquals(expected, modifications)); } From 32b5633bd2d552ba75c92c6b73ecfdf91b128f1b Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Thu, 28 Jul 2022 11:38:00 -0700 Subject: [PATCH 6/9] Refactors --- .../AzureAdProperties.cs | 14 ++--- .../AppSettingsModifier.cs | 2 +- ...osoftIdentityPlatformApplicationManager.cs | 57 ++++++++----------- .../Tool/AppProvisioningTool.cs | 2 +- ...IdentityPlatformApplicationManagerTests.cs | 12 ++-- 5 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs index e6f35ba43..87d47d19f 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs @@ -52,12 +52,12 @@ public class AzureAdBlock public bool IsB2C; public string? ClientId; - public string? Instance = DefaultProperties.Instance; + public string? Instance; public string? Domain; public string? TenantId; public string? Authority; - public string? CallbackPath = DefaultProperties.CallbackPath; - public string? SignUpSignInPolicyId = DefaultProperties.SignUpSignInPolicyId; + public string? CallbackPath; + public string? SignUpSignInPolicyId; public string? ResetPasswordPolicyId = DefaultProperties.ResetPasswordPolicyId; public string? EditProfilePolicyId = DefaultProperties.EditProfilePolicyId; public string? SignedOutCallbackPath = DefaultProperties.SignedOutCallbackPath; @@ -78,19 +78,19 @@ public AzureAdBlock(ApplicationParameters applicationParameters, JObject? existi ClientId = !string.IsNullOrEmpty(applicationParameters.ClientId) ? applicationParameters.ClientId : existingBlock?.GetValue(PropertyNames.ClientId)?.ToString() ?? DefaultProperties.ClientId; Instance = !string.IsNullOrEmpty(applicationParameters.Instance) ? applicationParameters.Instance : existingBlock?.GetValue(PropertyNames.Instance)?.ToString() ?? DefaultProperties.Instance; CallbackPath = !string.IsNullOrEmpty(applicationParameters.CallbackPath) ? applicationParameters.CallbackPath : existingBlock?.GetValue(PropertyNames.CallbackPath)?.ToString() ?? DefaultProperties.CallbackPath; - Authority = !string.IsNullOrEmpty(applicationParameters.Authority) ? applicationParameters.Authority : existingBlock?.GetValue(PropertyNames.Authority)?.ToString(); Scopes = !string.IsNullOrEmpty(applicationParameters.CalledApiScopes) ? applicationParameters.CalledApiScopes : existingBlock?.GetValue(PropertyNames.Scopes)?.ToString() ?? (applicationParameters.CallsDownstreamApi ? DefaultProperties.ApiScopes : applicationParameters.CallsMicrosoftGraph ? DefaultProperties.MicrosoftGraphScopes : null); SignUpSignInPolicyId = !string.IsNullOrEmpty(applicationParameters.SusiPolicy) ? applicationParameters.SusiPolicy : existingBlock?.GetValue(PropertyNames.SignUpSignInPolicyId)?.ToString() ?? DefaultProperties.SignUpSignInPolicyId; - + // TODO determine the SusiPolicy from the graph beta + Authority = IsB2C ? $"{Instance}{TenantId}/{SignUpSignInPolicyId}" : $"{Instance}{TenantId}"; ClientSecret = existingBlock?.GetValue(PropertyNames.ClientSecret)?.ToString() ?? DefaultProperties.ClientSecret; ClientCertificates = existingBlock?.GetValue(PropertyNames.ClientCertificates)?.ToObject(); } public dynamic BlazorSettings => new { - ClientId = ClientId ?? DefaultProperties.ClientId, // here, if a value is null, we could use the default properties - Authority = Authority ?? (IsB2C ? $"{Instance}{TenantId}/{SignUpSignInPolicyId}" : $"{Instance}{TenantId}"), + ClientId, + Authority, ValidateAuthority = !IsB2C }; diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs index 523c13a07..28214ab0c 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs @@ -134,7 +134,7 @@ public void ModifyAppSettings(ApplicationParameters applicationParameters, IEnum /// (bool changesMade, JObject? updatedBlock) internal static (bool changesMade, JObject? updatedBlock) GetModifiedAzureAdBlock(JObject appSettings, ApplicationParameters applicationParameters) { - var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test AzureAdB2C, make sure that blazor WASM works + var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test "AzureAdB2C" string, make sure that blazor WASM works if (azAdToken is null) { return (true, new AzureAdBlock(applicationParameters).ToJObject()); diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs index 298f4d1a9..c79d6ad5c 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs @@ -196,7 +196,7 @@ internal async Task UpdateApplication( return new JsonResponse(commandName, State.Fail, output: string.Format(Resources.NotFound, parameters.ClientId)); } - (bool needsUpdates, Application appUpdates) = GetApplicationUpdates(remoteApp, toolOptions); + (bool needsUpdates, Application appUpdates) = GetApplicationUpdates(remoteApp, toolOptions, parameters); if (!needsUpdates) { return new JsonResponse(commandName, State.Success, output: string.Format(Resources.NoUpdateNecessary, remoteApp.DisplayName, remoteApp.AppId)); @@ -220,7 +220,10 @@ internal async Task UpdateApplication( /// /// /// Updated Application if changes were made, otherwise null - internal static (bool needsUpdate, Application appUpdates) GetApplicationUpdates(Application existingApplication, ProvisioningToolOptions toolOptions) + internal static (bool needsUpdate, Application appUpdates) GetApplicationUpdates( + Application existingApplication, + ProvisioningToolOptions toolOptions, + ApplicationParameters parameters) { bool needsUpdate = false; @@ -233,7 +236,7 @@ internal static (bool needsUpdate, Application appUpdates) GetApplicationUpdates // Make updates if necessary needsUpdate |= UpdateRedirectUris(updatedApp, toolOptions); - needsUpdate |= UpdateImplicitGrantSettings(updatedApp, toolOptions); + needsUpdate |= UpdateImplicitGrantSettings(updatedApp, toolOptions, parameters.IsB2C); if (toolOptions.IsBlazorWasmHostedServer) { needsUpdate |= PreAuthorizeBlazorWasmClientApp(existingApplication, toolOptions, updatedApp); @@ -347,45 +350,35 @@ private static string UpdateCallbackPath(string redirectUri, bool isBlazorWasm = /// /// /// true if ImplicitGrantSettings require updates, else false - internal static bool UpdateImplicitGrantSettings(Application app, ProvisioningToolOptions toolOptions) + internal static bool UpdateImplicitGrantSettings(Application app, ProvisioningToolOptions toolOptions, bool isB2C = false) { bool needsUpdate = false; var currentSettings = app.Web.ImplicitGrantSettings; - if (currentSettings.EnableAccessTokenIssuance is false || currentSettings.EnableIdTokenIssuance is false) + // In the case of Blazor WASM and B2C, Access Tokens and Id Tokens must both be true. + if ((toolOptions.IsBlazorWasm || isB2C) + && currentSettings.EnableAccessTokenIssuance is false + || currentSettings.EnableAccessTokenIssuance is false) { app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = true; app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = true; - needsUpdate = true; } + // Otherwise we make changes only when the tool options differ from the existing settings. + else + { + if (toolOptions.EnableAccessToken.HasValue && toolOptions.EnableAccessToken.Value != currentSettings.EnableAccessTokenIssuance) + { + app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = toolOptions.EnableAccessToken.Value; + needsUpdate = true; + } - //if (toolOptions.IsBlazorWasm) // In the case of Blazor WASM, Access Tokens and Id Tokens must both be true. - //{ - // if (currentSettings.EnableAccessTokenIssuance is false || currentSettings.EnableIdTokenIssuance is false) - // { - // app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = true; - // app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = true; - - // needsUpdate = true; - // } - //} - //else // Otherwise we make changes only when the tool options differ from the existing settings. - //{ - // if (toolOptions.EnableAccessToken.HasValue && - // currentSettings.EnableAccessTokenIssuance != toolOptions.EnableAccessToken.Value) - // { - // app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = toolOptions.EnableAccessToken.Value; - // needsUpdate = true; - // } - - // if (toolOptions.EnableIdToken.HasValue && - // currentSettings.EnableIdTokenIssuance != toolOptions.EnableIdToken.Value) - // { - // app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = toolOptions.EnableIdToken.Value; - // needsUpdate = true; - // } - //} + if (toolOptions.EnableIdToken.HasValue && toolOptions.EnableIdToken.Value != currentSettings.EnableIdTokenIssuance) + { + app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = toolOptions.EnableIdToken.Value; + needsUpdate = true; + } + } return needsUpdate; } diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs index 3f44844e8..5f6b29eab 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs @@ -203,7 +203,7 @@ private ProjectAuthenticationSettings InferApplicationParameters( if (!string.IsNullOrEmpty(provisioningToolOptions.ProjectType)) { if (provisioningToolOptions.ProjectType.Equals("webapp", StringComparison.OrdinalIgnoreCase) - || provisioningToolOptions.ProjectType.Equals("blazorserver", StringComparison.OrdinalIgnoreCase)) + || provisioningToolOptions.ProjectType.Equals("blazorserver", StringComparison.OrdinalIgnoreCase)) // TODO move project types to constants { projectSettings.ApplicationParameters.IsWebApp = projectSettings.ApplicationParameters.IsWebApp ?? true; } diff --git a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/MicrosoftIdentityPlatformApplicationManagerTests.cs b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/MicrosoftIdentityPlatformApplicationManagerTests.cs index a61b5024a..6acf3d036 100644 --- a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/MicrosoftIdentityPlatformApplicationManagerTests.cs +++ b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/MicrosoftIdentityPlatformApplicationManagerTests.cs @@ -165,7 +165,7 @@ public void PreAuthorizeBlazorWasmClientAppTest_NoMatchingPreAuthorizedApplicati } [Fact] - public void UpdateImplicitGrantSettingsTest_WhenBlazorWasm_SetCheckboxesFalse() + public void UpdateImplicitGrantSettingsTest_WhenBlazorWasm_SetCheckboxesTrue() { var originalApp = new Graph.Application { @@ -173,8 +173,8 @@ public void UpdateImplicitGrantSettingsTest_WhenBlazorWasm_SetCheckboxesFalse() { ImplicitGrantSettings = new ImplicitGrantSettings { - EnableAccessTokenIssuance = true, - EnableIdTokenIssuance = true + EnableAccessTokenIssuance = false, + EnableIdTokenIssuance = false } } }; @@ -183,10 +183,10 @@ public void UpdateImplicitGrantSettingsTest_WhenBlazorWasm_SetCheckboxesFalse() ProjectType = "blazorwasm" }; - var output = MicrosoftIdentityPlatformApplicationManager.UpdateImplicitGrantSettings(originalApp, toolOptions); // TODO unit tests + var output = MicrosoftIdentityPlatformApplicationManager.UpdateImplicitGrantSettings(originalApp, toolOptions); Assert.True(output); - Assert.False(originalApp.Web.ImplicitGrantSettings.EnableAccessTokenIssuance); - Assert.False(originalApp.Web.ImplicitGrantSettings.EnableIdTokenIssuance); + Assert.True(originalApp.Web.ImplicitGrantSettings.EnableAccessTokenIssuance); + Assert.True(originalApp.Web.ImplicitGrantSettings.EnableIdTokenIssuance); } [Theory] From 290d9049667f81cb276cb5bdae668931fa12f000 Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Fri, 29 Jul 2022 14:43:34 -0700 Subject: [PATCH 7/9] Remove samples --- ....NETFramework,Version=v4.7.2.AssemblyAttributes.cs | 4 ---- .../MicrosoftIdentityPlatformApplicationManager.cs | 6 ++++++ .../ProjectDescriptions/ProjectTypes.cs | 11 +++++++++++ .../Tool/AppProvisioningTool.cs | 11 ++++++----- .../Tool/ProvisioningToolOptions.cs | 2 +- 5 files changed, 24 insertions(+), 10 deletions(-) delete mode 100644 Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs create mode 100644 src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs diff --git a/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs deleted file mode 100644 index 3871b184d..000000000 --- a/Samples/net472/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs +++ /dev/null @@ -1,4 +0,0 @@ -// -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs index c79d6ad5c..cdff9c91b 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs @@ -188,6 +188,12 @@ internal async Task UpdateApplication( var graphServiceClient = GetGraphServiceClient(tokenCredential); + + // TODO: Add if it's B2C, acquire the SUSI Policy + + //TODO: If it's B2c and there is no SUSI policy, create one + + var remoteApp = (await graphServiceClient.Applications.Request() .Filter($"appId eq '{parameters.ClientId}'").GetAsync()).FirstOrDefault(app => app.AppId.Equals(parameters.ClientId)); diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs new file mode 100644 index 000000000..2c0e191f5 --- /dev/null +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs @@ -0,0 +1,11 @@ +namespace Microsoft.DotNet.MSIdentity +{ + public class ProjectTypes + { + public const string BlazorServer = "blazorserver"; + public const string WebApp = "webapp"; + public const string WebApi = "webapi"; + public const string BlazorWasmClient = "blazorwasm-client"; + public const string BlazorWasm = "blazorwasm"; + } +} diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs index 5f6b29eab..65c3f2039 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs @@ -15,6 +15,7 @@ using Microsoft.DotNet.MSIdentity.MicrosoftIdentityPlatform; using Microsoft.DotNet.MSIdentity.MicrosoftIdentityPlatformApplication; using Microsoft.DotNet.MSIdentity.Project; +using Microsoft.DotNet.MSIdentity.ProjectDescriptions; using Microsoft.DotNet.MSIdentity.Properties; using Microsoft.DotNet.MSIdentity.Shared; using Microsoft.DotNet.MSIdentity.Tool; @@ -42,7 +43,7 @@ public class AppProvisioningTool : IMsAADTool private ProjectDescriptionReader? _projectDescriptionReader; private ProjectDescriptionReader ProjectDescriptionReader => _projectDescriptionReader ??= new ProjectDescriptionReader(FilePaths); - public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = false) // TODO silent is temporary + public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions, bool silent = false) { CommandName = commandName; ProvisioningToolOptions = provisioningToolOptions; @@ -202,12 +203,12 @@ private ProjectAuthenticationSettings InferApplicationParameters( // there can multiple project types if (!string.IsNullOrEmpty(provisioningToolOptions.ProjectType)) { - if (provisioningToolOptions.ProjectType.Equals("webapp", StringComparison.OrdinalIgnoreCase) - || provisioningToolOptions.ProjectType.Equals("blazorserver", StringComparison.OrdinalIgnoreCase)) // TODO move project types to constants + if (provisioningToolOptions.ProjectType.Equals(ProjectTypes.WebApp, StringComparison.OrdinalIgnoreCase) + || provisioningToolOptions.ProjectType.Equals(ProjectTypes.BlazorServer, StringComparison.OrdinalIgnoreCase)) { projectSettings.ApplicationParameters.IsWebApp = projectSettings.ApplicationParameters.IsWebApp ?? true; } - if (provisioningToolOptions.ProjectType.Equals("webapi", StringComparison.OrdinalIgnoreCase) || provisioningToolOptions.IsBlazorWasmHostedServer) + if (provisioningToolOptions.ProjectType.Equals(ProjectTypes.WebApi, StringComparison.OrdinalIgnoreCase) || provisioningToolOptions.IsBlazorWasmHostedServer) { projectSettings.ApplicationParameters.IsWebApi = projectSettings.ApplicationParameters.IsWebApi ?? true; } @@ -322,7 +323,7 @@ private async Task ConfigureBlazorWasmHostedClientAsync(A clientToolOptions.ProjectFilePath = ProvisioningToolOptions.ClientProject ?? string.Empty; clientToolOptions.ClientId = null; clientToolOptions.ClientProject = null; - clientToolOptions.ProjectType = "blazorwasm-client"; + clientToolOptions.ProjectType = ProjectTypes.BlazorWasmClient; clientToolOptions.AppDisplayName = string.Concat(clientToolOptions.AppDisplayName ?? serverApplicationParameters.ApplicationDisplayName, "-Client"); clientToolOptions.HostedAppIdUri = serverApplicationParameters.AppIdUri; clientToolOptions.HostedApiScopes = $"{serverApplicationParameters.AppIdUri}/{DefaultProperties.ApiScopes}"; diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/ProvisioningToolOptions.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/ProvisioningToolOptions.cs index 8d23ab72c..f56d9cd03 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/ProvisioningToolOptions.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/ProvisioningToolOptions.cs @@ -173,7 +173,7 @@ public string ProjectTypeIdentifier /// /// Determines if the project type is blazor wasm /// - public bool IsBlazorWasm => "blazorwasm".Equals(ProjectType) || "blazorwasm-client".Equals(ProjectType); + public bool IsBlazorWasm => ProjectTypes.BlazorWasm.Equals(ProjectType) || ProjectTypes.BlazorWasmClient.Equals(ProjectType); /// /// App registration ID associated with the Blazor WASM hosted client, Used for the Blazor WASM hosted server API in order to pre-authorize the client app From 40b7d4e3e40eb2ed30d2d9b06f27e1d835c70a0f Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Fri, 29 Jul 2022 15:01:19 -0700 Subject: [PATCH 8/9] Fix tests, bug --- ...osoftIdentityPlatformApplicationManager.cs | 36 ++++++++----------- .../Tool/AppProvisioningTool.cs | 2 -- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs index cdff9c91b..d160b959b 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs @@ -78,21 +78,18 @@ public class MicrosoftIdentityPlatformApplicationManager .Request() .AddAsync(servicePrincipal).ConfigureAwait(false); - if (applicationParameters.IsB2C) // TODO B2C not fully supported at the moment + // B2C does not allow user consent, and therefore we need to explicity grant permissions + if (applicationParameters.IsB2C) { - // B2C does not allow user consent, and therefore we need to explicity grant permissions - if (applicationParameters.IsB2C) - { - IEnumerable>? scopesPerResource = await AddApiPermissions( - applicationParameters, - graphServiceClient, - application).ConfigureAwait(false); - - await AddAdminConsentToApiPermissions( - graphServiceClient, - createdServicePrincipal, - scopesPerResource); - } + IEnumerable>? scopesPerResource = await AddApiPermissions( + applicationParameters, + graphServiceClient, + application).ConfigureAwait(false); + + await AddAdminConsentToApiPermissions( + graphServiceClient, + createdServicePrincipal, + scopesPerResource); } // For web API, we need to know the appId of the created app to compute the Identifier URI, @@ -188,12 +185,7 @@ internal async Task UpdateApplication( var graphServiceClient = GetGraphServiceClient(tokenCredential); - - // TODO: Add if it's B2C, acquire the SUSI Policy - - //TODO: If it's B2c and there is no SUSI policy, create one - - + // TODO: Add if it's B2C, acquire or create the SUSI Policy var remoteApp = (await graphServiceClient.Applications.Request() .Filter($"appId eq '{parameters.ClientId}'").GetAsync()).FirstOrDefault(app => app.AppId.Equals(parameters.ClientId)); @@ -363,8 +355,8 @@ internal static bool UpdateImplicitGrantSettings(Application app, ProvisioningTo // In the case of Blazor WASM and B2C, Access Tokens and Id Tokens must both be true. if ((toolOptions.IsBlazorWasm || isB2C) - && currentSettings.EnableAccessTokenIssuance is false - || currentSettings.EnableAccessTokenIssuance is false) + && (currentSettings.EnableAccessTokenIssuance is false + || currentSettings.EnableAccessTokenIssuance is false)) { app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = true; app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = true; diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs index 65c3f2039..8026a505e 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/Tool/AppProvisioningTool.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -15,7 +14,6 @@ using Microsoft.DotNet.MSIdentity.MicrosoftIdentityPlatform; using Microsoft.DotNet.MSIdentity.MicrosoftIdentityPlatformApplication; using Microsoft.DotNet.MSIdentity.Project; -using Microsoft.DotNet.MSIdentity.ProjectDescriptions; using Microsoft.DotNet.MSIdentity.Properties; using Microsoft.DotNet.MSIdentity.Shared; using Microsoft.DotNet.MSIdentity.Tool; From 053b87e0c48bf6879a928464ddfa7df652c324c4 Mon Sep 17 00:00:00 2001 From: Zach Halzel Date: Mon, 1 Aug 2022 12:12:04 -0700 Subject: [PATCH 9/9] Make class static --- .../ProjectDescriptions/ProjectTypes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs index 2c0e191f5..54a836832 100644 --- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs +++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs @@ -1,6 +1,6 @@ namespace Microsoft.DotNet.MSIdentity { - public class ProjectTypes + public static class ProjectTypes { public const string BlazorServer = "blazorserver"; public const string WebApp = "webapp";