2015-06-19 20:46:00 +00:00
|
|
|
import logging
|
|
|
|
|
2015-07-13 20:34:43 +00:00
|
|
|
from Crypto.PublicKey import RSA
|
2015-07-24 09:36:45 +00:00
|
|
|
from django.contrib.auth.views import redirect_to_login, logout
|
2015-07-31 17:19:53 +00:00
|
|
|
from django.core.urlresolvers import reverse
|
2014-12-19 15:27:43 +00:00
|
|
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
|
|
|
from django.shortcuts import render
|
2015-01-29 17:03:17 +00:00
|
|
|
from django.template.loader import render_to_string
|
2014-12-19 15:27:43 +00:00
|
|
|
from django.views.decorators.http import require_http_methods
|
|
|
|
from django.views.generic import View
|
2015-07-13 20:34:43 +00:00
|
|
|
from hashlib import md5
|
|
|
|
from jwkest import long_to_base64
|
2015-03-04 19:24:41 +00:00
|
|
|
|
2015-02-18 18:07:22 +00:00
|
|
|
from oidc_provider.lib.endpoints.authorize import *
|
|
|
|
from oidc_provider.lib.endpoints.token import *
|
|
|
|
from oidc_provider.lib.endpoints.userinfo import *
|
2015-03-04 19:24:41 +00:00
|
|
|
from oidc_provider.lib.errors import *
|
2015-07-31 17:19:53 +00:00
|
|
|
from oidc_provider.lib.utils.common import get_issuer, get_rsa_key
|
2014-12-19 15:27:43 +00:00
|
|
|
|
|
|
|
|
2015-06-19 20:46:00 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2014-12-19 15:27:43 +00:00
|
|
|
class AuthorizeView(View):
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
|
|
|
|
authorize = AuthorizeEndpoint(request)
|
|
|
|
|
|
|
|
try:
|
|
|
|
authorize.validate_params()
|
|
|
|
|
|
|
|
if request.user.is_authenticated():
|
2015-03-19 17:04:32 +00:00
|
|
|
# Check if there's a hook setted.
|
|
|
|
hook_resp = settings.get('OIDC_AFTER_USERLOGIN_HOOK')(
|
|
|
|
request=request, user=request.user,
|
|
|
|
client=authorize.client)
|
|
|
|
if hook_resp:
|
|
|
|
return hook_resp
|
2015-01-12 22:13:48 +00:00
|
|
|
|
2015-06-24 15:40:00 +00:00
|
|
|
if settings.get('OIDC_SKIP_CONSENT_ENABLE'):
|
2015-06-22 21:42:42 +00:00
|
|
|
# Check if user previously give consent.
|
|
|
|
if authorize.client_has_user_consent():
|
|
|
|
uri = authorize.create_response_uri()
|
|
|
|
return HttpResponseRedirect(uri)
|
|
|
|
|
2015-01-29 17:03:17 +00:00
|
|
|
# Generate hidden inputs for the form.
|
2015-01-19 18:25:16 +00:00
|
|
|
context = {
|
2014-12-19 15:27:43 +00:00
|
|
|
'params': authorize.params,
|
2015-01-29 17:03:17 +00:00
|
|
|
}
|
|
|
|
hidden_inputs = render_to_string(
|
2015-02-18 18:07:22 +00:00
|
|
|
'oidc_provider/hidden_inputs.html', context)
|
2015-01-29 17:03:17 +00:00
|
|
|
|
2015-03-19 17:04:32 +00:00
|
|
|
# Remove `openid` from scope list
|
|
|
|
# since we don't need to print it.
|
2015-01-29 17:03:17 +00:00
|
|
|
authorize.params.scope.remove('openid')
|
|
|
|
|
|
|
|
context = {
|
2014-12-19 15:27:43 +00:00
|
|
|
'client': authorize.client,
|
2015-01-29 17:03:17 +00:00
|
|
|
'hidden_inputs': hidden_inputs,
|
|
|
|
'params': authorize.params,
|
2014-12-19 15:27:43 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 18:07:22 +00:00
|
|
|
return render(request, 'oidc_provider/authorize.html', context)
|
2014-12-19 15:27:43 +00:00
|
|
|
else:
|
2015-01-19 18:25:16 +00:00
|
|
|
path = request.get_full_path()
|
2015-02-09 20:36:29 +00:00
|
|
|
return redirect_to_login(path)
|
2014-12-19 15:27:43 +00:00
|
|
|
|
|
|
|
except (ClientIdError, RedirectUriError) as error:
|
2015-01-19 18:25:16 +00:00
|
|
|
context = {
|
2015-01-09 17:59:23 +00:00
|
|
|
'error': error.error,
|
|
|
|
'description': error.description,
|
|
|
|
}
|
|
|
|
|
2015-02-18 18:07:22 +00:00
|
|
|
return render(request, 'oidc_provider/error.html', context)
|
2014-12-19 15:27:43 +00:00
|
|
|
|
|
|
|
except (AuthorizeError) as error:
|
2015-01-12 22:13:48 +00:00
|
|
|
uri = error.create_uri(
|
|
|
|
authorize.params.redirect_uri,
|
|
|
|
authorize.params.state)
|
2014-12-19 15:27:43 +00:00
|
|
|
|
|
|
|
return HttpResponseRedirect(uri)
|
|
|
|
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
|
|
|
|
|
|
authorize = AuthorizeEndpoint(request)
|
|
|
|
|
|
|
|
allow = True if request.POST.get('allow') else False
|
|
|
|
|
2015-06-15 19:04:44 +00:00
|
|
|
try:
|
2015-06-15 20:34:36 +00:00
|
|
|
authorize.validate_params()
|
|
|
|
|
2015-06-15 19:04:44 +00:00
|
|
|
if not allow:
|
|
|
|
raise AuthorizeError(authorize.params.redirect_uri,
|
|
|
|
'access_denied',
|
|
|
|
authorize.grant_type)
|
|
|
|
|
2015-06-22 21:42:42 +00:00
|
|
|
# Save the user consent given to the client.
|
|
|
|
authorize.set_client_user_consent()
|
2014-12-19 15:27:43 +00:00
|
|
|
|
2015-06-22 21:42:42 +00:00
|
|
|
uri = authorize.create_response_uri()
|
2014-12-19 15:27:43 +00:00
|
|
|
return HttpResponseRedirect(uri)
|
|
|
|
|
|
|
|
except (AuthorizeError) as error:
|
2015-01-30 20:20:36 +00:00
|
|
|
uri = error.create_uri(
|
|
|
|
authorize.params.redirect_uri,
|
|
|
|
authorize.params.state)
|
2014-12-19 15:27:43 +00:00
|
|
|
|
|
|
|
return HttpResponseRedirect(uri)
|
|
|
|
|
2015-03-04 19:24:41 +00:00
|
|
|
|
2014-12-19 15:27:43 +00:00
|
|
|
class TokenView(View):
|
|
|
|
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
|
|
|
|
|
|
token = TokenEndpoint(request)
|
|
|
|
|
|
|
|
try:
|
|
|
|
token.validate_params()
|
|
|
|
|
|
|
|
dic = token.create_response_dic()
|
|
|
|
|
|
|
|
return TokenEndpoint.response(dic)
|
|
|
|
|
|
|
|
except (TokenError) as error:
|
|
|
|
return TokenEndpoint.response(error.create_dict(), status=400)
|
|
|
|
|
2015-03-04 19:24:41 +00:00
|
|
|
|
2014-12-19 15:27:43 +00:00
|
|
|
@require_http_methods(['GET', 'POST'])
|
|
|
|
def userinfo(request):
|
|
|
|
|
|
|
|
userinfo = UserInfoEndpoint(request)
|
|
|
|
|
|
|
|
try:
|
|
|
|
userinfo.validate_params()
|
|
|
|
|
|
|
|
dic = userinfo.create_response_dic()
|
|
|
|
|
|
|
|
return UserInfoEndpoint.response(dic)
|
|
|
|
|
|
|
|
except (UserInfoError) as error:
|
|
|
|
return UserInfoEndpoint.error_response(
|
|
|
|
error.code,
|
|
|
|
error.description,
|
2015-01-28 18:19:36 +00:00
|
|
|
error.status)
|
2015-03-04 19:24:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ProviderInfoView(View):
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
2015-07-31 17:19:53 +00:00
|
|
|
dic = dict()
|
2015-03-04 19:24:41 +00:00
|
|
|
|
2015-07-31 17:19:53 +00:00
|
|
|
dic['issuer'] = get_issuer()
|
|
|
|
|
|
|
|
SITE_URL = settings.get('SITE_URL')
|
|
|
|
|
|
|
|
dic['authorization_endpoint'] = SITE_URL + reverse('oidc_provider:authorize')
|
|
|
|
dic['token_endpoint'] = SITE_URL + reverse('oidc_provider:token')
|
|
|
|
dic['userinfo_endpoint'] = SITE_URL + reverse('oidc_provider:userinfo')
|
|
|
|
dic['end_session_endpoint'] = SITE_URL + reverse('oidc_provider:logout')
|
|
|
|
|
|
|
|
from oidc_provider.models import Client
|
|
|
|
types_supported = [x[0] for x in Client.RESPONSE_TYPE_CHOICES]
|
|
|
|
dic['response_types_supported'] = types_supported
|
|
|
|
|
|
|
|
dic['jwks_uri'] = SITE_URL + reverse('oidc_provider:jwks')
|
|
|
|
|
|
|
|
dic['id_token_signing_alg_values_supported'] = ['RS256']
|
|
|
|
|
|
|
|
# See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
|
|
|
dic['subject_types_supported'] = ['public']
|
2015-03-04 19:24:41 +00:00
|
|
|
|
2015-07-31 17:59:33 +00:00
|
|
|
dic['token_endpoint_auth_methods_supported'] = [ 'client_secret_post',
|
|
|
|
'client_secret_basic' ]
|
|
|
|
|
2015-06-19 20:46:00 +00:00
|
|
|
return JsonResponse(dic)
|
2015-07-13 20:34:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
class JwksView(View):
|
|
|
|
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
dic = dict(keys=[])
|
|
|
|
|
2015-07-23 19:07:55 +00:00
|
|
|
key = get_rsa_key().encode('utf-8')
|
2015-07-13 20:34:43 +00:00
|
|
|
public_key = RSA.importKey(key).publickey()
|
|
|
|
|
|
|
|
dic['keys'].append({
|
|
|
|
'kty': 'RSA',
|
|
|
|
'alg': 'RS256',
|
|
|
|
'use': 'sig',
|
|
|
|
'kid': md5(key).hexdigest(),
|
2015-07-23 19:17:28 +00:00
|
|
|
'n': long_to_base64(public_key.n).decode('utf-8'),
|
|
|
|
'e': long_to_base64(public_key.e).decode('utf-8'),
|
2015-07-13 20:34:43 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return JsonResponse(dic)
|
2015-07-24 09:36:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
class LogoutView(View):
|
2015-07-31 17:19:53 +00:00
|
|
|
|
2015-07-24 09:36:45 +00:00
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
# We should actually verify if the requested redirect URI is safe
|
|
|
|
return logout(request, next_page=request.GET.get('post_logout_redirect_uri'))
|