Statistics
| Branch: | Tag: | Revision:

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

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(
82
        'key', request.session.get('pending_key', False))
83
    if 'pending_key' in request.session:
84
        del request.session['pending_key']
85
    return third_party_token
86

    
87

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

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

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

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

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

    
112
    # user wants to add another third party login method
113
    if third_party_key:
114
        messages.error(request, provider.get_invalid_login_msg)
115
        return HttpResponseRedirect(reverse('login') + "?key=%s" %
116
                                    third_party_key)
117

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

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

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

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

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

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

    
149

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

    
155
    if not provider_info:
156
        provider_info = {}
157

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

    
161
    next_redirect = request.GET.get(
162
        'next', request.session.get('next_url', None))
163

    
164
    if 'next_url' in request.session:
165
        del request.session['next_url']
166

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

    
175
    provider = auth.get_provider(provider_module, request.user, identifier,
176
                                 **provider_data)
177

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

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

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

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

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

    
215
            messages.success(request, provider.get_switch_success_msg)
216
            return HttpResponseRedirect(reverse('edit_profile'))
217

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

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

    
238
    if not third_party_key:
239
        third_party_key = get_pending_key(request)
240

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

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

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