Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views / target / google.py @ a3e3917f

History | View | Annotate | Download (6.4 kB)

1 74796dd8 Kostas Papadimitriou
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 74796dd8 Kostas Papadimitriou
#
3 74796dd8 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 74796dd8 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 74796dd8 Kostas Papadimitriou
# conditions are met:
6 74796dd8 Kostas Papadimitriou
#
7 74796dd8 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 74796dd8 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 74796dd8 Kostas Papadimitriou
#      disclaimer.
10 74796dd8 Kostas Papadimitriou
#
11 74796dd8 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 74796dd8 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 74796dd8 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 74796dd8 Kostas Papadimitriou
#      provided with the distribution.
15 74796dd8 Kostas Papadimitriou
#
16 74796dd8 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 74796dd8 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 74796dd8 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 74796dd8 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 74796dd8 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 74796dd8 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 74796dd8 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 74796dd8 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 74796dd8 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 74796dd8 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 74796dd8 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 74796dd8 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 74796dd8 Kostas Papadimitriou
#
29 74796dd8 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 74796dd8 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 74796dd8 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 74796dd8 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 74796dd8 Kostas Papadimitriou
34 74796dd8 Kostas Papadimitriou
import json
35 3c5a2b21 Kostas Papadimitriou
import logging
36 3c5a2b21 Kostas Papadimitriou
import urllib
37 3c5a2b21 Kostas Papadimitriou
import oauth2 as oauth
38 74796dd8 Kostas Papadimitriou
39 74796dd8 Kostas Papadimitriou
from django.utils.translation import ugettext as _
40 74796dd8 Kostas Papadimitriou
from django.contrib import messages
41 74796dd8 Kostas Papadimitriou
from django.views.decorators.http import require_http_methods
42 74796dd8 Kostas Papadimitriou
from django.http import HttpResponseRedirect
43 74796dd8 Kostas Papadimitriou
from django.core.urlresolvers import reverse
44 3c5a2b21 Kostas Papadimitriou
from django.conf import settings as django_settings
45 74796dd8 Kostas Papadimitriou
46 3e0a032d Sofia Papagiannaki
from astakos.im.models import AstakosUser
47 74796dd8 Kostas Papadimitriou
from astakos.im import settings
48 3e0a032d Sofia Papagiannaki
from astakos.im.views.target import get_pending_key, \
49 3c5a2b21 Kostas Papadimitriou
    handle_third_party_signup, handle_third_party_login, \
50 3c5a2b21 Kostas Papadimitriou
    init_third_party_session
51 3e0a032d Sofia Papagiannaki
from astakos.im.views.decorators import cookie_fix, requires_auth_provider
52 74796dd8 Kostas Papadimitriou
53 74796dd8 Kostas Papadimitriou
logger = logging.getLogger(__name__)
54 74796dd8 Kostas Papadimitriou
signature_method = oauth.SignatureMethod_HMAC_SHA1()
55 74796dd8 Kostas Papadimitriou
56 74796dd8 Kostas Papadimitriou
OAUTH_CONSUMER_KEY = settings.GOOGLE_CLIENT_ID
57 74796dd8 Kostas Papadimitriou
OAUTH_CONSUMER_SECRET = settings.GOOGLE_SECRET
58 74796dd8 Kostas Papadimitriou
59 3c5a2b21 Kostas Papadimitriou
60 3c5a2b21 Kostas Papadimitriou
def django_setting(key, default):
61 3c5a2b21 Kostas Papadimitriou
    return getattr(django_settings, 'GOOGLE_%s' % key.upper, default)
62 3c5a2b21 Kostas Papadimitriou
63 3c5a2b21 Kostas Papadimitriou
default_token_scopes = ['https://www.googleapis.com/auth/userinfo.profile',
64 3c5a2b21 Kostas Papadimitriou
                        'https://www.googleapis.com/auth/userinfo.email']
65 3c5a2b21 Kostas Papadimitriou
66 3c5a2b21 Kostas Papadimitriou
token_scope = django_setting('token_scope', ' '.join(default_token_scopes))
67 3c5a2b21 Kostas Papadimitriou
authenticate_url = django_setting(
68 3c5a2b21 Kostas Papadimitriou
    'authenticate_url',
69 3c5a2b21 Kostas Papadimitriou
    'https://accounts.google.com/o/oauth2/auth')
