Skip to content

Commit

Permalink
Merge pull request #27 from johnduprey/dev
Browse files Browse the repository at this point in the history
Initial Policy v2 API support
  • Loading branch information
JohnDuprey authored Jun 30, 2023
2 parents 4a1108c + 3119536 commit 4dd9c38
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 12 deletions.
10 changes: 10 additions & 0 deletions DuoSecurity/Private/Hashing/Get-Sha512HexDigest.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function Get-Sha512HexDigest {
Param($String)

if ([string]::IsNullOrEmpty($String)) { $String = '' }
$StringBuilder = New-Object System.Text.StringBuilder
[System.Security.Cryptography.HashAlgorithm]::Create('SHA512').ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object {
[Void]$StringBuilder.Append($_.ToString('x2'))
}
$StringBuilder.ToString()
}
68 changes: 56 additions & 12 deletions DuoSecurity/Private/REST Handler/Invoke-DuoRequest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@ function Invoke-DuoRequest {
[switch]$NoAuth,

[Parameter()]
[string]$FilePath
[string]$FilePath,

[Parameter()]
$AdditionalHeaders = @{},

[Parameter()]
[string]$SignatureVersion = 2,

[Parameter()]
$Body = ''
)

# Get API credentials
Expand Down Expand Up @@ -97,26 +106,60 @@ function Invoke-DuoRequest {
$Request = [regex]::Replace($Request, "([!'()*])", { '%' + [System.Convert]::ToByte($args[0].Value[0]).ToString('X') })

# Build Duo signature body linefeed separated
$SignatureParts = @(
$XDuoDate
$Method.ToUpper()
$ApiHost.ToLower()
$Path
$Request
)
if ($SignatureVersion -eq 5) {
$HeaderCollection = [System.Collections.Generic.List[string]]::new()
$AdditionalHeaderString = ''
$AdditionalHeaders.'x-duo-date' = $XDuoDate
if ($AdditionalHeaders) {
foreach ($Header in ($AdditionalHeaders.GetEnumerator() | Sort-Object -Property Key)) {
$HeaderCollection.Add($Header.Key.ToLower()) | Out-Null
$HeaderCollection.Add($Header.Value) | Out-Null
}
}
$AdditionalHeaderString = $HeaderCollection -join "`0"

$SignatureParts = @(
$XDuoDate
$Method.ToUpper()
$ApiHost.ToLower()
$Path
$Request
(Get-Sha512HexDigest -String $Body)
(Get-Sha512HexDigest -String $AdditionalHeaderString)
)
} else {
$SignatureParts = @(
$XDuoDate
$Method.ToUpper()
$ApiHost.ToLower()
$Path
$Request
)
}

$SignatureBody = $SignatureParts -join "`n"

Write-Verbose "`n---Canon signature---`n$SignatureBody`n-------"

# Encode signature with secretbytes
[byte[]]$KeyBytes = [System.Text.Encoding]::UTF8.GetBytes($SecretKey.ToCharArray())
[byte[]]$DataBytes = [System.Text.Encoding]::UTF8.GetBytes($SignatureBody.ToCharArray())

# Generate an HMAC SHA1 hash
$HmacSha1 = New-Object System.Security.Cryptography.HMACSHA1
$HmacSha1.Key = $KeyBytes
$null = $HmacSha1.ComputeHash($DataBytes)
$HashHex = [System.BitConverter]::ToString($HmacSha1.Hash)

if ($SignatureVersion -eq 5) {
$HashLib = New-Object System.Security.Cryptography.HMACSHA512
} else {
$HashLib = New-Object System.Security.Cryptography.HMACSHA1
}
$HashLib.Key = $KeyBytes
$null = $HashLib.ComputeHash($DataBytes)
$HashHex = [System.BitConverter]::ToString($HashLib.Hash)

$Signature = $HashHex.Replace('-', '').ToLower()

Write-Verbose "Signature: $signature"

# Build base64 encoded auth string with IntegrationKey and Signature
$AuthString = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(('{0}:{1}' -f $IntegrationKey, $Signature)))

Expand All @@ -143,6 +186,7 @@ function Invoke-DuoRequest {
}

Write-Verbose ( '{0} [{1}]' -f $Method, $UriBuilder.Uri )
Write-Verbose ( 'Headers: {0}' -f ($Headers | ConvertTo-Json) )

$RestMethod = @{
Method = $Method
Expand Down
55 changes: 55 additions & 0 deletions DuoSecurity/Public/Admin API/Policies/Get-DuoPolicies.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
function Get-DuoPolicies {
<#
.SYNOPSIS
Retrieve Policies
.DESCRIPTION
Retrieve a complete set of all policies. Includes all policy section data for each policy. Requires "Grant read resource" API permission.
.PARAMETER PolicyKey
The key for the Policy
.EXAMPLE
Get-DuoPolicies
.LINK
https://duo.com/docs/adminapi#retrieve-policies
.LINK
https://duo.com/docs/adminapi#retrieve-policy-by-id
#>
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('policy_key')]
[string]$PolicyKey
)

process {
if ($PolicyKey) {
$Path = '/admin/v2/policies/{0}' -f $PolicyKey
} else {
$Path = '/admin/v2/policies'
}

$DuoRequest = @{
Method = 'GET'
Path = $Path
SignatureVersion = 5
}

if ($EndpointKey) {
$Request = Invoke-DuoRequest @DuoRequest
if ($Request.stat -ne 'OK') {
$Request
} else {
$Request.response
}
} else {
Invoke-DuoPaginatedRequest -DuoRequest $DuoRequest
}
}
}

Set-Alias -Name Get-DuoEndpoint -Value Get-DuoEndpoints

0 comments on commit 4dd9c38

Please sign in to comment.