How to generate an Authorization header for the SecureAuth API using Powershell

Follow
    Applies to:
  • Legacy SecureAuth IdP
Deployment model:
  • On Premises
  • SecureAuth IdP Version Affected:  8.2 and higher

     

    Description: 

    This article describes how to generate an authorization header for  the SecureAuth Authentication API using Powershell

     

    Cause

    GitHub contains C# and Javascript SDKs for the API but if implementing the API in a different language or not using the SDK, it can be useful to see a simple working example in Powershell for testing and demonstration purposes.

    Powershell is also relatively easy to understand and translate to other languages.

     

    Resolution

    This script is also attached as a text file:

    # Generate-IdP-API-Authorization-Header-via-Powershell 
    # Copyright (c) 2018, SecureAuth
    # All rights reserved.
    # More information: https://docs.secureauth.com/display/91docs/Authentication+API+Guide


    # Variables
    $IdPVersion92orHigher = $True # Set to FALSE for IdP 9.1 and lower
    $AppId = '4068954873794549a4acb0569aaf5af5' # Change to use your AppId
    $AppKey = '4c58595befbe30e40b661a46f554bee9dc3dbcdc8c5ad916dbc4eadf8f8e6183' # Change to use your AppKey
    $Method = 'GET'
    $ResourceUri = '/secureauth82/api/v1/users/user1/factors' # Change the realm number to the realm you are using, and user1 to the user account you want to test with
    $UriPrefix = 'https://idp.secureauthlab.com' # Change FQDN to match your IdP's FQDN

    If($IdPVersion92orHigher){$RequestDate = (Get-Date).ToUniversalTime().ToString('ddd, dd MMM yyyy HH:mm:ss.fff') + " GMT"}
    Else{$RequestDate = (Get-Date).ToUniversalTime().ToString('ddd, dd MMM yyyy HH:mm:ss') + " GMT"}


    # Functions

    function Test-Json
    {
    <#
    .SYNOPSIS
    Tests if a string is in valid JSON format

    .DESCRIPTION
    Test-Json takes an input string and tests for JSON validity.

    .PARAMETER InputString
    String to be evaluated for JSON format.

    .OUTPUTS
    Boolean True if Input string is valid JSON
    #>

    param
    (
    $InputString
    )
    try {
    $TempObject = ConvertFrom-Json $InputString -ErrorAction Stop;
    $IsJson = $true
    } catch {
    $IsJson = $false
    }
    return $IsJson
    }

    function Convert-HexToByte-HexString
    {
    <#
    .SYNOPSIS
    Converts a Hex string into a byte array

    .DESCRIPTION
    Convert-HexToByte-HexString takes a hex number string and converts each 2 hex characters into a single byte within an array of bytes.

    .PARAMETER HexString
    Hex string to be converted. Must be an even number of hex values.

    .OUTPUTS
    byte[]

    .EXAMPLE
    Convert-HexToByte-HexString -HexString '4c58595befbe30e40b661a46f554bee9dc3dbcdc8c5ad916dbc4eadf8f8e6183'
    #>
    param
    (
    [string]$HexString
    )
    $numberChars=$HexString.Length;

    [byte[]]$keyBytes=New-Object byte[] 32
    for([int]$i=0;$i-lt$numberChars;$i=$i+2)
    {
    $keyBytes[$i/2]=[Convert]::ToByte($HexString.Substring($i,2),16);
    }
    return $keyBytes;
    }

    function New-SecureAuthAuthorizationHeader
    {
    <#
    .SYNOPSIS
    Builds a SecureAuth REST API authorisation header.

    .DESCRIPTION
    New-SecureAuthAuthorizationHeader takes 5 mandatory parameters with an optional request body and produces an authorization header that can be used with the SecureAuth API.

    .PARAMETER AppId
    Hex string containing the Application ID as configured on the IdP realm

    .PARAMETER AppKey
    Hex string containing the Application Key as configured on the IdP realm

    .PARAMETER ResourceUri
    The URI to the API end point. This should not contain the protocol or the FQDN of the IdP but the part of the URL immediately following.

    .PARAMETER RequestDate
    String containing the request datetime in GMT.
    Format for IdP version 9.2+ should include milliseconds: ddd, dd MMM yyyy HH:mm:ss.fff plus a space then "GMT" for IdP v9.2+
    e.g.: Mon, 17 Dec 2018 11:51:30.934 GMT
    Format for 9.1 and lower should omit milliseconds: ddd, dd MMM yyyy HH:mm:ss plus a space then "GMT"
    e.g.: Mon, 17 Dec 2018 11:51:30 GMT

    .PARAMETER Method
    The HTTP Method being used, must be one of 'GET','POST', 'PUT' or 'DELETE'. Must be Uppercase.

    .PARAMETER RequestBody
    The request body in JSON format
    #>
    param
    (
    [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$AppId,
    [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$AppKey,
    [Parameter(Mandatory=$true)][Uri]$ResourceUri,
    [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$RequestDate,
    [Parameter(Mandatory=$true)][ValidateSet('GET','POST', 'PUT', 'DELETE')]$Method,
    [Parameter(Mandatory=$false)]$RequestBody
    )

    begin
    {
    if([string]::IsNullOrEmpty($RequestBody))
    {
    $hasBody=$false;
    }
    else
    {
    $hasBody=$true;
    }
    $appKeyByte=(Convert-HexToByte-HexString $AppKey);
    $dateString=$RequestDate
    }
    process
    {
    $pathstr = $ResourceUri
    if($hasBody)
    {
    if(Test-Json $RequestBody)
    {
    $RequestBodyJson = $RequestBody
    }
    else
    {
    $RequestBodyJson = $RequestBody | ConvertTo-Json -Compress
    }
    $message="$Method`n$dateString`n$AppId`n$pathstr`n$RequestBodyJson"
    }
    else
    {
    $message="$Method`n$dateString`n$AppId`n$pathstr"
    }
    write-host "`nMessage:`n$message"
    set-content -Path "c:\temp\hmac.txt" -Value $message
    $messageByte=[System.Text.Encoding]::UTF8.GetBytes($message);
    $hmacProvider=New-Object -TypeName 'System.Security.Cryptography.HMACSHA256'-ArgumentList @(,$appKeyByte);
    $hmac=[System.Convert]::ToBase64String($hmacProvider.ComputeHash($messageByte));
    write-host "`nHMAC: $hmac"
    $headerValue="Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(("{0}:{1}"-f $AppId,$hmac)));
    return $headerValue;
    }
    }


    #Main

    # Build authorization header
    $authHeaderParams= @{
    "AppId"=$AppId
    "AppKey"=$AppKey
    "Method"=$Method
    "ResourceUri"=$ResourceUri
    "RequestDate"=$RequestDate
    }
    $authHeader = New-SecureAuthAuthorizationHeader @authHeaderParams;
    Write-host "`nAuthorization Header: $authHeader"

    # Build headers
    if($IdPVersion92orHigher){
    $headers = @{
    'Authorization' = $authHeader
    'X-SA-Ext-Date' = $RequestDate
    'Content-Type' = 'application/json'
    }
    }
    else{
    $headers = @{
    'Authorization' = $authHeader
    'X-SA-Date' = $RequestDate
    'Content-Type' = 'application/json'
    }
    }

    write-host "`n`nHeaders:"
    $headers

    # Make HTTP request to API using created headers
    write-host "`n`n`nResponse:" -ForegroundColor Green
    $response = Invoke-RestMethod -Method $Method -Uri "$UriPrefix$ResourceUri" -Headers $headers | ConvertTo-Json -Depth 10
    $response


    Output from the above:

     

     

    More information:

    SecureAuth API:

    https://docs.secureauth.com/display/91docs/Authentication+API+Guide

     

    SecureAuth GitHub:

    https://github.com/SecureAuthCorp

     

    SecureAuth Knowledge Base Articles provide information based on specific use cases and may not apply to all appliances or configurations. Be advised that these instructions could cause harm to the environment if not followed correctly or if they do not apply to the current use case.

    Customers are responsible for their own due diligence prior to utilizing this information and agree that SecureAuth is not liable for any issues caused by misconfiguration directly or indirectly related to SecureAuth products.

    0 out of 0 found this helpful

    Comments

    1 comment
    • Would you be able to post the text file on github to provide more feedback directly on the example provided? I was able to trim it by about 60% and still submit GET requests with the headers, but unable to use it as-is to POST with a body (Invalid credentials)

      0
      Comment actions Permalink

    Please sign in to leave a comment.