JWT RS256 Token Validation

Hi,

I´m trying to do a plugin to validate the integrity of an JWT Token emitted my IDP (IdentityServer 4).

Steps:

  1. Retrieve the JWKS from the discovery endpoint, and filter for potential signing keys (e.g., any keys missing a public key or with a kid property).
  2. Extract the JWT from the request’s authorization header and decode it.
  3. Grab the kid property from the header of the decoded JWT.
  4. Search your filtered JWKS for the key with the matching kid property.
  5. Build a certificate using the corresponding x5c property in your JWKS.
  6. Use the certificate to verify the JWT’s signature.

Im using the method verify of https://github.com/Kong/kong/blob/master/kong/plugins/jwt/jwt_parser.lua but im getting this error "Consumer Public Key is Invalid "

Any idea or help?

Thanks

i´ve done some advances on the plugin and its working now, with a little workaround.

I need to found a way to convert x5c to pem format, with that we plugin works well

Hi, did you open source your plugin? And did you solve the conversion issue?
We need the same so it would be great if we could use your plugin.

Hi,

I had a similar requirement, to keep Kong and Azure in sync with respect to x5c and so on.

Because Azure rotate (lazy rotate) keys every so often it had to be a script that keeps the keys in sync, so I wrote a python script.
Now I don’t think this is what you are looking for, but it might be useful to others, so apologies if I am distracting your ticket, but since its related, I will paste the script here.

import json
import requests
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.x509 import load_pem_x509_certificate

PEMSTART = "-----BEGIN CERTIFICATE-----\n"
PEMEND = "\n-----END CERTIFICATE-----\n"


kongURL = 'https://api.kong.myapp.com'
username = 'admin'
password = 'password'
tenantID = '121212-12121-1212121-121212'
azureURL = 'https://login.microsoftonline.com/'+tenantID+'/discovery/keys'

class JWT:
  def __init__(self, algorithm, key, rsa_public_key):
    self.algorithm = algorithm
    self.key = key
    self.rsa_public_key = rsa_public_key

f = open("azure-apps.txt", "r")
for app in f:
  print("Processing App: " + app)

  # Get the consumer definitions from Kong
  consumerResponse = requests.get(kongURL+'/'+app.strip(), auth=(username, password))
  consumer = consumerResponse.json()
  appId = consumer['custom_id']
  consumerId = consumer['id']
  print('App ID: ' + appId)
  print('Consumer ID: ' + consumerId)

  # Get the consumer JWT details from Kong
  jwtResponse = requests.get(kongURL+'/'+consumerId+'/jwt', auth=(username, password))
  jwt = jwtResponse.json()
  kongKeys = list()
  for i in jwt['data']:
    key = i['key']
    if key:
      kongKeys.append(key)
  #print(kongKeys)

  # Get the keys/cert details from Azure
  azureResponse = requests.get(azureURL + "?appid=" + appId)
  azure = azureResponse.json()
  azureKeys = list()
  for i in azure['keys']:
    key = i['kid']
    if key:
      azureKeys.append(key)
  #print(azureKeys)

  # These are keys present in Azure but not in Kong
  keysToBeAdded = set(azureKeys) - set(kongKeys)
  print('Keys to be added: ' + ','.join(keysToBeAdded))

  # These are keys present in Kong but not in Azure
  keysToBeDeleted = set(kongKeys) - set(azureKeys)
  print('Keys to be deleted: ' + ','.join(keysToBeDeleted))

  # Add missing keys to Kong
  for key in keysToBeAdded:
    for i in azure['keys']:
      azureKey = i['kid']
      if azureKey == key:
        # Get the x509 cert and convert that to a PEM
        rawcert = ''.join(i['x5c'])
        cert_str = PEMSTART + rawcert + PEMEND
        #print(cert_str)
        cert_obj = load_pem_x509_certificate(cert_str.encode('ascii'), default_backend())
        pem = cert_obj.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo)
        #print(pem)

        # Prepare jwt request to be sent to Kong
        dataObj = JWT('RS256', key, pem)
        data = json.dumps(dataObj.__dict__)
        #print(data)
        headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
        response = requests.post(kongURL + '/' + consumerId + '/jwt', data=data, auth=(username, password), headers=headers)
        #print(response)
        if response.status_code == 201:
          print('Key ' + key + ' has been added to Kong')
        else:
          print('There was a problem adding key '+ key +' to Kong')

  # Delete redundant keys from Kong
  for key in keysToBeDeleted:
    response = requests.delete(kongURL+'/'+consumerId+'/jwt/' + key, auth=(username, password))
    #print(response)
    if response.status_code == 204:
      print('Key ' + key + ' has been deleted from Kong')
    else:
      print('There was a problem deleting key '+ key +' from Kong')

It will require an azure-apps.txt that contains the names of Azure apps. I use the custom_id to store the Azure App ID

hi all,

Yes i already have a way to convert to pen. I will open-source the plugin soon. The idea is to have automatic rotation policy of the certificates.

I follow the same approach of this guys: https://github.com/gbbirkisson/kong-plugin-jwt-keycloak

On convertion.lua you have the code to convert

Thanks


© 2018 Kong Inc.    Terms  •  Privacy  •  FAQ