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 from django.views.auth.login import logout 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. Same goes for the logout # view. if view_func in (passwords.password_reset, passwords.password_reset_done, logout): 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)