04-27-2022 07:20 AM
I am using a PowerShell script to attempt to sync a user to a directory. I am getting back a
{"code": 40401, "message": "Resource not found", "message_detail": "Directory not found", "stat": "FAIL"}
Generally when I modify the script I’m getting an “code”: 40401, “message”: “Resource not found”
This makes me believe its an Auth issue still
I Am able to successfully get /auth/v2/check to work however
function New-DuoRequest(){
param(
[Parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
$apiHost,
[Parameter(Mandatory=$true,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateNotNull()]
$apiEndpoint,
[Parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
$apiKey,
[Parameter(Mandatory=$true,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateNotNull()]
$apiSecret,
[Parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateNotNull()]
$requestMethod = 'GET',
[Parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[ValidateNotNull()]
[System.Collections.Hashtable]$requestParams
)
$date = (Get-Date).ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss -0000")
$formattedParams = ($requestParams.Keys | Sort-Object | ForEach-Object {$_ + "=" + [uri]::EscapeDataString($requestParams.$_)}) -join "&"
#DUO Params formatted and stored as bytes with StringAPIParams
$requestToSign = (@(
$Date.Trim(),
$requestMethod.ToUpper().Trim(),
$apiHost.ToLower().Trim(),
$apiEndpoint.Trim(),
$formattedParams
).trim() -join "`n").ToCharArray().ToByte([System.IFormatProvider]$UTF8)
$hmacsha1 = [System.Security.Cryptography.HMACSHA1]::new($apiSecret.ToCharArray().ToByte([System.IFormatProvider]$UTF8))
$hmacsha1.ComputeHash($requestToSign) | Out-Null
$authSignature = [System.BitConverter]::ToString($hmacsha1.Hash).Replace("-", "").ToLower()
$authHeader = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(('{0}:{1}' -f $apiKey, $authSignature)))
$httpRequest = @{
URI = ('https://{0}{1}' -f $apiHost, $apiEndpoint)
Headers = @{
"X-Duo-Date" = $Date
"Authorization" = "Basic $authHeader"
}
Body = $requestParams
Method = $requestMethod
ContentType = 'application/x-www-form-urlencoded'
}
$httpRequest
}
# Calling the function
$values = @{
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■'
apiEndpoint = '/admin/v1/users/directorysync/DIRECOTRYKEY/syncuser'
requestMethod = 'POST'
requestParams = @{username="JDOE"}
apiSecret = 'SECRETKEY'
apiKey = 'IKEY'
}
$contructWebRequest = New-DuoRequest @values
# Send the request
$wr = Invoke-WebRequest @contructWebRequest
$wr
04-29-2022 10:39 AM
for DIRECTORY NOT FOUND
I’d suggest double-checking the directory_key
value in your apiEndpoint
. If it was an authentication issue the response would not tell you the directory you specified wasn’t found, it would return a 401 like “Invalid signature in request credentials”.
05-02-2022 07:10 AM
I have 100% checked the directory key and even attempted multiple directories
05-02-2022 10:55 AM
I copied the PowerShell example you have here to my test Windows VM, replaced some of the $values
info with those specific to my API host (the censored ■■■■ text), Admin API integration key and secret key, and my directory key and the user to sync, and it worked.
PS C:\users\kristina\documents> $values = @{
>>
>> ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■'
>> apiEndpoint = '/admin/v1/users/directorysync/DZkey/syncuser'
>> requestMethod = 'POST'
>> requestParams = @{username="duoprem.testuser@domain"}
>> apiSecret = 'skey'
>> apiKey = 'ikey'
>> }
PS C:\users\kristina\documents> echo $values
Name Value
---- -----
apiEndpoint /admin/v1/users/directorysync/DZkey/syncuser
requestParams {username}
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
requestMethod POST
apiSecret skey
apiKey ikey
PS C:\users\kristina\documents> $contructWebRequest = New-DuoRequest @values
PS C:\users\kristina\documents> $wr = Invoke-WebRequest @contructWebRequest
PS C:\users\kristina\documents> $wr
StatusCode : 200
StatusDescription : OK
Content : {"response": {"message": "User duoprem.testuser@domain synced successfully.", "user": {"alias1": null, "alias2": null,
"alias3": null, "alias4": null, "aliases": {}, "created": 158...
RawContent : HTTP/1.1 200 OK
Connection: keep-alive
Pragma: no-cache
Strict-Transport-Security: max-age=31536000
Content-Security-Policy: default-src 'self'; frame-src 'self' ; img-src 'self' ; connect-src 's...
Forms : {}
Headers : {[Connection, keep-alive], [Pragma, no-cache], [Strict-Transport-Security, max-age=31536000], [Content-Security-Policy, default-src 'self';
frame-src 'self' ; img-src 'self' ; connect-src 'self']...}
Images : {}
InputFields : {}
Links : {}
ParsedHtml : System.__ComObject
RawContentLength : 899
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide