Enable app-only auth (#123)
* Enable app token auth * Read partner tenant id from config * Update readme * Fix dup issue with export
This commit is contained in:
Родитель
ecdae11638
Коммит
3a44c23afd
|
@ -33,4 +33,9 @@ internal record AppSettings
|
|||
return this.Upn[++index..];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating whether to use app only token.
|
||||
/// </summary>
|
||||
public bool UseAppToken { get; set; }
|
||||
}
|
|
@ -22,6 +22,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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<bool>("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<string>("clientId")))
|
||||
{
|
||||
Console.WriteLine("Please provide clientId in the appsettings file.");
|
||||
stopExecution = true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(config.GetValue<string>("clientSecret")))
|
||||
{
|
||||
Console.WriteLine("Please provide clientSecret in the appsettings file.");
|
||||
stopExecution = true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(config.GetValue<string>("tenantId")))
|
||||
{
|
||||
Console.WriteLine("Please provide tenantId in the appsettings file.");
|
||||
stopExecution = true;
|
||||
}
|
||||
}
|
||||
|
||||
services.AddSingleton(appSettings);
|
||||
services.AddSingleton<ITokenProvider, TokenProvider>();
|
||||
services.AddSingleton<ICustomerProvider, CustomerProvider>();
|
||||
|
@ -52,6 +85,12 @@ using IHost host = Host.CreateDefaultBuilder(args)
|
|||
services.AddSingleton<INewCommerceMigrationScheduleProvider, NewCommerceMigrationScheduleProvider>();
|
||||
}).Build();
|
||||
|
||||
if (stopExecution)
|
||||
{
|
||||
await host.StopAsync();
|
||||
Environment.Exit(Environment.ExitCode);
|
||||
}
|
||||
|
||||
await RunAsync(host.Services);
|
||||
|
||||
await host.RunAsync();
|
||||
|
|
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// SubscriptionProvider constructor.
|
||||
/// </summary>
|
||||
/// <param name="tokenProvider"></param>
|
||||
public SubscriptionProvider(ITokenProvider tokenProvider)
|
||||
public SubscriptionProvider(ITokenProvider tokenProvider, IConfiguration configuration)
|
||||
{
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -38,7 +40,7 @@ internal class SubscriptionProvider : ISubscriptionProvider
|
|||
var failedCustomersBag = new ConcurrentBag<CompanyProfile>();
|
||||
|
||||
var authenticationResult = await this.tokenProvider.GetTokenAsync();
|
||||
partnerTenantId = authenticationResult.TenantId;
|
||||
partnerTenantId = authenticationResult.TenantId ?? this.configuration.GetValue<string>("tenantId");
|
||||
|
||||
var httpClient = new HttpClient
|
||||
{
|
||||
|
@ -99,7 +101,7 @@ internal class SubscriptionProvider : ISubscriptionProvider
|
|||
var failedCustomersBag = new ConcurrentBag<CompanyProfile>();
|
||||
|
||||
var authenticationResult = await this.tokenProvider.GetTokenAsync();
|
||||
partnerTenantId = authenticationResult.TenantId;
|
||||
partnerTenantId = authenticationResult.TenantId ?? this.configuration.GetValue<string>("tenantId");
|
||||
|
||||
var httpClient = new HttpClient
|
||||
{
|
||||
|
|
|
@ -15,12 +15,14 @@ internal class TokenProvider : ITokenProvider
|
|||
/// TokenProvider constructor.
|
||||
/// </summary>
|
||||
/// <param name="appSettings">The app settings.</param>
|
||||
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;
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -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<string>("clientId")}")
|
||||
.WithAuthority($"https://login.microsoftonline.com/{this.configuration.GetValue<string>("tenantId")}")
|
||||
.WithClientSecret($"{this.configuration.GetValue<string>("clientSecret")}")
|
||||
.Build();
|
||||
var scopes = new List<string> { $"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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"useAppToken": false,
|
||||
"clientId": "",
|
||||
"clientSecret": "",
|
||||
"tenantId": ""
|
||||
}
|
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче