Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (10 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 02c1f22a Kostas Papadimitriou
    from_login = request.REQUEST.get('from_login', False)
112 02c1f22a Kostas Papadimitriou
    if from_login:
113 02c1f22a Kostas Papadimitriou
        messages.error(request, provider.get_invalid_login_msg)
114 02c1f22a Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login'))
115 02c1f22a Kostas Papadimitriou
116 dd5f8f4d Kostas Papadimitriou
    # user wants to add another third party login method
117 dd5f8f4d Kostas Papadimitriou
    if third_party_key:
118 9d20fe23 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login') + "?key=%s" %
119 9d20fe23 Kostas Papadimitriou
                                    third_party_key)
120 9d20fe23 Kostas Papadimitriou
121 9d20fe23 Kostas Papadimitriou
    if not provider.get_create_policy:
122 9d20fe23 Kostas Papadimitriou
        messages.error(request, provider.get_disabled_for_create_msg)
123 dd5f8f4d Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login'))
124 dd5f8f4d Kostas Papadimitriou
125 9d20fe23 Kostas Papadimitriou
    # TODO: this could be stored in session
126 9d20fe23 Kostas Papadimitriou
    # TODO: create a management command to clean old PendingThirdPartyUser
127 dd5f8f4d Kostas Papadimitriou
    user, created = PendingThirdPartyUser.objects.get_or_create(
128 dd5f8f4d Kostas Papadimitriou
        third_party_identifier=userid,
129 dd5f8f4d Kostas Papadimitriou
        provider=provider_module,
130 dd5f8f4d Kostas Papadimitriou
    )
131 9d20fe23 Kostas Papadimitriou
132 dd5f8f4d Kostas Papadimitriou
    # update pending user
133 dd5f8f4d Kostas Papadimitriou
    for param, value in pending_user_params.iteritems():
134 dd5f8f4d Kostas Papadimitriou
        setattr(user, param, value)
135 dd5f8f4d Kostas Papadimitriou
136 dd5f8f4d Kostas Papadimitriou
    user.info = json.dumps(provider_info)
137 dd5f8f4d Kostas Papadimitriou
    user.generate_token()
138 dd5f8f4d Kostas Papadimitriou
    user.save()
139 dd5f8f4d Kostas Papadimitriou
140 9d20fe23 Kostas Papadimitriou
    extra_context['provider'] = provider.module
141 9d20fe23 Kostas Papadimitriou
    extra_context['provider_title'] = provider.get_title_msg
142 dd5f8f4d Kostas Papadimitriou
    extra_context['token'] = user.token
143 dd5f8f4d Kostas Papadimitriou
    extra_context['signup_url'] = reverse('signup') + \
144 9d20fe23 Kostas Papadimitriou
        "?third_party_token=%s" % user.token
145 dd5f8f4d Kostas Papadimitriou
    extra_context['add_url'] = reverse('index') + \
146 9d20fe23 Kostas Papadimitriou
        "?key=%s#other-login-methods" % user.token
147 9d20fe23 Kostas Papadimitriou
    extra_context['can_create'] = provider.get_create_policy
148 9d20fe23 Kostas Papadimitriou
    extra_context['can_add'] = provider.get_add_policy
149 dd5f8f4d Kostas Papadimitriou
150 a148ae08 Kostas Papadimitriou
    return HttpResponseRedirect(extra_context['signup_url'])
151 c8d89a3c Kostas Papadimitriou
152 c8d89a3c Kostas Papadimitriou
153 9d20fe23 Kostas Papadimitriou
@transaction.commit_on_success
154 c8d89a3c Kostas Papadimitriou
def handle_third_party_login(request, provider_module, identifier,
155 0e79735c Kostas Papadimitriou
                             provider_info=None, affiliation=None,
156 0e79735c Kostas Papadimitriou
                             third_party_key=None):
157 c8d89a3c Kostas Papadimitriou
158 c8d89a3c Kostas Papadimitriou
    if not provider_info:
