Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / target / twitter.py @ badcb2a9

History | View | Annotate | Download (7.9 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

    
36
from django.http import HttpResponseBadRequest
37
from django.utils.translation import ugettext as _
38
from django.contrib import messages
39
from django.template import RequestContext
40
from django.views.decorators.http import require_http_methods
41
from django.http import HttpResponseRedirect
42
from django.core.urlresolvers import reverse
43
from django.core.exceptions import ImproperlyConfigured
44
from django.shortcuts import get_object_or_404
45

    
46
from urlparse import urlunsplit, urlsplit
47

    
48
from astakos.im.util import prepare_response, get_context
49

    
50
from astakos.im.views import requires_anonymous, render_response, \
51
        requires_auth_provider, required_auth_methods_assigned
52
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
53
from astakos.im.models import AstakosUser, PendingThirdPartyUser
54
from astakos.im.forms import LoginForm
55
from astakos.im.activation_backends import get_backend, SimpleBackend
56
from astakos.im import settings
57
from astakos.im import auth_providers
58

    
59
import astakos.im.messages as astakos_messages
60

    
61
import logging
62

    
63
logger = logging.getLogger(__name__)
64

    
65
import oauth2 as oauth
66
import cgi
67
import urllib
68

    
69
consumer = oauth.Consumer(settings.TWITTER_TOKEN, settings.TWITTER_SECRET)
70
client = oauth.Client(consumer)
71

    
72
request_token_url = 'http://twitter.com/oauth/request_token'
73
access_token_url = 'http://twitter.com/oauth/access_token'
74
authenticate_url = 'http://twitter.com/oauth/authenticate'
75

    
76
@requires_auth_provider('twitter', login=True)
77
@require_http_methods(["GET", "POST"])
78
def login(request):
79
    force_login = request.GET.get('force_login',
80
                                  settings.TWITTER_AUTH_FORCE_LOGIN)
81
    resp, content = client.request(request_token_url, "GET")
82
    if resp['status'] != '200':
83
        messages.error(request, 'Invalid Twitter response')
84
        return HttpResponseRedirect(reverse('edit_profile'))
85

    
86
    request.session['request_token'] = dict(cgi.parse_qsl(content))
87
    params = {
88
        'oauth_token': request.session['request_token']['oauth_token'],
89
    }
90
    if force_login:
91
        params['force_login'] = 1
92

    
93
    url = "%s?%s" % (authenticate_url, urllib.urlencode(params))
94

    
95
    return HttpResponseRedirect(url)
96

    
97

    
98
@requires_auth_provider('twitter', login=True)
99
@require_http_methods(["GET", "POST"])
100
def authenticated(
101
    request,
102
    template='im/third_party_check_local.html',
103
    extra_context={}):
104

    
105
    if request.GET.get('denied'):
106
        return HttpResponseRedirect(reverse('edit_profile'))
107

    
108
    if not 'request_token' in request.session:
109
        messages.error(request, 'Twitter handshake failed')
110
        return HttpResponseRedirect(reverse('edit_profile'))
111

    
112
    token = oauth.Token(request.session['request_token']['oauth_token'],
113
        request.session['request_token']['oauth_token_secret'])
114
    client = oauth.Client(consumer, token)
115

    
116
    # Step 2. Request the authorized access token from Twitter.
117
    resp, content = client.request(access_token_url, "GET")
118
    if resp['status'] != '200':
119
        try:
120
            del request.session['request_token']
121
        except:
122
            pass
123
        messages.error(request, 'Invalid Twitter response')
124
        return HttpResponseRedirect(reverse('edit_profile'))
125

    
126
    access_token = dict(cgi.parse_qsl(content))
127
    userid = access_token['user_id']
128
    username = access_token.get('screen_name', userid)
129
    provider_info = {'screen_name': username}
130
    affiliation = 'Twitter.com'
131

    
132
    # an existing user accessed the view
133
    if request.user.is_authenticated():
134
        if request.user.has_auth_provider('twitter', identifier=userid):
135
            return HttpResponseRedirect(reverse('edit_profile'))
136

    
137
        # automatically add eppn provider to user
138
        user = request.user
139
        if not request.user.can_add_auth_provider('twitter',
140
                                                  identifier=userid):
141
            messages.error(request, _(astakos_messages.AUTH_PROVIDER_ADD_FAILED) +
142
                          u' ' + _(astakos_messages.AUTH_PROVIDER_ADD_EXISTS))
143
            return HttpResponseRedirect(reverse('edit_profile'))
144

    
145
        user.add_auth_provider('twitter', identifier=userid,
146
                               affiliation=affiliation,
147
                               provider_info=provider_info)
148
        messages.success(request, astakos_messages.AUTH_PROVIDER_ADDED)
149
        return HttpResponseRedirect(reverse('edit_profile'))
150

    
151
    try:
152
        # astakos user exists ?
153
        user = AstakosUser.objects.get_auth_provider_user(
154
            'twitter',
155
            identifier=userid
156
        )
157
        if user.is_active:
158
            # authenticate user
159
            response = prepare_response(request,
160
                                    user,
161
                                    request.GET.get('next'),
162
                                    'renew' in request.GET)
163
            response.set_cookie('astakos_last_login_method', 'twitter')
164
            return response
165
        else:
166
            message = user.get_inactive_message()
167
            messages.error(request, message)
168
            return HttpResponseRedirect(reverse('login'))
169

    
170
    except AstakosUser.DoesNotExist, e:
171
        provider = auth_providers.get_provider('twitter')
172
        if not provider.is_available_for_create() and not provider.is_available_for_add():
173
            messages.error(request,
174
                           _(astakos_messages.AUTH_PROVIDER_INVALID_LOGIN))
175
            return HttpResponseRedirect(reverse('login'))
176

    
177
        # eppn not stored in astakos models, create pending profile
178
        user, created = PendingThirdPartyUser.objects.get_or_create(
179
            third_party_identifier=userid,
180
            provider='twitter',
181
        )
182
        # update pending user
183
        user.affiliation = affiliation
184
        user.info = json.dumps(provider_info)
185
        user.generate_token()
186
        user.save()
187

    
188
        extra_context['provider'] = 'twitter'
189
        extra_context['provider_title'] = provider.get_title_display
190
        extra_context['token'] = user.token
191
        extra_context['signup_url'] = reverse('signup') + \
192
                                    "?third_party_token=%s" % user.token
193
        extra_context['add_url'] = reverse('index') + \
194
                                    "?key=%s#other-login-methods" % user.token
195
        extra_context['can_create'] = provider.is_available_for_create()
196
        extra_context['can_add'] = provider.is_available_for_add()
197

    
198

    
199
        return render_response(
200
            template,
201
            context_instance=get_context(request, extra_context)
202
        )
203