Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (9.8 kB)

1 dd5f8f4d Kostas Papadimitriou
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 dd5f8f4d Kostas Papadimitriou
#
3 dd5f8f4d Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 dd5f8f4d Kostas Papadimitriou
# without modification, are permitted provided that the following
5 dd5f8f4d Kostas Papadimitriou
# conditions are met:
6 dd5f8f4d Kostas Papadimitriou
#
7 dd5f8f4d Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 dd5f8f4d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 dd5f8f4d Kostas Papadimitriou
#      disclaimer.
10 dd5f8f4d Kostas Papadimitriou
#
11 dd5f8f4d Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 dd5f8f4d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 dd5f8f4d Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 dd5f8f4d Kostas Papadimitriou
#      provided with the distribution.
15 dd5f8f4d Kostas Papadimitriou
#
16 dd5f8f4d Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 dd5f8f4d Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 dd5f8f4d Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 dd5f8f4d Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 dd5f8f4d Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 dd5f8f4d Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 dd5f8f4d Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 dd5f8f4d Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 dd5f8f4d Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 dd5f8f4d Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 dd5f8f4d Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 dd5f8f4d Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 dd5f8f4d Kostas Papadimitriou
#
29 dd5f8f4d Kostas Papadimitriou
# The views and conclusions contained in the software and
30 dd5f8f4d Kostas Papadimitriou
# documentation are those of the authors and should not be
31 dd5f8f4d Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 dd5f8f4d Kostas Papadimitriou
# or implied, of GRNET S.A.
33 dd5f8f4d Kostas Papadimitriou
34 dd5f8f4d Kostas Papadimitriou
import json
35 dd5f8f4d Kostas Papadimitriou
36 dd5f8f4d Kostas Papadimitriou
from django.contrib import messages
37 dd5f8f4d Kostas Papadimitriou
from django.http import HttpResponseRedirect
38 dd5f8f4d Kostas Papadimitriou
from django.core.urlresolvers import reverse
39 9d20fe23 Kostas Papadimitriou
from django.db import transaction
40 dd5f8f4d Kostas Papadimitriou
41 c8d89a3c Kostas Papadimitriou
from astakos.im.models import PendingThirdPartyUser, AstakosUser
42 c8d89a3c Kostas Papadimitriou
from astakos.im.util import get_query, login_url
43 dd5f8f4d Kostas Papadimitriou
from astakos.im import messages as astakos_messages
44 9d20fe23 Kostas Papadimitriou
from astakos.im import auth_providers as auth
45 3e0a032d Sofia Papagiannaki
from astakos.im.util import prepare_response
46 3e0a032d Sofia Papagiannaki
47 a53ee093 Kostas Papadimitriou
import logging
48 a53ee093 Kostas Papadimitriou
49 a53ee093 Kostas Papadimitriou
logger = logging.getLogger(__name__)
50 dd5f8f4d Kostas Papadimitriou
51 dd5f8f4d Kostas Papadimitriou
52 0e79735c Kostas Papadimitriou
def init_third_party_session(request):
53 0e79735c Kostas Papadimitriou
    params = dict(request.GET.items())
54 0e79735c Kostas Papadimitriou
    request.session['third_party_request_params'] = params
55 0e79735c Kostas Papadimitriou
56 0e79735c Kostas Papadimitriou
57 0e79735c Kostas Papadimitriou
def get_third_party_session_params(request):
58 0e79735c Kostas Papadimitriou
    if 'third_party_request_params' in request.session:
59 0e79735c Kostas Papadimitriou
        params = request.session['third_party_request_params']
60 0e79735c Kostas Papadimitriou
        del request.session['third_party_request_params']
61 0e79735c Kostas Papadimitriou
        return params
62 0e79735c Kostas Papadimitriou
    return {}
63 0e79735c Kostas Papadimitriou
64 0e79735c Kostas Papadimitriou
65 9d20fe23 Kostas Papadimitriou
def add_pending_auth_provider(request, third_party_token, provider):
66 dd5f8f4d Kostas Papadimitriou
    if third_party_token:
67 dd5f8f4d Kostas Papadimitriou
        # use requests to assign the account he just authenticated with with
68 dd5f8f4d Kostas Papadimitriou
        # a third party provider account
69 dd5f8f4d Kostas Papadimitriou
        try:
70 9d20fe23 Kostas Papadimitriou
            pending = PendingThirdPartyUser.objects.get(
71 9d20fe23 Kostas Papadimitriou
                                token=third_party_token,
72 9d20fe23 Kostas Papadimitriou
                                provider=provider.module)
73 9d20fe23 Kostas Papadimitriou
            provider = pending.get_provider()
74 9d20fe23 Kostas Papadimitriou
            provider.add_to_user()
