Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Commit

Permalink
Read claim handlers from Django settings
Browse files Browse the repository at this point in the history
  • Loading branch information
rocha authored and Carlos Andrés Rocha committed Sep 9, 2014
1 parent 7acdf1e commit c65a9c2
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 13 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ specification, it should use the `https` scheme, host and optionally the port nu
The `id_token` expiration, which defaults to 30 seconds, can be overriden by setting `OAUTH_ID_TOKEN_EXPIRATION` to a
different value.

It is possible to customize the OpenID Connect scopes and claims, using the settings `OAUTH_OIDC_ID_TOKEN_HANDLERS`
and `OAUTH_OIDC_USERINFO_HANDLERS`, which manage the claims associated with the `id_token` during authorization, and
the results of the `userinfo` endpoint respectively. For more information see `oauth2_profider/oidc/handlers.py`.


Testing
-------
Expand Down
19 changes: 18 additions & 1 deletion oauth2_provider/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import provider.scope
import provider.oauth2.forms


# REQUIRED Issuer Identifider (the `iss` field in the `id_token`)
OAUTH_OIDC_ISSUER = settings.OAUTH_OIDC_ISSUER

Expand Down Expand Up @@ -38,6 +37,24 @@
SCOPE_VALUE_DICT = dict([(value, name) for (value, name) in SCOPES])


# OpenID Connect claim handlers

DEFAULT_ID_TOKEN_HANDLERS = (
'oauth2_provider.oidc.handlers.BasicIDTokenHandler',
'oauth2_provider.oidc.handlers.ProfileHandler',
'oauth2_provider.oidc.handlers.EmailHandler',
)

DEFAULT_USERINFO_HANDLERS = (
'oauth2_provider.oidc.handlers.BasicUserInfoHandler',
'oauth2_provider.oidc.handlers.ProfileHandler',
'oauth2_provider.oidc.handlers.EmailHandler',
)

ID_TOKEN_HANDLERS = getattr(settings, 'OAUTH_OIDC_ID_TOKEN_HANDLERS', DEFAULT_ID_TOKEN_HANDLERS)
USERINFO_HANDLERS = getattr(settings, 'OAUTH_OIDC_USERINFO_HANDLERS', DEFAULT_USERINFO_HANDLERS)


# Override django-oauth2-provider scopes (OAUTH_SCOPES)
#
# `provider.scopes` values are loaded from Django settings. However,
Expand Down
2 changes: 2 additions & 0 deletions oauth2_provider/oidc/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ def _validate_claim_values(name, value, ignore_errors):

def _visit_handlers(handlers, visitor, preffix, suffixes):
""" Use visitor partern to collect information from handlers """

handlers = [cls() for cls in handlers]

results = []
for handler in handlers:
for suffix in suffixes:
Expand Down
20 changes: 8 additions & 12 deletions oauth2_provider/oidc/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@

import jwt

from oauth2_provider import constants
from oauth2_provider.utils import import_string
from oauth2_provider.oidc.collect import collect, collect_authorized_scope

from oauth2_provider.oidc.handlers import (
BasicIDTokenHandler,
BasicUserInfoHandler,
ProfileHandler,
EmailHandler
)

DEFAULT_ID_TOKEN_HANDLERS = (BasicIDTokenHandler, ProfileHandler, EmailHandler)
DEFAULT_USERINFO_HANDLERS = (BasicUserInfoHandler, ProfileHandler, EmailHandler)
# Resolve the claim handlers
ID_TOKEN_HANDLERS = [import_string(cls) for cls in constants.ID_TOKEN_HANDLERS]
USERINFO_HANDLERS = [import_string(cls) for cls in constants.USERINFO_HANDLERS]


def authorized_scopes(scope_names, user, client):
Expand All @@ -30,7 +26,7 @@ def authorized_scopes(scope_names, user, client):
client (Client): OAuth2 Client for the request.
"""
handlers = DEFAULT_ID_TOKEN_HANDLERS
handlers = ID_TOKEN_HANDLERS

return collect_authorized_scope(handlers, scope_names, user, client)

Expand All @@ -56,7 +52,7 @@ def id_token_claims(access_token, nonce=None, claims_request=None):

claims = claims_request.get('id_token', {}) if claims_request else {}

handlers = DEFAULT_ID_TOKEN_HANDLERS
handlers = ID_TOKEN_HANDLERS

if nonce:
claims.update({'nonce': {'value': nonce}})
Expand Down Expand Up @@ -90,7 +86,7 @@ def userinfo_claims(access_token, scope_names=None, claims_request=None):
"""

handlers = DEFAULT_USERINFO_HANDLERS
handlers = USERINFO_HANDLERS

claims = claims_request.get('userinfo', {}) if claims_request else {}

Expand Down
33 changes: 33 additions & 0 deletions oauth2_provider/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
""" Misc Utilities. """

from importlib import import_module
import sys

from django.utils import six


# NOTE: be careful not to create an import loop when extending this
# file, corrently `import_string` is used by `oauth2_provider.constants`.


def import_string(dotted_path):
"""
Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.
Borrowed from Django 1.7
"""
try:
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError:
msg = "%s doesn't look like a module path" % dotted_path
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

module = import_module(module_path)

try:
return getattr(module, class_name)
except AttributeError:
msg = 'Module "%s" does not define a "%s" attribute/class' % (
dotted_path, class_name)
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

0 comments on commit c65a9c2

Please sign in to comment.