Аутентифицироваться в веб-приложении Azure через вторую регистрацию приложения с использованием токена пользователя Azure? - PullRequest
0 голосов
/ 13 июля 2020

Рабочий сценарий

У меня есть веб-приложение Azure (https://www.contoso.com), для которого я хочу пройти аутентификацию и выполнить веб-вызов.

Я хочу аутентифицироваться, используя Connect-AzAccount, и звонить ему, используя свою личность.

Я успешно использую следующий код, чтобы получить действительный токен и вызвать приложение.

#Authenticate as myself or a sevice principal 
Connect-AzAccount -Tenant 'a736bac3-c259-450f-90a4-f7d5bd7c4c78'

# App registration ID for Contoso
$ResourceUri = '24114488-8c26-4e87-8f71-90de62f5a8aa'
$Context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceUri).AccessToken
$Headers = @{Headers = @{Authorization = "Bearer $token" } }
Invoke-RestMethod -Method Get -uri 'https://Contoso.com/module/Something' @Headers

При этом само приложение не реализует принудительное назначение пользователей и групп. Вместо этого каждый может подключиться к нему (по дизайну).

Проблема c

Решение, представленное выше, требует от меня добавления Powershell Azure (1950a258- 227b-4e31-a9cf-717495945fc2) в списке Авторизованное клиентское приложение , чтобы включить этот сценарий. Выполнив эту операцию, любой в моем каталоге теперь может технически совершать звонки на веб-сайт, что нежелательно.

Authorized client application

Desired Scenario

Because user assignment is not enforced, I removed the Powershell Azure client from the main app and instead created a second App Registration for which I authorized the PS AZ client and added an API permission so it had access to the main App. The idea is that I can require user assignement for the second app registration and therefore limit the user that can make these kind of calls.

Initial (working) flow:

  • Connect-AzAccount authenticate the user
  • Code sample above is ran to obtain the token and call the app.

Desired flow

  • Connect-AzAccount authenticate the user
  • User connect through the client app registraion (new app) that has api permission to the main app.
  • User make calls to the main app.

Now, if I try to use my initial code sample with the Application Id of the second registration acting as a client ID, I get the following error