159 c8d89a3c Kostas Papadimitriou
        provider_info = {}
160 c8d89a3c Kostas Papadimitriou
161 c8d89a3c Kostas Papadimitriou
    if not affiliation:
162 c8d89a3c Kostas Papadimitriou
        affiliation = provider_module.title()
163 c8d89a3c Kostas Papadimitriou
164 830747d2 Kostas Papadimitriou
    next_redirect = request.GET.get('next', request.session.get('next_url',
165 830747d2 Kostas Papadimitriou
                                                                None))
166 c8d89a3c Kostas Papadimitriou
    if 'next_url' in request.session:
167 c8d89a3c Kostas Papadimitriou
        del request.session['next_url']
168 c8d89a3c Kostas Papadimitriou
169 0e79735c Kostas Papadimitriou
    third_party_request_params = get_third_party_session_params(request)
170 0e79735c Kostas Papadimitriou
    from_login = third_party_request_params.get('from_login', False)
171 9d20fe23 Kostas Papadimitriou
    switch_from = third_party_request_params.get('switch_from', False)
172 9d20fe23 Kostas Papadimitriou
    provider_data = {
173 9d20fe23 Kostas Papadimitriou
        'affiliation': affiliation,
174 9d20fe23 Kostas Papadimitriou
        'info': provider_info
175 9d20fe23 Kostas Papadimitriou
    }
176 830747d2 Kostas Papadimitriou
177 9d20fe23 Kostas Papadimitriou
    provider = auth.get_provider(provider_module, request.user, identifier,
178 9d20fe23 Kostas Papadimitriou
                                 **provider_data)
179 0e79735c Kostas Papadimitriou
180 c8d89a3c Kostas Papadimitriou
    # an existing user accessed the view
181 c8d89a3c Kostas Papadimitriou
    if request.user.is_authenticated():
182 9d20fe23 Kostas Papadimitriou
        if request.user.has_auth_provider(provider.module,
183 9d20fe23 Kostas Papadimitriou
                                          identifier=identifier):
184 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
185 c8d89a3c Kostas Papadimitriou
186 9d20fe23 Kostas Papadimitriou
        if provider.verified_exists():
187 97246b51 Kostas Papadimitriou
            provider.log("add failed (identifier exists to another user)")
188 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_add_exists_msg)
189 c8d89a3c Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
190 c8d89a3c Kostas Papadimitriou
191 c8d89a3c Kostas Papadimitriou
        # automatically add identifier provider to user
192 9d20fe23 Kostas Papadimitriou
        if not switch_from and not provider.get_add_policy:
193 c8d89a3c Kostas Papadimitriou
            # TODO: handle existing uuid message separately
194 97246b51 Kostas Papadimitriou
            provider.log("user cannot add provider")
195 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_add_failed_msg)
196 c8d89a3c Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
197 c8d89a3c Kostas Papadimitriou
198 9d20fe23 Kostas Papadimitriou
        user = request.user
199 9d20fe23 Kostas Papadimitriou
        if switch_from:
200 9d20fe23 Kostas Papadimitriou
            existing_provider = \
201 9d20fe23 Kostas Papadimitriou
                request.user.auth_providers.active().get(
202 9d20fe23 Kostas Papadimitriou
                    pk=int(switch_from), module=provider_module).settings
203 9d20fe23 Kostas Papadimitriou
204 9d20fe23 Kostas Papadimitriou
            # this is not a provider removal so we don't not use
205 9d20fe23 Kostas Papadimitriou
            # provider.remove_from_user. Use low level access to the provider
206 9d20fe23 Kostas Papadimitriou
            # db instance.
207 9d20fe23 Kostas Papadimitriou
            if not provider.verified_exists():
208 9d20fe23 Kostas Papadimitriou
                if provider.get_add_policy:
209 97246b51 Kostas Papadimitriou
                    existing_provider._instance.delete()
