Skip to content

Commit

Permalink
Merge pull request #1778 from microsoft/lusassl-OAuthTokenSharedFunction
Browse files Browse the repository at this point in the history
Make CreateOAUTHToken a shared function
  • Loading branch information
lusassl-msft authored Jul 31, 2023
2 parents 307f609 + b16f753 commit be2b050
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 60 deletions.
92 changes: 32 additions & 60 deletions Security/src/CVE-2023-23397/CVE-2023-23397.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ begin {
. $PSScriptRoot\..\..\..\Shared\AzureFunctions\Get-GraphAccessToken.ps1
. $PSScriptRoot\..\..\..\Shared\AzureFunctions\Get-CloudServiceEndpoint.ps1
. $PSScriptRoot\..\..\..\Shared\AzureFunctions\Get-NewJsonWebToken.ps1
. $PSScriptRoot\..\..\..\Shared\AzureFunctions\Get-NewOAuthToken.ps1
. $PSScriptRoot\..\..\..\Shared\AzureFunctions\Invoke-GraphApiRequest.ps1
. $PSScriptRoot\..\..\..\Shared\Show-Disclaimer.ps1

Expand Down Expand Up @@ -440,51 +441,6 @@ begin {
return [Microsoft.Exchange.WebServices.Data.Item]::Bind($ExchangeService, $Id, $ps);
}

## function to create OAuth token
function CreateOAUTHToken {
param(
[string]$TenantID,
[string]$ClientID,
[string]$AppSecret,
[string]$AzureADEndpoint,
[bool]$UseCertificateToAuthenticate = $false,
[string]$Scope
)

try {
$body = @{
scope = $Scope
client_id = $ClientID
grant_type = "client_credentials"
}

if ($UseCertificateToAuthenticate) {
$body.Add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
$body.Add("client_assertion", $AppSecret)
} else {
$body.Add("client_secret", $AppSecret)
}

$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'

# Create string by joining bodyList with '&'
Body = $body
Uri = "$AzureADEndpoint/$TenantID/oauth2/v2.0/token"
}

$Token = Invoke-RestMethod @PostSplat
} catch {
Write-Host "`nFailure creating EWS auth token, exiting Program. Please review the error message below and re-run the program:`n`n$_" -ForegroundColor Red
exit
}

$script:tokenLastRefreshTime = (Get-Date)

return $Token
}

