summaryrefslogtreecommitdiff
path: root/django/middleware/admin.py
blob: 0a0a76201a4d8f01585e43775f530d193a42f949 (plain)
1
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from django.utils import httpwrappers
from django.core import template_loader
from django.core.extensions import DjangoContext as Context
from django.models.auth import sessions, users
from django.views.registration import passwords
import base64, md5
import cPickle as pickle

# secret used in pickled data to guard against tampering
TAMPER_SECRET = '09VJWE9_RIZZO_j0jwfe09j'

ERROR_MESSAGE = "Please enter a correct username and password. Note that both fields are case-sensitive."

class AdminUserRequired:
    """
    Admin middleware.  If this is enabled, access to the site will be granted only
    to valid users with the "is_staff" flag set.
    """

    def process_view(self, request, view_func, param_dict):
        """
        Make sure the user is logged in and is a valid admin user before
        allowing any access.

        Done at the view point because we need to know if we're running the
        password reset function.
        """

        # If this is the password reset view, we don't want to require login
        # Otherwise the password reset would need its own entry in the httpd
        # conf, which is a little uglier than this.
        if view_func == passwords.password_reset or view_func == passwords.password_reset_done:
            return

        # Check for a logged in, valid user
        if self.user_is_valid(request.user):
            return

        # If this isn't alreay the login page, display it
        if not request.POST.has_key('this_is_the_login_form'):
            if request.POST:
                message = "Please log in again, because your session has expired. "\
                          "Don't worry: Your submission has been saved."
            else:
                message = ""
            return self.display_login_form(request, message)

        # Check the password
        username = request.POST.get('username', '')
        try:
            user = users.get_object(username__exact=username)
        except users.UserDoesNotExist:
            message = ERROR_MESSAGE
            if '@' in username:
                # Mistakenly entered e-mail address instead of username? Look it up.
                try:
                    user = users.get_object(email__exact=username)
                except users.UserDoesNotExist:
                    message = "Usernames cannot contain the '@' character."
                else:
                    message = "Your e-mail address is not your username. Try '%s' instead." % user.username
            return self.display_login_form(request, message)

        # The user data is correct; log in the user in and continue
        else:
            if self.authenticate_user(user, request.POST.get('password', '')):
                if request.POST.has_key('post_data'):
                    post_data = decode_post_data(request.POST['post_data'])
                    if post_data and not post_data.has_key('this_is_the_login_form'):
                        # overwrite request.POST with the saved post_data, and continue
                        request.POST = post_data
                        request.user = user
                        request.session = sessions.create_session(user.id)
                        return
                    else:
                        response = httpwrappers.HttpResponseRedirect(request.path)
                        sessions.start_web_session(user.id, request, response)
                        return response
            else:
                return self.display_login_form(request, ERROR_MESSAGE)

    def display_login_form(self, request, error_message=''):
        if request.POST and request.POST.has_key('post_data'):
            # User has failed login BUT has previously saved 'post_data'
            post_data = request.POST['post_data']
        elif request.POST:
            # User's session must have expired; save their post data
            post_data = encode_post_data(request.POST)
        else:
            post_data = encode_post_data({})
        t = template_loader.get_template(self.get_login_template_name())
        c = Context(request, {
            'title': 'Log in',
            'app_path': request.path,
            'post_data': post_data,
            'error_message': error_message
        })
        return httpwrappers.HttpResponse(t.render(c))

    def authenticate_user(self, user, password):
        return user.check_password(password) and user.is_staff

    def user_is_valid(self, user):
        return not user.is_anonymous() and user.is_staff

    def get_login_template_name(self):
        return "login"

def encode_post_data(post_data):
    pickled = pickle.dumps(post_data)
    pickled_md5 = md5.new(pickled + TAMPER_SECRET).hexdigest()
    return base64.encodestring(pickled + pickled_md5)

def decode_post_data(encoded_data):
    encoded_data = base64.decodestring(encoded_data)
    pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
    if md5.new(pickled + TAMPER_SECRET).hexdigest() != tamper_check:
        from django.core.exceptions import SuspiciousOperation
        raise SuspiciousOperation, "User may have tampered with session cookie."
    return pickle.loads(pickled)