Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.4 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import json
35
import logging
36
import urllib
37
import oauth2 as oauth
38

    
39
from django.utils.translation import ugettext as _
40
from django.contrib import messages
41
from django.views.decorators.http import require_http_methods
42
from django.http import HttpResponseRedirect
43
from django.core.urlresolvers import reverse
44
from django.conf import settings as django_settings
45

    
46
from astakos.im.models import AstakosUser
47
from astakos.im import settings
48
from astakos.im.views.target import get_pending_key, \
49
    handle_third_party_signup, handle_third_party_login, \
50
    init_third_party_session
51
from astakos.im.views.decorators import cookie_fix, requires_auth_provider
52

    
53
logger = logging.getLogger(__name__)
54
signature_method = oauth.SignatureMethod_HMAC_SHA1()
55

    
56
OAUTH_CONSUMER_KEY = settings.GOOGLE_CLIENT_ID
57
OAUTH_CONSUMER_SECRET = settings.GOOGLE_SECRET
58

    
59

    
60
def django_setting(key, default):
61
    return getattr(django_settings, 'GOOGLE_%s' % key.upper, default)
62

    
63
default_token_scopes = ['https://www.googleapis.com/auth/userinfo.profile',
64
                        'https://www.googleapis.com/auth/userinfo.email']
65

    
66
token_scope = django_setting('token_scope', ' '.join(default_token_scopes))
67
authenticate_url = django_setting(
68
    'authenticate_url',
69
    'https://accounts.google.com/o/oauth2/auth')
70
access_token_url = django_setting(
71
    'access_token_url',
72
    'https://www.googleapis.com/oauth2/v1/tokeninfo')
73
request_token_url = django_setting(
74
    'request_token_url',
75
    'https://accounts.google.com/o/oauth2/token')
76

    
77

    
78
def get_redirect_uri():
79
    return "%s%s" % (settings.BASE_HOST,
80
                     reverse('astakos.im.views.target.google.authenticated'))
81

    
82

    
83
@requires_auth_provider('google')
84
@require_http_methods(["GET", "POST"])
85
def login(request):
86
    init_third_party_session(request)
87
    params = {
88
        'scope': token_scope,
89
        'response_type': 'code',
90
        'redirect_uri': get_redirect_uri(),
91
        'client_id': settings.GOOGLE_CLIENT_ID
92
    }
93
    force_login = request.GET.get('force_login', request.GET.get('from_login',
94
                                                                 True))
95
    if force_login:
96
        params['approval_prompt'] = 'force'
97

    
98
    if request.GET.get('key', None):
99
        request.session['pending_key'] = request.GET.get('key')
100

    
101
    if request.GET.get('next', None):
102
        request.session['next_url'] = request.GET.get('next')
103

    
104
    url = "%s?%s" % (authenticate_url, urllib.urlencode(params))
105
    return HttpResponseRedirect(url)
106

    
107

    
108
@requires_auth_provider('google')
109
@require_http_methods(["GET", "POST"])
110
@cookie_fix
111
def authenticated(
112
    request,
113
    template='im/third_party_check_local.html',
114
    extra_context=None
115
):
116

    
117
    if extra_context is None:
118
        extra_context = {}
119

    
120
    if request.GET.get('error', None):
121
        return HttpResponseRedirect(reverse('edit_profile'))
122

    
123
    # TODO: Handle errors, e.g. error=access_denied
124
    try:
125
        consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
126
                                  secret=OAUTH_CONSUMER_SECRET)
127
        client = oauth.Client(consumer)
128

    
129
        code = request.GET.get('code', None)
130
        params = {
131
            'code': code,
132
            'client_id': settings.GOOGLE_CLIENT_ID,
133
            'client_secret': settings.GOOGLE_SECRET,
134
            'redirect_uri': get_redirect_uri(),
135
            'grant_type': 'authorization_code'
136
        }
137
        get_token_url = "%s" % (request_token_url,)
138
        resp, content = client.request(get_token_url, "POST",
139
                                       body=urllib.urlencode(params))
140
        token = json.loads(content).get('access_token', None)
141

    
142
        resp, content = client.request("%s?access_token=%s" %
143
                                       (access_token_url, token), "GET")
144
        access_token_data = json.loads(content)
145
    except Exception:
146
        messages.error(request, _('Invalid Google response. Please '
147
                                  'contact support'))
148
        return HttpResponseRedirect(reverse('edit_profile'))
149

    
150
    if not access_token_data.get('user_id', None):
151
        messages.error(request, _('Invalid Google response. Please contact '
152
                                  ' support'))
153
        return HttpResponseRedirect(reverse('edit_profile'))
154

    
155
    userid = access_token_data['user_id']
156
    provider_info = access_token_data
157
    affiliation = 'Google.com'
158

    
159
    try:
160
        return handle_third_party_login(request, 'google', userid,
161
                                        provider_info, affiliation)
162
    except AstakosUser.DoesNotExist:
163
        third_party_key = get_pending_key(request)
164
        user_info = {'affiliation': affiliation}
165
        return handle_third_party_signup(request, userid, 'google',
166
                                         third_party_key,
167
                                         provider_info,
168
                                         user_info,
169
                                         template,
170
                                         extra_context)