我可以在Azure oauth2.0 ROPC上使用MFA应用程序密码吗? [英] Can I use MFA app passwords with Azure oauth2.0 ROPC?

查看:113
本文介绍了我可以在Azure oauth2.0 ROPC上使用MFA应用程序密码吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在powershell中,我们有一个脚本,该脚本使用资源所有者密码凭据从Azure REST API获取信息.

In powershell we have a script that gets info from Azure REST API using Resource Owner Password Credentials.

https://docs .microsoft.com/bs-latn-ba/azure/active-directory/develop/v2-oauth-ropc

该脚本可与未启用MFA的用户完美配合.对于具有MFA的用户,它不起作用. 我尝试使用在MFA的用户帐户上创建的应用密码,但这也无法正常工作.

The script works perfectly with users that don't have MFA enabled. For user with MFA it doesn't work. I tried to use an app password that I created on the user account with MFA but this didn't work also.

https ://support.microsoft.com/zh-CN/help/12409/microsoft-account-app-passwords-and-two-step-verification

该脚本作为服务运行,因此用户交互是不可选择的.我们还需要使用ROPC,因为我们所需的信息仅在Azure应用上通过委派权限提供.

The script is running as a service so user interaction is no option. We also need to use ROPC because the info we needed is only available trough delegated permisions on the Azure app.

有没有人对此有经验?

Is there anyone that has experience with this?

这是脚本:

$tenantid = '*************************'
$subscriptionid = '*********************'
$clientid = '***********************'
$clientsecret = '******************'
$username = '*****************'
$password = '************************'

##################################################################
##################################################################
##################################################################

$return = Invoke-Command -ScriptBlock { 
param($tenantid,$subscriptionid,$clientid,$clientsecret,$username,$password)    

Add-Type -AssemblyName System.Web

$encPass = [System.Web.HttpUtility]::UrlEncode($password)
$encScope = [System.Web.HttpUtility]::UrlEncode('https://management.azure.com/user_impersonation')
$encSecret = [System.Web.HttpUtility]::UrlEncode($clientsecret)

$body = "client_id=$clientid&scope=$encScope&username=$username&password=$encPass&grant_type=password&client_secret=$encSecret"

$auth = Invoke-WebRequest "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token" -Method Post -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing

$token = ($auth | ConvertFrom-Json).access_token
$headers = @{
    'Authorization'="Bearer $($token)"
}

$data = Invoke-WebRequest "https://management.azure.com/subscriptions/$subscriptionid/providers/Microsoft.Advisor/recommendations?api-version=2017-04-19" -Method GET -Headers $headers -UseBasicParsing

New-Object PSObject -Property @{
    content=$data.content
}

} -ArgumentList $tenantid,$subscriptionid,$clientid,$clientsecret,$username,$password

$content = $return.content

Write-Host $content

使用启用了MFA的用户时的输出:

The output when I use an user with MFA enabled:

Invoke-WebRequest : {"error":"invalid_grant","error_description":"AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to 
access '*******'.\r\nTrace ID: d9a7f9f2-c52c-40ca-b057-9513bd353900\r\nCorrelation ID: 3329e686-7bd0-409d-b7da-91e49221bacc\r\nTimestamp: 2019-10-02 
13:19:36Z","error_codes":[50076],"timestamp":"2019-10-02 
13:19:36Z","trace_id":"d9a7f9f2-c52c-40ca-b057-9513bd353900","correlation_id":"3329e686-7bd0-409d-b7da-91e49221bacc","error_uri":"https://login.microsoftonline.com/error?code=50076","suberror":"basic_action"}
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:27 char:9
+ $auth = Invoke-WebRequest "https://login.microsoftonline.com/$tenanti ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
ConvertFrom-Json : Cannot bind argument to parameter 'InputObject' because it is null.
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:29 char:19
+ $token = ($auth | ConvertFrom-Json).access_token
+                   ~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertFrom-Json], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertFromJsonCommand

Invoke-WebRequest : {"error":{"code":"AuthenticationFailedMissingToken","message":"Authentication failed. The 'Authorization' header is missing the access token."}}
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:34 char:9
+ $data = Invoke-WebRequest "https://management.azure.com/subscriptions ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

使用在用户帐户上创建的应用程序密码更改密码时的输出

The output when I change the password with an app password created on the user account

Invoke-WebRequest : {"error":"invalid_grant","error_description":"AADSTS50126: Invalid username or password.\r\nTrace ID: 3674934a-120b-48f3-96d8-7ec8ddf44300\r\nCorrelation ID: 
593aecd7-bbb2-4c5a-96e1-050bc00047ac\r\nTimestamp: 2019-10-02 13:26:46Z","error_codes":[50126],"timestamp":"2019-10-02 
13:26:46Z","trace_id":"3674934a-120b-48f3-96d8-7ec8ddf44300","correlation_id":"593aecd7-bbb2-4c5a-96e1-050bc00047ac","error_uri":"https://login.microsoftonline.com/error?code=50126"}
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:27 char:9
+ $auth = Invoke-WebRequest "https://login.microsoftonline.com/$tenanti ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
ConvertFrom-Json : Cannot bind argument to parameter 'InputObject' because it is null.
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:29 char:19
+ $token = ($auth | ConvertFrom-Json).access_token
+                   ~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertFrom-Json], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertFromJsonCommand

