Проверка подлинности сценария Powershell Exchange EWS с использованием Oauth не может использовать файл сохранения ha sh - PullRequest
0 голосов
/ 23 марта 2020

Обычно для запланированных сценариев я сохраняю файл ha sh на диск для учетных данных, которые будут использоваться сценарием следующим образом:

$Credential = Get-Credential Admin@domain.com 
$Credential.Password | ConvertFrom-SecureString | Set-Content "C:\admin.pwd" $Username = "Admin@domain.com" 
$Password = Get-Content "C:\admin.pwd" -ErrorAction stop | ConvertTo-SecureString
$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password) 

Следующий запрос маркера присяги работает, если элемент пароля в Тело вводится в виде простого текста, но оно не работает, если я использую переменную $ Credential.Password. Есть ли способ заставить это работать или защитить пароль иным образом?

Ошибка, которую генерирует следующий запрос токена:

Ошибка: Invoke-RestMethod: {"error": "invalid_grant "," error_description ":" AADSTS50126: Ошибка при проверке учетных данных из-за неверного имени пользователя или пароля ... "error_uri": "login.microsoftonline.com/error?code=50126"casts

## Request an access token

# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'AppIdHere'
$AppSecret = 'AppSecretHere'
$Scope = "https://outlook.office365.com/.default"
$TenantName = "Domain.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Create body
$Body = @{
    client_id = $AppId
    client_secret = $AppSecret
    scope = $Scope
    grant_type = 'password'
    username = 'Admin@domain.com'
    password = $Credential.Password
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'

    # Create string by joining bodylist with '&'
    Body = $Body
    Uri = $Url
}

# Request the token for user!
$Request = Invoke-RestMethod @PostSplat

$Request.access_token

##########

== =========================

Обновлен скрипт на основе ответа от thepip3r и поддержка Microsoft :

Пароль и секрет передаются в виде простого текста на проводе, но не раскрываются в скрипте, и имеют степень безопасности, сохраняемую в виде хеш-файлов

Настраивается, чтобы не сохранять пароль или секрет в переменные для повышения безопасности от атак, которые могут получить доступ к памяти (рекомендуется поддержка MS)

Возможность использовать сертификат для зарегистрированного приложения Azure вместо секретного приложения для повышения безопасности на проводе

Альтернативным вариантом является использование "Azure Au tomation", которая позволяет запускать скрипты из O365, что должно быть намного более безопасным. Другой возможной альтернативой могут быть Azure Функции.

# One time AppID\Secret hash save to file:
## $AppCredential = Get-Credential 'AppIdHere'
## $AppCredential.Password | ConvertFrom-SecureString | Set-Content "C:\App.pwd" 

# One time Admin hash save to file:
## $Credential = Get-Credential admin@domain.com
## $Credential.Password | ConvertFrom-SecureString | Set-Content "C:\admin.pwd" 

$AppId = 'AppIdHere'
$AppS = Get-Content "C:\App.pwd"  | ConvertTo-SecureString
$AppCredential = New-Object System.Management.Automation.PSCredential($AppId,$AppS)

$Username = "admin@domain.com"
$Password = Get-Content "C:\admin.pwd" | ConvertTo-SecureString
$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password)        

### Request an access token ###

$Scope = "https://outlook.office365.com/.default"
$TenantName = "usablelife.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Request the token!
$Request = Invoke-RestMethod -Body @{
    client_id = $AppId
    client_secret = $AppCredential.GetNetworkCredential().Password
    scope = $Scope
    grant_type = 'password'
    username = $Username 
    password = $Credential.GetNetworkCredential().Password
} `
-ContentType 'application/x-www-form-urlencoded' `
-Method 'POST' `
-Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

1 Ответ

2 голосов
/ 23 марта 2020

Итак ... Я собираюсь предоставить это в качестве ответа, потому что я хочу, чтобы люди поняли это как пример проблемы с сохранением пароля в файле (даже в виде строкового значения зашифрованного текста) с Get-Credential.

@ mbromb, это даст вам способ проверить , является ли полученное вами значение правильным:

для вашего объекта $ Credential (последняя строка ), запустите: $Credential.GetNetworkCredential().Password

Это будет значение PLAINTEXT того, что вы изначально добавили в приглашения с помощью Get-Credential. Таким образом, вы можете проверить, работает ли после получения этого файла, записи его в файл, считывания обратно и преобразования его в объект защищенной строки.

Чтобы попытаться нарисовать более прямую линию к этому проблема: если я найду ваш файл 'admin.pwd', очень просто создать из него открытый текст.

Предупреждение: Вы можете защитить это значение, предоставив защищенный ключ для этого процесса шифрования, используя свойства -Key или -SecureKey в командлетах ConvertTo / From-SecureString. Ключ принимает байтовый массив (желательно криптографически случайный с достаточной энтропией для ваших нужд), а SecureKey принимает строку (пароль) и генерирует байтовый массив из вашего пароля.

Caveat-to-the-caveat: Если вы ' Уже пытаясь сохранить пароль в файле, пароль, защищающий сохраненный пароль, вероятно, не правильный ответ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...