diff --git a/oidc_provider/lib/endpoints/authorize.py b/oidc_provider/lib/endpoints/authorize.py
index 43ff43f..602ff89 100644
--- a/oidc_provider/lib/endpoints/authorize.py
+++ b/oidc_provider/lib/endpoints/authorize.py
@@ -34,7 +34,7 @@ class AuthorizeEndpoint(object):
self.grant_type = None
# Determine if it's an OpenID Authentication request (or OAuth2).
- self.is_authentication = 'openid' in self.params.scope
+ self.is_authentication = 'openid' in self.params.scope
def _extract_params(self):
"""
@@ -53,7 +53,7 @@ class AuthorizeEndpoint(object):
self.params.response_type = query_dict.get('response_type', '')
self.params.scope = query_dict.get('scope', '').split()
self.params.state = query_dict.get('state', '')
-
+
self.params.nonce = query_dict.get('nonce', '')
self.params.prompt = query_dict.get('prompt', '')
self.params.code_challenge = query_dict.get('code_challenge', '')
@@ -113,7 +113,7 @@ class AuthorizeEndpoint(object):
is_authentication=self.is_authentication,
code_challenge=self.params.code_challenge,
code_challenge_method=self.params.code_challenge_method)
-
+
code.save()
query_params['code'] = code.code
@@ -169,18 +169,24 @@ class AuthorizeEndpoint(object):
Return None.
"""
- expires_at = timezone.now() + timedelta(
+ date_given = timezone.now()
+ expires_at = date_given + timedelta(
days=settings.get('OIDC_SKIP_CONSENT_EXPIRE'))
uc, created = UserConsent.objects.get_or_create(
user=self.request.user,
client=self.client,
- defaults={'expires_at': expires_at})
+ defaults={
+ 'expires_at': expires_at,
+ 'date_given': date_given,
+ }
+ )
uc.scope = self.params.scope
- # Rewrite expires_at if object already exists.
+ # Rewrite expires_at and date_given if object already exists.
if not created:
uc.expires_at = expires_at
+ uc.date_given = date_given
uc.save()
diff --git a/oidc_provider/migrations/0016_userconsent_and_verbosenames.py b/oidc_provider/migrations/0016_userconsent_and_verbosenames.py
new file mode 100644
index 0000000..afd043e
--- /dev/null
+++ b/oidc_provider/migrations/0016_userconsent_and_verbosenames.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.6 on 2016-06-10 17:53
+from __future__ import unicode_literals
+
+import datetime
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+from django.utils.timezone import utc
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('oidc_provider', '0015_change_client_code'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='userconsent',
+ name='date_given',
+ field=models.DateTimeField(default=datetime.datetime(2016, 6, 10, 17, 53, 48, 889808, tzinfo=utc), verbose_name='Date Given'),
+ preserve_default=False,
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='_redirect_uris',
+ field=models.TextField(default=b'', help_text='Enter each URI on a new line.', verbose_name='Redirect URIs'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='client_id',
+ field=models.CharField(max_length=255, unique=True, verbose_name='Client ID'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='client_secret',
+ field=models.CharField(blank=True, default=b'', max_length=255, verbose_name='Client SECRET'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='client_type',
+ field=models.CharField(choices=[(b'confidential', b'Confidential'), (b'public', b'Public')], default=b'confidential', help_text='Confidential clients are capable of maintaining the confidentiality of their credentials. Public clients are incapable.', max_length=30, verbose_name='Client Type'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='date_created',
+ field=models.DateField(auto_now_add=True, verbose_name='Date Created'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='name',
+ field=models.CharField(default=b'', max_length=100, verbose_name='Name'),
+ ),
+ migrations.AlterField(
+ model_name='client',
+ name='response_type',
+ field=models.CharField(choices=[(b'code', b'code (Authorization Code Flow)'), (b'id_token', b'id_token (Implicit Flow)'), (b'id_token token', b'id_token token (Implicit Flow)')], max_length=30, verbose_name='Response Type'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='_scope',
+ field=models.TextField(default=b'', verbose_name='Scopes'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='client',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='code',
+ field=models.CharField(max_length=255, unique=True, verbose_name='Code'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='code_challenge',
+ field=models.CharField(max_length=255, null=True, verbose_name='Code Challenge'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='code_challenge_method',
+ field=models.CharField(max_length=255, null=True, verbose_name='Code Challenge Method'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='expires_at',
+ field=models.DateTimeField(verbose_name='Expiration Date'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='is_authentication',
+ field=models.BooleanField(default=False, verbose_name='Is Authentication?'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='nonce',
+ field=models.CharField(blank=True, default=b'', max_length=255, verbose_name='Nonce'),
+ ),
+ migrations.AlterField(
+ model_name='code',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User'),
+ ),
+ migrations.AlterField(
+ model_name='rsakey',
+ name='key',
+ field=models.TextField(help_text='Paste your private RSA Key here.', verbose_name='Key'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='_id_token',
+ field=models.TextField(verbose_name='ID Token'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='_scope',
+ field=models.TextField(default=b'', verbose_name='Scopes'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='access_token',
+ field=models.CharField(max_length=255, unique=True, verbose_name='Access Token'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='client',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='expires_at',
+ field=models.DateTimeField(verbose_name='Expiration Date'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='refresh_token',
+ field=models.CharField(max_length=255, null=True, unique=True, verbose_name='Refresh Token'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User'),
+ ),
+ migrations.AlterField(
+ model_name='userconsent',
+ name='_scope',
+ field=models.TextField(default=b'', verbose_name='Scopes'),
+ ),
+ migrations.AlterField(
+ model_name='userconsent',
+ name='client',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='oidc_provider.Client', verbose_name='Client'),
+ ),
+ migrations.AlterField(
+ model_name='userconsent',
+ name='expires_at',
+ field=models.DateTimeField(verbose_name='Expiration Date'),
+ ),
+ migrations.AlterField(
+ model_name='userconsent',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='User'),
+ ),
+ ]
diff --git a/oidc_provider/models.py b/oidc_provider/models.py
index 4c280e3..7495044 100644
--- a/oidc_provider/models.py
+++ b/oidc_provider/models.py
@@ -26,15 +26,15 @@ JWT_ALGS = [
class Client(models.Model):
- name = models.CharField(max_length=100, default='')
- client_type = models.CharField(max_length=30, choices=CLIENT_TYPE_CHOICES, default='confidential', help_text=_(u'Confidential clients are capable of maintaining the confidentiality of their credentials. Public clients are incapable.'))
- client_id = models.CharField(max_length=255, unique=True)
- client_secret = models.CharField(max_length=255, blank=True, default='')
- response_type = models.CharField(max_length=30, choices=RESPONSE_TYPE_CHOICES)
+ name = models.CharField(max_length=100, default='', verbose_name=_(u'Name'))
+ client_type = models.CharField(max_length=30, choices=CLIENT_TYPE_CHOICES, default='confidential', verbose_name=_(u'Client Type'), help_text=_(u'Confidential clients are capable of maintaining the confidentiality of their credentials. Public clients are incapable.'))
+ client_id = models.CharField(max_length=255, unique=True, verbose_name=_(u'Client ID'))
+ client_secret = models.CharField(max_length=255, blank=True, default='', verbose_name=_(u'Client SECRET'))
+ response_type = models.CharField(max_length=30, choices=RESPONSE_TYPE_CHOICES, verbose_name=_(u'Response Type'))
jwt_alg = models.CharField(max_length=10, choices=JWT_ALGS, default='RS256', verbose_name=_(u'JWT Algorithm'))
- date_created = models.DateField(auto_now_add=True)
+ date_created = models.DateField(auto_now_add=True, verbose_name=_(u'Date Created'))
- _redirect_uris = models.TextField(default='', verbose_name=_(u'Redirect URI'), help_text=_(u'Enter each URI on a new line.'))
+ _redirect_uris = models.TextField(default='', verbose_name=_(u'Redirect URIs'), help_text=_(u'Enter each URI on a new line.'))
class Meta:
verbose_name = _(u'Client')
@@ -45,7 +45,7 @@ class Client(models.Model):
def __unicode__(self):
return self.__str__()
-
+
def redirect_uris():
def fget(self):
return self._redirect_uris.splitlines()
@@ -61,10 +61,10 @@ class Client(models.Model):
class BaseCodeTokenModel(models.Model):
- user = models.ForeignKey(settings.AUTH_USER_MODEL)
- client = models.ForeignKey(Client)
- expires_at = models.DateTimeField()
- _scope = models.TextField(default='')
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_(u'User'))
+ client = models.ForeignKey(Client, verbose_name=_(u'Client'))
+ expires_at = models.DateTimeField(verbose_name=_(u'Expiration Date'))
+ _scope = models.TextField(default='', verbose_name=_(u'Scopes'))
def scope():
def fget(self):
@@ -82,18 +82,18 @@ class BaseCodeTokenModel(models.Model):
def __unicode__(self):
return self.__str__()
-
+
class Meta:
abstract = True
class Code(BaseCodeTokenModel):
- code = models.CharField(max_length=255, unique=True)
- nonce = models.CharField(max_length=255, blank=True, default='')
- is_authentication = models.BooleanField(default=False)
- code_challenge = models.CharField(max_length=255, null=True)
- code_challenge_method = models.CharField(max_length=255, null=True)
+ code = models.CharField(max_length=255, unique=True, verbose_name=_(u'Code'))
+ nonce = models.CharField(max_length=255, blank=True, default='', verbose_name=_(u'Nonce'))
+ is_authentication = models.BooleanField(default=False, verbose_name=_(u'Is Authentication?'))
+ code_challenge = models.CharField(max_length=255, null=True, verbose_name=_(u'Code Challenge'))
+ code_challenge_method = models.CharField(max_length=255, null=True, verbose_name=_(u'Code Challenge Method'))
class Meta:
verbose_name = _(u'Authorization Code')
@@ -102,9 +102,9 @@ class Code(BaseCodeTokenModel):
class Token(BaseCodeTokenModel):
- access_token = models.CharField(max_length=255, unique=True)
- refresh_token = models.CharField(max_length=255, unique=True, null=True)
- _id_token = models.TextField()
+ access_token = models.CharField(max_length=255, unique=True, verbose_name=_(u'Access Token'))
+ refresh_token = models.CharField(max_length=255, unique=True, null=True, verbose_name=_(u'Refresh Token'))
+ _id_token = models.TextField(verbose_name=_(u'ID Token'))
def id_token():
def fget(self):
return json.loads(self._id_token)
@@ -120,13 +120,15 @@ class Token(BaseCodeTokenModel):
class UserConsent(BaseCodeTokenModel):
+ date_given = models.DateTimeField(verbose_name=_(u'Date Given'))
+
class Meta:
unique_together = ('user', 'client')
class RSAKey(models.Model):
- key = models.TextField(help_text=_(u'Paste your private RSA Key here.'))
+ key = models.TextField(verbose_name=_(u'Key'), help_text=_(u'Paste your private RSA Key here.'))
class Meta:
verbose_name = _(u'RSA Key')
diff --git a/oidc_provider/tests/app/settings.py b/oidc_provider/tests/app/settings.py
index ef5f92b..281b28c 100644
--- a/oidc_provider/tests/app/settings.py
+++ b/oidc_provider/tests/app/settings.py
@@ -53,6 +53,8 @@ TEMPLATE_DIRS = [
'oidc_provider/tests/templates',
]
+USE_TZ = True
+
# OIDC Provider settings.
SITE_URL = 'http://localhost:8000'