Invoke-WebRequest : {"error":{"code":"AuthenticationFailedMissingToken","message":"Authentication failed. The 'Authorization' header is missing the access token."}}
At C:\Users\Wouter.sterkens\Documents\VS Projects\Azure Monitoring\advisor.ps1:34 char:9
+ $data = Invoke-WebRequest "https://management.azure.com/subscriptions ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

推荐答案

据我所知,应用密码用于与不支持现代身份验证的客户端完成MFA.现在,您使用ROPC OAuth流. APP密码不支持.

As far as I know, app password is used to complete MFA with the clients which do not support modern authentication. Now, you use ROPC OAuth flow. APP password does not support it.

根据情况,我建议您手动完成MFA以获得 OAuth 2.0客户端凭据流以获取访问令牌.例如

According to the situation, I suggest you finish MFA manually to get refresh token then we use refresh token to get access token and call API. Because MFA refresh token will not expire until you revoke it. Or you use OAuth 2.0 client credentials flow to get the access token. For example

用户刷新令牌

  1. 注册Azure AD应用程序

  1. Register Azure AD application

使用 OAuth 2.0授权代码流程以完成MFA并获取刷新令牌

Use OAuth 2.0 authorization code flow to complete MFA and get refresh token

$Params = @{
    'client_id' = 'b0114608-677e-4eca-ae22-60c32e1782d9' 
    'redirect_URI' = 'https://www.baidu.com'
    'response_type'='code'
    'scope' = 'offline_access openid https://management.azure.com/user_impersonation'
}
$ClientSecret =''
$TeantID = ''
$Query = "?"; $Params.Keys | % {$Query+= "$($_)=$($Params.Item($_))&"} ; $Query = $Query.TrimEnd('&')


$IE= new-object -ComObject "InternetExplorer.Application"
$IE.Visible = $true
$IE.navigate2("https://login.microsoftonline.com/$($TeantID)/oauth2/v2.0/authorize$Query")

write-host "get authorization code"
pause

Add-Type -AssemblyName System.Web
[System.Web.HttpUtility]::ParseQueryString(([uri] $IE.LocationURL).Query)['code']
$Code = [System.Web.HttpUtility]::ParseQueryString(([uri] $IE.LocationURL).Query)['code']
$IE.Quit()

$TokenResult = Invoke-RestMethod -Method Post -ContentType 'application/x-www-form-urlencoded' -Uri "https://login.microsoftonline.com/$($TeantID)/oauth2/v2.0/token" -Body @{
    client_id     = $Params.client_id
    scope         = ''
    code          = $Code
    redirect_uri  = $Params.Redirect_URI
    grant_type    = 'authorization_code'
    client_secret = $ClientSecret
}

$TokenResult.refresh_token

  1. 获取访问令牌并调用api

$TokenResult = Invoke-RestMethod -Method Post -ContentType 'application/x-www-form-urlencoded' -Uri "https://login.microsoftonline.com/$($TeantID)/oauth2/v2.0/token" -Body @{
    client_id     = ''
    scope         = 'https://management.azure.com/user_impersonation'
    redirect_uri  = ''
    grant_type    = 'refresh_token'
    client_secret = ''
    refresh_token =''
}



 Invoke-RestMethod -Method Get -Uri '' -Headers @{Authorization = "Bearer "+ $TokenResult.access_token}

使用OAuth 2.0客户端凭据流

$TokenResult = Invoke-RestMethod -Method Post -ContentType 'application/x-www-form-urlencoded' -Uri "https://login.microsoftonline.com/$($TeantID)/oauth2/v2.0/token" -Body @{
    client_id     = ''
    scope         = 'https://management.azure.com/.default'
    grant_type    = 'client_credentials'
    client_secret = ''

}

 Invoke-RestMethod -Method Get -Uri '' -Headers @{Authorization = "Bearer "+ $TokenResult.access_token}

更新 根据您的需要,您可以创建服务主体并将RABC角色分配给服务主体.然后,您可以OAuth 2.0客户端凭据流来获取访问令牌并调用Azure rest api.详细步骤如下

Update According to your need, you can create a service principal and assign RABC role to the service principal. Then you can OAuth 2.0 client credentials flow to get access token and call Azure rest api. The detailed steps are as below

  1. 创建服务主体并将RABC角色分配给服务主体

Connect-AzAccount
$password=''
$credentials = New-Object Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential -Property @{ StartDate=Get-Date; EndDate=Get-Date -Year 2024; Password=$password'}
$sp = New-AzAdServicePrincipal -DisplayName jimtest1 -PasswordCredential $credentials

New-AzRoleAssignment -ApplicationId $sp.ApplicationId -RoleDefinitionName Owner

  1. 获取访问令牌

# get access token
$TeantID='hanxia.onmicrosoft.com'
$TokenResult = Invoke-RestMethod -Method Post -ContentType 'application/x-www-form-urlencoded' -Uri "https://login.microsoftonline.com/$($TeantID)/oauth2/v2.0/token" -Body @{
    client_id     = $sp.ApplicationId # the application id of service principal
    scope         = 'https://management.azure.com/.default'
    grant_type    = 'client_credentials'
    client_secret = $password # you use it in step 1

}

  1. 调用Azure Rest API

#list resource group
$values =Invoke-RestMethod -Method Get -Uri "https://management.azure.com/subscriptions/e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68/resourcegroups?api-version=2019-05-10" -Headers @{
Authorization = "Bearer "+ $TokenResult.access_token
ContentType = 'application/json'
}

有关更多详细信息,请参阅

For more details, please refer to

https://docs.microsoft.com/zh-CN/powershell/azure/create-azure-service-principal-azureps?view=azps-2.7.0

查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