Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views / target / __init__.py @ 3e0a032d

History | View | Annotate | Download (9.8 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
    # user wants to add another third party login method
112
    if third_party_key:
113
        messages.error(request, provider.get_invalid_login_msg)
114
        return HttpResponseRedirect(reverse('login') + "?key=%s" %
115
                                    third_party_key)
116

    
117
    if not provider.get_create_policy:
118
        messages.error(request, provider.get_disabled_for_create_msg)
119
        return HttpResponseRedirect(reverse('login'))
120

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

    
128
    # update pending user
129
    for param, value in pending_user_params.iteritems():
130
        setattr(user, param, value)
131

    
132
    user.info = json.dumps(provider_info)
133
    user.generate_token()
134
    user.save()
135

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

    
146
    return HttpResponseRedirect(extra_context['signup_url'])
147

    
148

    
149
@transaction.commit_on_success
150
def handle_third_party_login(request, provider_module, identifier,
151
                             provider_info=None, affiliation=None,
152
                             third_party_key=None):
153

    
154
    if not provider_info:
155
        provider_info = {}
156

    
157
    if not affiliation:
158
        affiliation = provider_module.title()
159

    
160
    next_redirect = request.GET.get('next', request.session.get('next_url', None))
161
    if 'next_url' in request.session:
162
        del request.session['next_url']
163

    
164
    third_party_request_params = get_third_party_session_params(request)
165
    from_login = third_party_request_params.get('from_login', False)
166
    switch_from = third_party_request_params.get('switch_from', False)
167
    provider_data = {
168
        'affiliation': affiliation,
169
        'info': provider_info
170
    }
171
    provider = auth.get_provider(provider_module, request.user, identifier,
172
                                 **provider_data)
173

    
174
    # an existing user accessed the view
175
    if request.user.is_authenticated():
176
        if request.user.has_auth_provider(provider.module,
177
                                          identifier=identifier):
178
            return HttpResponseRedirect(reverse('edit_profile'))
179

    
180
        if provider.verified_exists():
181
            provider.log("add failed (identifier exists to another user)")
182
            messages.error(request, provider.get_add_exists_msg)
183
            return HttpResponseRedirect(reverse('edit_profile'))
184

    
185
        # automatically add identifier provider to user
186
        if not switch_from and not provider.get_add_policy:
187
            # TODO: handle existing uuid message separately
188
            provider.log("user cannot add provider")
189
            messages.error(request, provider.get_add_failed_msg)
190
            return HttpResponseRedirect(reverse('edit_profile'))
191

    
192
        user = request.user
193
        if switch_from:
194
            existing_provider = \
195
                request.user.auth_providers.active().get(
196
                    pk=int(switch_from), module=provider_module).settings
197

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

    
211
            messages.success(request, provider.get_switch_success_msg)
212
            return HttpResponseRedirect(reverse('edit_profile'))
213

    
214
        provider.add_to_user()
215
        provider.log("added")
216
        provider = user.get_auth_provider(provider_module, identifier)
217
        messages.success(request, provider.get_added_msg)
218
        return HttpResponseRedirect(reverse('edit_profile'))
219

    
220
    # astakos user exists ?
221
    try:
222
        user = AstakosUser.objects.get_auth_provider_user(
223
            provider_module,
224
            identifier=identifier,
225
            user__email_verified=True,
226
        )
227
    except AstakosUser.DoesNotExist:
228
        # TODO: add a message ? redirec to login ?
229
        if astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN:
230
            messages.warning(request,
231
                             astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN)
232
        raise
233

    
234
    if not third_party_key:
235
        third_party_key = get_pending_key(request)
236

    
237
    provider = user.get_auth_provider(provider_module, identifier)
238
    if user.is_active:
239
        if not provider.get_login_policy:
240
            messages.error(request, provider.get_login_disabled_msg)
241
            return HttpResponseRedirect(reverse('login'))
242

    
243
        # authenticate user
244
        response = prepare_response(request, user, next_redirect,
245
                                    'renew' in request.GET)
246

    
247
        messages.success(request, provider.get_login_success_msg)
248
        add_pending_auth_provider(request, third_party_key, provider)
249
        response.set_cookie('astakos_last_login_method', provider_module)
250
        return response
251
    else:
252
        message = user.get_inactive_message(provider_module, identifier)
253
        messages.error(request, message)
254
        return HttpResponseRedirect(login_url(request))