diff --git a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/AuthenticationParameters/AzureAdProperties.cs
index 83a5ce91f..87d47d19f 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,12 +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,10 +32,14 @@ public static class DefaultProperties
public const string Instance = "https://login.microsoftonline.com/";
public const string CallbackPath = "/signin-oidc";
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 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";
@@ -43,59 +49,49 @@ public class AzureAdBlock
{
public bool IsBlazorWasm;
public bool IsWebApi;
+ 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? CallbackPath;
+ public string? SignUpSignInPolicyId;
+ 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();
-
- 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;
- }
-
- ///
- /// 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();
- ClientSecret ??= azureAdObj.GetValue(PropertyNames.ClientSecret)?.ToString();
- ClientCertificates ??= azureAdObj.GetValue(PropertyNames.ClientCertificates)?.ToObject();
-
- return this;
+ IsB2C = applicationParameters.IsB2C;
+
+ 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;
+ 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 ?? (string.IsNullOrEmpty(Instance) || string.IsNullOrEmpty(TenantId) ? DefaultProperties.Authority : $"{Instance}{TenantId}"),
- ValidateAuthority = true
+ ClientId,
+ Authority,
+ ValidateAuthority = !IsB2C
};
public dynamic WebAppSettings => new
@@ -119,18 +115,30 @@ public AzureAdBlock UpdateFromJToken(JToken azureAdToken)
ClientCertificates = ClientCertificates ?? Array.Empty()
};
+ public dynamic B2CSettings => new
+ {
+ SignUpSignInPolicyId = SignUpSignInPolicyId ?? DefaultProperties.SignUpSignInPolicyId,
+ SignedOutCallbackPath = SignedOutCallbackPath ?? DefaultProperties.SignedOutCallbackPath,
+ ResetPasswordPolicyId = ResetPasswordPolicyId ?? DefaultProperties.ResetPasswordPolicyId,
+ EditProfilePolicyId = EditProfilePolicyId ?? DefaultProperties.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)
{
- return JObject.FromObject(WebApiSettings);
+ 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..28214ab0c 100644
--- a/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs
+++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/AppSettingsModifier.cs
@@ -132,34 +132,29 @@ 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 azureAdBlock = new AzureAdBlock(applicationParameters);
- if (!appSettings.TryGetValue("AzureAd", out var azureAdToken))
+ var azAdToken = appSettings.GetValue("AzureAd") ?? appSettings.GetValue("AzureAdB2C"); // TODO test "AzureAdB2C" string, make sure that blazor WASM works
+ 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)
{
@@ -170,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
{
@@ -189,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/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs
index 9c1df5cb1..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,6 +185,7 @@ internal async Task UpdateApplication(
var graphServiceClient = GetGraphServiceClient(tokenCredential);
+ // 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));
@@ -196,7 +194,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 +218,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 +234,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,32 +348,30 @@ 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 (toolOptions.IsBlazorWasm) // In the case of Blazor WASM, Access Tokens and Id Tokens must both be true.
+ // 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))
{
- if (currentSettings.EnableAccessTokenIssuance is true || currentSettings.EnableIdTokenIssuance is true)
- {
- app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = false;
- app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = false;
-
- needsUpdate = true;
- }
+ 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.
+ // Otherwise we make changes only when the tool options differ from the existing settings.
+ else
{
- if (toolOptions.EnableAccessToken.HasValue &&
- currentSettings.EnableAccessTokenIssuance != toolOptions.EnableAccessToken.Value)
+ if (toolOptions.EnableAccessToken.HasValue && toolOptions.EnableAccessToken.Value != currentSettings.EnableAccessTokenIssuance)
{
app.Web.ImplicitGrantSettings.EnableAccessTokenIssuance = toolOptions.EnableAccessToken.Value;
needsUpdate = true;
}
- if (toolOptions.EnableIdToken.HasValue &&
- currentSettings.EnableIdTokenIssuance != toolOptions.EnableIdToken.Value)
+ if (toolOptions.EnableIdToken.HasValue && toolOptions.EnableIdToken.Value != currentSettings.EnableIdTokenIssuance)
{
app.Web.ImplicitGrantSettings.EnableIdTokenIssuance = toolOptions.EnableIdToken.Value;
needsUpdate = true;
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..54a836832
--- /dev/null
+++ b/src/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity/ProjectDescriptions/ProjectTypes.cs
@@ -0,0 +1,11 @@
+namespace Microsoft.DotNet.MSIdentity
+{
+ public static 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 88b5d6845..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;
@@ -42,7 +41,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 +201,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))
+ 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;
}
@@ -304,7 +303,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);
}
///
@@ -323,7 +321,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
diff --git a/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs b/test/MSIdentityScaffolding/Microsoft.DotNet.MSIdentity.UnitTests.Tests/AppProvisioningToolTests.cs
index 6761be9c5..443c3e55a 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()
@@ -35,7 +37,32 @@ 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));
+ }
+
+ [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,
+ DefaultProperties.SignedOutCallbackPath,
+ DefaultProperties.ResetPasswordPolicyId,
+ DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -48,12 +75,30 @@ public void ModifyAppSettings_NoInput_Blazor_DefaultOutput()
var expected = JObject.FromObject(new
{
- DefaultProperties.Authority,
+ Authority = $"{DefaultProperties.Instance}{DefaultProperties.TenantId}",
DefaultProperties.ClientId,
DefaultProperties.ValidateAuthority
});
- (bool needsUpdate, JObject modifications) = modifier.GetModifiedAzureAdBlock(appSettings, parameters);
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
+ 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.Instance}{DefaultProperties.TenantId}/{DefaultProperties.SignUpSignInPolicyId}",
+ DefaultProperties.ClientId,
+ ValidateAuthority = false
+ });
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -81,7 +126,41 @@ 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));
+ }
+
+ [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,
+ DefaultProperties.SignUpSignInPolicyId,
+ DefaultProperties.SignedOutCallbackPath,
+ DefaultProperties.ResetPasswordPolicyId,
+ DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ var parameters = new AuthenticationParameters.ApplicationParameters
+ {
+ Domain = inputDomain,
+ TenantId = inputTenantId,
+ ClientId = inputClientId,
+ Instance = inputInstance,
+ CallbackPath = inputCallbackPath,
+ IsB2C = true
+ };
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -118,7 +197,50 @@ 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));
+ }
+
+ [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,
+ DefaultProperties.SignUpSignInPolicyId,
+ DefaultProperties.SignedOutCallbackPath,
+ DefaultProperties.ResetPasswordPolicyId,
+ DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ var parameters = new AuthenticationParameters.ApplicationParameters
+ {
+ Domain = inputDomain,
+ TenantId = inputTenantId,
+ ClientId = inputClientId,
+ IsB2C = true
+ };
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -159,7 +281,57 @@ 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));
+ }
+
+ [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,
+ SignedOutCallbackPath = DefaultProperties.SignedOutCallbackPath,
+ ResetPasswordPolicyId = DefaultProperties.ResetPasswordPolicyId,
+ EditProfilePolicyId = DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
+
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -197,7 +369,51 @@ 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));
+ }
+
+ [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,
+ DefaultProperties.SignUpSignInPolicyId,
+ DefaultProperties.SignedOutCallbackPath,
+ DefaultProperties.ResetPasswordPolicyId,
+ DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
@@ -224,7 +440,7 @@ public void ModifyAppSettings_HasEmptyInputParameter_ExistingPropertiesNotModifi
{
Domain = inputDomain,
TenantId = "",
- ClientId = ""
+ ClientId = "",
};
var expected = JObject.FromObject(new
@@ -236,10 +452,54 @@ 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));
}
+ [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
+ {
+ Domain = inputDomain,
+ TenantId = existingTenantId,
+ ClientId = existingClientId,
+ Instance = existingInstance,
+ CallbackPath = existingCallbackPath,
+ DefaultProperties.SignUpSignInPolicyId,
+ DefaultProperties.SignedOutCallbackPath,
+ DefaultProperties.ResetPasswordPolicyId,
+ DefaultProperties.EditProfilePolicyId,
+ EnablePiiLogging = true
+ });
+
+ (bool needsUpdate, JObject modifications) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
+ Assert.True(JToken.DeepEquals(expected, modifications));
+ }
[Fact]
public void ModifyAppSettings_BlazorWasm_AuthorityIsCorrect()
@@ -276,7 +536,48 @@ 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));
+ }
+
+ [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) = AppSettingsModifier.GetModifiedAzureAdBlock(appSettings, parameters);
Assert.True(JToken.DeepEquals(expected, modifications));
}
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]