70 3c5a2b21 Kostas Papadimitriou
access_token_url = django_setting(
71 3c5a2b21 Kostas Papadimitriou
    'access_token_url',
72 3c5a2b21 Kostas Papadimitriou
    'https://www.googleapis.com/oauth2/v1/tokeninfo')
73 3c5a2b21 Kostas Papadimitriou
request_token_url = django_setting(
74 3c5a2b21 Kostas Papadimitriou
    'request_token_url',
75 3c5a2b21 Kostas Papadimitriou
    'https://accounts.google.com/o/oauth2/token')
76 74796dd8 Kostas Papadimitriou
77 74796dd8 Kostas Papadimitriou
78 74796dd8 Kostas Papadimitriou
def get_redirect_uri():
79 8c8e318d Kostas Papadimitriou
    return "%s%s" % (settings.BASE_HOST,
80 70e11eaa Sofia Papagiannaki
                     reverse('astakos.im.views.target.google.authenticated'))
81 9d20fe23 Kostas Papadimitriou
82 74796dd8 Kostas Papadimitriou
83 9d20fe23 Kostas Papadimitriou
@requires_auth_provider('google')
84 74796dd8 Kostas Papadimitriou
@require_http_methods(["GET", "POST"])
85 74796dd8 Kostas Papadimitriou
def login(request):
86 0e79735c Kostas Papadimitriou
    init_third_party_session(request)
87 74796dd8 Kostas Papadimitriou
    params = {
88 74796dd8 Kostas Papadimitriou
        'scope': token_scope,
89 74796dd8 Kostas Papadimitriou
        'response_type': 'code',
90 74796dd8 Kostas Papadimitriou
        'redirect_uri': get_redirect_uri(),
91 74796dd8 Kostas Papadimitriou
        'client_id': settings.GOOGLE_CLIENT_ID
92 74796dd8 Kostas Papadimitriou
    }
93 9d20fe23 Kostas Papadimitriou
    force_login = request.GET.get('force_login', request.GET.get('from_login',
94 9d20fe23 Kostas Papadimitriou
                                                                 True))
95 e339bd10 Kostas Papadimitriou
    if force_login:
96 e339bd10 Kostas Papadimitriou
        params['approval_prompt'] = 'force'
97 e339bd10 Kostas Papadimitriou
98 dd5f8f4d Kostas Papadimitriou
    if request.GET.get('key', None):
99 dd5f8f4d Kostas Papadimitriou
        request.session['pending_key'] = request.GET.get('key')
100 dd5f8f4d Kostas Papadimitriou
101 64492c49 Kostas Papadimitriou
    if request.GET.get('next', None):
102 64492c49 Kostas Papadimitriou
        request.session['next_url'] = request.GET.get('next')
103 64492c49 Kostas Papadimitriou
104 74796dd8 Kostas Papadimitriou
    url = "%s?%s" % (authenticate_url, urllib.urlencode(params))
105 74796dd8 Kostas Papadimitriou
    return HttpResponseRedirect(url)
106 74796dd8 Kostas Papadimitriou
107 74796dd8 Kostas Papadimitriou
108 9d20fe23 Kostas Papadimitriou
@requires_auth_provider('google')
109 74796dd8 Kostas Papadimitriou
@require_http_methods(["GET", "POST"])
110 222305b7 Sofia Papagiannaki
@cookie_fix
111 74796dd8 Kostas Papadimitriou
def authenticated(
112 74796dd8 Kostas Papadimitriou
    request,
113 74796dd8 Kostas Papadimitriou
    template='im/third_party_check_local.html',
114 7beef200 Kostas Papadimitriou
    extra_context=None
115 74796dd8 Kostas Papadimitriou
):
116 74796dd8 Kostas Papadimitriou
117 7beef200 Kostas Papadimitriou
    if extra_context is None:
118 7beef200 Kostas Papadimitriou
        extra_context = {}
