From 7b00c4d7b0eeedceb30f67ad569569a7969c4da9 Mon Sep 17 00:00:00 2001 From: mthompson Date: Tue, 7 May 2013 21:00:54 +0000 Subject: [PATCH] Added a new extension for oauth2 providers that integrates with flask. Modified the existing scopes argument for django provider so that it now will accept a function as well as a list object. This is done so that scopes can be dynamically set. --- AUTHORS | 1 + oauthlib/oauth2/ext/flask.py | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 oauthlib/oauth2/ext/flask.py diff --git a/AUTHORS b/AUTHORS index 6762ccbe..bb2f38a2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,3 +13,4 @@ Silas Snider Tom Christie Chez Ondrej Slinták +Mackenzie Thompson diff --git a/oauthlib/oauth2/ext/flask.py b/oauthlib/oauth2/ext/flask.py new file mode 100644 index 00000000..fef19202 --- /dev/null +++ b/oauthlib/oauth2/ext/flask.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, absolute_import +from flask import abort, g, make_response, redirect, request, session +import functools +import logging +from oauthlib.common import urlencode +from oauthlib.oauth2.draft25 import errors + +log = logging.getLogger('oauthlib') + + +class OAuth2ProviderDecorator(object): + + def __init__(self, error_uri, server=None, authorization_endpoint=None, + token_endpoint=None, resource_endpoint=None): + self._authorization_endpoint = authorization_endpoint or server + self._token_endpoint = token_endpoint or server + self._resource_endpoint = resource_endpoint or server + self._error_uri = error_uri + + def _extract_params(self): + log.debug('Extracting parameters from request.') + uri = request.url + http_method = request.method + headers = dict(request.headers) + if 'wsgi.input' in headers: + del headers['wsgi.input'] + if 'wsgi.errors' in headers: + del headers['wsgi.errors'] + if 'HTTP_AUTHORIZATION' in headers: + headers['Authorization'] = headers['HTTP_AUTHORIZATION'] + body = urlencode(request.form.items()) + return uri, http_method, body, headers + + def pre_authorization_view(self, f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + uri, http_method, body, headers = self._extract_params() + redirect_uri = request.args.get('redirect_uri', None) + log.debug('Found redirect uri %s.', redirect_uri) + try: + scopes, credentials = self._authorization_endpoint.validate_authorization_request( + uri, http_method, body, headers) + log.debug('Saving credentials to session, %r.', credentials) + session['oauth2_credentials'] = credentials + kwargs['scopes'] = scopes + kwargs.update(credentials) + log.debug('Invoking view method, %r.', f) + return f(*args, **kwargs) + + except errors.FatalClientError as e: + log.debug('Fatal client error, redirecting to error page.') + return redirect(e.in_uri(self._error_uri)) + return wrapper + + def post_authorization_view(self, f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + uri, http_method, body, headers = self._extract_params() + scopes, credentials = f(*args, **kwargs) + log.debug('Fetched credentials view, %r.', credentials) + credentials.update(request.session.get('oauth2_credentials', {})) + log.debug('Fetched credentials from session, %r.', credentials) + redirect_uri = credentials.get('redirect_uri') + log.debug('Found redirect uri %s.', redirect_uri) + try: + url, headers, body, status = self._authorization_endpoint.create_authorization_response( + uri, http_method, body, headers, scopes, credentials) + log.debug('Authorization successful, redirecting to client.') + return redirect(url) + except errors.FatalClientError as e: + log.debug('Fatal client error, redirecting to error page.') + return redirect(e.in_uri(self._error_uri)) + except errors.OAuth2Error as e: + log.debug('Client error, redirecting back to client.') + return redirect(e.in_uri(redirect_uri)) + + return wrapper + + def access_token_view(self, f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + uri, http_method, body, headers = self._extract_params() + credentials = f(*args, **kwargs) + log.debug('Fetched credentials view, %r.', credentials) + url, headers, body, status = self._token_endpoint.create_token_response( + uri, http_method, body, headers, credentials) + response = make_response(body, status) + for k, v in headers.items(): + response.headers[k] = v + return response + return wrapper + + def protected_resource_view(self, scopes=None, forbidden=None): + def decorator(f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + try: + scopes_list = scopes() + except TypeError: + scopes_list = scopes + uri, http_method, body, headers = self._extract_params() + valid, r = self._resource_endpoint.verify_request( + uri, http_method, body, headers, scopes_list) + g.client = r.client + g.user = r.user + g.scopes = r.scopes + g.token_scopes = r.token_scopes + if valid: + return f(*args, **kwargs) + elif forbidden is not None: + return forbidden() + else: + abort(401) + return wrapper + return decorator