Pull request PEP8 compliant from nicchub:master.
This commit is contained in:
parent
c323b0829b
commit
be741e79e3
11 changed files with 125 additions and 71 deletions
|
@ -50,6 +50,8 @@ Add the provider urls.
|
|||
Settings
|
||||
********
|
||||
|
||||
Add required variables to your project settings.
|
||||
|
||||
.. code:: python
|
||||
|
||||
# REQUIRED. Your server provider url.
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import uuid
|
||||
|
||||
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):
|
||||
|
@ -17,8 +20,7 @@ class AuthorizeEndpoint(object):
|
|||
|
||||
# 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.query_dict = (self.request.POST if self.request.method == 'POST' else self.request.GET)
|
||||
|
||||
self._extract_params()
|
||||
|
||||
|
@ -32,12 +34,12 @@ class AuthorizeEndpoint(object):
|
|||
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', '')
|
||||
|
@ -45,11 +47,11 @@ class AuthorizeEndpoint(object):
|
|||
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 validate_params(self):
|
||||
|
@ -69,8 +71,7 @@ class AuthorizeEndpoint(object):
|
|||
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):
|
||||
if not self.grant_type or not (self.params.response_type == self.client.response_type):
|
||||
|
||||
raise AuthorizeError(
|
||||
self.params.redirect_uri,
|
||||
|
@ -91,23 +92,23 @@ class AuthorizeEndpoint(object):
|
|||
try:
|
||||
self.validate_params()
|
||||
|
||||
if (self.grant_type == 'authorization_code'):
|
||||
if self.grant_type == 'authorization_code':
|
||||
|
||||
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.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: # Implicit Flow
|
||||
else: # Implicit Flow
|
||||
|
||||
id_token_dic = create_id_token_dic(
|
||||
self.request.user,
|
||||
'http://localhost:8000', # TODO: Add this into settings.
|
||||
'http://localhost:8000', # TODO: Add this into settings.
|
||||
self.client.client_id)
|
||||
|
||||
token = create_token(
|
||||
|
@ -123,11 +124,11 @@ class AuthorizeEndpoint(object):
|
|||
|
||||
# TODO: Check if response_type is 'id_token token' then
|
||||
# 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)
|
||||
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,
|
||||
|
@ -135,7 +136,6 @@ class AuthorizeEndpoint(object):
|
|||
self.grant_type)
|
||||
|
||||
# Add state if present.
|
||||
uri = uri + ('&state={0}'.format(self.params.state)
|
||||
if self.params.state else '')
|
||||
uri = uri + ('&state={0}'.format(self.params.state) if self.params.state else '')
|
||||
|
||||
return uri
|
|
@ -1,10 +1,12 @@
|
|||
import urllib
|
||||
|
||||
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 *
|
||||
from openid_provider import settings
|
||||
import urllib
|
||||
|
||||
|
||||
class TokenEndpoint(object):
|
||||
|
@ -54,15 +56,15 @@ class TokenEndpoint(object):
|
|||
def create_response_dic(self):
|
||||
|
||||
id_token_dic = create_id_token_dic(
|
||||
self.code.user,
|
||||
settings.get('SITE_URL'),
|
||||
self.client.client_id)
|
||||
self.code.user,
|
||||
settings.get('SITE_URL'),
|
||||
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)
|
||||
user=self.code.user,
|
||||
client=self.code.client,
|
||||
id_token_dic=id_token_dic,
|
||||
scope=self.code.scope)
|
||||
|
||||
# Store the token.
|
||||
token.save()
|
||||
|
@ -75,7 +77,7 @@ class TokenEndpoint(object):
|
|||
dic = {
|
||||
'access_token': token.access_token,
|
||||
'token_type': 'bearer',
|
||||
'expires_in': 60*60, # TODO: Add this into settings.
|
||||
'expires_in': 60*60, # TODO: Add this into settings.
|
||||
'id_token': id_token,
|
||||
}
|
||||
|
||||
|
@ -83,9 +85,9 @@ class TokenEndpoint(object):
|
|||
|
||||
@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'
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import re
|
||||
|
||||
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):
|
||||
|
@ -21,12 +23,12 @@ class UserInfoEndpoint(object):
|
|||
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):
|
||||
|
@ -45,12 +47,12 @@ class UserInfoEndpoint(object):
|
|||
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'),
|
||||
}
|
||||
|
|
|
@ -6,33 +6,52 @@ class RedirectUriError(Exception):
|
|||
error = 'Redirect URI Error'
|
||||
description = 'The request fails due to a missing, invalid, or mismatching redirection URI (redirect_uri).'
|
||||
|
||||
|
||||
class ClientIdError(Exception):
|
||||
|
||||
error = 'Client ID Error'
|
||||
description = 'The client identifier (client_id) is missing or invalid.'
|
||||
|
||||
|
||||
class AuthorizeError(Exception):
|
||||
|
||||
_errors = {
|
||||
# Oauth2 errors.
|
||||
# https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
'invalid_request': 'The request is otherwise malformed',
|
||||
|
||||
'unauthorized_client': 'The client is not authorized to request an authorization code using this method',
|
||||
|
||||
'access_denied': 'The resource owner or authorization server denied the request',
|
||||
'unsupported_response_type': 'The authorization server does not support obtaining an authorization code using this method',
|
||||
|
||||
'unsupported_response_type': 'The authorization server does not support obtaining an authorization code using '
|
||||
'this method',
|
||||
|
||||
'invalid_scope': 'The requested scope is invalid, unknown, or malformed',
|
||||
|
||||
'server_error': 'The authorization server encountered an error',
|
||||
'temporarily_unavailable': 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server',
|
||||
|
||||
'temporarily_unavailable': 'The authorization server is currently unable to handle the request due to a '
|
||||
'temporary overloading or maintenance of the server',
|
||||
|
||||
# OpenID errors.
|
||||
# http://openid.net/specs/openid-connect-core-1_0.html#AuthError
|
||||
'interaction_required': 'The Authorization Server requires End-User interaction of some form to proceed',
|
||||
|
||||
'login_required': 'The Authorization Server requires End-User authentication',
|
||||
|
||||
'account_selection_required': 'The End-User is required to select a session at the Authorization Server',
|
||||
|
||||
'consent_required': 'The Authorization Server requires End-User consent',
|
||||
|
||||
'invalid_request_uri': 'The request_uri in the Authorization Request returns an error or contains invalid data',
|
||||
|
||||
'invalid_request_object': 'The request parameter contains an invalid Request Object',
|
||||
|
||||
'request_not_supported': 'The provider does not support use of the request parameter',
|
||||
|
||||
'request_uri_not_supported': 'The provider does not support use of the request_uri parameter',
|
||||
|
||||
'registration_not_supported': 'The provider does not support use of the registration parameter',
|
||||
}
|
||||
|
||||
|
@ -65,17 +84,26 @@ class AuthorizeError(Exception):
|
|||
def response(self):
|
||||
pass
|
||||
|
||||
|
||||
class TokenError(Exception):
|
||||
|
||||
_errors = {
|
||||
# Oauth2 errors.
|
||||
# https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
'invalid_request': 'The request is otherwise malformed',
|
||||
'invalid_client': 'Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)',
|
||||
'invalid_grant': 'The provided authorization grant or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client',
|
||||
|
||||
'invalid_client': 'Client authentication failed (e.g., unknown client, no client authentication included, '
|
||||
'or unsupported authentication method)',
|
||||
|
||||
'invalid_grant': 'The provided authorization grant or refresh token is invalid, expired, revoked, does not '
|
||||
'match the redirection URI used in the authorization request, or was issued to another client',
|
||||
|
||||
'unauthorized_client': 'The authenticated client is not authorized to use this authorization grant type',
|
||||
|
||||
'unsupported_grant_type': 'The authorization grant type is not supported by the authorization server',
|
||||
'invalid_scope': 'The requested scope is invalid, unknown, malformed, or exceeds the scope granted by the resource owner',
|
||||
|
||||
'invalid_scope': 'The requested scope is invalid, unknown, malformed, or exceeds the scope granted by the '
|
||||
'resource owner',
|
||||
}
|
||||
|
||||
def __init__(self, error):
|
||||
|
@ -92,14 +120,20 @@ class TokenError(Exception):
|
|||
|
||||
return dic
|
||||
|
||||
class UserInfoError(Exception):
|
||||
|
||||
class UserInfoError(Exception):
|
||||
_errors = {
|
||||
# Oauth2 errors.
|
||||
# https://tools.ietf.org/html/rfc6750#section-3.1
|
||||
'invalid_request': ('The request is otherwise malformed', 400),
|
||||
'invalid_token': ('The access token provided is expired, revoked, malformed, or invalid for other reasons', 401),
|
||||
'insufficient_scope': ('The request requires higher privileges than provided by the access token', 403),
|
||||
'invalid_request': (
|
||||
'The request is otherwise malformed', 400
|
||||
),
|
||||
'invalid_token': (
|
||||
'The access token provided is expired, revoked, malformed, or invalid for other reasons', 401
|
||||
),
|
||||
'insufficient_scope': (
|
||||
'The request requires higher privileges than provided by the access token', 403
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, code):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openid_provider.models import UserInfo
|
||||
|
||||
|
||||
|
@ -32,10 +33,10 @@ class StandardClaims(object):
|
|||
return dic
|
||||
|
||||
def _scopes_registered(self):
|
||||
'''
|
||||
"""
|
||||
Return a list that contains all the scopes registered
|
||||
in the class.
|
||||
'''
|
||||
"""
|
||||
scopes = []
|
||||
|
||||
for name in self.__class__.__dict__:
|
||||
|
@ -47,9 +48,9 @@ class StandardClaims(object):
|
|||
return scopes
|
||||
|
||||
def _clean_dic(self, dic):
|
||||
'''
|
||||
"""
|
||||
Clean recursively all empty or None values inside a dict.
|
||||
'''
|
||||
"""
|
||||
aux_dic = dic.copy()
|
||||
for key, value in dic.iteritems():
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
|
||||
class Params(object):
|
||||
'''
|
||||
"""
|
||||
The purpose of this class is for accesing params via dot notation.
|
||||
'''
|
||||
"""
|
||||
pass
|
|
@ -1,19 +1,21 @@
|
|||
from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
import jwt
|
||||
from openid_provider.models import *
|
||||
import time
|
||||
import jwt
|
||||
import uuid
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from django.utils import timezone
|
||||
from openid_provider.models import *
|
||||
|
||||
|
||||
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()
|
||||
|
@ -34,22 +36,24 @@ def create_id_token_dic(user, iss, aud):
|
|||
|
||||
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
|
||||
|
@ -58,7 +62,7 @@ def create_token(user, client, id_token_dic, scope):
|
|||
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.expires_at = timezone.now() + timedelta(seconds=60*60) # TODO: Add this into settings.
|
||||
token.scope = scope
|
||||
|
||||
return token
|
|
@ -1,7 +1,8 @@
|
|||
from django.contrib.auth.models import User
|
||||
import json
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
import json
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class Client(models.Model):
|
||||
|
@ -18,6 +19,7 @@ class Client(models.Model):
|
|||
response_type = models.CharField(max_length=30, choices=RESPONSE_TYPE_CHOICES)
|
||||
|
||||
_redirect_uris = models.TextField(default='')
|
||||
|
||||
def redirect_uris():
|
||||
def fget(self):
|
||||
return self._redirect_uris.splitlines()
|
||||
|
@ -30,6 +32,7 @@ class Client(models.Model):
|
|||
def default_redirect_uri(self):
|
||||
return self.redirect_uris[0] if self.redirect_uris else ''
|
||||
|
||||
|
||||
class Code(models.Model):
|
||||
|
||||
user = models.ForeignKey(User)
|
||||
|
@ -38,6 +41,7 @@ class Code(models.Model):
|
|||
expires_at = models.DateTimeField()
|
||||
|
||||
_scope = models.TextField(default='')
|
||||
|
||||
def scope():
|
||||
def fget(self):
|
||||
return self._scope.split()
|
||||
|
@ -49,6 +53,7 @@ class Code(models.Model):
|
|||
def has_expired(self):
|
||||
return timezone.now() >= self.expires_at
|
||||
|
||||
|
||||
class Token(models.Model):
|
||||
|
||||
user = models.ForeignKey(User)
|
||||
|
@ -57,6 +62,7 @@ class Token(models.Model):
|
|||
expires_at = models.DateTimeField()
|
||||
|
||||
_scope = models.TextField(default='')
|
||||
|
||||
def scope():
|
||||
def fget(self):
|
||||
return self._scope.split()
|
||||
|
@ -66,6 +72,7 @@ class Token(models.Model):
|
|||
scope = property(**scope())
|
||||
|
||||
_id_token = models.TextField()
|
||||
|
||||
def id_token():
|
||||
def fget(self):
|
||||
return json.loads(self._id_token)
|
||||
|
@ -74,6 +81,7 @@ class Token(models.Model):
|
|||
return locals()
|
||||
id_token = property(**id_token())
|
||||
|
||||
|
||||
class UserInfo(models.Model):
|
||||
|
||||
user = models.OneToOneField(User, primary_key=True)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from django.conf.urls import patterns, include, url
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from openid_provider.views import *
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
|
||||
url(r'^authorize/$', AuthorizeView.as_view(), name='authorize'),
|
||||
url(r'^token/$', csrf_exempt(TokenView.as_view()), name='token'),
|
||||
url(r'^userinfo/$', csrf_exempt(userinfo), name='userinfo'),
|
||||
url(r'^authorize/$', AuthorizeView.as_view(), name='authorize'),
|
||||
url(r'^token/$', csrf_exempt(TokenView.as_view()), name='token'),
|
||||
url(r'^userinfo/$', csrf_exempt(userinfo), name='userinfo'),
|
||||
|
||||
)
|
|
@ -5,7 +5,7 @@ from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
|||
from django.shortcuts import render
|
||||
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.endpoints.authorize import *
|
||||
from openid_provider.lib.endpoints.token import *
|
||||
|
@ -69,6 +69,7 @@ class AuthorizeView(View):
|
|||
|
||||
return HttpResponseRedirect(uri)
|
||||
|
||||
|
||||
class TokenView(View):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
|
Loading…
Reference in a new issue