/
views.py
111 lines (96 loc) · 4.2 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from __future__ import absolute_import
from django.core.urlresolvers import reverse
from allauth.socialaccount.helpers import render_authentication_error
from allauth.socialaccount.providers.oauth.client import (OAuthClient,
OAuthError)
from allauth.socialaccount.helpers import complete_social_login
from allauth.socialaccount import providers
from allauth.socialaccount.models import SocialToken, SocialLogin
from ..base import AuthAction, AuthError
class OAuthAdapter(object):
def __init__(self, request):
self.request = request
def complete_login(self, request, app):
"""
Returns a SocialLogin instance
"""
raise NotImplementedError
def get_provider(self):
return providers.registry.by_id(self.provider_id)
class OAuthView(object):
@classmethod
def adapter_view(cls, adapter):
def view(request, *args, **kwargs):
self = cls()
self.request = request
self.adapter = adapter(request)
return self.dispatch(request, *args, **kwargs)
return view
def _get_client(self, request, callback_url):
provider = self.adapter.get_provider()
app = provider.get_app(request)
scope = ' '.join(provider.get_scope(request))
parameters = {}
if scope:
parameters['scope'] = scope
client = OAuthClient(request, app.client_id, app.secret,
self.adapter.request_token_url,
self.adapter.access_token_url,
callback_url,
parameters=parameters, provider=provider)
return client
class OAuthLoginView(OAuthView):
def dispatch(self, request):
callback_url = reverse(self.adapter.provider_id + "_callback")
SocialLogin.stash_state(request)
action = request.GET.get('action', AuthAction.AUTHENTICATE)
provider = self.adapter.get_provider()
auth_url = provider.get_auth_url(request,
action) or self.adapter.authorize_url
auth_params = provider.get_auth_params(request, action)
client = self._get_client(request, callback_url)
try:
return client.get_redirect(auth_url, auth_params)
except OAuthError as e:
return render_authentication_error(request,
self.adapter.provider_id,
exception=e)
class OAuthCallbackView(OAuthView):
def dispatch(self, request):
"""
View to handle final steps of OAuth based authentication where the user
gets redirected back to from the service provider
"""
login_done_url = reverse(self.adapter.provider_id + "_callback")
client = self._get_client(request, login_done_url)
if not client.is_valid():
if 'denied' in request.GET:
error = AuthError.CANCELLED
else:
error = AuthError.UNKNOWN
extra_context = dict(oauth_client=client)
return render_authentication_error(
request,
self.adapter.provider_id,
error=error,
extra_context=extra_context)
app = self.adapter.get_provider().get_app(request)
try:
access_token = client.get_access_token()
token = SocialToken(
app=app,
token=access_token['oauth_token'],
# .get() -- e.g. Evernote does not feature a secret
token_secret=access_token.get('oauth_token_secret', ''))
login = self.adapter.complete_login(request,
app,
token,
response=access_token)
login.token = token
login.state = SocialLogin.unstash_state(request)
return complete_social_login(request, login)
except OAuthError as e:
return render_authentication_error(
request,
self.adapter.provider_id,
exception=e)