Аутентификация SDK API Azure Magment с помощью MSAL.NET - PullRequest
1 голос
/ 27 июня 2019

Попытка аутентификации в API управления Azure с использованием их SDK . Я могу получить аутентификацию пользователя с помощью MSAL.NET SDK . Но когда я пытаюсь передать токен Bearer для ClientCrendentials, я могу и AuthorizationFailed Message.

Я включил user_impersination и делегировал разрешения в своем экземпляре Active Directory и зарегистрировал свое приложение через портал приложений.

Арендатор настроен на 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);
       }
   }

Я бы подумал, что пользователь может быть авторизован с использованием токена на предъявителя, полученного в моем методе GetCredentials.

1 Ответ

0 голосов
/ 11 июля 2019

Мне удалось разобраться с проблемой, и я хотел отметить две вещи

  1. Audience - это учетная запись TenantId. Если вы не знаете, как это работает, вы можете узнать об этом подробнее на официальной странице Microsoft.
  2. Параметр scopes, который выглядит так, как будто он поддерживает несколько областей, на самом деле это не так. Передача более одного scope вызывает ошибку

Полезные ресурсы

  • заявки от одного до нескольких арендаторов
  • прикладная аудитория
  • выбор поставщика аутентификации
  • Лучшие практики для 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);
        }
    }
    
...