Change setting OIDC_USERINFO.
This commit is contained in:
parent
ab65aab0e1
commit
dc9ec1863e
9 changed files with 99 additions and 98 deletions
|
@ -12,17 +12,17 @@ List of all the attributes grouped by scopes:
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| profile | email | phone | address |
|
| profile | email | phone | address |
|
||||||
+====================+================+=======================+========================+
|
+====================+================+=======================+========================+
|
||||||
| name | email | phone_number | address_formatted |
|
| name | email | phone_number | formatted |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| given_name | email_verified | phone_number_verified | address_street_address |
|
| given_name | email_verified | phone_number_verified | street_address |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| family_name | | | address_locality |
|
| family_name | | | locality |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| middle_name | | | address_region |
|
| middle_name | | | region |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| nickname | | | address_postal_code |
|
| nickname | | | postal_code |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| preferred_username | | | address_country |
|
| preferred_username | | | country |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
| profile | | | |
|
| profile | | | |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
|
@ -41,35 +41,22 @@ List of all the attributes grouped by scopes:
|
||||||
| updated_at | | | |
|
| updated_at | | | |
|
||||||
+--------------------+----------------+-----------------------+------------------------+
|
+--------------------+----------------+-----------------------+------------------------+
|
||||||
|
|
||||||
Example using a django model::
|
Somewhere in your Django ``settings.py``::
|
||||||
|
|
||||||
from django.conf import settings
|
OIDC_USERINFO = 'myproject.oidc_provider_settings.userinfo'
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class UserInfo(models.Model):
|
Then create the function for the ``OIDC_USERINFO`` setting::
|
||||||
|
|
||||||
GENDER_CHOICES = [
|
def userinfo(claims, user):
|
||||||
('F', 'Female'),
|
|
||||||
('M', 'Male'),
|
|
||||||
]
|
|
||||||
|
|
||||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True)
|
claims['name'] = '{0} {1}'.format(user.first_name, user.last_name)
|
||||||
|
claims['given_name'] = user.first_name
|
||||||
given_name = models.CharField(max_length=255, blank=True, null=True)
|
claims['family_name'] = user.last_name
|
||||||
family_name = models.CharField(max_length=255, blank=True, null=True)
|
claims['email'] = user.email
|
||||||
gender = models.CharField(max_length=100, choices=GENDER_CHOICES, null=True)
|
claims['address']['street_address'] = '...'
|
||||||
birthdate = models.DateField(null=True)
|
|
||||||
updated_at = models.DateTimeField(auto_now=True, null=True)
|
|
||||||
|
|
||||||
email_verified = models.NullBooleanField(default=False)
|
return claims
|
||||||
|
|
||||||
phone_number = models.CharField(max_length=255, blank=True, null=True)
|
.. note::
|
||||||
phone_number_verified = models.NullBooleanField(default=False)
|
Please **DO NOT** add extra keys or delete the existing ones in the ``claims`` dict. If you want to add extra claims to some scopes you can use the ``OIDC_EXTRA_SCOPE_CLAIMS`` setting.
|
||||||
|
|
||||||
address_locality = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
address_country = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_user(cls, user):
|
|
||||||
return cls.objects.get(user=user)
|
|
||||||
|
|
|
@ -162,4 +162,21 @@ Expressed in seconds. Default is ``60*60``.
|
||||||
OIDC_USERINFO
|
OIDC_USERINFO
|
||||||
=============
|
=============
|
||||||
|
|
||||||
OPTIONAL. ``str``. A string with the location of your class. Read **Standard Claims** section.
|
OPTIONAL. ``str``. A string with the location of your function. Read **Standard Claims** section.
|
||||||
|
|
||||||
|
The function receives a ``claims`` dictionary with all the standard claims and ``user`` instance. Must returns the ``claims`` dict again.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
def userinfo(claims, user):
|
||||||
|
|
||||||
|
claims['name'] = '{0} {1}'.format(user.first_name, user.last_name)
|
||||||
|
claims['given_name'] = user.first_name
|
||||||
|
claims['family_name'] = user.last_name
|
||||||
|
claims['email'] = user.email
|
||||||
|
claims['address']['street_address'] = '...'
|
||||||
|
|
||||||
|
return claims
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Please **DO NOT** add extra keys or delete the existing ones in the ``claims`` dict. If you want to add extra claims to some scopes you can use the ``OIDC_EXTRA_SCOPE_CLAIMS`` setting.
|
||||||
|
|
|
@ -3,11 +3,20 @@ from django.utils.translation import ugettext as _
|
||||||
from oidc_provider import settings
|
from oidc_provider import settings
|
||||||
|
|
||||||
|
|
||||||
|
STANDARD_CLAIMS = {
|
||||||
|
'name': '', 'given_name': '', 'family_name': '', 'middle_name': '', 'nickname': '',
|
||||||
|
'preferred_username': '', 'profile': '', 'picture': '', 'website': '', 'gender': '',
|
||||||
|
'birthdate': '', 'zoneinfo': '', 'locale': '', 'updated_at': '', 'email': '', 'email_verified': '',
|
||||||
|
'phone_number': '', 'phone_number_verified': '', 'address': { 'formatted': '',
|
||||||
|
'street_address': '', 'locality': '', 'region': '', 'postal_code': '', 'country': '', },
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ScopeClaims(object):
|
class ScopeClaims(object):
|
||||||
|
|
||||||
def __init__(self, user, scopes):
|
def __init__(self, user, scopes):
|
||||||
self.user = user
|
self.user = user
|
||||||
self.userinfo = settings.get('OIDC_USERINFO', import_str=True).get_by_user(self.user)
|
self.userinfo = settings.get('OIDC_USERINFO', import_str=True)(STANDARD_CLAIMS, self.user)
|
||||||
self.scopes = scopes
|
self.scopes = scopes
|
||||||
|
|
||||||
def create_response_dic(self):
|
def create_response_dic(self):
|
||||||
|
@ -85,20 +94,20 @@ class StandardScopeClaims(ScopeClaims):
|
||||||
)
|
)
|
||||||
def scope_profile(self):
|
def scope_profile(self):
|
||||||
dic = {
|
dic = {
|
||||||
'name': getattr(self.userinfo, 'name', None),
|
'name': self.userinfo.get('name'),
|
||||||
'given_name': getattr(self.userinfo, 'given_name', None),
|
'given_name': self.userinfo.get('given_name'),
|
||||||
'family_name': getattr(self.userinfo, 'family_name', None),
|
'family_name': self.userinfo.get('family_name'),
|
||||||
'middle_name': getattr(self.userinfo, 'middle_name', None),
|
'middle_name': self.userinfo.get('middle_name'),
|
||||||
'nickname': getattr(self.userinfo, 'nickname', None),
|
'nickname': self.userinfo.get('nickname'),
|
||||||
'preferred_username': getattr(self.userinfo, 'preferred_username', None),
|
'preferred_username': self.userinfo.get('preferred_username'),
|
||||||
'profile': getattr(self.userinfo, 'profile', None),
|
'profile': self.userinfo.get('profile'),
|
||||||
'picture': getattr(self.userinfo, 'picture', None),
|
'picture': self.userinfo.get('picture'),
|
||||||
'website': getattr(self.userinfo, 'website', None),
|
'website': self.userinfo.get('website'),
|
||||||
'gender': getattr(self.userinfo, 'gender', None),
|
'gender': self.userinfo.get('gender'),
|
||||||
'birthdate': getattr(self.userinfo, 'birthdate', None),
|
'birthdate': self.userinfo.get('birthdate'),
|
||||||
'zoneinfo': getattr(self.userinfo, 'zoneinfo', None),
|
'zoneinfo': self.userinfo.get('zoneinfo'),
|
||||||
'locale': getattr(self.userinfo, 'locale', None),
|
'locale': self.userinfo.get('locale'),
|
||||||
'updated_at': getattr(self.userinfo, 'updated_at', None),
|
'updated_at': self.userinfo.get('updated_at'),
|
||||||
}
|
}
|
||||||
|
|
||||||
return dic
|
return dic
|
||||||
|
@ -109,8 +118,8 @@ class StandardScopeClaims(ScopeClaims):
|
||||||
)
|
)
|
||||||
def scope_email(self):
|
def scope_email(self):
|
||||||
dic = {
|
dic = {
|
||||||
'email': getattr(self.user, 'email', None),
|
'email': self.userinfo.get('email'),
|
||||||
'email_verified': getattr(self.userinfo, 'email_verified', None),
|
'email_verified': self.userinfo.get('email_verified'),
|
||||||
}
|
}
|
||||||
|
|
||||||
return dic
|
return dic
|
||||||
|
@ -121,8 +130,8 @@ class StandardScopeClaims(ScopeClaims):
|
||||||
)
|
)
|
||||||
def scope_phone(self):
|
def scope_phone(self):
|
||||||
dic = {
|
dic = {
|
||||||
'phone_number': getattr(self.userinfo, 'phone_number', None),
|
'phone_number': self.userinfo.get('phone_number'),
|
||||||
'phone_number_verified': getattr(self.userinfo, 'phone_number_verified', None),
|
'phone_number_verified': self.userinfo.get('phone_number_verified'),
|
||||||
}
|
}
|
||||||
|
|
||||||
return dic
|
return dic
|
||||||
|
@ -134,12 +143,12 @@ class StandardScopeClaims(ScopeClaims):
|
||||||
def scope_address(self):
|
def scope_address(self):
|
||||||
dic = {
|
dic = {
|
||||||
'address': {
|
'address': {
|
||||||
'formatted': getattr(self.userinfo, 'address_formatted', None),
|
'formatted': self.userinfo.get('address', {}).get('formatted'),
|
||||||
'street_address': getattr(self.userinfo, 'address_street_address', None),
|
'street_address': self.userinfo.get('address', {}).get('street_address'),
|
||||||
'locality': getattr(self.userinfo, 'address_locality', None),
|
'locality': self.userinfo.get('address', {}).get('locality'),
|
||||||
'region': getattr(self.userinfo, 'address_region', None),
|
'region': self.userinfo.get('address', {}).get('region'),
|
||||||
'postal_code': getattr(self.userinfo, 'address_postal_code', None),
|
'postal_code': self.userinfo.get('address', {}).get('postal_code'),
|
||||||
'country': getattr(self.userinfo, 'address_country', None),
|
'country': self.userinfo.get('address', {}).get('country'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,10 +214,13 @@ class AuthorizeEndpoint(object):
|
||||||
Return a list with the description of all the scopes requested.
|
Return a list with the description of all the scopes requested.
|
||||||
"""
|
"""
|
||||||
scopes = StandardScopeClaims.get_scopes_info(self.params.scope)
|
scopes = StandardScopeClaims.get_scopes_info(self.params.scope)
|
||||||
scopes_extra = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True).get_scopes_info(self.params.scope)
|
if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'):
|
||||||
for index_extra, scope_extra in enumerate(scopes_extra):
|
scopes_extra = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True).get_scopes_info(self.params.scope)
|
||||||
for index, scope in enumerate(scopes[:]):
|
for index_extra, scope_extra in enumerate(scopes_extra):
|
||||||
if scope_extra['scope'] == scope['scope']:
|
for index, scope in enumerate(scopes[:]):
|
||||||
del scopes[index]
|
if scope_extra['scope'] == scope['scope']:
|
||||||
|
del scopes[index]
|
||||||
|
else:
|
||||||
|
scopes_extra = []
|
||||||
|
|
||||||
return scopes + scopes_extra
|
return scopes + scopes_extra
|
||||||
|
|
|
@ -45,14 +45,12 @@ def get_issuer(site_url=None, request=None):
|
||||||
return issuer
|
return issuer
|
||||||
|
|
||||||
|
|
||||||
class DefaultUserInfo(object):
|
def default_userinfo(claims, user):
|
||||||
"""
|
"""
|
||||||
Default class for setting OIDC_USERINFO.
|
Default function for setting OIDC_USERINFO.
|
||||||
|
`claims` is a dict that contains all the OIDC standard claims.
|
||||||
"""
|
"""
|
||||||
|
return claims
|
||||||
@classmethod
|
|
||||||
def get_by_user(cls, user):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def default_sub_generator(user):
|
def default_sub_generator(user):
|
||||||
|
|
|
@ -41,9 +41,9 @@ class DefaultSettings(object):
|
||||||
def OIDC_EXTRA_SCOPE_CLAIMS(self):
|
def OIDC_EXTRA_SCOPE_CLAIMS(self):
|
||||||
"""
|
"""
|
||||||
OPTIONAL. A string with the location of your class.
|
OPTIONAL. A string with the location of your class.
|
||||||
Used to add extra scopes specific for your app.
|
Used to add extra scopes specific for your app.
|
||||||
"""
|
"""
|
||||||
return 'oidc_provider.lib.claims.ScopeClaims'
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def OIDC_IDTOKEN_EXPIRE(self):
|
def OIDC_IDTOKEN_EXPIRE(self):
|
||||||
|
@ -95,10 +95,10 @@ class DefaultSettings(object):
|
||||||
@property
|
@property
|
||||||
def OIDC_USERINFO(self):
|
def OIDC_USERINFO(self):
|
||||||
"""
|
"""
|
||||||
OPTIONAL. A string with the location of your class.
|
OPTIONAL. A string with the location of your function.
|
||||||
Used to add extra scopes specific for your app.
|
Used to populate standard claims with your user information.
|
||||||
"""
|
"""
|
||||||
return 'oidc_provider.lib.utils.common.DefaultUserInfo'
|
return 'oidc_provider.lib.utils.common.default_userinfo'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def OIDC_IDTOKEN_PROCESSING_HOOK(self):
|
def OIDC_IDTOKEN_PROCESSING_HOOK(self):
|
||||||
|
|
|
@ -58,4 +58,4 @@ USE_TZ = True
|
||||||
# OIDC Provider settings.
|
# OIDC Provider settings.
|
||||||
|
|
||||||
SITE_URL = 'http://localhost:8000'
|
SITE_URL = 'http://localhost:8000'
|
||||||
OIDC_USERINFO = 'oidc_provider.tests.app.utils.FakeUserInfo'
|
OIDC_USERINFO = 'oidc_provider.tests.app.utils.userinfo'
|
||||||
|
|
|
@ -73,27 +73,16 @@ def is_code_valid(url, user, client):
|
||||||
return is_code_ok
|
return is_code_ok
|
||||||
|
|
||||||
|
|
||||||
class FakeUserInfo(object):
|
def userinfo(claims, user):
|
||||||
"""
|
"""
|
||||||
Fake class for setting OIDC_USERINFO.
|
Fake function for setting OIDC_USERINFO.
|
||||||
"""
|
"""
|
||||||
|
claims['given_name'] = 'John'
|
||||||
given_name = 'John'
|
claims['family_name'] = 'Doe'
|
||||||
family_name = 'Doe'
|
claims['name'] = '{0} {1}'.format(claims['given_name'], claims['family_name'])
|
||||||
nickname = 'johndoe'
|
claims['email'] = user.email
|
||||||
website = 'http://johndoe.com'
|
claims['address']['country'] = 'Argentina'
|
||||||
|
return claims
|
||||||
phone_number = '+49-89-636-48018'
|
|
||||||
phone_number_verified = True
|
|
||||||
|
|
||||||
address_street_address = 'Evergreen 742'
|
|
||||||
address_locality = 'Glendive'
|
|
||||||
address_region = 'Montana'
|
|
||||||
address_country = 'United States'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_user(cls, user):
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
|
|
||||||
def fake_sub_generator(user):
|
def fake_sub_generator(user):
|
||||||
|
|
|
@ -157,13 +157,11 @@ def userinfo(request, *args, **kwargs):
|
||||||
}
|
}
|
||||||
|
|
||||||
standard_claims = StandardScopeClaims(token.user, token.scope)
|
standard_claims = StandardScopeClaims(token.user, token.scope)
|
||||||
|
|
||||||
dic.update(standard_claims.create_response_dic())
|
dic.update(standard_claims.create_response_dic())
|
||||||
|
|
||||||
extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(
|
if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'):
|
||||||
token.user, token.scope)
|
extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token.user, token.scope)
|
||||||
|
dic.update(extra_claims.create_response_dic())
|
||||||
dic.update(extra_claims.create_response_dic())
|
|
||||||
|
|
||||||
response = JsonResponse(dic, status=200)
|
response = JsonResponse(dic, status=200)
|
||||||
response['Cache-Control'] = 'no-store'
|
response['Cache-Control'] = 'no-store'
|
||||||
|
|
Loading…
Reference in a new issue