Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views / target / __init__.py @ 07ad7b1c

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',
161
                                                                None))
162
    if 'next_url' in request.session:
163
        del request.session['next_url']
164

    
165
    third_party_request_params = get_third_party_session_params(request)
166
    from_login = third_party_request_params.get('from_login', False)
167
    switch_from = third_party_request_params.get('switch_from', False)
168
    provider_data = {
169
        'affiliation': affiliation,
170
        'info': provider_info
171
    }
172

    
173
    provider = auth.get_provider(provider_module, request.user, identifier,
174
                                 **provider_data)
175

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

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

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

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

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

    
213
            messages.success(request, provider.get_switch_success_msg)
214
            return HttpResponseRedirect(reverse('edit_profile'))
215

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

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

    
236
    if not third_party_key:
237
        third_party_key = get_pending_key(request)
238

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

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

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