75 9d20fe23 Kostas Papadimitriou
            pending.delete()
76 dd5f8f4d Kostas Papadimitriou
        except PendingThirdPartyUser.DoesNotExist:
77 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_add_failed_msg)
78 dd5f8f4d Kostas Papadimitriou
79 dd5f8f4d Kostas Papadimitriou
80 dd5f8f4d Kostas Papadimitriou
def get_pending_key(request):
81 0e79735c Kostas Papadimitriou
    third_party_token = get_query(request).get('key', request.session.get('pending_key', False))
82 0e79735c Kostas Papadimitriou
    if 'pending_key' in request.session:
83 0e79735c Kostas Papadimitriou
        del request.session['pending_key']
84 dd5f8f4d Kostas Papadimitriou
    return third_party_token
85 dd5f8f4d Kostas Papadimitriou
86 dd5f8f4d Kostas Papadimitriou
87 9d20fe23 Kostas Papadimitriou
def handle_third_party_signup(request, userid, provider_module,
88 9d20fe23 Kostas Papadimitriou
                              third_party_key,
89 7beef200 Kostas Papadimitriou
                              provider_info=None,
90 7beef200 Kostas Papadimitriou
                              pending_user_params=None,
91 dd5f8f4d Kostas Papadimitriou
                              template="im/third_party_check_local.html",
92 7beef200 Kostas Papadimitriou
                              extra_context=None):
93 7beef200 Kostas Papadimitriou
94 7beef200 Kostas Papadimitriou
    if provider_info is None:
95 7beef200 Kostas Papadimitriou
        provider_info = {}
96 7beef200 Kostas Papadimitriou
97 7beef200 Kostas Papadimitriou
    if pending_user_params is None:
98 7beef200 Kostas Papadimitriou
        pending_user_params = {}
99 7beef200 Kostas Papadimitriou
100 7beef200 Kostas Papadimitriou
    if extra_context is None:
101 7beef200 Kostas Papadimitriou
        extra_context = {}
102 dd5f8f4d Kostas Papadimitriou
103 9d20fe23 Kostas Papadimitriou
    # build provider module object
104 9d20fe23 Kostas Papadimitriou
    provider_data = {
105 9d20fe23 Kostas Papadimitriou
        'affiliation': pending_user_params.get('affiliation', provider_module),
106 9d20fe23 Kostas Papadimitriou
        'info_data': provider_info
107 9d20fe23 Kostas Papadimitriou
    }
108 9d20fe23 Kostas Papadimitriou
    provider = auth.get_provider(provider_module, request.user, userid,
109 9d20fe23 Kostas Papadimitriou
                                 **provider_data)
110 9d20fe23 Kostas Papadimitriou
111 dd5f8f4d Kostas Papadimitriou
    # user wants to add another third party login method
112 dd5f8f4d Kostas Papadimitriou
    if third_party_key:
113 9d20fe23 Kostas Papadimitriou
        messages.error(request, provider.get_invalid_login_msg)
114 9d20fe23 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login') + "?key=%s" %
115 9d20fe23 Kostas Papadimitriou
                                    third_party_key)
116 9d20fe23 Kostas Papadimitriou
117 9d20fe23 Kostas Papadimitriou
    if not provider.get_create_policy:
118 9d20fe23 Kostas Papadimitriou
        messages.error(request, provider.get_disabled_for_create_msg)
119 dd5f8f4d Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login'))
120 dd5f8f4d Kostas Papadimitriou
121 9d20fe23 Kostas Papadimitriou
    # TODO: this could be stored in session
122 9d20fe23 Kostas Papadimitriou
    # TODO: create a management command to clean old PendingThirdPartyUser
123 dd5f8f4d Kostas Papadimitriou
    user, created = PendingThirdPartyUser.objects.get_or_create(
124 dd5f8f4d Kostas Papadimitriou
        third_party_identifier=userid,
125 dd5f8f4d Kostas Papadimitriou
        provider=provider_module,
126 dd5f8f4d Kostas Papadimitriou
    )
127 9d20fe23 Kostas Papadimitriou
128 dd5f8f4d Kostas Papadimitriou
    # update pending user
129 dd5f8f4d Kostas Papadimitriou
    for param, value in pending_user_params.iteritems():
130 dd5f8f4d Kostas Papadimitriou
        setattr(user, param, value)
131 dd5f8f4d Kostas Papadimitriou
132 dd5f8f4d Kostas Papadimitriou
    user.info = json.dumps(provider_info)
133 dd5f8f4d Kostas Papadimitriou
    user.generate_token()
134 dd5f8f4d Kostas Papadimitriou
    user.save()
