Ticket #215: paste.diff

File paste.diff, 9.8 KB (added by catlee, 4 years ago)
  • paste/auth/auth_tkt.py

    diff -urN -x '*.pyc' paste-1.5.1.orig/paste/auth/auth_tkt.py paste/paste/auth/auth_tkt.py
    old new  
    216216        The path under this middleware that should signify a logout.  The 
    217217        page will be shown as usual, but the user will also be logged out 
    218218        when they visit this page. 
     219 
     220    ``timeout``: 
     221        How many seconds before the cookie is considered invalid.  Default 
     222        is None (never timeout) 
     223 
     224    ``refresh``: 
     225        A number between 0 and 1 representing the number of seconds (as 
     226        a fraction of ``timeout``) after which a valid cookie is refreshed. 
     227        Set to 0 to never refresh (the default) 
     228        Set to 1 to always refresh 
     229        Set to 0.33 to refresh the cookie after 0.33 * ``timeout`` seconds 
    219230         
    220231    If used with mod_auth_tkt, then these settings (except logout_path) should  
    221232    match the analogous Apache configuration settings. 
     
    234245    """ 
    235246 
    236247    def __init__(self, app, secret, cookie_name='auth_tkt', secure=False, 
    237                  include_ip=True, logout_path=None): 
     248                 include_ip=True, logout_path=None, timeout=None, 
     249                 refresh=0): 
    238250        self.app = app 
    239251        self.secret = secret 
    240252        self.cookie_name = cookie_name 
    241253        self.secure = secure 
    242254        self.include_ip = include_ip 
    243255        self.logout_path = logout_path 
     256        self.timeout = timeout 
     257        self.refresh = float(refresh) 
    244258 
    245259    def __call__(self, environ, start_response): 
     260        set_cookies = [] 
     261        def set_user(userid, tokens='', user_data=''): 
     262            set_cookies.extend(self.set_user_cookie( 
     263                environ, userid, tokens, user_data)) 
     264        def logout_user(): 
     265            set_cookies.extend(self.logout_user_cookie(environ)) 
     266        environ['paste.auth_tkt.set_user'] = set_user 
     267        environ['paste.auth_tkt.logout_user'] = logout_user 
     268 
     269        def cookie_setting_start_response(status, headers, exc_info=None): 
     270            headers.extend(set_cookies) 
     271            return start_response(status, headers, exc_info) 
     272 
    246273        cookies = request.get_cookies(environ) 
    247274        if cookies.has_key(self.cookie_name): 
    248275            cookie_value = cookies[self.cookie_name].value 
    249276        else: 
    250277            cookie_value = '' 
     278 
     279        if self.logout_path and environ.get('PATH_INFO') == self.logout_path: 
     280            logout_user() 
     281 
    251282        if cookie_value: 
    252283            if self.include_ip: 
    253284                remote_addr = environ['REMOTE_ADDR'] 
     
    256287                # checked: 
    257288                remote_addr = '0.0.0.0' 
    258289            # @@: This should handle bad signatures better: 
    259             # Also, timeouts should cause cookie refresh 
    260290            timestamp, userid, tokens, user_data = parse_ticket( 
    261291                self.secret, cookie_value, remote_addr) 
    262             tokens = ','.join(tokens) 
    263             environ['REMOTE_USER'] = userid 
    264             if environ.get('REMOTE_USER_TOKENS'): 
    265                 # We want to add tokens/roles to what's there: 
    266                 tokens = environ['REMOTE_USER_TOKENS'] + ',' + tokens 
    267             environ['REMOTE_USER_TOKENS'] = tokens 
    268             environ['REMOTE_USER_DATA'] = user_data 
    269             environ['AUTH_TYPE'] = 'cookie' 
    270         set_cookies = [] 
    271         def set_user(userid, tokens='', user_data=''): 
    272             set_cookies.extend(self.set_user_cookie( 
    273                 environ, userid, tokens, user_data)) 
    274         def logout_user(): 
    275             set_cookies.extend(self.logout_user_cookie(environ)) 
    276         environ['paste.auth_tkt.set_user'] = set_user 
    277         environ['paste.auth_tkt.logout_user'] = logout_user 
    278         if self.logout_path and environ.get('PATH_INFO') == self.logout_path: 
    279             logout_user() 
    280         def cookie_setting_start_response(status, headers, exc_info=None): 
    281             headers.extend(set_cookies) 
    282             return start_response(status, headers, exc_info) 
     292            # Check the timestamp 
     293            now = time_mod.time() 
     294            if self.timeout is None or timestamp + self.timeout > now: 
     295                cookieTokens = ','.join(tokens) 
     296                environ['REMOTE_USER'] = userid 
     297                if environ.get('REMOTE_USER_TOKENS'): 
     298                    # We want to add tokens/roles to what's there: 
     299                    tokens = environ['REMOTE_USER_TOKENS'] + ',' + cookieTokens 
     300                environ['REMOTE_USER_TOKENS'] = tokens 
     301                environ['REMOTE_USER_DATA'] = user_data 
     302                environ['AUTH_TYPE'] = 'cookie' 
     303                # Refresh the cookie if necessary 
     304                if self.timeout is not None: 
     305                    elapsed = now - timestamp 
     306                    if elapsed > (self.refresh * self.timeout): 
     307                        set_user(userid, cookieTokens, user_data) 
     308            else: 
     309                # The cookie expired 
     310                pass 
     311 
    283312        return self.app(environ, cookie_setting_start_response) 
    284313 
    285314    def set_user_cookie(self, environ, userid, tokens, user_data): 
     
    323352    cookie_name='auth_tkt', 
    324353    secure=False, 
    325354    include_ip=True, 
    326     logout_path=None): 
     355    logout_path=None, 
     356    timeout=None, 
     357    refresh=0): 
    327358    """ 
    328359    Creates the `AuthTKTMiddleware 
    329360    <class-paste.auth.auth_tkt.AuthTKTMiddleware.html>`_. 
     
    339370        raise ValueError( 
    340371            "You must provide a 'secret' (in global or local configuration)") 
    341372    return AuthTKTMiddleware( 
    342         app, secret, cookie_name, secure, include_ip, logout_path or None) 
     373        app, secret, cookie_name, secure, include_ip, logout_path or None, 
     374        timeout, refresh) 
  • tests/test_auth/test_auth_tkt.py

    diff -urN -x '*.pyc' paste-1.5.1.orig/tests/test_auth/test_auth_tkt.py paste/tests/test_auth/test_auth_tkt.py
    old new  
     1# (c) 2007 Chris AtLee 
     2# This module is part of the Python Paste Project and is released under 
     3# the MIT License: http://www.opensource.org/licenses/mit-license.php 
     4 
     5from paste.auth.auth_tkt import * 
     6from paste.wsgilib import raw_interactive, dump_environ 
     7from paste.response import header_value 
     8from paste.httpexceptions import * 
     9import os 
     10 
     11import py.test 
     12import time as time_mod 
     13 
     14secret = "s3krit" 
     15 
     16def test_noop(): 
     17    app = AuthTKTMiddleware(dump_environ, secret) 
     18 
     19    (status, headers, content, errors) = \ 
     20            raw_interactive(app) 
     21 
     22    value = header_value(headers, 'Set-Cookie') 
     23    assert value is None 
     24 
     25def test_basic(): 
     26    app = AuthTKTMiddleware(dump_environ, secret) 
     27 
     28    tkt = AuthTicket(secret, 'catlee', '0.0.0.0') 
     29 
     30    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     31 
     32    (status, headers, content, errors) = \ 
     33            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     34 
     35    assert "REMOTE_USER: catlee" in content 
     36 
     37def test_ipcheck(): 
     38    app = AuthTKTMiddleware(dump_environ, secret) 
     39 
     40    tkt = AuthTicket(secret, 'catlee', '0.0.0.1') 
     41 
     42    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     43 
     44    py.test.raises(BadTicket, 
     45            raw_interactive, app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     46 
     47def test_cookiename(): 
     48    app = AuthTKTMiddleware(dump_environ, secret, cookie_name = "secret") 
     49 
     50    tkt = AuthTicket(secret, 'catlee', '0.0.0.0') 
     51 
     52    cookie = "%s=%s" % ("secret", tkt.cookie_value()) 
     53 
     54    (status, headers, content, errors) = \ 
     55            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     56 
     57    assert "REMOTE_USER: catlee" in content 
     58 
     59def test_logout(): 
     60    app = AuthTKTMiddleware(dump_environ, secret, logout_path="/logout") 
     61 
     62    (status, headers, content, errors) = \ 
     63            raw_interactive(app, "/logout") 
     64 
     65    value = header_value(headers, 'Set-Cookie') 
     66    assert value is not None 
     67 
     68def test_nologout(): 
     69    app = AuthTKTMiddleware(dump_environ, secret, logout_path="/logout") 
     70 
     71    (status, headers, content, errors) = \ 
     72            raw_interactive(app, "/dontlogout") 
     73 
     74    value = header_value(headers, 'Set-Cookie') 
     75    assert value is None 
     76 
     77def test_notimeout(): 
     78    app = AuthTKTMiddleware(dump_environ, secret, timeout=60) 
     79 
     80    now = time_mod.time() 
     81 
     82    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now) 
     83    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     84 
     85    (status, headers, content, errors) = \ 
     86            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     87 
     88    assert "REMOTE_USER: catlee" in content 
     89 
     90def test_timeout(): 
     91    app = AuthTKTMiddleware(dump_environ, secret, timeout=60) 
     92 
     93    now = time_mod.time() 
     94 
     95    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-120) 
     96    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     97 
     98    (status, headers, content, errors) = \ 
     99            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     100 
     101    assert "REMOTE_USER: catlee" not in content 
     102 
     103def test_refresh(): 
     104    app = AuthTKTMiddleware(dump_environ, secret, timeout=60, refresh=0.5) 
     105 
     106    now = time_mod.time() 
     107 
     108    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-40) 
     109    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     110 
     111    (status, headers, content, errors) = \ 
     112            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     113 
     114    value = header_value(headers, 'Set-Cookie') 
     115    assert value is not None 
     116 
     117def test_norefresh(): 
     118    app = AuthTKTMiddleware(dump_environ, secret, timeout=60, refresh=0.5) 
     119 
     120    now = time_mod.time() 
     121 
     122    tkt = AuthTicket(secret, 'catlee', '0.0.0.0', time=now-20) 
     123    cookie = "%s=%s" % ("auth_tkt", tkt.cookie_value()) 
     124 
     125    (status, headers, content, errors) = \ 
     126            raw_interactive(app, HTTP_COOKIE=cookie, REMOTE_ADDR="0.0.0.0") 
     127 
     128    value = header_value(headers, 'Set-Cookie') 
     129    assert value is None