210 97246b51 Kostas Papadimitriou
                    existing_provider.log("removed")
211 9d20fe23 Kostas Papadimitriou
                    provider.add_to_user()
212 97246b51 Kostas Papadimitriou
                    provider.log("added")
213 9d20fe23 Kostas Papadimitriou
            else:
214 9d20fe23 Kostas Papadimitriou
                messages.error(request, provider.get_add_exists_msg)
215 97246b51 Kostas Papadimitriou
                return HttpResponseRedirect(reverse('edit_profile'))
216 97246b51 Kostas Papadimitriou
217 9d20fe23 Kostas Papadimitriou
            messages.success(request, provider.get_switch_success_msg)
218 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
219 9d20fe23 Kostas Papadimitriou
220 9d20fe23 Kostas Papadimitriou
        provider.add_to_user()
221 97246b51 Kostas Papadimitriou
        provider.log("added")
222 9d20fe23 Kostas Papadimitriou
        provider = user.get_auth_provider(provider_module, identifier)
223 9d20fe23 Kostas Papadimitriou
        messages.success(request, provider.get_added_msg)
224 c8d89a3c Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
225 c8d89a3c Kostas Papadimitriou
226 c8d89a3c Kostas Papadimitriou
    # astakos user exists ?
227 0e79735c Kostas Papadimitriou
    try:
228 0e79735c Kostas Papadimitriou
        user = AstakosUser.objects.get_auth_provider_user(
229 0e79735c Kostas Papadimitriou
            provider_module,
230 0e79735c Kostas Papadimitriou
            identifier=identifier,
231 0e79735c Kostas Papadimitriou
            user__email_verified=True,
232 0e79735c Kostas Papadimitriou
        )
233 0e79735c Kostas Papadimitriou
    except AstakosUser.DoesNotExist:
234 0e79735c Kostas Papadimitriou
        # TODO: add a message ? redirec to login ?
235 0e79735c Kostas Papadimitriou
        if astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN:
236 0e79735c Kostas Papadimitriou
            messages.warning(request,
237 0e79735c Kostas Papadimitriou
                             astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN)
238 0e79735c Kostas Papadimitriou
        raise
239 0e79735c Kostas Papadimitriou
240 0e79735c Kostas Papadimitriou
    if not third_party_key:
241 0e79735c Kostas Papadimitriou
        third_party_key = get_pending_key(request)
242 0e79735c Kostas Papadimitriou
243 9d20fe23 Kostas Papadimitriou
    provider = user.get_auth_provider(provider_module, identifier)
244 c8d89a3c Kostas Papadimitriou
    if user.is_active:
245 9d20fe23 Kostas Papadimitriou
        if not provider.get_login_policy:
246 9d20fe23 Kostas Papadimitriou
            messages.error(request, provider.get_login_disabled_msg)
247 9d20fe23 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('login'))
248 9d20fe23 Kostas Papadimitriou
249 c8d89a3c Kostas Papadimitriou
        # authenticate user
250 9d20fe23 Kostas Papadimitriou
        response = prepare_response(request, user, next_redirect,
251 9d20fe23 Kostas Papadimitriou
                                    'renew' in request.GET)
252 9d20fe23 Kostas Papadimitriou
253 9d20fe23 Kostas Papadimitriou
        messages.success(request, provider.get_login_success_msg)
254 9d20fe23 Kostas Papadimitriou
        add_pending_auth_provider(request, third_party_key, provider)
255 c8d89a3c Kostas Papadimitriou
        response.set_cookie('astakos_last_login_method', provider_module)
256 c8d89a3c Kostas Papadimitriou
        return response
257 c8d89a3c Kostas Papadimitriou
    else:
258 9d20fe23 Kostas Papadimitriou
        message = user.get_inactive_message(provider_module, identifier)
259 c8d89a3c Kostas Papadimitriou
        messages.error(request, message)
260 c8d89a3c Kostas Papadimitriou
        return HttpResponseRedirect(login_url(request))