Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views / target / __init__.py @ 02c1f22a

History | View | Annotate | Download (10 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.contrib import messages
37
from django.http import HttpResponseRedirect
38
from django.core.urlresolvers import reverse
39
from django.db import transaction
40

    
41
from astakos.im.models import PendingThirdPartyUser, AstakosUser
42
from astakos.im.util import get_query, login_url
43
from astakos.im import messages as astakos_messages
44
from astakos.im import auth_providers as auth
45
from astakos.im.util import prepare_response
46

    
47
import logging
48

    
49
logger = logging.getLogger(__name__)
50

    
51

    
52
def init_third_party_session(request):
53
    params = dict(request.GET.items())
54
    request.session['third_party_request_params'] = params
55

    
56

    
57
def get_third_party_session_params(request):
58
    if 'third_party_request_params' in request.session:
59
        params = request.session['third_party_request_params']
60
        del request.session['third_party_request_params']
61
        return params
62
    return {}
63

    
64

    
65
def add_pending_auth_provider(request, third_party_token, provider):
66
    if third_party_token:
67
        # use requests to assign the account he just authenticated with with
68
        # a third party provider account
69
        try:
70
            pending = PendingThirdPartyUser.objects.get(
71
                                token=third_party_token,
72
                                provider=provider.module)
73
            provider = pending.get_provider()
74
            provider.add_to_user()
75
            pending.delete()
76
        except PendingThirdPartyUser.DoesNotExist:
77
            messages.error(request, provider.get_add_failed_msg)
78

    
79

    
80
def get_pending_key(request):
81
    third_party_token = get_query(request).get('key', request.session.get('pending_key', False))
82
    if 'pending_key' in request.session:
83
        del request.session['pending_key']
84
    return third_party_token
85

    
86

    
87
def handle_third_party_signup(request, userid, provider_module,
88
                              third_party_key,
89
                              provider_info=None,
90
                              pending_user_params=None,
91
                              template="im/third_party_check_local.html",
92
                              extra_context=None):
93

    
94
    if provider_info is None:
95
        provider_info = {}
96

    
97
    if pending_user_params is None:
98
        pending_user_params = {}
99

    
100
    if extra_context is None:
101
        extra_context = {}
102

    
103
    # build provider module object
104
    provider_data = {
105
        'affiliation': pending_user_params.get('affiliation', provider_module),
106
        'info_data': provider_info
107
    }
108
    provider = auth.get_provider(provider_module, request.user, userid,
109
                                 **provider_data)
110

    
111
    from_login = request.REQUEST.get('from_login', False)
112
    if from_login:
113
        messages.error(request, provider.get_invalid_login_msg)
114
        return HttpResponseRedirect(reverse('login'))
115

    
116
    # user wants to add another third party login method
117
    if third_party_key:
118
        return HttpResponseRedirect(reverse('login') + "?key=%s" %
119
                                    third_party_key)
120

    
121
    if not provider.get_create_policy:
122
        messages.error(request, provider.get_disabled_for_create_msg)
123
        return HttpResponseRedirect(reverse('login'))
124

    
125
    # TODO: this could be stored in session
126
    # TODO: create a management command to clean old PendingThirdPartyUser
127
    user, created = PendingThirdPartyUser.objects.get_or_create(
128
        third_party_identifier=userid,
129
        provider=provider_module,
130
    )
131

    
132
    # update pending user
133
    for param, value in pending_user_params.iteritems():
134
        setattr(user, param, value)
135

    
136
    user.info = json.dumps(provider_info)
137
    user.generate_token()
138
    user.save()
139

    
140
    extra_context['provider'] = provider.module
141
    extra_context['provider_title'] = provider.get_title_msg
142
    extra_context['token'] = user.token
143
    extra_context['signup_url'] = reverse('signup') + \
144
        "?third_party_token=%s" % user.token
145
    extra_context['add_url'] = reverse('index') + \
146
        "?key=%s#other-login-methods" % user.token
147
    extra_context['can_create'] = provider.get_create_policy
148
    extra_context['can_add'] = provider.get_add_policy
149

    
150
    return HttpResponseRedirect(extra_context['signup_url'])
151

    
152

    
153
@transaction.commit_on_success
154
def handle_third_party_login(request, provider_module, identifier,
155
                             provider_info=None, affiliation=None,
156
                             third_party_key=None):
157

    
158
    if not provider_info:
159
        provider_info = {}
160

    
161
    if not affiliation:
162
        affiliation = provider_module.title()
163

    
164
    next_redirect = request.GET.get('next', request.session.get('next_url',
165
                                                                None))
166
    if 'next_url' in request.session:
167
        del request.session['next_url']
168

    
169
    third_party_request_params = get_third_party_session_params(request)
170
    from_login = third_party_request_params.get('from_login', False)
171
    switch_from = third_party_request_params.get('switch_from', False)
172
    provider_data = {
173
        'affiliation': affiliation,
174
        'info': provider_info
175
    }
176

    
177
    provider = auth.get_provider(provider_module, request.user, identifier,
178
                                 **provider_data)
179

    
180
    # an existing user accessed the view
181
    if request.user.is_authenticated():
182
        if request.user.has_auth_provider(provider.module,
183
                                          identifier=identifier):
184
            return HttpResponseRedirect(reverse('edit_profile'))
185

    
186
        if provider.verified_exists():
187
            provider.log("add failed (identifier exists to another user)")
188
            messages.error(request, provider.get_add_exists_msg)
189
            return HttpResponseRedirect(reverse('edit_profile'))
190

    
191
        # automatically add identifier provider to user
192
        if not switch_from and not provider.get_add_policy:
193
            # TODO: handle existing uuid message separately
194
            provider.log("user cannot add provider")
195
            messages.error(request, provider.get_add_failed_msg)
196
            return HttpResponseRedirect(reverse('edit_profile'))
197

    
198
        user = request.user
199
        if switch_from:
200
            existing_provider = \
201
                request.user.auth_providers.active().get(
202
                    pk=int(switch_from), module=provider_module).settings
203

    
204
            # this is not a provider removal so we don't not use
205
            # provider.remove_from_user. Use low level access to the provider
206
            # db instance.
207
            if not provider.verified_exists():
208
                if provider.get_add_policy:
209
                    existing_provider._instance.delete()
210
                    existing_provider.log("removed")
211
                    provider.add_to_user()
212
                    provider.log("added")
213
            else:
214
                messages.error(request, provider.get_add_exists_msg)
215
                return HttpResponseRedirect(reverse('edit_profile'))
216

    
217
            messages.success(request, provider.get_switch_success_msg)
218
            return HttpResponseRedirect(reverse('edit_profile'))
219

    
220
        provider.add_to_user()
221
        provider.log("added")
222
        provider = user.get_auth_provider(provider_module, identifier)
223
        messages.success(request, provider.get_added_msg)
224
        return HttpResponseRedirect(reverse('edit_profile'))
225

    
226
    # astakos user exists ?
227
    try:
228
        user = AstakosUser.objects.get_auth_provider_user(
229
            provider_module,
230
            identifier=identifier,
231
            user__email_verified=True,
232
        )
233
    except AstakosUser.DoesNotExist:
234
        # TODO: add a message ? redirec to login ?
235
        if astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN:
236
            messages.warning(request,
237
                             astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN)
238
        raise
239

    
240
    if not third_party_key:
241
        third_party_key = get_pending_key(request)
242

    
243
    provider = user.get_auth_provider(provider_module, identifier)
244
    if user.is_active:
245
        if not provider.get_login_policy:
246
            messages.error(request, provider.get_login_disabled_msg)
247
            return HttpResponseRedirect(reverse('login'))
248

    
249
        # authenticate user
250
        response = prepare_response(request, user, next_redirect,
251
                                    'renew' in request.GET)
252

    
253
        messages.success(request, provider.get_login_success_msg)
254
        add_pending_auth_provider(request, third_party_key, provider)
255
        response.set_cookie('astakos_last_login_method', provider_module)
256
        return response
257
    else:
258
        message = user.get_inactive_message(provider_module, identifier)
259
        messages.error(request, message)
260
        return HttpResponseRedirect(login_url(request))