* Move all Django code into contrib.django_util. * Add DjangORMStorage. This is backwards compatible with old django_orm storage. * Add new functionality to decorators and views that integrate with Django ORM-based storage. * Fix issue where Django storage always creates new Models. * Move tests into Django package and have them create an actual test app to create test databases etc. * Remove FlowField.
146 lines
5.4 KiB
Python
146 lines
5.4 KiB
Python
# Copyright 2015 Google Inc. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Decorators for Django OAuth2 Flow.
|
|
|
|
Contains two decorators, ``oauth_required`` and ``oauth_enabled``.
|
|
|
|
``oauth_required`` will ensure that a user has an oauth object containing
|
|
credentials associated with the request, and if not, redirect to the
|
|
authorization flow.
|
|
|
|
``oauth_enabled`` will attach the oauth2 object containing credentials if it
|
|
exists. If it doesn't, the view will still render, but helper methods will be
|
|
attached to start the oauth2 flow.
|
|
"""
|
|
|
|
from django import shortcuts
|
|
import django.conf
|
|
from six import wraps
|
|
from six.moves.urllib import parse
|
|
|
|
from oauth2client.contrib import django_util
|
|
|
|
|
|
def oauth_required(decorated_function=None, scopes=None, **decorator_kwargs):
|
|
""" Decorator to require OAuth2 credentials for a view.
|
|
|
|
|
|
.. code-block:: python
|
|
:caption: views.py
|
|
:name: views_required_2
|
|
|
|
|
|
from oauth2client.django_util.decorators import oauth_required
|
|
|
|
@oauth_required
|
|
def requires_default_scopes(request):
|
|
email = request.credentials.id_token['email']
|
|
service = build(serviceName='calendar', version='v3',
|
|
http=request.oauth.http,
|
|
developerKey=API_KEY)
|
|
events = service.events().list(
|
|
calendarId='primary').execute()['items']
|
|
return HttpResponse(
|
|
"email: {0}, calendar: {1}".format(email, str(events)))
|
|
|
|
Args:
|
|
decorated_function: View function to decorate, must have the Django
|
|
request object as the first argument.
|
|
scopes: Scopes to require, will default.
|
|
decorator_kwargs: Can include ``return_url`` to specify the URL to
|
|
return to after OAuth2 authorization is complete.
|
|
|
|
Returns:
|
|
An OAuth2 Authorize view if credentials are not found or if the
|
|
credentials are missing the required scopes. Otherwise,
|
|
the decorated view.
|
|
"""
|
|
def curry_wrapper(wrapped_function):
|
|
@wraps(wrapped_function)
|
|
def required_wrapper(request, *args, **kwargs):
|
|
if not (django_util.oauth2_settings.storage_model is None or
|
|
request.user.is_authenticated()):
|
|
redirect_str = '{0}?next={1}'.format(
|
|
django.conf.settings.LOGIN_URL,
|
|
parse.quote(request.path))
|
|
return shortcuts.redirect(redirect_str)
|
|
|
|
return_url = decorator_kwargs.pop('return_url',
|
|
request.get_full_path())
|
|
user_oauth = django_util.UserOAuth2(request, scopes, return_url)
|
|
if not user_oauth.has_credentials():
|
|
return shortcuts.redirect(user_oauth.get_authorize_redirect())
|
|
setattr(request, django_util.oauth2_settings.request_prefix,
|
|
user_oauth)
|
|
return wrapped_function(request, *args, **kwargs)
|
|
|
|
return required_wrapper
|
|
|
|
if decorated_function:
|
|
return curry_wrapper(decorated_function)
|
|
else:
|
|
return curry_wrapper
|
|
|
|
|
|
def oauth_enabled(decorated_function=None, scopes=None, **decorator_kwargs):
|
|
""" Decorator to enable OAuth Credentials if authorized, and setup
|
|
the oauth object on the request object to provide helper functions
|
|
to start the flow otherwise.
|
|
|
|
.. code-block:: python
|
|
:caption: views.py
|
|
:name: views_enabled3
|
|
|
|
from oauth2client.django_util.decorators import oauth_enabled
|
|
|
|
@oauth_enabled
|
|
def optional_oauth2(request):
|
|
if request.oauth.has_credentials():
|
|
# this could be passed into a view
|
|
# request.oauth.http is also initialized
|
|
return HttpResponse("User email: {0}".format(
|
|
request.oauth.credentials.id_token['email'])
|
|
else:
|
|
return HttpResponse('Here is an OAuth Authorize link:
|
|
<a href="{0}">Authorize</a>'.format(
|
|
request.oauth.get_authorize_redirect()))
|
|
|
|
|
|
Args:
|
|
decorated_function: View function to decorate.
|
|
scopes: Scopes to require, will default.
|
|
decorator_kwargs: Can include ``return_url`` to specify the URL to
|
|
return to after OAuth2 authorization is complete.
|
|
|
|
Returns:
|
|
The decorated view function.
|
|
"""
|
|
def curry_wrapper(wrapped_function):
|
|
@wraps(wrapped_function)
|
|
def enabled_wrapper(request, *args, **kwargs):
|
|
return_url = decorator_kwargs.pop('return_url',
|
|
request.get_full_path())
|
|
user_oauth = django_util.UserOAuth2(request, scopes, return_url)
|
|
setattr(request, django_util.oauth2_settings.request_prefix,
|
|
user_oauth)
|
|
return wrapped_function(request, *args, **kwargs)
|
|
|
|
return enabled_wrapper
|
|
|
|
if decorated_function:
|
|
return curry_wrapper(decorated_function)
|
|
else:
|
|
return curry_wrapper
|