Skip to content

Commit 53f86a8

Browse files
eirsylstefanfoulis
andcommitted
Add OIDC_CLIENT_MODEL setting to enable client model swapping
Co-authored-by: Eirik Martiniussen Sylliaas <eirik@sylliaas.no> Co-authored-by: Stefan Foulis <stefan@foulis.ch>
1 parent b1eb3ae commit 53f86a8

File tree

12 files changed

+133
-13
lines changed

12 files changed

+133
-13
lines changed

docs/sections/settings.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ If not specified, it will be automatically generated using ``request.scheme`` an
2121

2222
For example ``http://localhost:8000``.
2323

24+
OIDC_CLIENT_MODEL
25+
=================
26+
27+
OPTIONAL. ``str``. The client model.
28+
29+
If not specified, the default oidc_provider.Client model is used. This is typically used when
30+
you need to override the Client model to add custom properties on the class. The custom class
31+
should override the oidc_provider.AbstractClient model.
32+
2433
OIDC_AFTER_USERLOGIN_HOOK
2534
=========================
2635

oidc_provider/lib/endpoints/authorize.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@
2626
encode_id_token,
2727
)
2828
from oidc_provider.models import (
29-
Client,
3029
UserConsent,
30+
get_client_model
3131
)
3232
from oidc_provider import settings
3333
from oidc_provider.lib.utils.common import get_browser_state_or_default
3434

3535
logger = logging.getLogger(__name__)
36+
Client = get_client_model()
3637

3738

3839
class AuthorizeEndpoint(object):

oidc_provider/lib/endpoints/token.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
encode_id_token,
1818
)
1919
from oidc_provider.models import (
20-
Client,
2120
Code,
2221
Token,
22+
get_client_model
2323
)
2424
from oidc_provider import settings
2525

2626
logger = logging.getLogger(__name__)
27+
Client = get_client_model()
2728

2829

2930
class TokenEndpoint(object):

oidc_provider/migrations/0001_initial.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
from django.db import models, migrations
55
from django.conf import settings
6+
from oidc_provider import settings as oidc_settings
67

78

89
class Migration(migrations.Migration):
910

1011
dependencies = [
1112
('auth', '0001_initial'),
1213
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
migrations.swappable_dependency(oidc_settings.get('OIDC_CLIENT_MODEL')),
1315
]
1416

1517
operations = [
@@ -26,6 +28,8 @@ class Migration(migrations.Migration):
2628
('_redirect_uris', models.TextField(default=b'')),
2729
],
2830
options={
31+
'abstract': False,
32+
'swappable': 'OIDC_CLIENT_MODEL'
2933
},
3034
bases=(models.Model,),
3135
),
@@ -36,7 +40,7 @@ class Migration(migrations.Migration):
3640
('expires_at', models.DateTimeField()),
3741
('_scope', models.TextField(default=b'')),
3842
('code', models.CharField(unique=True, max_length=255)),
39-
('client', models.ForeignKey(to='oidc_provider.Client', on_delete=models.CASCADE)),
43+
('client', models.ForeignKey(oidc_settings.get('OIDC_CLIENT_MODEL'), on_delete=models.CASCADE)),
4044
],
4145
options={
4246
'abstract': False,
@@ -51,7 +55,7 @@ class Migration(migrations.Migration):
5155
('_scope', models.TextField(default=b'')),
5256
('access_token', models.CharField(unique=True, max_length=255)),
5357
('_id_token', models.TextField()),
54-
('client', models.ForeignKey(to='oidc_provider.Client', on_delete=models.CASCADE)),
58+
('client', models.ForeignKey(oidc_settings.get('OIDC_CLIENT_MODEL'), on_delete=models.CASCADE)),
5559
],
5660
options={
5761
'abstract': False,

oidc_provider/migrations/0002_userconsent.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from django.db import models, migrations
55
from django.conf import settings
66

7+
from oidc_provider import settings as oidc_settings
8+
79

810
class Migration(migrations.Migration):
911

@@ -19,7 +21,7 @@ class Migration(migrations.Migration):
1921
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
2022
('expires_at', models.DateTimeField()),
2123
('_scope', models.TextField(default=b'')),
22-
('client', models.ForeignKey(to='oidc_provider.Client', on_delete=models.CASCADE)),
24+
('client', models.ForeignKey(to=oidc_settings.get('OIDC_CLIENT_MODEL'), on_delete=models.CASCADE)),
2325
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
2426
],
2527
options={

oidc_provider/migrations/0016_userconsent_and_verbosenames.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import django.db.models.deletion
99
from django.utils.timezone import utc
1010

11+
from oidc_provider import settings as oidc_settings
12+
1113

1214
class Migration(migrations.Migration):
1315

@@ -79,7 +81,7 @@ class Migration(migrations.Migration):
7981
model_name='code',
8082
name='client',
8183
field=models.ForeignKey(
82-
on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
84+
on_delete=django.db.models.deletion.CASCADE, to=oidc_settings.get('OIDC_CLIENT_MODEL'), verbose_name='Client'),
8385
),
8486
migrations.AlterField(
8587
model_name='code',
@@ -141,7 +143,7 @@ class Migration(migrations.Migration):
141143
model_name='token',
142144
name='client',
143145
field=models.ForeignKey(
144-
on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
146+
on_delete=django.db.models.deletion.CASCADE, to=oidc_settings.get('OIDC_CLIENT_MODEL'), verbose_name='Client'),
145147
),
146148
migrations.AlterField(
147149
model_name='token',
@@ -168,7 +170,7 @@ class Migration(migrations.Migration):
168170
model_name='userconsent',
169171
name='client',
170172
field=models.ForeignKey(
171-
on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
173+
on_delete=django.db.models.deletion.CASCADE, to=oidc_settings.get('OIDC_CLIENT_MODEL'), verbose_name='Client'),
172174
),
173175
migrations.AlterField(
174176
model_name='userconsent',
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.4 on 2018-12-07 13:11
3+
from __future__ import unicode_literals
4+
5+
from django.conf import settings
6+
from django.db import migrations, models
7+
import django.db.models.deletion
8+
9+
10+
class Migration(migrations.Migration):
11+
12+
dependencies = [
13+
('oidc_provider', '0026_client_multiple_response_types'),
14+
]
15+
16+
operations = [
17+
migrations.AlterField(
18+
model_name='client',
19+
name='owner',
20+
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='oidc_provider_client_set', to=settings.AUTH_USER_MODEL, verbose_name='Owner'),
21+
),
22+
]