135 dd5f8f4d Kostas Papadimitriou
136 9d20fe23 Kostas Papadimitriou
    extra_context['provider'] = provider.module
137 9d20fe23 Kostas Papadimitriou
    extra_context['provider_title'] = provider.get_title_msg
138 dd5f8f4d Kostas Papadimitriou
    extra_context['token'] = user.token
139 dd5f8f4d Kostas Papadimitriou
    extra_context['signup_url'] = reverse('signup') + \
140 9d20fe23 Kostas Papadimitriou
        "?third_party_token=%s" % user.token
141 dd5f8f4d Kostas Papadimitriou
    extra_context['add_url'] = reverse('index') + \
142 9d20fe23 Kostas Papadimitriou
        "?key=%s#other-login-methods" % user.token
143 9d20fe23 Kostas Papadimitriou
    extra_context['can_create'] = provider.get_create_policy
144 9d20fe23 Kostas Papadimitriou
    extra_context['can_add'] = provider.get_add_policy
145 dd5f8f4d Kostas Papadimitriou
146 a148ae08 Kostas Papadimitriou
    return HttpResponseRedirect(extra_context['signup_url'])
147 c8d89a3c Kostas Papadimitriou
148 c8d89a3c Kostas Papadimitriou
149 9d20fe23 Kostas Papadimitriou
@transaction.commit_on_success
150 c8d89a3c Kostas Papadimitriou
def handle_third_party_login(request, provider_module, identifier,
151 0e79735c Kostas Papadimitriou
                             provider_info=None, affiliation=None,
152 0e79735c Kostas Papadimitriou
                             third_party_key=None):
153 c8d89a3c Kostas Papadimitriou
154 c8d89a3c Kostas Papadimitriou
    if not provider_info:
155 c8d89a3c Kostas Papadimitriou
        provider_info = {}
156 c8d89a3c Kostas Papadimitriou
157 c8d89a3c Kostas Papadimitriou
    if not affiliation:
158 c8d89a3c Kostas Papadimitriou
        affiliation = provider_module.title()
159 c8d89a3c Kostas Papadimitriou
160 c8d89a3c Kostas Papadimitriou
    next_redirect = request.GET.get('next', request.session.get('next_url', None))
161 c8d89a3c Kostas Papadimitriou
    if 'next_url' in request.session:
162 c8d89a3c Kostas Papadimitriou
        del request.session['next_url']
163 c8d89a3c Kostas Papadimitriou
164 0e79735c Kostas Papadimitriou
    third_party_request_params = get_third_party_session_params(request)
165 0e79735c Kostas Papadimitriou
    from_login = third_party_request_params.get('from_login', False)
166 9d20fe23 Kostas Papadimitriou
    switch_from = third_party_request_params.get('switch_from', False)
167 9d20fe23 Kostas Papadimitriou
    provider_data = {
168 9d20fe23 Kostas Papadimitriou
        'affiliation': affiliation,
169 9d20fe23 Kostas Papadimitriou
        'info': provider_info
170 9d20fe23 Kostas Papadimitriou
    }
171 9d20fe23 Kostas Papadimitriou
    provider = auth.get_provider(provider_module, request.user, identifier,
172 9d20fe23 Kostas Papadimitriou
                                 **provider_data)
173 0e79735c Kostas Papadimitriou
174 c8d89a3c Kostas Papadimitriou
    # an existing user accessed the view
175 c8d89a3c Kostas Papadimitriou
    if request.user.is_authenticated():
176 9d20fe23 Kostas Papadimitriou
        if request.user.has_auth_provider(provider.module,
177 9d20fe23 Kostas Papadimitriou
                                          identifier=identifier):
178 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
179 c8d89a3c Kostas Papadimitriou
180 9d20fe23 Kostas Papadimitriou
        if provider.verified_exists():
181 97246b51 Kostas Papadimitriou
            provider.log("add failed (identifier exists to another user)")
182 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_add_exists_msg)
183 c8d89a3c Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
184 c8d89a3c Kostas Papadimitriou
185 c8d89a3c Kostas Papadimitriou
        # automatically add identifier provider to user
186 9d20fe23 Kostas Papadimitriou
        if not switch_from and not provider.get_add_policy:
187 c8d89a3c Kostas Papadimitriou
            # TODO: handle existing uuid message separately
188 97246b51 Kostas Papadimitriou
            provider.log("user cannot add provider")
189 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_add_failed_msg)
190 c8d89a3c Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
191 c8d89a3c Kostas Papadimitriou
192 9d20fe23 Kostas Papadimitriou
        user = request.user
193 9d20fe23 Kostas Papadimitriou
        if switch_from:
