Latest Version: 0.9.6.2
/Users/bbangert/Programming/Python/pylons/pylons/decorators/secure.py
0001"""Security related decorators"""
0002import logging
0003
0004from decorator import decorator
0005from webhelpers.rails import secure_form_tag
0006
0007import pylons
0008from pylons.controllers.util import abort, redirect_to
0009
0010__all__ = ['authenticate_form', 'https']
0011
0012log = logging.getLogger(__name__)
0013
0014csrf_detected_message = (
0015    "Cross-site request forgery detected, request denied. See "
0016    "http://en.wikipedia.org/wiki/Cross-site_request_forgery for more "
0017    "information.")
0018
0019def authenticated_form(params):
0020    submitted_token = params.get(secure_form_tag.token_key)
0021    return submitted_token is not None and           submitted_token == secure_form_tag.authentication_token()
0023
0024def authenticate_form(func, *args, **kwargs):
0025    """Decorator for authenticating a form according to an authorization token
0026    stored in the client's session. For prevention of certain Cross-site
0027    request forgery (CSRF) attacks (See
0028    http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
0029    information).
0030
0031    For use with the ``webhelpers.rails.secure_form_tag`` helper functions.
0032    """
0033    request = pylons.request._current_obj()
0034    if authenticated_form(request.POST):
0035        del request.POST[secure_form_tag.token_key]
0036        return func(*args, **kwargs)
0037    else:
0038        log.debug('Cross-site request forgery detected, request denied: %r' %
0039                  request)
0040        abort(403, detail=csrf_detected_message)
0041authenticate_form = decorator(authenticate_form)
0042
0043def https(*redirect_args, **redirect_kwargs):
0044    """Decorator to redirect to the SSL version of a page if not currently
0045    using HTTPS. Takes as arguments the parameters to pass to redirect_to.
0046    (Specify no arguments necessary to redirect the current page).  Apply this
0047    decorator to controller methods (actions).
0048
0049    Non-https POST requests are aborted (405 response code) by this decorator.
0050
0051    Example:
0052
0053    .. code-block: Python
0054
0055        @https('/pylons') # redirect to HTTPS /pylons
0056        def index(self):
0057            #...
0058
0059        # redirect to HTTPS /auth/login
0060        @https(controller='auth', action='login')
0061        def login(self):
0062            #...
0063
0064        @https() # redirect to HTTPS version of myself
0065        def get(self):
0066            #...
0067    """
0068    def wrapper(func, *args, **kwargs):
0069        """Decorator Wrapper function"""
0070        request = pylons.request._current_obj()
0071        if request.scheme.lower() == 'https':
0072            return func(*args, **kwargs)
0073        else:
0074            if request.method.upper() != 'POST':
0075                redirect_kwargs['protocol'] = 'https' # ensure https
0076                log.debug('Redirecting non-https request: %s to redirect '
0077                          'args: *%r, **%r', request.path_info, redirect_args,
0078                          redirect_kwargs)
0079                redirect_to(*redirect_args, **redirect_kwargs)
0080            else:
0081                abort(405, headers=[('Allow', 'GET')]) # don't allow POSTs.
0082    return decorator(wrapper)

Top