Ajout type contrat
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import datetime
|
||||
from urllib.parse import urlparse, urlencode, urlunparse
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.options import ModelAdmin
|
||||
from django.http import (HttpResponseForbidden, HttpResponseBadRequest, HttpResponseRedirect, QueryDict)
|
||||
from django.urls import re_path
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.views.generic.base import View
|
||||
from itsdangerous import URLSafeTimedSerializer
|
||||
|
||||
from simple_sso.sso_server.models import Token, Consumer
|
||||
from simple_sso.utils import BaseProvider, provider_wrapper
|
||||
|
||||
|
||||
class Provider(BaseProvider):
|
||||
max_age = 5
|
||||
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
|
||||
def get_private_key(self, public_key):
|
||||
try:
|
||||
self.consumer = Consumer.objects.get(public_key=public_key)
|
||||
except Consumer.DoesNotExist:
|
||||
return None
|
||||
return self.consumer.private_key
|
||||
|
||||
|
||||
class RequestTokenProvider(Provider):
|
||||
def provide(self, data):
|
||||
redirect_to = data['redirect_to']
|
||||
token = Token.objects.create(consumer=self.consumer, redirect_to=redirect_to)
|
||||
return {'request_token': token.request_token}
|
||||
|
||||
|
||||
class AuthorizeView(View):
|
||||
"""
|
||||
The client get's redirected to this view with the `request_token` obtained
|
||||
by the Request Token Request by the client application beforehand.
|
||||
|
||||
This view checks if the user is logged in on the server application and if
|
||||
that user has the necessary rights.
|
||||
|
||||
If the user is not logged in, the user is prompted to log in.
|
||||
"""
|
||||
server = None
|
||||
|
||||
def get(self, request):
|
||||
request_token = request.GET.get('token', None)
|
||||
if not request_token:
|
||||
return self.missing_token_argument()
|
||||
try:
|
||||
self.token = Token.objects.select_related('consumer').get(request_token=request_token)
|
||||
except Token.DoesNotExist:
|
||||
return self.token_not_found()
|
||||
if not self.check_token_timeout():
|
||||
return self.token_timeout()
|
||||
self.token.refresh()
|
||||
if request.user.is_authenticated:
|
||||
return self.handle_authenticated_user()
|
||||
else:
|
||||
return self.handle_unauthenticated_user()
|
||||
|
||||
def missing_token_argument(self):
|
||||
return HttpResponseBadRequest('Token missing')
|
||||
|
||||
def token_not_found(self):
|
||||
return HttpResponseForbidden('Token not found')
|
||||
|
||||
def token_timeout(self):
|
||||
return HttpResponseForbidden('Token timed out')
|
||||
|
||||
def check_token_timeout(self):
|
||||
delta = timezone.now() - self.token.timestamp
|
||||
if delta > self.server.token_timeout:
|
||||
self.token.delete()
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def handle_authenticated_user(self):
|
||||
if self.server.has_access(self.request.user, self.token.consumer):
|
||||
return self.success()
|
||||
else:
|
||||
return self.access_denied()
|
||||
|
||||
def handle_unauthenticated_user(self):
|
||||
next_ = '%s?%s' % (self.request.path, urlencode([('token', self.token.request_token)]))
|
||||
url = '%s?%s' % (reverse(self.server.auth_view_name), urlencode([('next', next_)]))
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
def access_denied(self):
|
||||
return HttpResponseForbidden("Access denied")
|
||||
|
||||
def success(self):
|
||||
self.token.user = self.request.user
|
||||
self.token.save()
|
||||
serializer = URLSafeTimedSerializer(self.token.consumer.private_key)
|
||||
parse_result = urlparse(self.token.redirect_to)
|
||||
query_dict = QueryDict(parse_result.query, mutable=True)
|
||||
query_dict['access_token'] = serializer.dumps(self.token.access_token)
|
||||
url = urlunparse((parse_result.scheme, parse_result.netloc, parse_result.path, '', query_dict.urlencode(), ''))
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
class VerificationProvider(Provider, AuthorizeView):
|
||||
def provide(self, data):
|
||||
token = data['access_token']
|
||||
try:
|
||||
self.token = Token.objects.select_related('user').get(access_token=token, consumer=self.consumer)
|
||||
except Token.DoesNotExist:
|
||||
return self.token_not_found()
|
||||
if not self.check_token_timeout():
|
||||
return self.token_timeout()
|
||||
if not self.token.user:
|
||||
return self.token_not_bound()
|
||||
extra_data = data.get('extra_data', None)
|
||||
return self.server.get_user_data(
|
||||
self.token.user, self.consumer, extra_data=extra_data)
|
||||
|
||||
def token_not_bound(self):
|
||||
return HttpResponseForbidden("Invalid token")
|
||||
|
||||
|
||||
class ConsumerAdmin(ModelAdmin):
|
||||
readonly_fields = ['public_key', 'private_key']
|
||||
|
||||
|
||||
class Server:
|
||||
request_token_provider = RequestTokenProvider
|
||||
authorize_view = AuthorizeView
|
||||
verification_provider = VerificationProvider
|
||||
token_timeout = datetime.timedelta(minutes=5)
|
||||
client_admin = ConsumerAdmin
|
||||
auth_view_name = 'login'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
self.register_admin()
|
||||
|
||||
def register_admin(self):
|
||||
admin.site.register(Consumer, self.client_admin)
|
||||
|
||||
def has_access(self, user, consumer):
|
||||
return True
|
||||
|
||||
def get_user_extra_data(self, user, consumer, extra_data):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_user_data(self, user, consumer, extra_data=None):
|
||||
user_data = {
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
'first_name': user.first_name,
|
||||
'last_name': user.last_name,
|
||||
'is_staff': False,
|
||||
'is_superuser': False,
|
||||
'is_active': user.is_active,
|
||||
}
|
||||
if extra_data:
|
||||
user_data['extra_data'] = self.get_user_extra_data(
|
||||
user, consumer, extra_data)
|
||||
return user_data
|
||||
|
||||
def get_urls(self):
|
||||
return [
|
||||
re_path(r'^request-token/$', provider_wrapper(self.request_token_provider(server=self)),
|
||||
name='simple-sso-request-token'),
|
||||
re_path(r'^authorize/$', self.authorize_view.as_view(server=self), name='simple-sso-authorize'),
|
||||
re_path(r'^verify/$', provider_wrapper(
|
||||
self.verification_provider(server=self)), name='simple-sso-verify'),
|
||||
]
|
||||
Reference in New Issue
Block a user