194 9d20fe23 Kostas Papadimitriou
            existing_provider = \
195 9d20fe23 Kostas Papadimitriou
                request.user.auth_providers.active().get(
196 9d20fe23 Kostas Papadimitriou
                    pk=int(switch_from), module=provider_module).settings
197 9d20fe23 Kostas Papadimitriou
198 9d20fe23 Kostas Papadimitriou
            # this is not a provider removal so we don't not use
199 9d20fe23 Kostas Papadimitriou
            # provider.remove_from_user. Use low level access to the provider
200 9d20fe23 Kostas Papadimitriou
            # db instance.
201 9d20fe23 Kostas Papadimitriou
            if not provider.verified_exists():
202 9d20fe23 Kostas Papadimitriou
                if provider.get_add_policy:
203 97246b51 Kostas Papadimitriou
                    existing_provider._instance.delete()
204 97246b51 Kostas Papadimitriou
                    existing_provider.log("removed")
205 9d20fe23 Kostas Papadimitriou
                    provider.add_to_user()
206 97246b51 Kostas Papadimitriou
                    provider.log("added")
207 9d20fe23 Kostas Papadimitriou
            else:
208 9d20fe23 Kostas Papadimitriou
                messages.error(request, provider.get_add_exists_msg)
209 97246b51 Kostas Papadimitriou
                return HttpResponseRedirect(reverse('edit_profile'))
210 97246b51 Kostas Papadimitriou
211 9d20fe23 Kostas Papadimitriou
            messages.success(request, provider.get_switch_success_msg)
212 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
213 9d20fe23 Kostas Papadimitriou
214 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
215 97246b51 Kostas Papadimitriou
        provider.log("added")
216 9d20fe23 Kostas Papadimitriou
        provider = user.get_auth_provider(provider_module, identifier)
217 9d20fe23 Kostas Papadimitriou
        messages.success(request, provider.get_added_msg)
218 c8d89a3c Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
219 c8d89a3c Kostas Papadimitriou
220 c8d89a3c Kostas Papadimitriou
    # astakos user exists ?
221 0e79735c Kostas Papadimitriou
    try:
222 0e79735c Kostas Papadimitriou
        user = AstakosUser.objects.get_auth_provider_user(
223 0e79735c Kostas Papadimitriou
            provider_module,
224 0e79735c Kostas Papadimitriou
            identifier=identifier,
225 0e79735c Kostas Papadimitriou
            user__email_verified=True,
226 0e79735c Kostas Papadimitriou
        )
227 0e79735c Kostas Papadimitriou
    except AstakosUser.DoesNotExist:
228 0e79735c Kostas Papadimitriou
        # TODO: add a message ? redirec to login ?
229 0e79735c Kostas Papadimitriou
        if astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN:
230 0e79735c Kostas Papadimitriou
            messages.warning(request,
231 0e79735c Kostas Papadimitriou
                             astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN)
232 0e79735c Kostas Papadimitriou
        raise
233 0e79735c Kostas Papadimitriou
234 0e79735c Kostas Papadimitriou
    if not third_party_key:
235 0e79735c Kostas Papadimitriou
        third_party_key = get_pending_key(request)
236 0e79735c Kostas Papadimitriou
237 9d20fe23 Kostas Papadimitriou
    provider = user.get_auth_provider(provider_module, identifier)
238 c8d89a3c Kostas Papadimitriou
    if user.is_active:
239 9d20fe23 Kostas Papadimitriou
        if not provider.get_login_policy:
240 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_login_disabled_msg)
241 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('login'))
242 9d20fe23 Kostas Papadimitriou
243 c8d89a3c Kostas Papadimitriou
        # authenticate user
244 9d20fe23 Kostas Papadimitriou
        response = prepare_response(request, user, next_redirect,
245 9d20fe23 Kostas Papadimitriou
                                    'renew' in request.GET)
246 9d20fe23 Kostas Papadimitriou
247 9d20fe23 Kostas Papadimitriou
        messages.success(request, provider.get_login_success_msg)
248 9d20fe23 Kostas Papadimitriou
        add_pending_auth_provider(request, third_party_key, provider)
249 c8d89a3c Kostas Papadimitriou
        response.set_cookie('astakos_last_login_method', provider_module)
250 c8d89a3c Kostas Papadimitriou
        return response
251 c8d89a3c Kostas Papadimitriou
    else:
252 9d20fe23 Kostas Papadimitriou
        message = user.get_inactive_message(provider_module, identifier)
253 c8d89a3c Kostas Papadimitriou
        messages.error(request, message)
254 c8d89a3c Kostas Papadimitriou
        return HttpResponseRedirect(login_url(request))