/// <summary> /// 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). /// Use this tool in folders containing applications created with the following command: /// /// <c>dotnet new <template> --auth <authOption> [--calls-graph] [--called-api-url <URI> --called-api-scopes <scopes>]</c> /// /// where the <template> is a <c>webapp</c>, <c>mvc</c>, <c>webapi</c>, <c>blazorserver</c>, <c>blazorwasm</c>. /// See https://aka.ms/msidentity-app-sync. /// </summary> /// <param name="tenantId">Azure AD or Azure AD B2C tenant in which to create/update the app. /// - If specified, the tool will create the application in the specified tenant. /// - Otherwise it will create the app in your home tenant.</param> /// <param name="username">Username to use to connect to the Azure AD or Azure AD B2C tenant. /// It's only needed when you are signed-in in Visual Studio, or Azure CLI with /// several identities. In that case, the username param is used to disambiguate /// which identity to use to create the app in the tenant.</param> /// <param name="clientId">Client ID of an existing application from which to update the code. This is /// used when you don't want to register a new app, but want to configure the code /// from an existing application (which can also be updated by the tool if needed). /// You might want to also pass-in the <paramref name="clientSecret"/> if you know it.</param> /// <param name="folder">When specified, will analyze the application code in the specified folder. /// Otherwise analyzes the code in the current directory.</param> /// <param name="clientSecret">Client secret to use as a client credential.</param> /// <param name="susiPolicyId">Sign-up/Sign-in policy required for configurating /// a B2C application from code that was created for AAD.</param> /// <param name="apiClientId">Client ID of the blazorwasm hosted web API. /// This is only used on the case of a blazorwasm hosted application where you only /// want to configure the code (named after the --api-client-id blazorwasm /// template parameter).</param> /// <param name="appIdUri">The App ID Uri for the blazorwasm hosted API. It's only used /// on the case of a blazorwasm hosted application (named after the --app-id-uri /// blazorwasm template parameter).</param> /// <param name="unregister">Unregister the application, instead of registering it.</param> /// <returns></returns> static public async Task Main( string?tenantId, string?username, string?clientId, string?folder, string?clientSecret, string?susiPolicyId, string?apiClientId, string?appIdUri, bool?unregister) { // Read options ProvisioningToolOptions provisioningToolOptions = new ProvisioningToolOptions { Username = username, ClientId = clientId, ClientSecret = clientSecret, TenantId = tenantId, SusiPolicyId = susiPolicyId, WebApiClientId = apiClientId, AppIdUri = appIdUri, Unregister = unregister ?? false }; if (folder != null) { provisioningToolOptions.CodeFolder = folder; } AppProvisioningTool appProvisionningTool = new AppProvisioningTool(provisioningToolOptions); await appProvisionningTool.Run(); }
private TokenCredential GetTokenCredential(ProvisioningToolOptions provisioningToolOptions, string?currentApplicationTenantId) { DeveloperCredentialsReader developerCredentialsReader = new DeveloperCredentialsReader(); return(developerCredentialsReader.GetDeveloperCredentials( provisioningToolOptions.Username, currentApplicationTenantId ?? provisioningToolOptions.TenantId)); }
private ProjectAuthenticationSettings InferApplicationParameters( ProvisioningToolOptions provisioningToolOptions, ProjectDescription projectDescription, IEnumerable <ProjectDescription> projectDescriptions) { CodeReader reader = new CodeReader(); ProjectAuthenticationSettings projectSettings = reader.ReadFromFiles(provisioningToolOptions.CodeFolder, projectDescription, projectDescriptions); // Override with the tools options projectSettings.ApplicationParameters.ApplicationDisplayName ??= Path.GetFileName(provisioningToolOptions.CodeFolder); projectSettings.ApplicationParameters.ClientId ??= provisioningToolOptions.ClientId; projectSettings.ApplicationParameters.TenantId ??= provisioningToolOptions.TenantId; projectSettings.ApplicationParameters.CalledApiScopes ??= provisioningToolOptions.CalledApiScopes; if (!string.IsNullOrEmpty(provisioningToolOptions.AppIdUri)) { projectSettings.ApplicationParameters.AppIdUri = provisioningToolOptions.AppIdUri; } return(projectSettings); }
/// <summary> /// Identifier of a project type. This is the concatenation of the framework /// and the project type. This is the identifier of the extension describing /// the authentication pieces of the project /// </summary> public static string GetProjectTypeIdentifier(this ProvisioningToolOptions provisioningToolOptions) { return($"{provisioningToolOptions.LanguageOrFramework}-{provisioningToolOptions.ProjectType}"); }
public async Task <ApplicationParameters?> Run() { // If needed, infer project type from code ProjectDescription?projectDescription = ProjectDescriptionReader.GetProjectDescription( ProvisioningToolOptions.ProjectTypeIdentifier, ProvisioningToolOptions.CodeFolder); if (projectDescription == null) { Console.WriteLine($"The code in {ProvisioningToolOptions.CodeFolder} wasn't recognized as supported by the tool. Rerun with --help for details."); return(null); } else { Console.WriteLine($"Detected project type {projectDescription.Identifier}. "); } ProjectAuthenticationSettings projectSettings = InferApplicationParameters( ProvisioningToolOptions, projectDescription, ProjectDescriptionReader.projectDescriptions); // Case of a blazorwasm hosted application. We need to create two applications: // - the hosted web API // - the SPA. if (projectSettings.ApplicationParameters.IsBlazorWasm && projectSettings.ApplicationParameters.IsWebApi) { // Processes the hosted web API ProvisioningToolOptions provisioningToolOptionsBlazorServer = ProvisioningToolOptions.Clone(); provisioningToolOptionsBlazorServer.CodeFolder = Path.Combine(ProvisioningToolOptions.CodeFolder, "Server"); provisioningToolOptionsBlazorServer.ClientId = ProvisioningToolOptions.WebApiClientId; provisioningToolOptionsBlazorServer.WebApiClientId = null; AppProvisioningTool appProvisioningToolBlazorServer = new AppProvisioningTool(provisioningToolOptionsBlazorServer); ApplicationParameters?applicationParametersServer = await appProvisioningToolBlazorServer.Run(); /// Processes the Blazorwasm client ProvisioningToolOptions provisioningToolOptionsBlazorClient = ProvisioningToolOptions.Clone(); provisioningToolOptionsBlazorClient.CodeFolder = Path.Combine(ProvisioningToolOptions.CodeFolder, "Client"); provisioningToolOptionsBlazorClient.WebApiClientId = applicationParametersServer?.ClientId; provisioningToolOptionsBlazorClient.AppIdUri = applicationParametersServer?.AppIdUri; provisioningToolOptionsBlazorClient.CalledApiScopes = $"{applicationParametersServer?.AppIdUri}/access_as_user"; AppProvisioningTool appProvisioningToolBlazorClient = new AppProvisioningTool(provisioningToolOptionsBlazorClient); return(await appProvisioningToolBlazorClient.Run()); } // Case where the developer wants to have a B2C application, but the created application is an AAD one. The // tool needs to convert it if (!projectSettings.ApplicationParameters.IsB2C && !string.IsNullOrEmpty(ProvisioningToolOptions.SusiPolicyId)) { projectSettings = ConvertAadApplicationToB2CApplication(projectDescription, projectSettings); } // Case where there is no code for the authentication if (!projectSettings.ApplicationParameters.HasAuthentication) { Console.WriteLine($"Authentication is not enabled yet in this project. An app registration will " + $"be created, but the tool does not add the code yet (work in progress). "); } // Get developer credentials TokenCredential tokenCredential = GetTokenCredential( ProvisioningToolOptions, projectSettings.ApplicationParameters.EffectiveTenantId ?? projectSettings.ApplicationParameters.EffectiveDomain); // Unregister the app if (ProvisioningToolOptions.Unregister) { await UnregisterApplication(tokenCredential, projectSettings.ApplicationParameters); return(null); } // Read or provision Microsoft identity platform application ApplicationParameters?effectiveApplicationParameters = await ReadOrProvisionMicrosoftIdentityApplication( tokenCredential, projectSettings.ApplicationParameters); Summary summary = new Summary(); // Reconciliate code configuration and app registration if (effectiveApplicationParameters != null) { 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); } // Summarizes what happened WriteSummary(summary); return(effectiveApplicationParameters); }
public AppProvisioningTool(ProvisioningToolOptions provisioningToolOptions) { ProvisioningToolOptions = provisioningToolOptions; }