Change setting OIDC_USERINFO.
This commit is contained in:
parent
ab65aab0e1
commit
dc9ec1863e
|
@ -12,17 +12,17 @@ List of all the attributes grouped by scopes:
|
|||
+--------------------+----------------+-----------------------+------------------------+
|
||||
| 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 | | | |
|
||||
+--------------------+----------------+-----------------------+------------------------+
|
||||
|
@ -41,35 +41,22 @@ List of all the attributes grouped by scopes:
|
|||
| updated_at | | | |
|
||||
+--------------------+----------------+-----------------------+------------------------+
|
||||
|
||||
Example using a django model::
|
||||
Somewhere in your Django ``settings.py``::
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
OIDC_USERINFO = 'myproject.oidc_provider_settings.userinfo'
|
||||
|
||||
|
||||
class UserInfo(models.Model):
|
||||
Then create the function for the ``OIDC_USERINFO`` setting::
|
||||
|
||||
GENDER_CHOICES = [
|
||||
('F', 'Female'),
|
||||
('M', 'Male'),
|
||||
]
|
||||
def userinfo(claims, user):
|
||||
|
||||
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
|
||||
claims['family_name'] = user.last_name
|
||||
claims['email'] = user.email
|
||||
claims['address']['street_address'] = '...'
|
||||
|
||||
given_name = models.CharField(max_length=255, blank=True, null=True)
|
||||
family_name = models.CharField(max_length=255, blank=True, null=True)
|
||||
gender = models.CharField(max_length=100, choices=GENDER_CHOICES, null=True)
|
||||
birthdate = models.DateField(null=True)
|
||||
updated_at = models.DateTimeField(auto_now=True, null=True)
|
||||
return claims
|
||||
|
||||
email_verified = models.NullBooleanField(default=False)
|
||||
|
||||
phone_number = models.CharField(max_length=255, blank=True, null=True)
|
||||
phone_number_verified = models.NullBooleanField(default=False)
|
||||
|
||||
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)
|
||||
.. 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.
|
||||
|
|
|
@ -162,4 +162,21 @@ Expressed in seconds. Default is ``60*60``.
|
|||
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
|
||||
|
||||
|
||||
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):
|
||||
|
||||
def __init__(self, user, scopes):
|
||||
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
|
||||
|
||||
def create_response_dic(self):
|
||||
|
@ -85,20 +94,20 @@ class StandardScopeClaims(ScopeClaims):
|
|||
)
|
||||
def scope_profile(self):
|
||||
dic = {
|
||||
'name': getattr(self.userinfo, 'name', None),
|
||||
'given_name': getattr(self.userinfo, 'given_name', None),
|
||||
'family_name': getattr(self.userinfo, 'family_name', None),
|
||||
'middle_name': getattr(self.userinfo, 'middle_name', None),
|
||||
'nickname': getattr(self.userinfo, 'nickname', None),
|
||||
'preferred_username': getattr(self.userinfo, 'preferred_username', None),
|
||||
'profile': getattr(self.userinfo, 'profile', None),
|
||||
'picture': getattr(self.userinfo, 'picture', None),
|
||||
'website': getattr(self.userinfo, 'website', None),
|
||||
'gender': getattr(self.userinfo, 'gender', None),
|
||||
'birthdate': getattr(self.userinfo, 'birthdate', None),
|
||||
'zoneinfo': getattr(self.userinfo, 'zoneinfo', None),
|
||||
'locale': getattr(self.userinfo, 'locale', None),
|
||||
'updated_at': getattr(self.userinfo, 'updated_at', None),
|
||||
'name': self.userinfo.get('name'),
|
||||
'given_name': self.userinfo.get('given_name'),
|
||||
'family_name': self.userinfo.get('family_name'),
|
||||
'middle_name': self.userinfo.get('middle_name'),
|
||||
'nickname': self.userinfo.get('nickname'),
|
||||
'preferred_username': self.userinfo.get('preferred_username'),
|
||||
'profile': self.userinfo.get('profile'),
|
||||
'picture': self.userinfo.get('picture'),
|
||||
'website': self.userinfo.get('website'),
|
||||
'gender': self.userinfo.get('gender'),
|
||||
'birthdate': self.userinfo.get('birthdate'),
|
||||
'zoneinfo': self.userinfo.get('zoneinfo'),
|
||||
'locale': self.userinfo.get('locale'),
|
||||
'updated_at': self.userinfo.get('updated_at'),
|
||||
}
|
||||
|
||||
return dic
|
||||
|
@ -109,8 +118,8 @@ class StandardScopeClaims(ScopeClaims):
|
|||
)
|
||||
def scope_email(self):
|
||||
dic = {
|
||||
'email': getattr(self.user, 'email', None),
|
||||
'email_verified': getattr(self.userinfo, 'email_verified', None),
|
||||
'email': self.userinfo.get('email'),
|
||||
'email_verified': self.userinfo.get('email_verified'),
|
||||
}
|
||||
|
||||
return dic
|
||||
|
@ -121,8 +130,8 @@ class StandardScopeClaims(ScopeClaims):
|
|||
)
|
||||
def scope_phone(self):
|
||||
dic = {
|
||||
'phone_number': getattr(self.userinfo, 'phone_number', None),
|
||||
'phone_number_verified': getattr(self.userinfo, 'phone_number_verified', None),
|
||||
'phone_number': self.userinfo.get('phone_number'),
|
||||
'phone_number_verified': self.userinfo.get('phone_number_verified'),
|
||||
}
|
||||
|
||||
return dic
|
||||
|
@ -134,12 +143,12 @@ class StandardScopeClaims(ScopeClaims):
|
|||
def scope_address(self):
|
||||
dic = {
|
||||
'address': {
|
||||
'formatted': getattr(self.userinfo, 'address_formatted', None),
|
||||
'street_address': getattr(self.userinfo, 'address_street_address', None),
|
||||
'locality': getattr(self.userinfo, 'address_locality', None),
|
||||
'region': getattr(self.userinfo, 'address_region', None),
|
||||
'postal_code': getattr(self.userinfo, 'address_postal_code', None),
|
||||
'country': getattr(self.userinfo, 'address_country', None),
|
||||
'formatted': self.userinfo.get('address', {}).get('formatted'),
|
||||
'street_address': self.userinfo.get('address', {}).get('street_address'),
|
||||
'locality': self.userinfo.get('address', {}).get('locality'),
|
||||
'region': self.userinfo.get('address', {}).get('region'),
|
||||
'postal_code': self.userinfo.get('address', {}).get('postal_code'),
|
||||
'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.
|
||||
"""
|
||||
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)
|
||||
for index_extra, scope_extra in enumerate(scopes_extra):
|
||||
for index, scope in enumerate(scopes[:]):
|
||||
if scope_extra['scope'] == scope['scope']:
|
||||
del scopes[index]
|
||||
if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'):
|
||||
scopes_extra = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True).get_scopes_info(self.params.scope)
|
||||
for index_extra, scope_extra in enumerate(scopes_extra):
|
||||
for index, scope in enumerate(scopes[:]):
|
||||
if scope_extra['scope'] == scope['scope']:
|
||||
del scopes[index]
|
||||
else:
|
||||
scopes_extra = []
|
||||
|
||||
return scopes + scopes_extra
|
||||
|
|
|
@ -45,14 +45,12 @@ def get_issuer(site_url=None, request=None):
|
|||
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.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_by_user(cls, user):
|
||||
return None
|
||||
return claims
|
||||
|
||||
|
||||
def default_sub_generator(user):
|
||||
|
|
|
@ -43,7 +43,7 @@ class DefaultSettings(object):
|
|||
OPTIONAL. A string with the location of your class.
|
||||
Used to add extra scopes specific for your app.
|
||||
"""
|
||||
return 'oidc_provider.lib.claims.ScopeClaims'
|
||||
return None
|
||||
|
||||
@property
|
||||
def OIDC_IDTOKEN_EXPIRE(self):
|
||||
|
@ -95,10 +95,10 @@ class DefaultSettings(object):
|
|||
@property
|
||||
def OIDC_USERINFO(self):
|
||||
"""
|
||||
OPTIONAL. A string with the location of your class.
|
||||
Used to add extra scopes specific for your app.
|
||||
OPTIONAL. A string with the location of your function.
|
||||
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
|
||||
def OIDC_IDTOKEN_PROCESSING_HOOK(self):
|
||||
|
|
|
@ -58,4 +58,4 @@ USE_TZ = True
|
|||
# OIDC Provider settings.
|
||||
|
||||
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
|
||||
|
||||
|
||||
class FakeUserInfo(object):
|
||||
def userinfo(claims, user):
|
||||
"""
|
||||
Fake class for setting OIDC_USERINFO.
|
||||
Fake function for setting OIDC_USERINFO.
|
||||
"""
|
||||
|
||||
given_name = 'John'
|
||||
family_name = 'Doe'
|
||||
nickname = 'johndoe'
|
||||
website = 'http://johndoe.com'
|
||||
|
||||
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()
|
||||
claims['given_name'] = 'John'
|
||||
claims['family_name'] = 'Doe'
|
||||
claims['name'] = '{0} {1}'.format(claims['given_name'], claims['family_name'])
|
||||
claims['email'] = user.email
|
||||
claims['address']['country'] = 'Argentina'
|
||||
return claims
|
||||
|
||||
|
||||
def fake_sub_generator(user):
|
||||
|
|
|
@ -157,13 +157,11 @@ def userinfo(request, *args, **kwargs):
|
|||
}
|
||||
|
||||
standard_claims = StandardScopeClaims(token.user, token.scope)
|
||||
|
||||
dic.update(standard_claims.create_response_dic())
|
||||
|
||||
extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(
|
||||
token.user, token.scope)
|
||||
|
||||
dic.update(extra_claims.create_response_dic())
|
||||
if settings.get('OIDC_EXTRA_SCOPE_CLAIMS'):
|
||||
extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token.user, token.scope)
|
||||
dic.update(extra_claims.create_response_dic())
|
||||
|
||||
response = JsonResponse(dic, status=200)
|
||||
response['Cache-Control'] = 'no-store'
|
||||
|
|
Loading…
Reference in a new issue