Django

Code

Changeset 8877

Show
Ignore:
Timestamp:
09/02/08 16:10:00 (10 months ago)
Author:
jacob
Message:

Security fix. Announcement forthcoming.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/0.91-bugfixes/django/contrib/admin/templates/admin/login.html

    r1068 r8877  
    1818<label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> 
    1919<input type="hidden" name="this_is_the_login_form" value="1" /> 
    20 <input type="hidden" name="post_data" value="{{ post_data }}" />{% comment %} <span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %} 
    2120</p> 
    2221 
  • django/branches/0.91-bugfixes/django/contrib/admin/views/decorators.py

    r7529 r8877  
    55from django.utils.html import escape 
    66from django.utils.translation import gettext_lazy 
    7 import base64, datetime, md5 
    8 import cPickle as pickle 
     7import base64, datetime 
    98 
    109ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") 
     
    1312def _display_login_form(request, error_message=''): 
    1413    request.session.set_test_cookie() 
    15     if request.POST and request.POST.has_key('post_data'): 
    16         # User has failed login BUT has previously saved post data. 
    17         post_data = request.POST['post_data'] 
    18     elif request.POST: 
    19         # User's session must have expired; save their post data. 
    20         post_data = _encode_post_data(request.POST) 
    21     else: 
    22         post_data = _encode_post_data({}) 
    2314    return render_to_response('admin/login', { 
    2415        'title': _('Log in'), 
    2516        'app_path': escape(request.path), 
    26         'post_data': post_data, 
    2717        'error_message': error_message 
    2818    }, context_instance=DjangoContext(request)) 
    29  
    30 def _encode_post_data(post_data): 
    31     pickled = pickle.dumps(post_data) 
    32     pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest() 
    33     return base64.encodestring(pickled + pickled_md5) 
    34  
    35 def _decode_post_data(encoded_data): 
    36     encoded_data = base64.decodestring(encoded_data) 
    37     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 
    38     if md5.new(pickled + SECRET_KEY).hexdigest() != tamper_check: 
    39         from django.core.exceptions import SuspiciousOperation 
    40         raise SuspiciousOperation, "User may have tampered with session cookie." 
    41     return pickle.loads(pickled) 
    4219 
    4320def staff_member_required(view_func): 
     
    4926        if not request.user.is_anonymous() and request.user.is_staff: 
    5027            # The user is valid. Continue to the admin page. 
    51             if request.POST.has_key('post_data'): 
    52                 # User must have re-authenticated through a different window 
    53                 # or tab. 
    54                 request.POST = _decode_post_data(request.POST['post_data']) 
    5528            return view_func(request, *args, **kwargs) 
    5629 
     
    6033        if not request.POST.has_key(LOGIN_FORM_KEY): 
    6134            if request.POST: 
    62                 message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") 
     35                message = _("Please log in again, because your session has expired.") 
    6336            else: 
    6437                message = "" 
     
    9265                user.last_login = datetime.datetime.now() 
    9366                user.save() 
    94                 if request.POST.has_key('post_data'): 
    95                     post_data = _decode_post_data(request.POST['post_data']) 
    96                     if post_data and not post_data.has_key(LOGIN_FORM_KEY): 
    97                         # overwrite request.POST with the saved post_data, and continue 
    98                         request.POST = post_data 
    99                         request.user = user 
    100                         return view_func(request, *args, **kwargs) 
    101                     else: 
    102                         request.session.delete_test_cookie() 
    103                         return httpwrappers.HttpResponseRedirect(request.path) 
     67                return httpwrappers.HttpResponseRedirect(request.path) 
    10468            else: 
    10569                return _display_login_form(request, ERROR_MESSAGE) 
  • django/branches/0.95-bugfixes/django/contrib/admin/templates/admin/login.html

    r3415 r8877  
    2020    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> 
    2121    <input type="hidden" name="this_is_the_login_form" value="1" /> 
    22     <input type="hidden" name="post_data" value="{{ post_data }}" /> {% comment %}<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>{% endcomment %} 
    2322  </div> 
    2423  <div class="submit-row"> 
  • django/branches/0.95-bugfixes/django/contrib/admin/views/decorators.py

    r7528 r8877  
    66from django.utils.html import escape 
    77from django.utils.translation import gettext_lazy 
    8 import base64, datetime, md5 
    9 import cPickle as pickle 
     8import base64, datetime 
    109 
    1110ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") 
     
    1413def _display_login_form(request, error_message=''): 
    1514    request.session.set_test_cookie() 
    16     if request.POST and request.POST.has_key('post_data'): 
    17         # User has failed login BUT has previously saved post data. 
    18         post_data = request.POST['post_data'] 
    19     elif request.POST: 
    20         # User's session must have expired; save their post data. 
    21         post_data = _encode_post_data(request.POST) 
    22     else: 
    23         post_data = _encode_post_data({}) 
    2415    return render_to_response('admin/login.html', { 
    2516        'title': _('Log in'), 
    2617        'app_path': escape(request.path), 
    27         'post_data': post_data, 
    2818        'error_message': error_message 
    2919    }, context_instance=template.RequestContext(request)) 
    30  
    31 def _encode_post_data(post_data): 
    32     pickled = pickle.dumps(post_data) 
    33     pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest() 
    34     return base64.encodestring(pickled + pickled_md5) 
    35  
    36 def _decode_post_data(encoded_data): 
    37     encoded_data = base64.decodestring(encoded_data) 
    38     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 
    39     if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: 
    40         from django.core.exceptions import SuspiciousOperation 
    41         raise SuspiciousOperation, "User may have tampered with session cookie." 
    42     return pickle.loads(pickled) 
    4320 
    4421def staff_member_required(view_func): 
     
    5027        if request.user.is_authenticated() and request.user.is_staff: 
    5128            # The user is valid. Continue to the admin page. 
    52             if request.POST.has_key('post_data'): 
    53                 # User must have re-authenticated through a different window 
    54                 # or tab. 
    55                 request.POST = _decode_post_data(request.POST['post_data']) 
    5629            return view_func(request, *args, **kwargs) 
    5730 
     
    6134        if not request.POST.has_key(LOGIN_FORM_KEY): 
    6235            if request.POST: 
    63                 message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") 
     36                message = _("Please log in again, because your session has expired.") 
    6437            else: 
    6538                message = "" 
     
    9467                user.last_login = datetime.datetime.now() 
    9568                user.save() 
    96                 if request.POST.has_key('post_data'): 
    97                     post_data = _decode_post_data(request.POST['post_data']) 
    98                     if post_data and not post_data.has_key(LOGIN_FORM_KEY): 
    99                         # overwrite request.POST with the saved post_data, and continue 
    100                         request.POST = post_data 
    101                         request.user = user 
    102                         return view_func(request, *args, **kwargs) 
    103                     else: 
    104                         request.session.delete_test_cookie() 
    105                         return http.HttpResponseRedirect(request.path) 
     69                return http.HttpResponseRedirect(request.path) 
    10670            else: 
    10771                return _display_login_form(request, ERROR_MESSAGE) 
  • django/branches/0.96-bugfixes/django/contrib/admin/templates/admin/login.html

    r3931 r8877  
    2020    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> 
    2121    <input type="hidden" name="this_is_the_login_form" value="1" /> 
    22     <input type="hidden" name="post_data" value="{{ post_data }}" /> {#<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>#} 
    2322  </div> 
    2423  <div class="submit-row"> 
  • django/branches/0.96-bugfixes/django/contrib/admin/views/decorators.py

    r7527 r8877  
    66from django.utils.html import escape 
    77from django.utils.translation import gettext_lazy 
    8 import base64, datetime, md5 
    9 import cPickle as pickle 
     8import base64, datetime 
    109 
    1110ERROR_MESSAGE = gettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") 
     
    1413def _display_login_form(request, error_message=''): 
    1514    request.session.set_test_cookie() 
    16     if request.POST and request.POST.has_key('post_data'): 
    17         # User has failed login BUT has previously saved post data. 
    18         post_data = request.POST['post_data'] 
    19     elif request.POST: 
    20         # User's session must have expired; save their post data. 
    21         post_data = _encode_post_data(request.POST) 
    22     else: 
    23         post_data = _encode_post_data({}) 
    2415    return render_to_response('admin/login.html', { 
    2516        'title': _('Log in'), 
    2617        'app_path': escape(request.path), 
    27         'post_data': post_data, 
    2818        'error_message': error_message 
    2919    }, context_instance=template.RequestContext(request)) 
    30  
    31 def _encode_post_data(post_data): 
    32     pickled = pickle.dumps(post_data) 
    33     pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest() 
    34     return base64.encodestring(pickled + pickled_md5) 
    35  
    36 def _decode_post_data(encoded_data): 
    37     encoded_data = base64.decodestring(encoded_data) 
    38     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 
    39     if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: 
    40         from django.core.exceptions import SuspiciousOperation 
    41         raise SuspiciousOperation, "User may have tampered with session cookie." 
    42     return pickle.loads(pickled) 
    4320 
    4421def staff_member_required(view_func): 
     
    5027        if request.user.is_authenticated() and request.user.is_staff: 
    5128            # The user is valid. Continue to the admin page. 
    52             if request.POST.has_key('post_data'): 
    53                 # User must have re-authenticated through a different window 
    54                 # or tab. 
    55                 request.POST = _decode_post_data(request.POST['post_data']) 
    5629            return view_func(request, *args, **kwargs) 
    5730 
     
    6134        if not request.POST.has_key(LOGIN_FORM_KEY): 
    6235            if request.POST: 
    63                 message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") 
     36                message = _("Please log in again, because your session has expired.") 
    6437            else: 
    6538                message = "" 
     
    9467                user.last_login = datetime.datetime.now() 
    9568                user.save() 
    96                 if request.POST.has_key('post_data'): 
    97                     post_data = _decode_post_data(request.POST['post_data']) 
    98                     if post_data and not post_data.has_key(LOGIN_FORM_KEY): 
    99                         # overwrite request.POST with the saved post_data, and continue 
    100                         request.POST = post_data 
    101                         request.user = user 
    102                         return view_func(request, *args, **kwargs) 
    103                     else: 
    104                         request.session.delete_test_cookie() 
    105                         return http.HttpResponseRedirect(request.path) 
     69                return http.HttpResponseRedirect(request.path) 
    10670            else: 
    10771                return _display_login_form(request, ERROR_MESSAGE) 
  • django/trunk/django/contrib/admin/sites.py

    r8679 r8877  
    11import base64 
    2 import cPickle as pickle 
    32import re 
    4  
    53from django import http, template 
    64from django.contrib.admin import ModelAdmin 
     
    2523    pass 
    2624 
    27 def _encode_post_data(post_data): 
    28     pickled = pickle.dumps(post_data) 
    29     pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest() 
    30     return base64.encodestring(pickled + pickled_md5) 
    31  
    32 def _decode_post_data(encoded_data): 
    33     encoded_data = base64.decodestring(encoded_data) 
    34     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 
    35     if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: 
    36         from django.core.exceptions import SuspiciousOperation 
    37         raise SuspiciousOperation, "User may have tampered with session cookie." 
    38     return pickle.loads(pickled) 
    39  
    4025class AdminSite(object): 
    4126    """ 
     
    240225        if not request.POST.has_key(LOGIN_FORM_KEY): 
    241226            if request.POST: 
    242                 message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") 
     227                message = _("Please log in again, because your session has expired.") 
    243228            else: 
    244229                message = "" 
     
    276261            if user.is_active and user.is_staff: 
    277262                login(request, user) 
    278                 if request.POST.has_key('post_data'): 
    279                     post_data = _decode_post_data(request.POST['post_data']) 
    280                     if post_data and not post_data.has_key(LOGIN_FORM_KEY): 
    281                         # overwrite request.POST with the saved post_data, and continue 
    282                         request.POST = post_data 
    283                         request.user = user 
    284                         return self.root(request, request.path.split(self.root_path)[-1]) 
    285                     else: 
    286                         return http.HttpResponseRedirect(request.get_full_path()) 
     263                return http.HttpResponseRedirect(request.get_full_path()) 
    287264            else: 
    288265                return self.display_login_form(request, ERROR_MESSAGE) 
     
    346323    def display_login_form(self, request, error_message='', extra_context=None): 
    347324        request.session.set_test_cookie() 
    348         if request.POST and request.POST.has_key('post_data'): 
    349             # User has failed login BUT has previously saved post data. 
    350             post_data = request.POST['post_data'] 
    351         elif request.POST: 
    352             # User's session must have expired; save their post data. 
    353             post_data = _encode_post_data(request.POST) 
    354         else: 
    355             post_data = _encode_post_data({}) 
    356  
    357325        context = { 
    358326            'title': _('Log in'), 
    359327            'app_path': request.get_full_path(), 
    360             'post_data': post_data, 
    361328            'error_message': error_message, 
    362329            'root_path': self.root_path, 
  • django/trunk/django/contrib/admin/templates/admin/login.html

    r7967 r8877  
    2222    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" /> 
    2323    <input type="hidden" name="this_is_the_login_form" value="1" /> 
    24     <input type="hidden" name="post_data" value="{{ post_data }}" /> {#<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>#} 
    2524  </div> 
    2625  <div class="submit-row"> 
  • django/trunk/django/contrib/admin/views/decorators.py

    r8509 r8877  
    11import base64 
    2 import cPickle as pickle 
    32try: 
    43    from functools import wraps 
     
    1211from django.shortcuts import render_to_response 
    1312from django.utils.translation import ugettext_lazy, ugettext as _ 
    14 from django.utils.hashcompat import md5_constructor 
    1513 
    1614ERROR_MESSAGE = ugettext_lazy("Please enter a correct username and password. Note that both fields are case-sensitive.") 
     
    1917def _display_login_form(request, error_message=''): 
    2018    request.session.set_test_cookie() 
    21     if request.POST and 'post_data' in request.POST: 
    22         # User has failed login BUT has previously saved post data. 
    23         post_data = request.POST['post_data'] 
    24     elif request.POST: 
    25         # User's session must have expired; save their post data. 
    26         post_data = _encode_post_data(request.POST) 
    27     else: 
    28         post_data = _encode_post_data({}) 
    2919    return render_to_response('admin/login.html', { 
    3020        'title': _('Log in'), 
    3121        'app_path': request.get_full_path(), 
    32         'post_data': post_data, 
    3322        'error_message': error_message 
    3423    }, context_instance=template.RequestContext(request)) 
    35  
    36 def _encode_post_data(post_data): 
    37     pickled = pickle.dumps(post_data) 
    38     pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest() 
    39     return base64.encodestring(pickled + pickled_md5) 
    40  
    41 def _decode_post_data(encoded_data): 
    42     encoded_data = base64.decodestring(encoded_data) 
    43     pickled, tamper_check = encoded_data[:-32], encoded_data[-32:] 
    44     if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check: 
    45         from django.core.exceptions import SuspiciousOperation 
    46         raise SuspiciousOperation, "User may have tampered with session cookie." 
    47     return pickle.loads(pickled) 
    4824 
    4925def staff_member_required(view_func): 
     
    5531        if request.user.is_authenticated() and request.user.is_staff: 
    5632            # The user is valid. Continue to the admin page. 
    57             if 'post_data' in request.POST: 
    58                 # User must have re-authenticated through a different window 
    59                 # or tab. 
    60                 request.POST = _decode_post_data(request.POST['post_data']) 
    6133            return view_func(request, *args, **kwargs) 
    6234 
     
    6638        if LOGIN_FORM_KEY not in request.POST: 
    6739            if request.POST: 
    68                 message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") 
     40                message = _("Please log in again, because your session has expired.") 
    6941            else: 
    7042                message = "" 
     
    9971            if user.is_active and user.is_staff: 
    10072                login(request, user) 
    101                 # TODO: set last_login with an event. 
    102                 if 'post_data' in request.POST: 
    103                     post_data = _decode_post_data(request.POST['post_data']) 
    104                     if post_data and LOGIN_FORM_KEY not in post_data: 
    105                         # overwrite request.POST with the saved post_data, and continue 
    106                         request.POST = post_data 
    107                         request.user = user 
    108                         return view_func(request, *args, **kwargs) 
    109                     else: 
    110                         return http.HttpResponseRedirect(request.get_full_path()) 
     73                return http.HttpResponseRedirect(request.get_full_path()) 
    11174            else: 
    11275                return _display_login_form(request, ERROR_MESSAGE) 
  • django/trunk/tests/regressiontests/admin_views/tests.py

    r8704 r8877  
    55from django.contrib.contenttypes.models import ContentType 
    66from django.contrib.admin.models import LogEntry 
    7 from django.contrib.admin.sites import LOGIN_FORM_KEY, _encode_post_data 
     7from django.contrib.admin.sites import LOGIN_FORM_KEY 
    88from django.contrib.admin.util import quote 
    99from django.utils.html import escape 
     
    137137 
    138138        # login POST dicts 
    139         self.super_login = {'post_data': _encode_post_data({}), 
     139        self.super_login = { 
    140140                     LOGIN_FORM_KEY: 1, 
    141141                     'username': 'super', 
    142142                     'password': 'secret'} 
    143         self.super_email_login = {'post_data': _encode_post_data({}), 
     143        self.super_email_login = { 
    144144                     LOGIN_FORM_KEY: 1, 
    145145                     'username': 'super@example.com', 
    146146                     'password': 'secret'} 
    147         self.super_email_bad_login = {'post_data': _encode_post_data({}), 
     147        self.super_email_bad_login = { 
    148148                      LOGIN_FORM_KEY: 1, 
    149149                      'username': 'super@example.com', 
    150150                      'password': 'notsecret'} 
    151         self.adduser_login = {'post_data': _encode_post_data({}), 
     151        self.adduser_login = { 
    152152                     LOGIN_FORM_KEY: 1, 
    153153                     'username': 'adduser', 
    154154                     'password': 'secret'} 
    155         self.changeuser_login = {'post_data': _encode_post_data({}), 
     155        self.changeuser_login = { 
    156156                     LOGIN_FORM_KEY: 1, 
    157157                     'username': 'changeuser', 
    158158                     'password': 'secret'} 
    159         self.deleteuser_login = {'post_data': _encode_post_data({}), 
     159        self.deleteuser_login = { 
    160160                     LOGIN_FORM_KEY: 1, 
    161161                     'username': 'deleteuser', 
    162162                     'password': 'secret'} 
    163         self.joepublic_login = {'post_data': _encode_post_data({}), 
     163        self.joepublic_login = { 
    164164                     LOGIN_FORM_KEY: 1, 
    165165                     'username': 'joepublic', 
     
    272272        self.client.get('/test_admin/admin/logout/') 
    273273 
    274         # Check and make sure that if user expires, data still persists 
    275         post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) 
    276         self.assertContains(post, 'Please log in again, because your session has expired.') 
    277         self.super_login['post_data'] = _encode_post_data(add_dict) 
    278         post = self.client.post('/test_admin/admin/admin_views/article/add/', self.super_login) 
    279         # make sure the view removes test cookie 
    280         self.failUnlessEqual(self.client.session.test_cookie_worked(), False) 
    281         self.assertRedirects(post, '/test_admin/admin/admin_views/article/') 
    282         self.failUnlessEqual(Article.objects.all().count(), 4) 
    283         self.client.get('/test_admin/admin/logout/') 
    284  
    285274        # 8509 - if a normal user is already logged in, it is possible 
    286275        # to change user into the superuser without error 
     
    490479    def setUp(self): 
    491480        # login POST dicts 
    492         self.super_login = {'post_data': _encode_post_data({}), 
     481        self.super_login = { 
    493482                     LOGIN_FORM_KEY: 1, 
    494483                     'username': 'super', 
    495484                     'password': 'secret'} 
    496         self.super_email_login = {'post_data': _encode_post_data({}), 
     485        self.super_email_login = { 
    497486                     LOGIN_FORM_KEY: 1, 
    498487                     'username': 'super@example.com', 
    499488                     'password': 'secret'} 
    500         self.super_email_bad_login = {'post_data': _encode_post_data({}), 
     489        self.super_email_bad_login = { 
    501490                      LOGIN_FORM_KEY: 1, 
    502491                      'username': 'super@example.com', 
    503492                      'password': 'notsecret'} 
    504         self.adduser_login = {'post_data': _encode_post_data({}), 
     493        self.adduser_login = { 
    505494                     LOGIN_FORM_KEY: 1, 
    506495                     'username': 'adduser', 
    507496                     'password': 'secret'} 
    508         self.changeuser_login = {'post_data': _encode_post_data({}), 
     497        self.changeuser_login = { 
    509498                     LOGIN_FORM_KEY: 1, 
    510499                     'username': 'changeuser', 
    511500                     'password': 'secret'} 
    512         self.deleteuser_login = {'post_data': _encode_post_data({}), 
     501        self.deleteuser_login = { 
    513502                     LOGIN_FORM_KEY: 1, 
    514503                     'username': 'deleteuser', 
    515504                     'password': 'secret'} 
    516         self.joepublic_login = {'post_data': _encode_post_data({}), 
     505        self.joepublic_login = { 
    517506                     LOGIN_FORM_KEY: 1, 
    518507                     'username': 'joepublic', 
     
    598587        self.assert_(login.context[0].get('error_message')) 
    599588 
    600         # Check and make sure that if user expires, data still persists 
    601         data = {'foo': 'bar'} 
    602         post = self.client.post('/test_admin/admin/secure-view/', data) 
    603         self.assertContains(post, 'Please log in again, because your session has expired.') 
    604         self.super_login['post_data'] = _encode_post_data(data) 
    605         post = self.client.post('/test_admin/admin/secure-view/', self.super_login) 
    606         # make sure the view removes test cookie 
    607         self.failUnlessEqual(self.client.session.test_cookie_worked(), False) 
    608         self.assertContains(post, "{'foo': 'bar'}") 
    609         self.client.get('/test_admin/admin/logout/') 
    610                  
    611589        # 8509 - if a normal user is already logged in, it is possible 
    612590        # to change user into the superuser without error