local.py 6.1 KB
Newer Older
Antony Chazapis's avatar
Antony Chazapis committed
1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
#   1. Redistributions of source code must retain the above
#      copyright notice, this list of conditions and the following
#      disclaimer.
#
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

34
from django.http import HttpResponseBadRequest, HttpResponseRedirect
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
35
36
37
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth import authenticate
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
38
from django.contrib import messages
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
39
from django.utils.translation import ugettext as _
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
40
from django.views.decorators.csrf import csrf_exempt
41
from django.views.decorators.http import require_http_methods
42
from django.core.urlresolvers import reverse
43
from django.contrib.auth.decorators import login_required
44

45
from astakos.im.util import prepare_response, get_query
46
47
from astakos.im.views import requires_anonymous, signed_terms_required, \
        requires_auth_provider
48
from astakos.im.models import AstakosUser, PendingThirdPartyUser
49
50
51
52
53
from astakos.im.forms import LoginForm, ExtendedPasswordChangeForm, \
        ExtendedSetPasswordForm
from astakos.im.settings import (RATELIMIT_RETRIES_ALLOWED,
                                ENABLE_LOCAL_ACCOUNT_MIGRATION)
from astakos.im import settings
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
54
55
56
57
58

from ratelimit.decorators import ratelimit

retries = RATELIMIT_RETRIES_ALLOWED-1
rate = str(retries)+'/m'
59

60
@requires_auth_provider('local', login=True)
61
@require_http_methods(["GET", "POST"])
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
62
@csrf_exempt
63
@requires_anonymous
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
64
@ratelimit(field='username', method='POST', rate=rate)
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
65
def login(request, on_failure='im/login.html'):
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
66
    """
67
    on_failure: the template name to render on login failure
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
68
    """
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
69
70
    was_limited = getattr(request, 'limited', False)
    form = LoginForm(data=request.POST, was_limited=was_limited, request=request)
71
    next = get_query(request).get('next', '')
72
73
    third_party_token = get_query(request).get('key', False)

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
74
    if not form.is_valid():
75
76
77
78
        return render_to_response(
            on_failure,
            {'login_form':form,
             'next':next,
79
             'key': third_party_token},
80
81
            context_instance=RequestContext(request)
        )
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
82
83
    # get the user from the cash
    user = form.user_cache
84
    
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
85
    message = None
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
86
87
88
    if not user:
        message = _('Cannot authenticate account')
    elif not user.is_active:
89
        if not user.activation_sent:
90
91
            message = _('Your request is pending activation')
        else:
92
            url = reverse('send_activation', kwargs={'user_id':user.id})
93
94
95
96
97
98
99
100
            msg = _('You have not followed the activation link.')
            if settings.MODERATION_ENABLED:
                msg_extra = ' ' + _('Please contact support.')
            else:
                msg_extra = _('<a href="%s">Resend activation email?</a>') % url

            message = msg + msg_extra
    elif not user.can_login_with_auth_provider('local'):
101
102
103
        message = _(
            'Local login is not the current authentication method for this account.'
        )
104

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
105
    if message:
106
        messages.error(request, message)
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
107
        return render_to_response(on_failure,
108
                                  {'login_form': form},
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
109
                                  context_instance=RequestContext(request))
110
111
112
113
114

    response = prepare_response(request, user, next)
    if third_party_token:
        # use requests to assign the account he just authenticated with with
        # a third party provider account
115
        try:
116
117
118
119
120
121
          request.user.add_pending_auth_provider(third_party_token)
          messages.success(request, _('Your new login method has been added'))
        except PendingThirdPartyUser.DoesNotExist:
          messages.error(request, _('Account method assignment failed'))

    return response
122
123
124
125

@require_http_methods(["GET", "POST"])
@signed_terms_required
@login_required
126
@requires_auth_provider('local', login=True)
127
128
def password_change(request, template_name='registration/password_change_form.html',
                    post_change_redirect=None, password_change_form=ExtendedPasswordChangeForm):
129
130
131
132
133
134
135
136

    create_password = False

    # no local backend user wants to create a password
    if not request.user.has_auth_provider('local'):
        create_password = True
        password_change_form = ExtendedSetPasswordForm

137
    if post_change_redirect is None:
138
139
        post_change_redirect = reverse('edit_profile')

140
    if request.method == "POST":
141
        form_kwargs = dict(
142
143
144
            user=request.user,
            data=request.POST,
        )
145
146
147
148
        if not create_password:
            form_kwargs['session_key'] = session_key=request.session.session_key

        form = password_change_form(**form_kwargs)
149
150
151
152
153
154
155
156
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(post_change_redirect)
    else:
        form = password_change_form(user=request.user)
    return render_to_response(template_name, {
        'form': form,
    }, context_instance=RequestContext(request))