119 7beef200 Kostas Papadimitriou
120 e339bd10 Kostas Papadimitriou
    if request.GET.get('error', None):
121 e339bd10 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
122 e339bd10 Kostas Papadimitriou
123 74796dd8 Kostas Papadimitriou
    # TODO: Handle errors, e.g. error=access_denied
124 74796dd8 Kostas Papadimitriou
    try:
125 9d20fe23 Kostas Papadimitriou
        consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
126 9d20fe23 Kostas Papadimitriou
                                  secret=OAUTH_CONSUMER_SECRET)
127 9d20fe23 Kostas Papadimitriou
        client = oauth.Client(consumer)
128 9d20fe23 Kostas Papadimitriou
129 74796dd8 Kostas Papadimitriou
        code = request.GET.get('code', None)
130 74796dd8 Kostas Papadimitriou
        params = {
131 74796dd8 Kostas Papadimitriou
            'code': code,
132 74796dd8 Kostas Papadimitriou
            'client_id': settings.GOOGLE_CLIENT_ID,
133 74796dd8 Kostas Papadimitriou
            'client_secret': settings.GOOGLE_SECRET,
134 74796dd8 Kostas Papadimitriou
            'redirect_uri': get_redirect_uri(),
135 74796dd8 Kostas Papadimitriou
            'grant_type': 'authorization_code'
136 74796dd8 Kostas Papadimitriou
        }
137 74796dd8 Kostas Papadimitriou
        get_token_url = "%s" % (request_token_url,)
138 74796dd8 Kostas Papadimitriou
        resp, content = client.request(get_token_url, "POST",
139 74796dd8 Kostas Papadimitriou
                                       body=urllib.urlencode(params))
140 74796dd8 Kostas Papadimitriou
        token = json.loads(content).get('access_token', None)
141 74796dd8 Kostas Papadimitriou
142 9d20fe23 Kostas Papadimitriou
        resp, content = client.request("%s?access_token=%s" %
143 9d20fe23 Kostas Papadimitriou
                                       (access_token_url, token), "GET")
144 74796dd8 Kostas Papadimitriou
        access_token_data = json.loads(content)
145 9d20fe23 Kostas Papadimitriou
    except Exception:
146 9d20fe23 Kostas Papadimitriou
        messages.error(request, _('Invalid Google response. Please '
147 9d20fe23 Kostas Papadimitriou
                                  'contact support'))
148 9f12cd1c Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
149 9f12cd1c Kostas Papadimitriou
150 9f12cd1c Kostas Papadimitriou
    if not access_token_data.get('user_id', None):
151 9d20fe23 Kostas Papadimitriou
        messages.error(request, _('Invalid Google response. Please contact '
152 9d20fe23 Kostas Papadimitriou
                                  ' support'))
153 74796dd8 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
154 74796dd8 Kostas Papadimitriou
155 74796dd8 Kostas Papadimitriou
    userid = access_token_data['user_id']
156 74796dd8 Kostas Papadimitriou
    provider_info = access_token_data
157 74796dd8 Kostas Papadimitriou
    affiliation = 'Google.com'
158 74796dd8 Kostas Papadimitriou
159 74796dd8 Kostas Papadimitriou
    try:
160 c8d89a3c Kostas Papadimitriou
        return handle_third_party_login(request, 'google', userid,
161 c8d89a3c Kostas Papadimitriou
                                        provider_info, affiliation)
162 9d20fe23 Kostas Papadimitriou
    except AstakosUser.DoesNotExist:
163 c8d89a3c Kostas Papadimitriou
        third_party_key = get_pending_key(request)
164 dd5f8f4d Kostas Papadimitriou
        user_info = {'affiliation': affiliation}
165 dd5f8f4d Kostas Papadimitriou
        return handle_third_party_signup(request, userid, 'google',
166 dd5f8f4d Kostas Papadimitriou
                                         third_party_key,
167 dd5f8f4d Kostas Papadimitriou
                                         provider_info,
168 dd5f8f4d Kostas Papadimitriou
                                         user_info,
169 dd5f8f4d Kostas Papadimitriou
                                         template,
170 dd5f8f4d Kostas Papadimitriou
                                         extra_context)