Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / target / linkedin.py @ 222305b7

History | View | Annotate | Download (6.5 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, login_url
49
from astakos.im.views import requires_anonymous, render_response, \
50
        requires_auth_provider
51
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
52
from astakos.im.models import AstakosUser, PendingThirdPartyUser
53
from astakos.im.forms import LoginForm
54
from astakos.im.activation_backends import get_backend, SimpleBackend
55
from astakos.im import settings
56
from astakos.im import auth_providers
57
from astakos.im.target import add_pending_auth_provider, get_pending_key, \
58
    handle_third_party_signup, handle_third_party_login, init_third_party_session
59
from astakos.im.decorators import cookie_fix
60

    
61
import astakos.im.messages as astakos_messages
62

    
63
import logging
64

    
65
logger = logging.getLogger(__name__)
66

    
67
import oauth2 as oauth
68
import cgi
69

    
70

    
71
request_token_url      = 'https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress'
72
access_token_url       = 'https://api.linkedin.com/uas/oauth/accessToken'
73
authenticate_url       = 'https://www.linkedin.com/uas/oauth/authorize'
74

    
75

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

    
86
    request_token = dict(cgi.parse_qsl(content))
87
    request.session['request_token'] = request_token
88

    
89
    url = request_token.get('xoauth_request_auth_url') + "?oauth_token=%s" % request_token.get('oauth_token')
90

    
91
    if request.GET.get('key', None):
92
        request.session['pending_key'] = request.GET.get('key')
93

    
94
    if request.GET.get('next', None):
95
        request.session['next_url'] = request.GET.get('next')
96

    
97
    return HttpResponseRedirect(url)
98

    
99

    
100
@requires_auth_provider('linkedin', login=True)
101
@require_http_methods(["GET", "POST"])
102
@cookie_fix
103
def authenticated(
104
    request,
105
    template='im/third_party_check_local.html',
106
    extra_context=None
107
):
108

    
109
    if extra_context is None:
110
        extra_context = {}
111

    
112
    consumer = oauth.Consumer(settings.LINKEDIN_TOKEN,
113
                              settings.LINKEDIN_SECRET)
114
    client = oauth.Client(consumer)
115

    
116
    if request.GET.get('denied'):
117
        return HttpResponseRedirect(reverse('edit_profile'))
118

    
119
    if not 'request_token' in request.session:
120
        messages.error(request, 'linkedin handshake failed')
121
        return HttpResponseRedirect(reverse('edit_profile'))
122

    
123
    token = oauth.Token(request.session['request_token']['oauth_token'],
124
        request.session['request_token']['oauth_token_secret'])
125
    token.set_verifier(request.GET.get('oauth_verifier'))
126
    client = oauth.Client(consumer, token)
127
    resp, content = client.request(access_token_url, "POST")
128
    if resp['status'] != '200':
129
        try:
130
            del request.session['request_token']
131
        except:
132
            pass
133
        messages.error(request, 'Invalid linkedin token response')
134
        return HttpResponseRedirect(reverse('edit_profile'))
135
    access_token = dict(cgi.parse_qsl(content))
136

    
137
    token = oauth.Token(access_token['oauth_token'],
138
        access_token['oauth_token_secret'])
139
    client = oauth.Client(consumer, token)
140
    resp, content = client.request("http://api.linkedin.com/v1/people/~:(id,first-name,last-name,industry,email-address)?format=json", "GET")
141
    if resp['status'] != '200':
142
        try:
143
            del request.session['request_token']
144
        except:
145
            pass
146
        messages.error(request, 'Invalid linkedin profile response')
147
        return HttpResponseRedirect(reverse('edit_profile'))
148

    
149
    profile_data = json.loads(content)
150
    userid = profile_data['id']
151
    username = profile_data.get('emailAddress', None)
152
    realname = profile_data.get('firstName', '') + ' ' + profile_data.get('lastName', '')
153
    provider_info = profile_data
154
    affiliation = 'LinkedIn.com'
155

    
156

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