django1/django/middleware/admin.py

119 lines
5.0 KiB
Python

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
from django.conf.settings import SECRET_KEY
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 + SECRET_KEY).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 + SECRET_KEY).hexdigest() != tamper_check:
from django.core.exceptions import SuspiciousOperation
raise SuspiciousOperation, "User may have tampered with session cookie."
return pickle.loads(pickled)