Added OpenID Connect discovery endpoint

Although we are phasing out our support of OIDC, this particular feature will allow us to eliminate many of the settings we
share across services. Instead of reading various endpoints and secret keys from settings or hardcoded values, services
with the proper authentication backend can simply read (and cache) the information from this endpoint.

ECOM-3629
This commit is contained in:
Clinton Blackburn
2017-04-23 03:07:49 -04:00
parent 0df079a9c6
commit 2b4817b102
8 changed files with 191 additions and 33 deletions

View File

@@ -1,11 +1,12 @@
"""Utilities for working with ID tokens."""
import json
from time import time
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from Cryptodome.PublicKey import RSA
from django.conf import settings
from django.utils.functional import cached_property
import jwt
from jwkest.jwk import KEYS, RSAKey
from jwkest.jws import JWS
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from student.models import UserProfile, anonymous_id_for_user
@@ -27,6 +28,7 @@ class JwtBuilder(object):
asymmetric (Boolean): Whether the JWT should be signed with this app's private key.
secret (string): Overrides configured JWT secret (signing) key. Unused if an asymmetric signature is requested.
"""
def __init__(self, user, asymmetric=False, secret=None):
self.user = user
self.asymmetric = asymmetric
@@ -50,6 +52,7 @@ class JwtBuilder(object):
now = int(time())
expires_in = expires_in or self.jwt_auth['JWT_EXPIRATION']
payload = {
# TODO Consider getting rid of this claim since we don't use it.
'aud': aud if aud else self.jwt_auth['JWT_AUDIENCE'],
'exp': now + expires_in,
'iat': now,
@@ -100,11 +103,16 @@ class JwtBuilder(object):
def encode(self, payload):
"""Encode the provided payload."""
keys = KEYS()
if self.asymmetric:
secret = load_pem_private_key(settings.PRIVATE_RSA_KEY, None, default_backend())
keys.add(RSAKey(key=RSA.importKey(settings.JWT_PRIVATE_SIGNING_KEY)))
algorithm = 'RS512'
else:
secret = self.secret if self.secret else self.jwt_auth['JWT_SECRET_KEY']
key = self.secret if self.secret else self.jwt_auth['JWT_SECRET_KEY']
keys.add({'key': key, 'kty': 'oct'})
algorithm = self.jwt_auth['JWT_ALGORITHM']
return jwt.encode(payload, secret, algorithm=algorithm)
data = json.dumps(payload)
jws = JWS(data, alg=algorithm)
return jws.sign_compact(keys=keys)