Reputation:
Trying to Authenticate against Azure Management API using their SDK. I can get the user authenticated with the MSAL.NET SDK. But when I try to pass the Bearer token for ClientCrendentials I can and AuthorizationFailed Message.
I've enabled user_impersination
and delegate permissions in my Active Directory instance and register my application through the application portal.
The Tenant is set to common
class Program
{
static readonly string TenantID = ConfigurationManager.AppSettings.Get("tenant_id");
static readonly string ClientID = ConfigurationManager.AppSettings.Get("client_id");
static readonly string Scopes = ConfigurationManager.AppSettings.Get("scopes");
static AuthenticationResult Authentication { get; set; }
static AzureEnvironment AzureEnvironment => AzureEnvironment.AzureGlobalCloud;
static void Main(string[] args)
{
// useful links
// Micorosft.Identity.Client https://github.com/AzureAD/microsoft-authentication-library-for-dotnet
DoLoginAsync().Wait();
CallAzure().Wait();
//CallMsGraphAPI().Wait();
Console.Read();
}
static async Task DoLoginAsync()
{
try
{
IPublicClientApplication client = PublicClientApplicationBuilder.Create(ClientID)
.WithAuthority(AzureCloudInstance.AzurePublic, TenantID)
.Build();
Authentication = await client.AcquireTokenInteractive(Scopes.Split(','))
.ExecuteAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static async Task CallAzure()
{
try
{
var client = RestClient.Configure()
.WithEnvironment(AzureEnvironment)
.WithCredentials(GetCredentials())
.WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
.Build();
var subscriptionClient = new SubscriptionClient(client);
var subscriptions = await subscriptionClient.Subscriptions.ListAsync();
Console.WriteLine(subscriptions); // fails
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
static AzureCredentials GetCredentials()
{
var provider = new StringTokenProvider(Authentication.AccessToken, "Bearer");
var tokenCredentials = new TokenCredentials(provider, TenantID, Authentication.Account.Username);
return new AzureCredentials(tokenCredentials, tokenCredentials, TenantID, AzureEnvironment);
}
}
I would think the user could be authorized using the Bearer Token given back in the GetCredentials
method I have.
Upvotes: 4
Views: 517
Reputation:
I managed to work through the issue and had two things worth pointing out
Audience
is the Account TenantId
. If you're unsure of how this works you can learn more about it on the Official Microsoft Page.scopes
parameter which appears to look like it supports multiple scopes, it indeed does not. Passing more than one scope
causes an error to occurUseful resources
Best practices for ConfigureAwait
class Program
{
static AuthenticationResult AuthenticationResult { get; set; }
static readonly string ClientId = ConfigurationManager.AppSettings.Get("ClientId") ?? throw new ApplicationException("No ClientID configured in <appsettings /> App.Config");
static readonly IEnumerable<string> Scopes = new[] { "https://management.azure.com/user_impersonation" };
static IPublicClientApplication App { get; set; }
static void Main(string[] args)
{
App = PublicClientApplicationBuilder.Create(ClientId)
.WithLogging((level, message, containsPii) =>
{
Console.WriteLine("Error when using Public Client");
Console.WriteLine($"{level}: {message}");
}, LogLevel.Verbose, true, true)
.WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdMultipleOrgs, true)
.Build();
DoLoginAsync().Wait();
CallAzureMangementRestApiAsync().Wait();
}
static async Task DoLoginAsync()
{
try
{
var accounts = await App.GetAccountsAsync().ConfigureAwait(false);
try
{
AuthenticationResult = await App.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
AuthenticationResult = await App.AcquireTokenInteractive(Scopes)
.ExecuteAsync()
.ConfigureAwait(false);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
static async Task CallAzureMangementRestApiAsync()
{
try
{
try
{
var accounts = await App.GetAccountsAsync().ConfigureAwait(false);
AuthenticationResult = await App.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
.WithAuthority(AzureCloudInstance.AzurePublic, AuthenticationResult.TenantId)
.ExecuteAsync()
.ConfigureAwait(false);
}
catch (MsalUiRequiredException)
{
// UI needs to have the user call in
AuthenticationResult = await App.AcquireTokenInteractive(Scopes)
.WithAuthority(AzureCloudInstance.AzurePublic, AuthenticationResult.TenantId)
.ExecuteAsync()
.ConfigureAwait(false);
}
var client = RestClient.Configure()
.WithEnvironment(AzureEnvironment.FromName(AuthenticationResult?.Account?.Environment) ?? AzureEnvironment.AzureGlobalCloud)
.WithCredentials(GetAzureCredentials())
.WithLogLevel(HttpLoggingDelegatingHandler.Level.BodyAndHeaders)
.Build();
using (var subscriptionClient = new SubscriptionClient(client))
{
var subscriptions = await subscriptionClient.Subscriptions
.ListAsync()
.ConfigureAwait(false);
foreach (var s in subscriptions)
{
Console.WriteLine($"Id={s.Id};subscriptionId={s.SubscriptionId};displayName={s.DisplayName}");
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
static AzureCredentials GetAzureCredentials()
{
var provider = new StringTokenProvider(AuthenticationResult.AccessToken, "Bearer");
var token = new TokenCredentials(provider, AuthenticationResult.TenantId, AuthenticationResult.IdToken != null ? AuthenticationResult.UniqueId : AuthenticationResult.IdToken);
return new AzureCredentials(token, token, AuthenticationResult.TenantId, AzureEnvironment.AzureGlobalCloud);
}
}
Upvotes: 2