Add Implicit flow support.
This commit is contained in:
parent
a95d41a386
commit
c24f0ccc29
12 changed files with 398 additions and 283 deletions
|
@ -2,10 +2,12 @@
|
|||
Django OpenID Provider
|
||||
######################
|
||||
|
||||
**This project is in ALFA version and is rapidly changing. DO NOT USE IT FOR PRODUCTION SITES.**
|
||||
|
||||
Important things that you should know:
|
||||
|
||||
- Although OpenID was built on top of OAuth2, this isn't an OAuth2 server. Maybe in a future it will be.
|
||||
- This just cover the ``authorization_code`` flow, no support for ``implicit`` flow at this moment.
|
||||
- This cover ``authorization_code`` flow and ``implicit`` flow, NO support for ``hibrid`` flow at this moment.
|
||||
- Only support for requesting Claims using Scope Values.
|
||||
|
||||
************
|
||||
|
|
141
openid_provider/lib/endpoints/authorize.py
Normal file
141
openid_provider/lib/endpoints/authorize.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
from openid_provider.lib.errors import *
|
||||
from openid_provider.lib.utils.params import *
|
||||
from openid_provider.lib.utils.token import *
|
||||
from openid_provider.models import *
|
||||
import uuid
|
||||
|
||||
|
||||
class AuthorizeEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
|
||||
self.params = Params
|
||||
|
||||
# Because in this endpoint we handle both GET
|
||||
# and POST request.
|
||||
self.query_dict = (self.request.POST if self.request.method == 'POST'
|
||||
else self.request.GET)
|
||||
|
||||
self._extract_params()
|
||||
|
||||
# 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']:
|
||||
self.grant_type = 'implicit'
|
||||
self._extract_implicit_params()
|
||||
else:
|
||||
self.grant_type = None
|
||||
|
||||
def _extract_params(self):
|
||||
'''
|
||||
Get all the params used by the Authorization Code Flow
|
||||
(and also for the Implicit).
|
||||
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||
'''
|
||||
self.params.client_id = self.query_dict.get('client_id', '')
|
||||
self.params.redirect_uri = self.query_dict.get('redirect_uri', '')
|
||||
self.params.response_type = self.query_dict.get('response_type', '')
|
||||
self.params.scope = self.query_dict.get('scope', '')
|
||||
self.params.state = self.query_dict.get('state', '')
|
||||
|
||||
def _extract_implicit_params(self):
|
||||
'''
|
||||
Get specific params used by the Implicit Flow.
|
||||
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest
|
||||
'''
|
||||
self.params.nonce = self.query_dict.get('nonce', '')
|
||||
|
||||
def is_code_flow(self):
|
||||
'''
|
||||
True if the client is using Authorization Code Flow.
|
||||
|
||||
Return a boolean.
|
||||
'''
|
||||
return self.grant_type == 'authorization_code'
|
||||
|
||||
def is_implicit_flow(self):
|
||||
'''
|
||||
True if the client is using Implicit Flow.
|
||||
|
||||
Return a boolean.
|
||||
'''
|
||||
return self.grant_type == 'implicit'
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
if not self.params.redirect_uri:
|
||||
raise RedirectUriError()
|
||||
|
||||
if not ('openid' in self.params.scope.split()):
|
||||
raise AuthorizeError(self.params.redirect_uri, 'invalid_scope', self.grant_type)
|
||||
|
||||
try:
|
||||
self.client = Client.objects.get(client_id=self.params.client_id)
|
||||
|
||||
if not (self.params.redirect_uri in self.client.redirect_uris):
|
||||
raise RedirectUriError()
|
||||
|
||||
if not (self.grant_type) or not (self.params.response_type == self.client.response_type):
|
||||
raise AuthorizeError(self.params.redirect_uri, 'unsupported_response_type', self.grant_type)
|
||||
|
||||
except Client.DoesNotExist:
|
||||
raise ClientIdError()
|
||||
|
||||
def create_response_uri(self, allow):
|
||||
|
||||
if not allow:
|
||||
raise AuthorizeError(self.params.redirect_uri, 'access_denied', self.grant_type)
|
||||
|
||||
try:
|
||||
self.validate_params()
|
||||
|
||||
if self.is_code_flow():
|
||||
|
||||
code = Code()
|
||||
code.user = self.request.user
|
||||
code.client = self.client
|
||||
code.code = uuid.uuid4().hex
|
||||
code.expires_at = timezone.now() + timedelta(seconds=60*10) # TODO: Add this into settings.
|
||||
code.scope = self.params.scope
|
||||
code.save()
|
||||
|
||||
uri = self.params.redirect_uri + '?code={0}'.format(code.code)
|
||||
else:
|
||||
|
||||
id_token_dic = create_id_token_dic(
|
||||
self.request.user,
|
||||
'http://localhost:8000', # TODO: Add this into settings.
|
||||
self.client.client_id)
|
||||
|
||||
token = create_token(
|
||||
user=self.request.user,
|
||||
client=self.client,
|
||||
id_token_dic=id_token_dic,
|
||||
scope=self.params.scope)
|
||||
|
||||
# Store the token.
|
||||
token.save()
|
||||
|
||||
id_token = encode_id_token(id_token_dic, self.client.client_secret)
|
||||
|
||||
# TODO: Check if response_type is 'id_token token' and
|
||||
# add access_token to the fragment.
|
||||
uri = self.params.redirect_uri + \
|
||||
'#token_type={0}&id_token={1}&expires_in={2}'.format(
|
||||
'bearer',
|
||||
id_token,
|
||||
60*10)
|
||||
except:
|
||||
raise AuthorizeError(self.params.redirect_uri, 'server_error', self.grant_type)
|
||||
|
||||
# Add state if present.
|
||||
uri = uri + ('&state={0}'.format(self.params.state) if self.params.state else '')
|
||||
|
||||
return uri
|
92
openid_provider/lib/endpoints/token.py
Normal file
92
openid_provider/lib/endpoints/token.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
from django.http import JsonResponse
|
||||
from openid_provider.lib.errors import *
|
||||
from openid_provider.lib.utils.params import *
|
||||
from openid_provider.lib.utils.token import *
|
||||
from openid_provider.models import *
|
||||
import urllib
|
||||
|
||||
|
||||
class TokenEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
self.params = Params
|
||||
self._extract_params()
|
||||
|
||||
def _extract_params(self):
|
||||
|
||||
query_dict = self.request.POST
|
||||
|
||||
self.params.client_id = query_dict.get('client_id', '')
|
||||
self.params.client_secret = query_dict.get('client_secret', '')
|
||||
self.params.redirect_uri = urllib.unquote(query_dict.get('redirect_uri', ''))
|
||||
self.params.grant_type = query_dict.get('grant_type', '')
|
||||
self.params.code = query_dict.get('code', '')
|
||||
self.params.state = query_dict.get('state', '')
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
if not (self.params.grant_type == 'authorization_code'):
|
||||
raise TokenError('unsupported_grant_type')
|
||||
|
||||
try:
|
||||
self.client = Client.objects.get(client_id=self.params.client_id)
|
||||
|
||||
if not (self.client.client_secret == self.params.client_secret):
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
if not (self.params.redirect_uri in self.client.redirect_uris):
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
self.code = Code.objects.get(code=self.params.code)
|
||||
|
||||
if not (self.code.client == self.client) and not self.code.has_expired():
|
||||
raise TokenError('invalid_grant')
|
||||
|
||||
except Client.DoesNotExist:
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
except Code.DoesNotExist:
|
||||
raise TokenError('invalid_grant')
|
||||
|
||||
def create_response_dic(self):
|
||||
|
||||
id_token_dic = create_id_token_dic(
|
||||
self.code.user,
|
||||
'http://localhost:8000', # TODO: Add this into settings.
|
||||
self.client.client_id)
|
||||
|
||||
token = create_token(
|
||||
user=self.code.user,
|
||||
client=self.code.client,
|
||||
id_token_dic=id_token_dic,
|
||||
scope=self.code.scope)
|
||||
|
||||
# Store the token.
|
||||
token.save()
|
||||
|
||||
# We don't need to store the code anymore.
|
||||
self.code.delete()
|
||||
|
||||
id_token = encode_id_token(id_token_dic, self.client.client_secret)
|
||||
|
||||
dic = {
|
||||
'access_token': token.access_token,
|
||||
'token_type': 'bearer',
|
||||
'expires_in': 60*60, # TODO: Add this into settings.
|
||||
'id_token': id_token,
|
||||
}
|
||||
|
||||
return dic
|
||||
|
||||
@classmethod
|
||||
def response(self, dic, status=200):
|
||||
'''
|
||||
Create and return a response object.
|
||||
'''
|
||||
response = JsonResponse(dic, status=status)
|
||||
response['Cache-Control'] = 'no-store'
|
||||
response['Pragma'] = 'no-cache'
|
||||
|
||||
return response
|
79
openid_provider/lib/endpoints/userinfo.py
Normal file
79
openid_provider/lib/endpoints/userinfo.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
from django.http import HttpResponse, JsonResponse
|
||||
from openid_provider.lib.errors import *
|
||||
from openid_provider.lib.scopes import *
|
||||
from openid_provider.lib.utils.params import *
|
||||
from openid_provider.models import *
|
||||
import re
|
||||
|
||||
|
||||
class UserInfoEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
self.params = Params
|
||||
self._extract_params()
|
||||
|
||||
def _extract_params(self):
|
||||
|
||||
# TODO: Maybe add other ways of passing access token
|
||||
# http://tools.ietf.org/html/rfc6750#section-2
|
||||
self.params.access_token = self._get_access_token()
|
||||
|
||||
def _get_access_token(self):
|
||||
'''
|
||||
Get the access token using Authorization Request Header Field method.
|
||||
See: http://tools.ietf.org/html/rfc6750#section-2.1
|
||||
|
||||
Return a string.
|
||||
'''
|
||||
auth_header = self.request.META.get('HTTP_AUTHORIZATION', '')
|
||||
|
||||
if re.compile('^Bearer\s{1}.+$').match(auth_header):
|
||||
access_token = auth_header.split()[1]
|
||||
else:
|
||||
access_token = ''
|
||||
|
||||
return access_token
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
try:
|
||||
self.token = Token.objects.get(access_token=self.params.access_token)
|
||||
|
||||
except Token.DoesNotExist:
|
||||
raise UserInfoError('invalid_token')
|
||||
|
||||
def create_response_dic(self):
|
||||
'''
|
||||
Create a diccionary with all the requested claims about the End-User.
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
|
||||
Return a diccionary.
|
||||
'''
|
||||
dic = {
|
||||
'sub': self.token.id_token.get('sub'),
|
||||
}
|
||||
|
||||
standard_claims = StandardClaims(self.token.user, self.token.scope.split())
|
||||
|
||||
dic.update(standard_claims.create_response_dic())
|
||||
|
||||
return dic
|
||||
|
||||
@classmethod
|
||||
def response(self, dic):
|
||||
|
||||
response = JsonResponse(dic, status=200)
|
||||
response['Cache-Control'] = 'no-store'
|
||||
response['Pragma'] = 'no-cache'
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def error_response(self, code, description, status):
|
||||
|
||||
response = HttpResponse(status=status)
|
||||
response['WWW-Authenticate'] = 'error="{0}", error_description="{1}"'.format(code, description)
|
||||
|
||||
return response
|
|
@ -43,17 +43,25 @@ class AuthorizeError(Exception):
|
|||
'registration_not_supported': 'The provider does not support use of the registration parameter',
|
||||
}
|
||||
|
||||
def __init__(self, redirect_uri, error):
|
||||
def __init__(self, redirect_uri, error, grant_type):
|
||||
|
||||
self.error = error
|
||||
self.description = self._errors.get(error)
|
||||
self.redirect_uri = redirect_uri
|
||||
self.grant_type = grant_type
|
||||
|
||||
def create_uri(self, redirect_uri, state):
|
||||
|
||||
description = urllib.quote(self.description)
|
||||
|
||||
uri = '{0}?error={1}&error_description={2}'.format(redirect_uri, self.error, description)
|
||||
# See: http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthError
|
||||
hash_or_question = '#' if self.grant_type == 'implicit' else '?'
|
||||
|
||||
uri = '{0}{1}error={2}&error_description={3}'.format(
|
||||
redirect_uri,
|
||||
hash_or_question,
|
||||
self.error,
|
||||
description)
|
||||
|
||||
# Add state if present.
|
||||
uri = uri + ('&state={0}'.format(state) if state else '')
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
from datetime import timedelta
|
||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||||
from django.utils import timezone
|
||||
import urllib
|
||||
import uuid
|
||||
import json
|
||||
import jwt
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
from openid_provider.models import *
|
||||
from openid_provider.lib.errors import *
|
||||
from openid_provider.lib.scopes import *
|
||||
|
||||
|
||||
class AuthorizeEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
self.extract_params()
|
||||
|
||||
def extract_params(self):
|
||||
|
||||
query_dict = self.request.POST if self.request.method == 'POST' else self.request.GET
|
||||
|
||||
class Params(object): pass
|
||||
|
||||
Params.client_id = query_dict.get('client_id', '')
|
||||
Params.redirect_uri = query_dict.get('redirect_uri', '')
|
||||
Params.response_type = query_dict.get('response_type', '')
|
||||
Params.scope = query_dict.get('scope', '')
|
||||
Params.state = query_dict.get('state', '')
|
||||
|
||||
self.params = Params
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
if not self.params.redirect_uri:
|
||||
raise RedirectUriError()
|
||||
|
||||
if not ('openid' in self.params.scope.split()):
|
||||
raise AuthorizeError(self.params.redirect_uri, 'invalid_scope')
|
||||
|
||||
try:
|
||||
self.client = Client.objects.get(client_id=self.params.client_id)
|
||||
|
||||
if not (self.params.redirect_uri in self.client.redirect_uris):
|
||||
raise RedirectUriError()
|
||||
|
||||
if not (self.params.response_type == 'code'):
|
||||
raise AuthorizeError(self.params.redirect_uri, 'unsupported_response_type')
|
||||
|
||||
except Client.DoesNotExist:
|
||||
raise ClientIdError()
|
||||
|
||||
def create_response_uri(self, allow):
|
||||
|
||||
if not allow:
|
||||
raise AuthorizeError(self.params.redirect_uri, 'access_denied')
|
||||
|
||||
try:
|
||||
self.validate_params()
|
||||
|
||||
code = Code()
|
||||
code.user = self.request.user
|
||||
code.client = self.client
|
||||
code.code = uuid.uuid4().hex
|
||||
code.expires_at = timezone.now() + timedelta(seconds=60*10)
|
||||
code.scope = self.params.scope
|
||||
|
||||
code.save()
|
||||
except:
|
||||
raise AuthorizeError(self.params.redirect_uri, 'server_error')
|
||||
|
||||
uri = self.params.redirect_uri + '?code={0}'.format(code.code)
|
||||
|
||||
# Add state if present.
|
||||
uri = uri + ('&state={0}'.format(self.params.state) if self.params.state else '')
|
||||
|
||||
return uri
|
||||
|
||||
class TokenEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
self.extract_params()
|
||||
|
||||
def extract_params(self):
|
||||
|
||||
query_dict = self.request.POST
|
||||
|
||||
class Params(object): pass
|
||||
|
||||
Params.client_id = query_dict.get('client_id', '')
|
||||
Params.client_secret = query_dict.get('client_secret', '')
|
||||
Params.redirect_uri = urllib.unquote(query_dict.get('redirect_uri', ''))
|
||||
Params.grant_type = query_dict.get('grant_type', '')
|
||||
Params.code = query_dict.get('code', '')
|
||||
Params.state = query_dict.get('state', '')
|
||||
|
||||
self.params = Params
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
if not (self.params.grant_type == 'authorization_code'):
|
||||
raise TokenError('unsupported_grant_type')
|
||||
|
||||
try:
|
||||
self.client = Client.objects.get(client_id=self.params.client_id)
|
||||
|
||||
if not (self.client.client_secret == self.params.client_secret):
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
if not (self.params.redirect_uri in self.client.redirect_uris):
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
self.code = Code.objects.get(code=self.params.code)
|
||||
|
||||
if not (self.code.client == self.client) and not self.code.has_expired():
|
||||
raise TokenError('invalid_grant')
|
||||
|
||||
except Client.DoesNotExist:
|
||||
raise TokenError('invalid_client')
|
||||
|
||||
except Code.DoesNotExist:
|
||||
raise TokenError('invalid_grant')
|
||||
|
||||
def create_response_dic(self):
|
||||
|
||||
expires_in = 60*60 # TODO: Probably add into settings
|
||||
|
||||
token = Token()
|
||||
token.user = self.code.user
|
||||
token.client = self.code.client
|
||||
token.access_token = uuid.uuid4().hex
|
||||
|
||||
id_token_dic = self.generate_id_token_dic()
|
||||
token.id_token = id_token_dic
|
||||
|
||||
token.refresh_token = uuid.uuid4().hex
|
||||
token.expires_at = timezone.now() + timedelta(seconds=expires_in)
|
||||
token.scope = self.code.scope
|
||||
|
||||
token.save()
|
||||
|
||||
self.code.delete()
|
||||
|
||||
id_token = jwt.encode(id_token_dic, self.client.client_secret)
|
||||
|
||||
dic = {
|
||||
'access_token': token.access_token,
|
||||
'token_type': 'bearer',
|
||||
'expires_in': expires_in,
|
||||
'id_token': id_token,
|
||||
# TODO: 'refresh_token': token.refresh_token,
|
||||
}
|
||||
|
||||
return dic
|
||||
|
||||
def generate_id_token_dic(self):
|
||||
|
||||
expires_in = 60*10
|
||||
|
||||
now = timezone.now()
|
||||
|
||||
# Convert datetimes into timestamps.
|
||||
iat_time = time.mktime(now.timetuple())
|
||||
exp_time = time.mktime((now + timedelta(seconds=expires_in)).timetuple())
|
||||
user_auth_time = time.mktime(self.code.user.last_login.timetuple())
|
||||
|
||||
dic = {
|
||||
'iss': 'https://localhost:8000', # TODO: this should not be hardcoded.
|
||||
'sub': self.code.user.id,
|
||||
'aud': self.client.client_id,
|
||||
'exp': exp_time,
|
||||
'iat': iat_time,
|
||||
'auth_time': user_auth_time,
|
||||
}
|
||||
|
||||
return dic
|
||||
|
||||
@classmethod
|
||||
def response(self, dic, status=200):
|
||||
'''
|
||||
Create and return a response object.
|
||||
'''
|
||||
response = JsonResponse(dic, status=status)
|
||||
response['Cache-Control'] = 'no-store'
|
||||
response['Pragma'] = 'no-cache'
|
||||
|
||||
return response
|
||||
|
||||
class UserInfoEndpoint(object):
|
||||
|
||||
def __init__(self, request):
|
||||
|
||||
self.request = request
|
||||
self.extract_params()
|
||||
|
||||
def extract_params(self):
|
||||
|
||||
# TODO: Add other ways of passing access token
|
||||
# http://tools.ietf.org/html/rfc6750#section-2
|
||||
|
||||
class Params(object): pass
|
||||
|
||||
Params.access_token = self._get_access_token()
|
||||
|
||||
self.params = Params
|
||||
|
||||
def validate_params(self):
|
||||
|
||||
try:
|
||||
self.token = Token.objects.get(access_token=self.params.access_token)
|
||||
|
||||
except Token.DoesNotExist:
|
||||
raise UserInfoError('invalid_token')
|
||||
|
||||
def _get_access_token(self):
|
||||
'''
|
||||
Get the access token using Authorization Request Header Field method.
|
||||
See: http://tools.ietf.org/html/rfc6750#section-2.1
|
||||
|
||||
Return a string.
|
||||
'''
|
||||
auth_header = self.request.META.get('HTTP_AUTHORIZATION', '')
|
||||
|
||||
if re.compile('^Bearer\s{1}.+$').match(auth_header):
|
||||
access_token = auth_header.split()[1]
|
||||
else:
|
||||
access_token = ''
|
||||
|
||||
return access_token
|
||||
|
||||
def create_response_dic(self):
|
||||
'''
|
||||
Create a diccionary with all the requested claims about the End-User.
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
||||
|
||||
Return a diccionary.
|
||||
'''
|
||||
dic = {
|
||||
'sub': self.token.id_token.get('sub'),
|
||||
}
|
||||
|
||||
standard_claims = StandardClaims(self.token.user, self.token.scope.split())
|
||||
|
||||
dic.update(standard_claims.create_response_dic())
|
||||
|
||||
return dic
|
||||
|
||||
@classmethod
|
||||
def response(self, dic):
|
||||
|
||||
response = JsonResponse(dic, status=200)
|
||||
response['Cache-Control'] = 'no-store'
|
||||
response['Pragma'] = 'no-cache'
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def error_response(self, code, description, status):
|
||||
|
||||
response = HttpResponse(status=status)
|
||||
response['WWW-Authenticate'] = 'error="{0}", error_description="{1}"'.format(code, description)
|
||||
|
||||
return response
|
0
openid_provider/lib/utils/__init__.py
Normal file
0
openid_provider/lib/utils/__init__.py
Normal file
2
openid_provider/lib/utils/params.py
Normal file
2
openid_provider/lib/utils/params.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
class Params(object):
|
||||
pass
|
64
openid_provider/lib/utils/token.py
Normal file
64
openid_provider/lib/utils/token.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
import jwt
|
||||
from openid_provider.models import *
|
||||
import time
|
||||
import uuid
|
||||
|
||||
|
||||
def create_id_token_dic(user, iss, aud):
|
||||
'''
|
||||
Receives a user object, iss (issuer) and aud (audience).
|
||||
Then creates the id_token dic.
|
||||
See: http://openid.net/specs/openid-connect-core-1_0.html#IDToken
|
||||
|
||||
Return a dic.
|
||||
'''
|
||||
expires_in = 60*10
|
||||
|
||||
now = timezone.now()
|
||||
|
||||
# Convert datetimes into timestamps.
|
||||
iat_time = time.mktime(now.timetuple())
|
||||
exp_time = time.mktime((now + timedelta(seconds=expires_in)).timetuple())
|
||||
user_auth_time = time.mktime(user.last_login.timetuple())
|
||||
|
||||
dic = {
|
||||
'iss': iss, # TODO: this should not be hardcoded.
|
||||
'sub': user.id,
|
||||
'aud': aud,
|
||||
'exp': exp_time,
|
||||
'iat': iat_time,
|
||||
'auth_time': user_auth_time,
|
||||
}
|
||||
|
||||
return dic
|
||||
|
||||
def encode_id_token(id_token_dic, client_secret):
|
||||
'''
|
||||
Represent the ID Token as a JSON Web Token (JWT).
|
||||
|
||||
Return a hash.
|
||||
'''
|
||||
id_token_hash = jwt.encode(id_token_dic, client_secret)
|
||||
|
||||
return id_token_hash
|
||||
|
||||
def create_token(user, client, id_token_dic, scope):
|
||||
'''
|
||||
Create and populate a Token object.
|
||||
|
||||
Return a Token object.
|
||||
'''
|
||||
token = Token()
|
||||
token.user = user
|
||||
token.client = client
|
||||
token.access_token = uuid.uuid4().hex
|
||||
|
||||
token.id_token = id_token_dic
|
||||
|
||||
token.refresh_token = uuid.uuid4().hex
|
||||
token.expires_at = timezone.now() + timedelta(seconds=60*60) # TODO: Add this into settings.
|
||||
token.scope = scope
|
||||
|
||||
return token
|
|
@ -8,18 +8,13 @@ class Client(models.Model):
|
|||
|
||||
CLIENT_TYPE_CHOICES = [
|
||||
('confidential', 'Confidential'),
|
||||
#('public', 'Public'),
|
||||
]
|
||||
|
||||
GRANT_TYPE_CHOICES = [
|
||||
('authorization_code', 'Authorization Code Flow'),
|
||||
#('implicit', 'Implicit Flow'),
|
||||
('public', 'Public'),
|
||||
]
|
||||
|
||||
RESPONSE_TYPE_CHOICES = [
|
||||
('code', 'Authorization Code Flow'),
|
||||
#('id_token', 'Implicit Flow'),
|
||||
#('id_token token', 'Implicit Flow'),
|
||||
('code', 'code (Authorization Code Flow)'),
|
||||
('id_token', 'id_token (Implicit Flow)'),
|
||||
('id_token token', 'id_token token (Implicit Flow)'),
|
||||
]
|
||||
|
||||
name = models.CharField(max_length=100, default='')
|
||||
|
@ -27,7 +22,6 @@ class Client(models.Model):
|
|||
client_id = models.CharField(max_length=255, unique=True)
|
||||
client_secret = models.CharField(max_length=255, unique=True)
|
||||
client_type = models.CharField(max_length=20, choices=CLIENT_TYPE_CHOICES)
|
||||
grant_type = models.CharField(max_length=30, choices=GRANT_TYPE_CHOICES)
|
||||
response_type = models.CharField(max_length=30, choices=RESPONSE_TYPE_CHOICES)
|
||||
|
||||
# TODO: Need to be implemented.
|
||||
|
|
|
@ -6,7 +6,9 @@ from django.views.decorators.http import require_http_methods
|
|||
from django.views.generic import View
|
||||
import urllib
|
||||
from openid_provider.lib.errors import *
|
||||
from openid_provider.lib.grants.authorization_code import *
|
||||
from openid_provider.lib.endpoints.authorize import *
|
||||
from openid_provider.lib.endpoints.token import *
|
||||
from openid_provider.lib.endpoints.userinfo import *
|
||||
|
||||
|
||||
class AuthorizeView(View):
|
||||
|
|
Loading…
Reference in a new issue