diff --git a/eng/Versions.MsIdentity.props b/eng/Versions.MsIdentity.props index 9be109fe1f..c04c6a6ce4 100644 --- a/eng/Versions.MsIdentity.props +++ b/eng/Versions.MsIdentity.props @@ -13,25 +13,14 @@ - 0.0.1 + 1.0.0 preview 1 - true + false - false + true release - - - 1.3.0 - 3.1.9 - 3.1.9 - 3.1.9 - 3.25.0 - 2.18.0 - 4.7.2 - 2.0.0-beta1.20574.7 - diff --git a/eng/Versions.props b/eng/Versions.props index ba857bc0bf..e8fde7a41c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -124,4 +124,17 @@ 6.0.0-preview.2.21154.6 6.0.0-preview.2.21154.6 + + + + 1.3.0 + 3.1.9 + 3.1.9 + 3.1.9 + 3.25.0 + 2.18.0 + 4.7.2 + 2.0.0-beta1.20574.7 + + diff --git a/scripts/install-msidentity.cmd b/scripts/install-msidentity.cmd index 133c9d10ec..dd5040bb82 100644 --- a/scripts/install-msidentity.cmd +++ b/scripts/install-msidentity.cmd @@ -1,4 +1,4 @@ -set VERSION=0.0.1-dev +set VERSION=1.0.0-dev set SRC_DIR=%cd% set NUPKG=artifacts/packages/Debug/Shipping/ diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs index 36ff66958a..a2c3370756 100644 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs +++ b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/MicrosoftIdentityPlatform/MicrosoftIdentityPlatformApplicationManager.cs @@ -530,9 +530,12 @@ internal async Task Unregister(TokenCredential tokenCredential, ApplicationParam var readApplication = apps.FirstOrDefault(); if (readApplication != null) { + var clientId = readApplication.Id; await graphServiceClient.Applications[$"{readApplication.Id}"] .Request() .DeleteAsync(); + + Console.WriteLine($"Unregistered the Azure AD w/ client id = {clientId}\n"); } } diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/AppProvisioningTool.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/AppProvisioningTool.cs index 8d0574eb21..6b8a7cdf23 100644 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/AppProvisioningTool.cs +++ b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/AppProvisioningTool.cs @@ -2,9 +2,9 @@ // Licensed under the MIT License. using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; -using System.Text.Json; using System.Threading.Tasks; using Azure.Core; using Microsoft.DotNet.MsIdentity.Properties; @@ -14,7 +14,6 @@ using Microsoft.DotNet.MsIdentity.MicrosoftIdentityPlatformApplication; using Microsoft.DotNet.MsIdentity.Project; - namespace Microsoft.DotNet.MsIdentity { /// @@ -24,12 +23,15 @@ public class AppProvisioningTool : IMsAADTool { private ProvisioningToolOptions ProvisioningToolOptions { get; set; } + private string CommandName { get; } + private MicrosoftIdentityPlatformApplicationManager MicrosoftIdentityPlatformApplicationManager { get; } = new MicrosoftIdentityPlatformApplicationManager(); private ProjectDescriptionReader ProjectDescriptionReader { get; } = new ProjectDescriptionReader(); - public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) + public AppProvisioningTool(string commandName, ProvisioningToolOptions provisioningToolOptions) { + CommandName = commandName; ProvisioningToolOptions = provisioningToolOptions; } @@ -48,10 +50,7 @@ public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) } else { - if (ProvisioningToolOptions.Json == null || ProvisioningToolOptions.Json == false) - { - Console.WriteLine($"Detected project type {projectDescription.Identifier}. "); - } + Console.WriteLine($"Detected project type {projectDescription.Identifier}. "); } ProjectAuthenticationSettings projectSettings = InferApplicationParameters( @@ -69,7 +68,7 @@ public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) provisioningToolOptionsBlazorServer.ProjectPath = Path.Combine(ProvisioningToolOptions.ProjectPath, "Server"); provisioningToolOptionsBlazorServer.ClientId = ProvisioningToolOptions.WebApiClientId; provisioningToolOptionsBlazorServer.WebApiClientId = null; - AppProvisioningTool appProvisioningToolBlazorServer = new AppProvisioningTool(provisioningToolOptionsBlazorServer); + AppProvisioningTool appProvisioningToolBlazorServer = new AppProvisioningTool(CommandName, provisioningToolOptionsBlazorServer); ApplicationParameters? applicationParametersServer = await appProvisioningToolBlazorServer.Run(); /// Processes the Blazorwasm client @@ -78,7 +77,7 @@ public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) provisioningToolOptionsBlazorClient.WebApiClientId = applicationParametersServer?.ClientId; provisioningToolOptionsBlazorClient.AppIdUri = applicationParametersServer?.AppIdUri; provisioningToolOptionsBlazorClient.CalledApiScopes = $"{applicationParametersServer?.AppIdUri}/access_as_user"; - AppProvisioningTool appProvisioningToolBlazorClient = new AppProvisioningTool(provisioningToolOptionsBlazorClient); + AppProvisioningTool appProvisioningToolBlazorClient = new AppProvisioningTool(CommandName, provisioningToolOptionsBlazorClient); return await appProvisioningToolBlazorClient.Run(); } @@ -102,7 +101,7 @@ public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) projectSettings.ApplicationParameters.EffectiveTenantId ?? projectSettings.ApplicationParameters.EffectiveDomain); // Unregister the app - if (ProvisioningToolOptions.Unregister) + if (CommandName.Equals(Commands.UNREGISTER_APPLICATION_COMMAND, StringComparison.OrdinalIgnoreCase)) { await UnregisterApplication(tokenCredential, projectSettings.ApplicationParameters); return null; @@ -118,35 +117,27 @@ public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) // Reconciliate code configuration and app registration if (effectiveApplicationParameters != null) { - if (ProvisioningToolOptions.Json ?? false) + bool appNeedsUpdate = Reconciliate( + projectSettings.ApplicationParameters, + effectiveApplicationParameters); + + // Update appp registration if needed + if (appNeedsUpdate) { - var jsonParameters = JsonSerializer.Serialize(effectiveApplicationParameters); - Console.WriteLine(jsonParameters); + await WriteApplicationRegistration( + summary, + effectiveApplicationParameters, + tokenCredential); } - else - { - bool appNeedsUpdate = Reconciliate( - projectSettings.ApplicationParameters, - effectiveApplicationParameters); - // Update appp registration if needed - if (appNeedsUpdate) - { - await WriteApplicationRegistration( - summary, - effectiveApplicationParameters, - tokenCredential); - } - - // Write code configuration if needed - WriteProjectConfiguration( - summary, - projectSettings, - effectiveApplicationParameters); + // Write code configuration if needed + WriteProjectConfiguration( + summary, + projectSettings, + effectiveApplicationParameters); - // Summarizes what happened - WriteSummary(summary); - } + // Summarizes what happened + WriteSummary(summary); } return effectiveApplicationParameters; @@ -259,10 +250,7 @@ private bool Reconciliate(ApplicationParameters applicationParameters, Applicati if (currentApplicationParameters == null && !ProvisioningToolOptions.Unregister) { currentApplicationParameters = await MicrosoftIdentityPlatformApplicationManager.CreateNewApp(tokenCredential, applicationParameters); - if (ProvisioningToolOptions.Json == null || ProvisioningToolOptions.Json == false) - { - Console.Write($"Created app {currentApplicationParameters.ClientId}. "); - } + Console.Write($"Created app {currentApplicationParameters.ClientId}. "); } return currentApplicationParameters; } diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/Commands.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/Commands.cs index 1949ffc1fa..29989734d7 100644 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/Commands.cs +++ b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/Commands.cs @@ -5,9 +5,10 @@ public class Commands public const string LIST_AAD_APPS_COMMAND = "--list-aad-apps"; public const string LIST_SERVICE_PRINCIPALS_COMMAND = "--list-service-principals"; public const string LIST_TENANTS_COMMAND = "--list-tenants"; - public const string REGISTER_APPLICATIION_COMMAND = "--register-application"; - public const string UPDATE_APPLICATION_COMMAND = "--update-application"; - public const string UNREGISTER_COMMAND = "--unregister"; + public const string REGISTER_APPLICATIION_COMMAND = "--register-app"; + public const string UPDATE_APPLICATION_COMMAND = "--update-app"; + public const string UPDATE_PROJECT_COMMAND = "--update-project"; + public const string UNREGISTER_APPLICATION_COMMAND = "--unregister-app"; public const string VALIDATE_APP_PARAMS_COMMAND = "--validate-app-params"; } -} \ No newline at end of file +} diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/MsAADTool.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/MsAADTool.cs index ab56e362ed..db19f75e26 100644 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/MsAADTool.cs +++ b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/MsAADTool.cs @@ -9,12 +9,13 @@ using Microsoft.DotNet.MsIdentity.AuthenticationParameters; using Microsoft.DotNet.MsIdentity.DeveloperCredentials; using Microsoft.DotNet.MsIdentity.MicrosoftIdentityPlatformApplication; + namespace Microsoft.DotNet.MsIdentity { internal class MsAADTool : IMsAADTool { private ProvisioningToolOptions ProvisioningToolOptions { get; set; } - private string _commandName { get; set; } + private string CommandName { get; } public IGraphServiceClient GraphServiceClient { get; set; } public IAzureManagementAuthenticationProvider AzureManagementAPI { get; set;} private MsalTokenCredential TokenCredential { get; set; } @@ -22,7 +23,7 @@ internal class MsAADTool : IMsAADTool public MsAADTool(string commandName, ProvisioningToolOptions provisioningToolOptions) { ProvisioningToolOptions = provisioningToolOptions; - _commandName = commandName; + CommandName = commandName; TokenCredential = new MsalTokenCredential(ProvisioningToolOptions.TenantId, ProvisioningToolOptions.Username); GraphServiceClient = new GraphServiceClient(new TokenCredentialAuthenticationProvider(TokenCredential)); AzureManagementAPI = new AzureManagementAuthenticationProvider(TokenCredential); @@ -33,7 +34,7 @@ public MsAADTool(string commandName, ProvisioningToolOptions provisioningToolOpt string outputJsonString = string.Empty; if (TokenCredential != null && GraphServiceClient != null) { - switch(_commandName) + switch(CommandName) { //--list-aad-apps case Commands.LIST_AAD_APPS_COMMAND: @@ -50,7 +51,7 @@ public MsAADTool(string commandName, ProvisioningToolOptions provisioningToolOpt default: break; } - if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value) + if (ProvisioningToolOptions.Json) { Console.WriteLine(outputJsonString); } @@ -79,9 +80,10 @@ internal async Task PrintApplicationsList() if (applicationList.Any()) { - if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value) + if (ProvisioningToolOptions.Json) { - outputJsonString = JsonSerializer.Serialize(applicationList); } + outputJsonString = JsonSerializer.Serialize(applicationList); + } else { Console.Write( @@ -116,7 +118,7 @@ internal async Task PrintServicePrincipalList() } if (servicePrincipalList.Any()) { - if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value) + if (ProvisioningToolOptions.Json) { outputJsonString = JsonSerializer.Serialize(servicePrincipalList); } @@ -175,7 +177,7 @@ internal async Task PrintTenantsList() } } - if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value) + if (ProvisioningToolOptions.Json) { outputJsonString = JsonSerializer.Serialize(tenantList); } diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ProvisioningToolOptions.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ProvisioningToolOptions.cs index 33bc81c417..9dfe2a8113 100644 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ProvisioningToolOptions.cs +++ b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ProvisioningToolOptions.cs @@ -103,7 +103,7 @@ public string ProjectTypeIdentifier /// /// Format for console output for list commands. /// - public bool? Json { get; set; } + public bool Json { get; set; } = false; /// /// Clones the options diff --git a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ToolOptions.cs b/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ToolOptions.cs deleted file mode 100644 index b727e67837..0000000000 --- a/src/MsIdentityScaffolding/Microsoft.DotNet.MsIdentity/Tool/ToolOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.DotNet.MsIdentity -{ - public class ToolOptions - { - public bool ListAADApps { get; set; } - public bool ListServicePrincipals { get; set; } - public bool ProvisionApp { get; set; } - public bool ValidateAppParams { get; set; } - } -} \ No newline at end of file diff --git a/tools/dotnet-msidentity/MsAADToolFactory.cs b/tools/dotnet-msidentity/MsAADToolFactory.cs index ad75baa34a..456587eed0 100644 --- a/tools/dotnet-msidentity/MsAADToolFactory.cs +++ b/tools/dotnet-msidentity/MsAADToolFactory.cs @@ -11,8 +11,8 @@ internal static IMsAADTool CreateTool(string commandName, ProvisioningToolOption case Commands.LIST_TENANTS_COMMAND: return new MsAADTool(commandName, provisioningToolOptions); default: - return new AppProvisioningTool(provisioningToolOptions); + return new AppProvisioningTool(commandName, provisioningToolOptions); } } } -} \ No newline at end of file +} diff --git a/tools/dotnet-msidentity/Program.cs b/tools/dotnet-msidentity/Program.cs index 97027ce3b6..5646f2f8d8 100644 --- a/tools/dotnet-msidentity/Program.cs +++ b/tools/dotnet-msidentity/Program.cs @@ -16,23 +16,32 @@ public static async Task Main(string []args) var listAadAppsCommand = ListAADAppsCommand(); var listServicePrincipalsCommand = ListServicePrincipalsCommand(); var listTenantsCommand = ListTenantsCommand(); - var provisionApplicationCommand = ProvisionApplicationCommand(); - + var registerApplicationCommand = RegisterApplicationCommand(); + var unregisterApplicationCommand = UnregisterApplicationCommand(); + var updateApplicationCommand = UpdateApplicationCommand(); + var updateProjectCommand = UpdateProjectCommand(); //hide internal commands. listAadAppsCommand.IsHidden = true; listServicePrincipalsCommand.IsHidden = true; listTenantsCommand.IsHidden = true; + updateProjectCommand.IsHidden = true; listAadAppsCommand.Handler = CommandHandler.Create(HandleListApps); listServicePrincipalsCommand.Handler = CommandHandler.Create(HandleListServicePrincipals); listTenantsCommand.Handler = CommandHandler.Create(HandleListTenants); - provisionApplicationCommand.Handler = CommandHandler.Create(HandleProvisionApplication); - + registerApplicationCommand.Handler = CommandHandler.Create(HandleRegisterApplication); + unregisterApplicationCommand.Handler = CommandHandler.Create(HandleUnregisterApplication); + updateApplicationCommand.Handler = CommandHandler.Create(HandleUpdateApplication); + updateProjectCommand.Handler = CommandHandler.Create(HandleUpdateProject); + //add all commands to root command. rootCommand.AddCommand(listAadAppsCommand); rootCommand.AddCommand(listServicePrincipalsCommand); rootCommand.AddCommand(listTenantsCommand); - rootCommand.AddCommand(provisionApplicationCommand); + rootCommand.AddCommand(registerApplicationCommand); + rootCommand.AddCommand(unregisterApplicationCommand); + rootCommand.AddCommand(updateApplicationCommand); + rootCommand.AddCommand(updateProjectCommand); //if no args are present, show default help. if (args == null || args.Length == 0) @@ -80,7 +89,7 @@ private static async Task HandleListServicePrincipals(ProvisioningToolOptio return -1; } - private static async Task HandleProvisionApplication(ProvisioningToolOptions provisioningToolOptions) + private static async Task HandleRegisterApplication(ProvisioningToolOptions provisioningToolOptions) { if (provisioningToolOptions != null) { @@ -91,6 +100,39 @@ private static async Task HandleProvisionApplication(ProvisioningToolOption return -1; } + private static async Task HandleUpdateApplication(ProvisioningToolOptions provisioningToolOptions) + { + if (provisioningToolOptions != null) + { + IMsAADTool msAADTool = MsAADToolFactory.CreateTool(Commands.UPDATE_APPLICATION_COMMAND, provisioningToolOptions); + await msAADTool.Run(); + return 0; + } + return -1; + } + + private static async Task HandleUnregisterApplication(ProvisioningToolOptions provisioningToolOptions) + { + if (provisioningToolOptions != null) + { + IMsAADTool msAADTool = MsAADToolFactory.CreateTool(Commands.UNREGISTER_APPLICATION_COMMAND, provisioningToolOptions); + await msAADTool.Run(); + return 0; + } + return -1; + } + + private static async Task HandleUpdateProject(ProvisioningToolOptions provisioningToolOptions) + { + if (provisioningToolOptions != null) + { + IMsAADTool msAADTool = MsAADToolFactory.CreateTool(Commands.UPDATE_APPLICATION_COMMAND, provisioningToolOptions); + await msAADTool.Run(); + return 0; + } + return -1; + } + private static RootCommand MsIdentityCommand()=> new RootCommand( description: "Creates or updates an Azure AD / Azure AD B2C application, and updates the code, using your developer credentials (from Visual Studio, Azure CLI, Azure RM PowerShell, VS Code).") @@ -121,27 +163,48 @@ private static Command ListTenantsCommand()=> UsernameOption(), JsonOption() }; - private static Command ProvisionApplicationCommand()=> + private static Command RegisterApplicationCommand()=> new Command( name: Commands.REGISTER_APPLICATIION_COMMAND, - description: "Register/update/unregister an AAD/AAD B2C application in Azure." + + description: "Register an AAD/AAD B2C application in Azure and updates .NET application." + "\n\t- Updates the appsettings.json file.") { - TenantOption(), UsernameOption(), JsonOption(), ClientIdOption(), ClientSecretOption(), AppIdUriOption(), ApiClientIdOption(), SusiPolicyIdOption(), UnregisterOption(), ProjectPathOption() + TenantOption(), UsernameOption(), JsonOption(), ClientIdOption(), ClientSecretOption(), AppIdUriOption(), ApiClientIdOption(), SusiPolicyIdOption(), ProjectPathOption() }; - private static Option JsonOption()=> - new Option( - aliases: new [] {"-j", "--json"}, - description: "Output format for list commands.") + private static Command UpdateProjectCommand()=> + new Command( + name: Commands.UPDATE_PROJECT_COMMAND, + description: "Update an AAD/AAD B2C application in Azure and .NET application." + + "\n\t- Updates the appsettings.json file." + + "\n\t- Updates the Startup.cs file." + + "\n\t- Updates the user secrets.") { - IsRequired = false + TenantOption(), UsernameOption(), JsonOption(), ProjectPathOption(), ClientIdOption() }; - private static Option UnregisterOption()=> + private static Command UpdateApplicationCommand() => + new Command( + name: Commands.UPDATE_APPLICATION_COMMAND, + description: "Update an AAD/AAD B2C application in Azure." + + "\n\t- Updates the appsettings.json file.") + { + TenantOption(), UsernameOption(), JsonOption(), AppIdUriOption(), ClientIdOption(), ProjectPathOption() + }; + + private static Command UnregisterApplicationCommand() => + new Command( + name: Commands.UNREGISTER_APPLICATION_COMMAND, + description: "Unregister an AAD/AAD B2C application in Azure." + + "\n\t- Updates the appsettings.json file.") + { + TenantOption(), UsernameOption(), JsonOption(), AppIdUriOption(), ProjectPathOption(), ClientIdOption() + }; + + private static Option JsonOption()=> new Option( - aliases: new [] {"-ur", "--unregister"}, - description: "Unregister the application, instead of registering it.") + aliases: new [] {"-j", "--json"}, + description: "Output format for commands.") { IsRequired = false };