From 42fa36551b7b2c43366ad262f95edecf05ab3a58 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 6 Mar 2014 15:57:27 +0100 Subject: [PATCH] first commit --- README.txt | 18 +++++++++ authentic2_idp_oauth2/__init__.py | 7 ++++ authentic2_idp_oauth2/app_settings.py | 24 ++++++++++++ authentic2_idp_oauth2/forms.py | 11 ++++++ authentic2_idp_oauth2/models.py | 0 .../templates/rest_framework/api.html | 1 + authentic2_idp_oauth2/urls.py | 12 ++++++ authentic2_idp_oauth2/views.py | 39 +++++++++++++++++++ setup.py | 21 ++++++++++ 9 files changed, 133 insertions(+) create mode 100644 README.txt create mode 100644 authentic2_idp_oauth2/__init__.py create mode 100644 authentic2_idp_oauth2/app_settings.py create mode 100644 authentic2_idp_oauth2/forms.py create mode 100644 authentic2_idp_oauth2/models.py create mode 100644 authentic2_idp_oauth2/templates/rest_framework/api.html create mode 100644 authentic2_idp_oauth2/urls.py create mode 100644 authentic2_idp_oauth2/views.py create mode 100755 setup.py diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..832025b --- /dev/null +++ b/README.txt @@ -0,0 +1,18 @@ +Install +======= + +You just have to install the package in your virtualenv and relaunch, it will +be automatically loaded by the plugin framework. + + +Settings +======== + +AUTOMATIC_GRANT: + + A list of URL prefix which are automatically granted scopes without asking + the user. Example:: + + A2_OAUTH2_AUTOMATIC_GRANT = ( + ('http://localhost:8000/', ('read',)), + ) diff --git a/authentic2_idp_oauth2/__init__.py b/authentic2_idp_oauth2/__init__.py new file mode 100644 index 0000000..5713c12 --- /dev/null +++ b/authentic2_idp_oauth2/__init__.py @@ -0,0 +1,7 @@ +class Plugin(object): + def get_before_urls(self): + from . import urls + return urls.urlpatterns + + def get_apps(self): + return [__name__, 'rest_framework', 'provider', 'provider.oauth2'] diff --git a/authentic2_idp_oauth2/app_settings.py b/authentic2_idp_oauth2/app_settings.py new file mode 100644 index 0000000..29819a6 --- /dev/null +++ b/authentic2_idp_oauth2/app_settings.py @@ -0,0 +1,24 @@ +class AppSettings(object): + + def __init__(self, prefix): + self.prefix = prefix + + @property + def AUTOMATIC_GRANT(self): + return self._setting('AUTOMATIC_GRANT', ()) + + def _setting(self, name, dflt): + from django.conf import settings + getter = getattr(settings, + 'ALLAUTH_SETTING_GETTER', + lambda name, dflt: getattr(settings, name, dflt)) + return getter(self.prefix + name, dflt) + + + +# Ugly? Guido recommends this himself ... +# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html +import sys +app_settings = AppSettings('A2_OAUTH2_') +app_settings.__name__ = __name__ +sys.modules[__name__] = app_settings diff --git a/authentic2_idp_oauth2/forms.py b/authentic2_idp_oauth2/forms.py new file mode 100644 index 0000000..10366fb --- /dev/null +++ b/authentic2_idp_oauth2/forms.py @@ -0,0 +1,11 @@ +from django.forms import Form + +from provider.oauth2.models import Grant + +class EmptyForm(Form): + def __init__(self, *args, **kwargs): + self.scope = kwargs.pop('scope') + super(EmptyForm, self).__init__(*args, **kwargs) + + def save(self, **kwargs): + return Grant(scope=self.scope) diff --git a/authentic2_idp_oauth2/models.py b/authentic2_idp_oauth2/models.py new file mode 100644 index 0000000..e69de29 diff --git a/authentic2_idp_oauth2/templates/rest_framework/api.html b/authentic2_idp_oauth2/templates/rest_framework/api.html new file mode 100644 index 0000000..9c44916 --- /dev/null +++ b/authentic2_idp_oauth2/templates/rest_framework/api.html @@ -0,0 +1 @@ +{% extends "rest_framework/base.html" %} diff --git a/authentic2_idp_oauth2/urls.py b/authentic2_idp_oauth2/urls.py new file mode 100644 index 0000000..c257d8e --- /dev/null +++ b/authentic2_idp_oauth2/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import patterns, url, include +from django.contrib.auth.decorators import login_required + +from .views import Authorize + +urlpatterns = patterns('authentic2_idp_oauth2.views', + url('^idp/oauth2/authorize/confirm/?$', + login_required(Authorize.as_view()), name='authorize'), + url('^idp/oauth2/', include('provider.oauth2.urls', namespace='oauth2')), + url('^idp/oauth2/federation/$', 'user_info', name='user-info'), + url('^idp/oauth2/user-info/$', 'user_info', name='user-info'), +) diff --git a/authentic2_idp_oauth2/views.py b/authentic2_idp_oauth2/views.py new file mode 100644 index 0000000..8ee9c41 --- /dev/null +++ b/authentic2_idp_oauth2/views.py @@ -0,0 +1,39 @@ +from django.conf import settings + +from rest_framework.decorators import (api_view, authentication_classes, + permission_classes) +from rest_framework.authentication import (OAuth2Authentication, + SessionAuthentication) +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response + +from provider.oauth2.views import Authorize +from provider import scope + +from . import forms, app_settings + +@api_view(['GET']) +@authentication_classes([OAuth2Authentication, SessionAuthentication]) +@permission_classes([IsAuthenticated]) +def user_info(request): + user = request.user + return Response({ + 'username': user.username, + 'first_name': user.first_name, + 'last_name': user.last_name, + 'email': user.email, + 'display_name': user.get_full_name(), + 'role': user.groups.values_list('name', flat=True), + }) + +class Authorize(Authorize): + def get_authorization_form(self, request, client, data, client_data): + for url_prefix, scopes in app_settings.AUTOMATIC_GRANT: + if client.url.startswith(url_prefix) and \ + scope.check(client_data['scope'], scope.to_int(*scopes)): + # return an always valid form + return forms.EmptyForm({}, scope=client_data['scope']) + return super(Authorize, self).get_authorization_form( + request, client, data, client_data) + + diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..337557c --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from setuptools import setup, find_packages +import os + +setup(name='authentic2-idp-oauth2', + version='1.0', + license='AGPLv3', + description='Authentic2 IdP OAuth2', + author="Entr'ouvert", + author_email="info@entrouvert.com", + packages=find_packages(os.path.dirname(__file__) or '.'), + install_requires=[ + 'django-oauth2-provider', + 'djangorestframework', + ], + entry_points={ + 'authentic2.plugin': [ + 'authentic-idp-oauth2 = authentic2_idp_oauth2:Plugin', + ], + }, +)