diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/AppSettings.cs b/nce-bulk-migration-tool/NCEBulkMigrationTool/AppSettings.cs index 3e1f727..bb2b8d0 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/AppSettings.cs +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/AppSettings.cs @@ -33,4 +33,9 @@ internal record AppSettings return this.Upn[++index..]; } } + + /// + /// Gets or sets a flag indicating whether to use app only token. + /// + public bool UseAppToken { get; set; } } \ No newline at end of file diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/NCEBulkMigrationTool.csproj b/nce-bulk-migration-tool/NCEBulkMigrationTool/NCEBulkMigrationTool.csproj index f8888eb..7eef721 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/NCEBulkMigrationTool.csproj +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/NCEBulkMigrationTool.csproj @@ -22,6 +22,9 @@ + + Always + diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/NewCommerceMigrationProvider.cs b/nce-bulk-migration-tool/NCEBulkMigrationTool/NewCommerceMigrationProvider.cs index c2a1bc4..6d86842 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/NewCommerceMigrationProvider.cs +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/NewCommerceMigrationProvider.cs @@ -141,7 +141,7 @@ internal class NewCommerceMigrationProvider : INewCommerceMigrationProvider var inputBaseMigrationRequests = inputMigrations.Where(m => !m.AddOn); var inputAddOnMigrationRequests = inputMigrations.Where(m => m.AddOn); - var baseSubscriptionIds = inputBaseMigrationRequests.Select(b => b.LegacySubscriptionId).ToList(); + var baseSubscriptionIds = inputMigrations.Select(b => b.LegacySubscriptionId).ToList(); var addOnsWithoutBase = inputAddOnMigrationRequests.Where(a => !baseSubscriptionIds.Contains(a.BaseSubscriptionId)); diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/Program.cs b/nce-bulk-migration-tool/NCEBulkMigrationTool/Program.cs index 4174d5e..cd3c4f7 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/Program.cs +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/Program.cs @@ -5,33 +5,40 @@ // ----------------------------------------------------------------------- Console.WriteLine("Welcome to NCE Bulk Migration Tool!"); -string? appId; -string? upn; +string? appId = null; +string? upn = null; -if (args.Length == 2) -{ - appId = args[0]; - upn = args[1]; -} -else -{ -AppId: - Console.WriteLine("Enter AppId"); - appId = Console.ReadLine(); +var configurationManager = new ConfigurationManager(); +configurationManager.AddJsonFile("appsettings.json"); +var useAppToken = configurationManager.GetValue("useAppToken"); - if (string.IsNullOrWhiteSpace(appId) || !Guid.TryParse(appId, out _)) +if (!useAppToken) +{ + if (args.Length == 2) { - Console.WriteLine("Invalid input, Please try again!"); - goto AppId; + appId = args[0]; + upn = args[1]; } - -Upn: - Console.WriteLine("Enter Upn"); - upn = Console.ReadLine(); - if (string.IsNullOrWhiteSpace(upn)) + else { - Console.WriteLine("Invalid input, Please try again!"); - goto Upn; + AppId: + Console.WriteLine("Enter AppId"); + appId = Console.ReadLine(); + + if (string.IsNullOrWhiteSpace(appId) || !Guid.TryParse(appId, out _)) + { + Console.WriteLine("Invalid input, Please try again!"); + goto AppId; + } + + Upn: + Console.WriteLine("Enter Upn"); + upn = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(upn)) + { + Console.WriteLine("Invalid input, Please try again!"); + goto Upn; + } } } @@ -39,11 +46,37 @@ var appSettings = new AppSettings() { AppId = appId, Upn = upn, + UseAppToken = useAppToken }; +bool stopExecution = false; + using IHost host = Host.CreateDefaultBuilder(args) - .ConfigureServices((services) => + .ConfigureAppConfiguration(c => c.AddJsonFile("appsettings.json")) + .ConfigureServices((hostBuilder, services) => { + var config = hostBuilder.Configuration; + if (appSettings.UseAppToken) + { + if (string.IsNullOrWhiteSpace(config.GetValue("clientId"))) + { + Console.WriteLine("Please provide clientId in the appsettings file."); + stopExecution = true; + } + + if (string.IsNullOrWhiteSpace(config.GetValue("clientSecret"))) + { + Console.WriteLine("Please provide clientSecret in the appsettings file."); + stopExecution = true; + } + + if (string.IsNullOrWhiteSpace(config.GetValue("tenantId"))) + { + Console.WriteLine("Please provide tenantId in the appsettings file."); + stopExecution = true; + } + } + services.AddSingleton(appSettings); services.AddSingleton(); services.AddSingleton(); @@ -52,6 +85,12 @@ using IHost host = Host.CreateDefaultBuilder(args) services.AddSingleton(); }).Build(); +if (stopExecution) +{ + await host.StopAsync(); + Environment.Exit(Environment.ExitCode); +} + await RunAsync(host.Services); await host.RunAsync(); diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/SubscriptionProvider.cs b/nce-bulk-migration-tool/NCEBulkMigrationTool/SubscriptionProvider.cs index c7fe5f2..2cf4dd4 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/SubscriptionProvider.cs +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/SubscriptionProvider.cs @@ -14,15 +14,17 @@ internal class SubscriptionProvider : ISubscriptionProvider private static string partnerTenantId = string.Empty; private readonly ITokenProvider tokenProvider; + private readonly IConfiguration configuration; private long subscriptionsCntr = 0; /// /// SubscriptionProvider constructor. /// /// - public SubscriptionProvider(ITokenProvider tokenProvider) + public SubscriptionProvider(ITokenProvider tokenProvider, IConfiguration configuration) { this.tokenProvider = tokenProvider; + this.configuration = configuration; } /// @@ -38,7 +40,7 @@ internal class SubscriptionProvider : ISubscriptionProvider var failedCustomersBag = new ConcurrentBag(); var authenticationResult = await this.tokenProvider.GetTokenAsync(); - partnerTenantId = authenticationResult.TenantId; + partnerTenantId = authenticationResult.TenantId ?? this.configuration.GetValue("tenantId"); var httpClient = new HttpClient { @@ -99,7 +101,7 @@ internal class SubscriptionProvider : ISubscriptionProvider var failedCustomersBag = new ConcurrentBag(); var authenticationResult = await this.tokenProvider.GetTokenAsync(); - partnerTenantId = authenticationResult.TenantId; + partnerTenantId = authenticationResult.TenantId ?? this.configuration.GetValue("tenantId"); var httpClient = new HttpClient { diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/TokenProvider.cs b/nce-bulk-migration-tool/NCEBulkMigrationTool/TokenProvider.cs index bd86022..a1ab29e 100644 --- a/nce-bulk-migration-tool/NCEBulkMigrationTool/TokenProvider.cs +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/TokenProvider.cs @@ -15,12 +15,14 @@ internal class TokenProvider : ITokenProvider /// TokenProvider constructor. /// /// The app settings. - public TokenProvider(AppSettings appSettings) + public TokenProvider(AppSettings appSettings, IConfiguration configuration) { this.appSettings = appSettings; + this.configuration = configuration; } private readonly AppSettings appSettings; + private readonly IConfiguration configuration; private AuthenticationResult? authenticationResult; /// @@ -31,42 +33,57 @@ internal class TokenProvider : ITokenProvider return authenticationResult; } - var scopes = new string[] { $"https://api.partnercenter.microsoft.com/.default" }; - var app = PublicClientApplicationBuilder.Create(this.appSettings.AppId) - .WithAuthority("https://login.microsoftonline.com", this.appSettings.Domain, true) - .WithRedirectUri("http://localhost") - .Build(); - - var accounts = await app.GetAccountsAsync(); - AuthenticationResult result; - - try + if (appSettings.UseAppToken) { - result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) - .ExecuteAsync(); + var authenticationBuilder = ConfidentialClientApplicationBuilder.Create($"{this.configuration.GetValue("clientId")}") + .WithAuthority($"https://login.microsoftonline.com/{this.configuration.GetValue("tenantId")}") + .WithClientSecret($"{this.configuration.GetValue("clientSecret")}") + .Build(); + var scopes = new List { $"https://graph.windows.net/.default" }; + authenticationResult = await authenticationBuilder.AcquireTokenForClient(scopes) + .ExecuteAsync(); + + return authenticationResult; } - catch (MsalUiRequiredException) + else { + var scopes = new string[] { $"https://api.partnercenter.microsoft.com/.default" }; + var app = PublicClientApplicationBuilder.Create(this.appSettings.AppId) + .WithAuthority("https://login.microsoftonline.com", this.appSettings.Domain, true) + .WithRedirectUri("http://localhost") + .Build(); + + var accounts = await app.GetAccountsAsync(); + AuthenticationResult result; + try { - result = await app.AcquireTokenInteractive(scopes) - .WithLoginHint(this.appSettings.Upn) - .WithPrompt(Prompt.NoPrompt) - .ExecuteAsync(); + result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) + .ExecuteAsync(); } - catch (MsalException msalex) + catch (MsalUiRequiredException) { - throw msalex; + try + { + result = await app.AcquireTokenInteractive(scopes) + .WithLoginHint(this.appSettings.Upn) + .WithPrompt(Prompt.NoPrompt) + .ExecuteAsync(); + } + catch (MsalException msalex) + { + throw msalex; + } + } + catch (Exception ex) + { + Console.WriteLine($"Exception while generating token {ex}"); + throw; } - } - catch (Exception ex) - { - Console.WriteLine($"Exception while generating token {ex}"); - throw; - } - authenticationResult = result; + authenticationResult = result; - return result; + return result; + } } } \ No newline at end of file diff --git a/nce-bulk-migration-tool/NCEBulkMigrationTool/appsettings.json b/nce-bulk-migration-tool/NCEBulkMigrationTool/appsettings.json new file mode 100644 index 0000000..61ab207 --- /dev/null +++ b/nce-bulk-migration-tool/NCEBulkMigrationTool/appsettings.json @@ -0,0 +1,6 @@ +{ + "useAppToken": false, + "clientId": "", + "clientSecret": "", + "tenantId": "" +} \ No newline at end of file diff --git a/nce-bulk-migration-tool/Readme.md b/nce-bulk-migration-tool/Readme.md index 318b21a..52ac2cb 100644 --- a/nce-bulk-migration-tool/Readme.md +++ b/nce-bulk-migration-tool/Readme.md @@ -58,7 +58,7 @@ Note that steps six through nine are only for scheduled migrations. ## Prerequisites * In order to build and run the BAM tool, .NET 6.0 SDK is required. -* AAD AppId that is onboarded to access Partner Center Apis. The batch migration (BAM) tool is not configured for multitenant apps. When registering the App please use single tenant app. +* AAD AppId that is onboarded to access Partner Center Apis. * Follow the below steps to create an app if not already exists. 1. Login to Partner Center and navigate to Account Settings. 2. Select App Management and then select “Native App” tab.