Invoke-RestMethod : {"code":401,"message":"IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not 
match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'."}
At line:1 char:12
+ $result2 = Invoke-RestMethod -Method Get -uri 'https://Contoso.com/so...
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExcept  
   ion
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I believe that this is because I am obtaining a token for the second app registration and trying to call the main app URL, which is not authorized through the token.

A "working" alternative to this problem would be to connect using Client_credentials as grant_type such as this:

function get-Bearer([string]$TenantID, [string]$ClientID, [string]$ClientSecret) {
    $TokenEndpoint = "https://login.windows.net/{0}/oauth2/token" -f $TenantID 


    $Body = @{
        'resource'      = '24114488-8c26-4e87-8f71-90de62f5a8aa'
        'client_id'     = $ClientID
        'grant_type'    = 'client_credentials'
        'client_secret' = $ClientSecret
    }

    $params = @{
        ContentType = 'application/x-www-form-urlencoded'
        Headers     = @{'accept' = 'application/json' }
        Body        = $Body
        Method      = 'Post'
        URI         = $TokenEndpoint
    }

    $token = Invoke-RestMethod @params

    Return "Bearer " + ($token.access_token).ToString()
}

If I do that, even though I can make calls to the main app. again but it is connected with the actual client app. and not using the user identity obtained through Connect-AzAccount (for which tokens can be generated through the initial sample)

I was also able to make it work with a password grant_type but this is not making use of my bearer token and is also invalidated by MFA enabled users.

All insights are welcome.

References

Документация по платформе Microsoft Identity - v2-oauth2-on-name-of- поток (копаемся в потоке приложения, чтобы попытаться заставить что-нибудь работать)

Ответы [ 2 ]

1 голос
/ 16 июля 2020

Приложение app ids, а не object ids, следует использовать в качестве идентификаторов ресурсов. Продолжайте получать токены, используя первое приложение (24114488-8c26-4e87-8f71-90de62f5a8aa) как ресурс / аудиторию (используя его идентификатор приложения uri ), а второе приложение как клиент. Connect-Az будет исключен из уравнения.

#Install the ADAL.PS package if it's not installed.
if(!(Get-Package adal.ps)) { Install-Package -Name adal.ps }

$authority = "https://login.windows.net/common/oauth2/authorize"
#this is the security and compliance center endpoint
$resourceUrl = "{first application id uri}"
#replace <redirect-uri>, with the Redirect URI from your Azure AD application registration.
$clientId = "{second application app id}"
$redirectUri = "<redirect-uri>"

$response = Get-ADALToken -Resource $resourceUrl -ClientId $clientId -RedirectUri $redirectUri -Authority $authority -PromptBehavior:Always
$response.AccessToken | clip
0 голосов
/ 05 сентября 2020
• 1000 API A

Причина заключалась в том, что я не мог реализовать управляющий доступ на Web API B (это требование, чтобы он был доступен для всех пользователей клиента), и я также не удалось добавить идентификатор клиента Powershell в Web API B напрямую, поскольку это позволило бы каждому получить токен и выполнить вызов Web API B с помощью Powershell.

Следовательно , Мне понадобился посредник Web API A , чтобы разрешить идентификатор клиента Powershell и предоставить контролируемый / ограниченный доступ пользователей к Web API B

В Платформа идентификации Microsoft и Oauth 2.0, называемые потоком On-Behal-Of , которые допускают именно этот сценарий.

OAuth 2.0 On-Behalf-Of flow

Prerequisites

App Registration for Web API B

  • API Permission: Delegated permission to User.Read (Graph API)
  • Expose an API: add a User_Impersonation scope and the Application ID of Web API A in the authorized client ID

App Registration for Web API A

  • In Api Permissions, add the User_Impersonation scope of Web API B

From there, the following code will get you connected

Connect-AzAccount -TenantId '584e32bc-214f-4046-89e5-79b7bac9ae75'

$Params = @{
    ClientId     = '6788d279-fb83-4962-b371-445479875e0e'
    ClientSecret = '16cc0f3d88cb4dd189fe6bf8e845982d'
    resourceId   = 'aeefa559-cb1c-41eb-ac5d-0bcb0bc01eaf'
    Scope        = 'https://graph.microsoft.com/user.read+offline_access'
}

function Get-AzCustomTokenOnBehalOf {
    [CmdletBinding()]
    param (
        $ClientId, 
        $ClientSecret,
        #Application ID of the target resource
        $ResourceId,
        $Scope 
    )
    
    # Get Token For WebApp A $TenantId
    $Context = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile.DefaultContext
    $IntermediaryToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ClientId).AccessToken
    $TokenUri = "https://login.microsoftonline.com/$($Context.Tenant.Id)/oauth2/token" 
    
    $FinalToken = Invoke-RestMethod -Uri $TokenUri -Method Post -Body @{
        grant_type          = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
        resource            = $ResourceId
        client_id           = $ClientId
        client_secret       = $ClientSecret
        assertion           = $IntermediaryToken
        scope               = $Scope
        requested_token_use = 'on_behalf_of'
    }

    return $FinalToken
}

$Token = Get-AzCustomTokenOnBehalOf @Params
$Headers = @{Headers = @{Authorization = "bearer $($Token.access_token)" } }

$MYsite = Invoke-RestMethod -Method Get -uri 'https://SomeWebsite.com/' @Headers

Additional considerations This scenario do require a client secret (This is the one I demonstratedO or a client certificate in order to work.

It is also subject to some limitations defined in the reference documentation and might not be suitable to all scenarios.

References:

Платформа идентификации Microsoft и поток OAuth 2.0 On-Behalf-Of

...