Skip to content

Instantly share code, notes, and snippets.

@regisb
Last active October 15, 2021 16:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save regisb/ec99266b5a8ae02b216443266ebda1ed to your computer and use it in GitHub Desktop.
Save regisb/ec99266b5a8ae02b216443266ebda1ed to your computer and use it in GitHub Desktop.
useful piece of code to manually generate private/public JWK in edx-platform
"""
To add the private and public JWK to edx-platform in Juniper, you should do something similar to the following code.
First install dependendies with:
pip install pycryptodome
"""
import json
from Crypto.PublicKey import RSA
def rsa_private_key(bits=2048):
"""
Export an RSA private key in PEM format.
"""
key = RSA.generate(bits)
return key.export_key().decode()
def rsa_import_key(key):
"""
Import PEM-formatted RSA key and return the corresponding object.
"""
return RSA.import_key(key.encode())
def long_to_base64(n):
"""
Borrowed from jwkest.__init__
"""
def long2intarr(long_int):
_bytes = []
while long_int:
long_int, r = divmod(long_int, 256)
_bytes.insert(0, r)
return _bytes
bys = long2intarr(n)
data = struct.pack("%sB" % len(bys), *bys)
if not data:
data = "\x00"
s = base64.urlsafe_b64encode(data).rstrip(b"=")
return s.decode("ascii")
# This key should be stored and never modified. I suggest this should be a setting.
JWT_RSA_PRIVATE_KEY = rsa_private_key(2048)
jwt_rsa_key = rsa_import_key(JWT_RSA_PRIVATE_KEY)
# Modify the edx-platform settings with the following code:
JWT_AUTH["JWT_PRIVATE_SIGNING_JWK"] = json.dumps(
{
"kid": "openedx",
"kty": "RSA",
"e": long_to_base64(jwt_rsa_key.e),
"d": long_to_base64(jwt_rsa_key.d),
"n": long_to_base64(jwt_rsa_key.n),
"p": long_to_base64(jwt_rsa_key.p),
"q": long_to_base64(jwt_rsa_key.q),
}
)
JWT_AUTH["JWT_PUBLIC_SIGNING_JWK_SET"] = json.dumps(
{
"keys": [
{
"kid": "openedx",
"kty": "RSA",
"e": long_to_base64(jwt_rsa_key.e),
"n": long_to_base64(jwt_rsa_key.n),
}
]
}
)
@NIXKnight
Copy link

NIXKnight commented May 21, 2020

I wrote this as an alternative around 2 months ago:

import json
from Cryptodome.PublicKey import RSA
from jwkest import jwk
import argparse

ap = argparse.ArgumentParser()
ap.add_argument("--kid", required=True, help="A 32 character random string.")
args = vars(ap.parse_args())

rsa_key = RSA.generate(2048)
rsa_jwk = jwk.RSAKey(kid=str(args["kid"]), key=rsa_key)
public_keys = jwk.KEYS()
public_keys.append(rsa_jwk)
serialized_keypair = rsa_jwk.serialize(private=True)

print("COMMON_JWT_PUBLIC_SIGNING_JWK_SET: '%s'" % public_keys.dump_jwks())
print("EDXAPP_JWT_PRIVATE_SIGNING_JWK: '%s'" % json.dumps(serialized_keypair))
print("EDXAPP_JWT_SIGNING_ALGORITHM: 'RS512'")

Helps a lot with Ansible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment