Validating JSON Web Token (JWT) with PowerShell

By popular demand, finally my second blog post online. Please feel free to feedback to me what you think about it.

Validating your JSON Web Token (JWT) with PowerShell
In some organizations, where you have a segregation in the management infrastructure, you might only manage part of the infrastructure (i.e. WebServers) and not the ADFS part of the infrastructure. In this case you are only the Administrator on the WebServer, you are just a normal user of the ADFS infrastructure. Your ADFS Administrator has setup ADFS for you, in line with the requirements that came with your application.

Background WAP and JSON Web Token (JWT):
In this example we will use Windows Azure Pack (WAP) as the application running on the WebServer. Several blogs have been written on how to setup ADFSv3 with WAP so it generates the required JSON Web Token (JWT). Referral to some by Marc van Eijk listed below:
http://www.hyper-v.nu/archives/mvaneijk/2014/01/windows-azure-pack-with-adfs-and-windows-azure-multi-factor-authentication-part-1/
http://www.hyper-v.nu/archives/mvaneijk/2014/02/windows-azure-pack-with-adfs-and-windows-azure-multi-factor-authentication-part-2/
http://www.hyper-v.nu/archives/mvaneijk/2014/03/windows-azure-pack-with-adfs-and-windows-azure-multi-factor-authentication-part-3/

Background WAP Tenant Public API:
A useful tool (by Ben Gelens) which we combine with the above setup of WAP & JSON Web Token (JWT) is the PowerShell Module WAPTenantPublicAPI. Just fire up your PowerShell 5 and install via the PowerShell Gallery:

Install-Module -Name WAPTenantPublicAPI

 

The use case – Validating your JSON Web Token (JWT) with PowerShell
Let’s go! Get a JWT Token:

JWT_Pic1_Desktop

Get-WAPToken -Credential (Get-Credential -UserName menno.stevens@madeofthings.net -Message 'ADFS Account') –URL https://fs.madeofthings.net -ADFS

Get-WAPToken is a CmdLet in the WAPTenantPublicAPI. The CmdLet formats the request for your ADFS infrastructure in the right way, authenticates and stores your token in the $token variable.JWT_Pic2_Desktop

 

Decoding your JSON Web Token (JWT) with PowerShell
Let’s decode!

As per JWT Specifications (https://tools.ietf.org/html/rfc7519), the token is split in 3 parts, separated by a ‘.’ (dot). The easiest way I know to decode the first 2 parts with PowerShell is using these few lines (core from Shriram [MSFT] in the Technet Gallery):

foreach ($i in 0..1) {
    $data=$token.Split('.')[$i].Replace('-', '+').Replace('_', '/')
    switch ($data.Length % 4) {
        0 {break}
        2 {$data += '=='}
        3 {$data += '='}
    }
    [System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String($data))
    '---'
}

The result is shown below:JWT_Pic3b_DesktopBut what about the 3rd part?
That is the signature proving the token is not tampered with. And we can read it easily.
Using the same few PowerShell script-lines, just replace “foreach ($i in 0..1)” with “foreach ($i in 0..2)”:JWT_Pic4_DesktopRight… But that 3rd part of your token (the garbage) does not proof anything. We can’t validate the JWT Token that way.

 

Validating your JSON Web Token (JWT) with PowerShell
Let’s validate!

As explained in the introduction, we use Windows Azure Pack (WAP) as the example application. You have to retrieve the ADFS/JWT Certificate you are going to validate your Token against from your configuration. Or get the Certificate from your ADFS Administrator.
To be short, in our example case, login to the Azure Pack Webserver and retrieve the installed certificate using the following commands. And store it in the $cert variable which MUST be of the type “X509Certificate2”.

$Connectionstring='Data Source=MYSQLSERVER;Integrated Security=SSPI;Trusted_Connection=yes'
$TenantSiteTenant=Get-MgmtSvcRelyingPartySettings -ConnectionString $Connectionstring -Target 'Tenant'
$certs=$TenantSiteTenant.Certificates|%{[System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String($_))}
$cert=$certs|where Issuer -like 'CN=DigiCert*'

JWT_Pic5_Desktop

PowerShell and Windows don’t really understand the JSON Web Token (JWT). But again, PowerShell 5 to the rescue. Get the Package “System.IdentityModel.Tokens.Jwt” from the NuGet Repository. I found that I got the best results with version 3.0.2. You might want to improve my scripting and try a newer version. Get it installed with this command:

Install-Package System.IdentityModel.Tokens.Jwt -Version 3.0.2

And load the DLL into PowerShell with:

Add-Type -Path 'C:\the..absolute..path..to\v3.02\net45\System.IdentityModel.Tokens.Jwt.dll'

Now the script-lines that actually will validate your JWT Token in the $token variable against the Certificate in the $cert variable:

$X509SecurityToken=New-Object System.IdentityModel.Tokens.X509SecurityToken($cert)
$JwtSecurityToken=(New-Object System.IdentityModel.Tokens.JwtSecurityTokenHandler).ReadToken($token)
$TokenProperties=@{
    SigningToken=$X509SecurityToken;
    AllowedAudience=$JwtSecurityToken.Audience;
    ValidIssuer=$JwtSecurityToken.Issuer
}
$TokenValidationParameters=New-Object System.IdentityModel.Tokens.TokenValidationParameters -Property $TokenProperties
$ValidateTokenResult=(New-Object System.IdentityModel.Tokens.JwtSecurityTokenHandler).ValidateToken($JwtSecurityToken,$TokenValidationParameters)
Write-Verbose -Verbose "The token validation result is: $($ValidateTokenResult.Identity.IsAuthenticated)"

Let’s see some results.

The below is an example where a valid $token is validating against the wrong $cert: JWT_Pic6a_Desktop
Here an example where a valid $token is validating against a valid $cert, but the CRL Service of the CA was not available: JWT_Pic6b_Desktop
Now a valid $token, against a valid $cert with the CRL Service of the CA running. But with an obvious explanation “The token is expired”: JWT_Pic6c_Desktop

Now some messing around with the $token. And result is that something totally has gone wrong “Check to make sure the SecurityAlgorithm is supported”: JWT_Pic6d_Desktop
And finally, this one seems right:
JWT_Pic6e_Desktop
So with this Boolean value of $ValidateTokenResult.Identity.IsAuthenticated being “True”, we can say we have actually validated that the value of $token is a valid one. Now it is save to use the claims provided.

Advertisements