function GetAzureApplication {
param(
$AzAccountsObject,
Expand Down Expand Up @@ -837,11 +793,11 @@ begin {
# if token is going to expire in next 5 min then refresh it
if ($null -eq $script:tokenLastRefreshTime -or $script:tokenLastRefreshTime.AddMinutes(55) -lt (Get-Date)) {
$createOAuthTokenParams = @{
TenantID = $ApplicationInfo.TenantID
ClientID = $ApplicationInfo.ClientID
AzureADEndpoint = $AzureADEndpoint
UseCertificateToAuthenticate = (-not([System.String]::IsNullOrEmpty($ApplicationInfo.CertificateThumbprint)))
Scope = $EWSOnlineScope
TenantID = $ApplicationInfo.TenantID
ClientID = $ApplicationInfo.ClientID
Endpoint = $AzureADEndpoint
CertificateBasedAuthentication = (-not([System.String]::IsNullOrEmpty($ApplicationInfo.CertificateThumbprint)))
Scope = $EWSOnlineScope
}

# Check if we use an app secret or certificate by using regex to match Json Web Token (JWT)
Expand All @@ -860,12 +816,20 @@ begin {
exit
}

$createOAuthTokenParams.Add("AppSecret", $jwt)
$createOAuthTokenParams.Add("Secret", $jwt)
} else {
$createOAuthTokenParams.Add("AppSecret", $ApplicationInfo.AppSecret)
$createOAuthTokenParams.Add("Secret", $ApplicationInfo.AppSecret)
}

$Token.Value = CreateOAUTHToken @createOAuthTokenParams
$oAuthReturnObject = Get-NewOAuthToken @createOAuthTokenParams
if ($oAuthReturnObject.Successful -eq $false) {
Write-Host ""
Write-Host "Unable to refresh EWS OAuth token. Please review the error message below and re-run the script:" -ForegroundColor Red
Write-Host $oAuthReturnObject.ExceptionMessage -ForegroundColor Red
exit
}
$Token.Value = $oAuthReturnObject.OAuthToken
$script:tokenLastRefreshTime = $oAuthReturnObject.LastTokenRefreshTime
$EWSService.Value = EWSAuth -Environment $Environment -Token $Token.Value -EWSOnlineURL $EWSOnlineURL
}
}
Expand Down Expand Up @@ -1110,16 +1074,24 @@ begin {
}

$createOAuthTokenParams = @{
TenantID = $tenantID
ClientID = $clientID
AppSecret = $applicationInfo.AppSecret
Scope = $ewsOnlineScope
AzureADEndpoint = $azureADEndpoint
UseCertificateToAuthenticate = (-not([System.String]::IsNullOrEmpty($CertificateThumbprint)))
TenantID = $tenantID
ClientID = $clientID
Secret = $applicationInfo.AppSecret
Scope = $ewsOnlineScope
Endpoint = $azureADEndpoint
CertificateBasedAuthentication = (-not([System.String]::IsNullOrEmpty($CertificateThumbprint)))
}

#Create OAUTH token
$EWSToken = CreateOAUTHToken @createOAuthTokenParams
$oAuthReturnObject = Get-NewOAuthToken @createOAuthTokenParams
if ($oAuthReturnObject.Successful -eq $false) {
Write-Host ""
Write-Host "Unable to fetch an OAuth token for accessing EWS. Please review the error message below and re-run the script:" -ForegroundColor Red
Write-Host $oAuthReturnObject.ExceptionMessage -ForegroundColor Red
exit
}
$EWSToken = $oAuthReturnObject.OAuthToken
$script:tokenLastRefreshTime = $oAuthReturnObject.LastTokenRefreshTime
$ewsService = EWSAuth -Environment $Environment -Token $EWSToken -EWSOnlineURL $ewsOnlineURL
} else {
#Server
Expand Down
85 changes: 85 additions & 0 deletions Shared/AzureFunctions/Get-NewOAuthToken.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

function Get-NewOAuthToken {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$TenantID,

[Parameter(Mandatory = $true)]
[string]$ClientID,

[Parameter(Mandatory = $true)]
[string]$Secret,

[Parameter(Mandatory = $true)]
[string]$Endpoint,

[Parameter(Mandatory = $false)]
[string]$TokenService = "oauth2/v2.0/token",

[Parameter(Mandatory = $false)]
[switch]$CertificateBasedAuthentication,

[Parameter(Mandatory = $true)]
[string]$Scope
)

<#
Shared function to create an OAuth token by using a JWT or secret.
If you want to use a certificate, set the CertificateBasedAuthentication switch and pass a JWT token as the Secret parameter.
You can use the Get-NewJsonWebToken function to create a JWT token.
If you want to use a secret, pass the secret as the Secret parameter.
This function returns a PSCustomObject with the OAuth token, status and the time the token was created.
If the request fails, the PSCustomObject will contain the exception message.
#>

begin {
Write-Verbose "Calling $($MyInvocation.MyCommand)"
$oAuthTokenCallSuccess = $false
$exceptionMessage = $null

Write-Verbose "TenantID: $TenantID - ClientID: $ClientID - Endpoint: $Endpoint - TokenService: $TokenService - Scope: $Scope"
$body = @{
scope = $Scope
client_id = $ClientID
grant_type = "client_credentials"
}

if ($CertificateBasedAuthentication) {
Write-Verbose "Function was called with CertificateBasedAuthentication switch"
$body.Add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
$body.Add("client_assertion", $Secret)
} else {
Write-Verbose "Authentication is based on a secret"
$body.Add("client_secret", $Secret)
}

$invokeRestMethodParams = @{
ContentType = "application/x-www-form-urlencoded"
Method = "POST"
Body = $body # Create string by joining bodyList with '&'
Uri = "$Endpoint/$TenantID/$TokenService"
}
}
process {
try {
Write-Verbose "Now calling the Invoke-RestMethod cmdlet to create an OAuth token"
$oAuthToken = Invoke-RestMethod @invokeRestMethodParams
Write-Verbose "Invoke-RestMethod call was successful"
$oAuthTokenCallSuccess = $true
} catch {
Write-Host "We fail to create an OAuth token - Exception: $($_.Exception.Message)" -ForegroundColor Red
$exceptionMessage = $_.Exception.Message
}
}
end {
return [PSCustomObject]@{
OAuthToken = $oAuthToken
Successful = $oAuthTokenCallSuccess
ExceptionMessage = $exceptionMessage
LastTokenRefreshTime = (Get-Date)
}
}
}

0 comments on commit be2b050

Please sign in to comment.