Functions/Get-JwkCollection.ps1
|
function Get-JwkCollection { <# .SYNOPSIS Gets a collection of JSON Web Keys (JWKs) from a URI. .DESCRIPTION Gets a collection of JSON Web Keys (JWKs) from a well known openid configuration endpoint or URI containing only JSON Web Keys. .PARAMETER Uri Specifies the Uniform Resource Identifier (URI) containing the JSON Web Keys. Can be a well-known OpenID Connect discovery endpoint or a link containing the JWKs directly. .PARAMETER AsJson Tells the function to return compressed JSON as opposed to an object. .PARAMETER Formatted Returns JSON as formatted (indented) output. Must be used with -AsJson. .PARAMETER IncludeX509Certificate If the JWK in the collection contains a populated x5c property, this parameter converts this value into an System.Security.Cryptography.X509Certificates.X509Certificate2 object. This parameter does not work with the AsJson parameter. .EXAMPLE $oidcUrl = 'https://accounts.google.com/.well-known/openid-configuration' Get-JwkCollection -Uri $oidcUrl Gets JSON Web Keys from google's well known openid configuration endpoint as objects. .EXAMPLE $jwkUrl = 'https://login.windows.net/common/discovery/keys' Get-JwkCollection -Uri $jwkUrl -AsJson Gets JSON Web Keys from Microsoft's JWK endpoint as compressed JSON. .EXAMPLE $jwkUrl = 'https://login.windows.net/common/discovery/keys' Get-JwkCollection -Uri $jwkUrl -AsJson -Formatted Gets JSON Web Keys from Microsoft's JWK endpoint as formatted JSON. .EXAMPLE $jwkUrl = 'https://login.windows.net/common/discovery/keys' Get-JwkCollection -Uri $jwkUrl -IncludeX509Certificate Gets JSON Web Keys from Microsoft's JWK endpoint as objects including the x5c string values converted into X509Certificate2 objects. .EXAMPLE $jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IjJ5Q3Zabms3azhXNjZ3UjJMWFI5V0Nzd2hBYyIsImtpZCI6IjJ5Q3Zabms3azhXNjZ3UjJMWFI5V0Nzd2hBYyJ9.eyJpYXQiOjE2MTgyNTAzODksIm5iZiI6MTYxODI1MDM4OSwiZXhwIjoxNjE4MjU1MTg5LCJzdWIiOiJ0b255In0.X-RZm-3Hto5U-8Q-Wp1ggqWTFPkO5-Cz9lzoKsH5-1RR9GOrGPuWn-bjIv1YJ46h5Bw-KpiX-dOS47TAq2A0BWdAwczLVA6pzha1WswkT_u3cO1_KSoOjD9qFLjCgk-ns7A48iXpNcOoPBFXgfx8G0rRK68sSnokJ7N2NH-YNUOjg3U7DNJ_-iz8WZ5dNlOvpDsTy0BHMX-lho18sUmakUNpadJr-oD7BXIp--Z57UERBFibppaoxseYRo3VfmhgHibTxP-39mcxU6sH9a99fEEt80hj4w6rZobRxZV-pFPS22B8TBAfVf8L9faMLaXmgV7xtQohqQZgL6oKdJzFPQ" $jwkUri = "https://app.mycompany.com/common/discovery/keys" Get-JwkCollection -Uri $jwkUri -AsJson | ForEach-Object { Test-JsonWebToken -JsonWebToken $jwt -HashAlgorithm SHA256 -JsonWebKey $_ -SkipExpirationCheck } Attempts to validate a JSON Web Token signature against a collection of JSON Web Keys in https://app.mycompany.com/common/discovery/keys. .INPUTS System.Uri .OUTPUTS System.String or System.Management.Automation.PSCustomObject .LINK https://tools.ietf.org/html/rfc7517 Test-JsonWebToken New-JsonWebKeySet #> [CmdletBinding()] [Alias('gjwkc')] [OutputType([String[]], [PSCustomObject[]])] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)][Alias('Url', 'u')][System.Uri]$Uri, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false, Position = 1)][Alias('aj', 'j', 'json')][Switch]$AsJson, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false, Position = 2)][Switch]$Formatted, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $false, Position = 3)][Alias('ic', 'IncludeCert', 'IncludeCertificate', 'cert')][Switch]$IncludeX509Certificate ) PROCESS { $jwks = @() $response = $null try { $response = Invoke-RestMethod -Method Get -Uri $Uri -ErrorAction Stop } catch { Write-Error -Exception $_.Exception -ErrorAction Stop } if ($null -eq $response.keys) { if ($null -ne $response.jwks_uri) { try { $jwkUri = [Uri]::new($response.jwks_uri) $response = Invoke-RestMethod -Method Get -Uri $jwkUri -ErrorAction Stop } catch { Write-Error -Exception $_.Exception -ErrorAction Stop } } else { $ArgumentException = New-Object -TypeName ArgumentException -ArgumentList ("Zero JSON Web Keys found at {0}" -f $Uri) Write-Error -Exception $ArgumentException -ErrorAction Stop } } foreach ($key in $response.keys) { if (($null -eq $key.kty) -or ($null -eq $key.n) -or ($null -eq $key.e)) { $ArgumentException = New-Object -TypeName ArgumentException -ArgumentList 'JSON Web Key schema validation failed. Ensure that a valid JWK is passed that contains the key type expressed as "kty", a public exponent as "e”, and modulus as "n" parameters per RFC 7517.' Write-Error -Exception $ArgumentException -ErrorAction Stop } else { if ($key.kty -eq "RSA") { if ($PSBoundParameters.ContainsKey("AsJson")) { if ($PSBoundParameters.ContainsKey("Formatted")) { $jwks += ($key | ConvertTo-Json) } else { $jwks += ($key | ConvertTo-Json -Compress) } } else { if ($PSBoundParameters.ContainsKey("IncludeX509Certificate")) { if ($key.x5c) { try { $certBytes = [Encoding]::ASCII.GetBytes($key.x5c) $x509Cert = [X509Certificate2]::new($certBytes) $keyHashTable = $key | Convert-PSObjectToHashTable $keyHashTable.Add("X509Certificate", $x509Cert) $augmentedKey = [PSCustomObject]$keyHashTable $jwks += $augmentedKey } catch { $jwks += $key $ArgumentException = [System.ArgumentException]::new("Unable to decode and deserialize x5c value.") Write-Error -Exception $ArgumentException -Category InvalidArgument -ErrorAction Continue } } else { $jwks += $key Write-Warning -Message "x5c property does not exist on JSON Web Key." } } else { $jwks += $key } } } else { $ArgumentException = New-Object -TypeName ArgumentException -ArgumentList 'Only RSA JSON Web Keys are supported at this time.' Write-Error -Exception $ArgumentException -ErrorAction Stop } } } return $jwks } } |