oidc_provider/models.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
from hashlib import md5, sha256
55
import json
66

7+
from django.apps import apps
78
from django.db import models
89
from django.utils import timezone
910
from django.utils.translation import ugettext_lazy as _
1011
from django.conf import settings
1112

13+
from oidc_provider import settings as oidc_settings
14+
1215

1316
CLIENT_TYPE_CHOICES = [
1417
('confidential', 'Confidential'),
@@ -54,12 +57,13 @@ def __str__(self):
5457
return u'{0}'.format(self.description)
5558

5659

57-
class Client(models.Model):
60+
class AbstractClient(models.Model):
5861

5962
name = models.CharField(max_length=100, default='', verbose_name=_(u'Name'))
6063
owner = models.ForeignKey(
6164
settings.AUTH_USER_MODEL, verbose_name=_(u'Owner'), blank=True,
62-
null=True, default=None, on_delete=models.SET_NULL, related_name='oidc_clients_set')
65+
null=True, default=None, on_delete=models.SET_NULL,
66+
related_name='%(app_label)s_%(class)s_set')
6367
client_type = models.CharField(
6468
max_length=30,
6569
choices=CLIENT_TYPE_CHOICES,
@@ -115,6 +119,7 @@ class Client(models.Model):
115119
class Meta:
116120
verbose_name = _(u'Client')
117121
verbose_name_plural = _(u'Clients')
122+
abstract = True
118123

119124
def __str__(self):
120125
return u'{0}'.format(self.name)
@@ -158,9 +163,21 @@ def default_redirect_uri(self):
158163
return self.redirect_uris[0] if self.redirect_uris else ''
159164

160165

166+
class Client(AbstractClient):
167+
class Meta(AbstractClient.Meta):
168+
swappable = 'OIDC_CLIENT_MODEL'
169+
170+
171+
def get_client_model():
172+
""" Return the Application model that is active in this project. """
173+
return apps.get_model(oidc_settings.get('OIDC_CLIENT_MODEL'))
174+
175+
161176
class BaseCodeTokenModel(models.Model):
162177

163-
client = models.ForeignKey(Client, verbose_name=_(u'Client'), on_delete=models.CASCADE)
178+
client = models.ForeignKey(
179+
oidc_settings.get('OIDC_CLIENT_MODEL'), verbose_name=_(u'Client'),
180+
on_delete=models.CASCADE)
164181
expires_at = models.DateTimeField(verbose_name=_(u'Expiration Date'))
165182
_scope = models.TextField(default='', verbose_name=_(u'Scopes'))
166183

oidc_provider/settings.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ def SITE_URL(self):
2525
"""
2626
return None
2727

28+
@property
29+
def OIDC_CLIENT_MODEL(self):
30+
"""
31+
OPTIONAL. Use a custom client model, typically used to extend the client model
32+
with custom fields. The custom model should override oidc_provider.AbstractClient.
33+
"""
34+
return 'oidc_provider.Client'
35+
2836
@property
2937
def OIDC_AFTER_USERLOGIN_HOOK(self):
3038
"""

oidc_provider/tests/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from django.db import models
2+
3+
from oidc_provider.models import AbstractClient
4+
5+
6+
class CustomClient(AbstractClient):
7+
custom_field = models.CharField(max_length=255)

0 commit comments

Comments
 (0)