Refactoring supporting OAuth2 flow.

This commit is contained in:
juanifioren 2016-02-16 17:33:12 -03:00
parent 3da1ff4c85
commit 25a59c8344
6 changed files with 75 additions and 46 deletions

View file

@ -29,11 +29,14 @@ class AuthorizeEndpoint(object):
# Determine which flow to use.
if self.params.response_type in ['code']:
self.grant_type = 'authorization_code'
elif self.params.response_type in ['id_token', 'id_token token']:
elif self.params.response_type in ['id_token', 'id_token token', 'token']:
self.grant_type = 'implicit'
else:
self.grant_type = None
# Determine if it's an OpenID Authentication request (or OAuth2).
self.is_authentication = 'openid' in self.params.scope
def _extract_params(self):
"""
Get all the params used by the Authorization Code Flow
@ -54,36 +57,31 @@ class AuthorizeEndpoint(object):
self.params.nonce = query_dict.get('nonce', '')
def validate_params(self):
if not self.params.redirect_uri:
logger.error('[Authorize] Missing redirect uri.')
raise RedirectUriError()
if not ('openid' in self.params.scope):
logger.error('[Authorize] Missing openid scope.')
raise AuthorizeError(self.params.redirect_uri, 'invalid_scope',
self.grant_type)
# http://openid.net/specs/openid-connect-implicit-1_0.html#RequestParameters
if self.grant_type == 'implicit' and not self.params.nonce:
raise AuthorizeError(self.params.redirect_uri, 'invalid_request',
self.grant_type)
try:
self.client = Client.objects.get(client_id=self.params.client_id)
except Client.DoesNotExist:
logger.error('[Authorize] Invalid client identifier: %s', self.params.client_id)
raise ClientIdError()
if self.is_authentication and not self.params.redirect_uri:
logger.error('[Authorize] Missing redirect uri.')
raise RedirectUriError()
if not self.grant_type:
logger.error('[Authorize] Invalid response type: %s', self.params.response_type)
raise AuthorizeError(self.params.redirect_uri, 'unsupported_response_type',
self.grant_type)
if self.is_authentication and self.grant_type == 'implicit' and not self.params.nonce:
raise AuthorizeError(self.params.redirect_uri, 'invalid_request',
self.grant_type)
clean_redirect_uri = urlsplit(self.params.redirect_uri)
clean_redirect_uri = urlunsplit(clean_redirect_uri._replace(query=''))
if not (clean_redirect_uri in self.client.redirect_uris):
logger.error('[Authorize] Invalid redirect uri: %s', self.params.redirect_uri)
raise RedirectUriError()
if not self.grant_type or not (self.params.response_type == self.client.response_type):
logger.error('[Authorize] Invalid response type: %s', self.params.response_type)
raise AuthorizeError(self.params.redirect_uri, 'unsupported_response_type',
self.grant_type)
def create_response_uri(self):
uri = urlsplit(self.params.redirect_uri)
@ -96,7 +94,8 @@ class AuthorizeEndpoint(object):
user=self.request.user,
client=self.client,
scope=self.params.scope,
nonce=self.params.nonce)
nonce=self.params.nonce,
is_authentication=self.is_authentication)
code.save()
@ -104,10 +103,15 @@ class AuthorizeEndpoint(object):
query_params['state'] = self.params.state if self.params.state else ''
elif self.grant_type == 'implicit':
id_token_dic = create_id_token(
user=self.request.user,
aud=self.client.client_id,
nonce=self.params.nonce)
# We don't need id_token if it's an OAuth2 request.
if self.is_authentication:
id_token_dic = create_id_token(
user=self.request.user,
aud=self.client.client_id,
nonce=self.params.nonce)
query_fragment['id_token'] = encode_id_token(id_token_dic)
else:
id_token_dic = {}
token = create_token(
user=self.request.user,
@ -119,12 +123,12 @@ class AuthorizeEndpoint(object):
token.save()
query_fragment['token_type'] = 'bearer'
query_fragment['id_token'] = encode_id_token(id_token_dic)
# TODO: Create setting 'OIDC_TOKEN_EXPIRE'.
query_fragment['expires_in'] = 60 * 10
# Check if response_type is 'id_token token' then
# add access_token to the fragment.
if self.params.response_type == 'id_token token':
# Check if response_type is an OpenID request with value 'id_token token'
# or it's an OAuth2 Implicit Flow request.
if self.params.response_type in ['id_token token', 'token']:
query_fragment['access_token'] = token.access_token
query_fragment['state'] = self.params.state if self.params.state else ''

View file

@ -64,7 +64,6 @@ class TokenEndpoint(object):
def validate_params(self):
try:
self.client = Client.objects.get(client_id=self.params.client_id)
except Client.DoesNotExist:
logger.error('[Token] Client does not exist: %s', self.params.client_id)
raise TokenError('invalid_client')
@ -81,7 +80,6 @@ class TokenEndpoint(object):
try:
self.code = Code.objects.get(code=self.params.code)
except Code.DoesNotExist:
logger.error('[Token] Code does not exist: %s', self.params.code)
raise TokenError('invalid_grant')
@ -114,16 +112,16 @@ class TokenEndpoint(object):
return self.create_code_response_dic()
elif self.params.grant_type == 'refresh_token':
return self.create_refresh_response_dic()
else:
# Should have already been catched by validate_params
raise RuntimeError('Invalid grant type')
def create_code_response_dic(self):
id_token_dic = create_id_token(
user=self.code.user,
aud=self.client.client_id,
nonce=self.code.nonce,
)
if self.code.is_authentication:
id_token_dic = create_id_token(
user=self.code.user,
aud=self.client.client_id,
nonce=self.code.nonce,
)
else:
id_token_dic = {}
token = create_token(
user=self.code.user,
@ -148,11 +146,15 @@ class TokenEndpoint(object):
return dic
def create_refresh_response_dic(self):
id_token_dic = create_id_token(
user=self.token.user,
aud=self.client.client_id,
nonce=None,
)
# If the Token has an id_token it's an Authentication request.
if self.token.id_token:
id_token_dic = create_id_token(
user=self.token.user,
aud=self.client.client_id,
nonce=None,
)
else:
id_token_dic = {}
token = create_token(
user=self.token.user,

View file

@ -89,7 +89,7 @@ def create_token(user, client, id_token_dic, scope):
return token
def create_code(user, client, scope, nonce):
def create_code(user, client, scope, nonce, is_authentication):
"""
Create and populate a Code object.
@ -103,5 +103,6 @@ def create_code(user, client, scope, nonce):
seconds=settings.get('OIDC_CODE_EXPIRE'))
code.scope = scope
code.nonce = nonce
code.is_authentication = is_authentication
return code

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-02-16 20:32
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('oidc_provider', '0009_auto_20160202_1945'),
]
operations = [
migrations.AddField(
model_name='code',
name='is_authentication',
field=models.BooleanField(default=False),
),
]

View file

@ -80,6 +80,7 @@ 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)
class Meta:
verbose_name = _(u'Authorization Code')

View file

@ -81,7 +81,8 @@ class TokenTestCase(TestCase):
user=self.user,
client=self.client,
scope=['openid', 'email'],
nonce=FAKE_NONCE)
nonce=FAKE_NONCE,
is_authentication=True)
code.save()
return code