views:

220

answers:

3

I'm using Pylons and want to add some middleware to it so that it catches 401 status codes and makes HTTP Redirect (302) to Signin page.

I know there is built-in StatusCodeRedirect in Pylons that acts in a similar fashion, but it does not produce HTTP redirect, and rather redirects internally (this is what I do not want).

Is there any existing middleware to add, or any generic middleware that can be easily modified to make HTTP redirects on specific status codes?

+1  A: 

This should get you pretty close i didn't test it though but it's loosely based on something I wrote that I am using so tweak as necessary.

from webob.dec import wsgify


class Catch401AndRedirect(object):
    """
    responds to 401 redirects to signin page
    """

    def __init__(self, app, signin_url):
        self._app = app
        self._signin_url = signin_url

    @wsgify
    def __call__(self, request):

        response = request.get_response(self._app)

        if response.status_int == 401:
            response.headers["Location"] = self._signin_url
            response.status_int = 302
        else:
            return response

edit: forgot to mention this solution requires webob, but since you are using pylons already, you have that dependency.

Tom Willis
A: 

You can use a complete authentication & authorization library for Pylons. The two most popular are: AuthKit and repoze.who. They already implement what you want to do.

If you don't want to use an existing library, you can write a custom middleware. It is simply a Python callable f(environ, start_response) which processes request data kept in environ. Look into config/environment.py.

Adam Dziendziel
A: 

Finally. I've implemented my own middleware class that uses *call_wsgi_application* helper function of pylons.util

from pylons.util import call_wsgi_application

class StatusCodeHTTPRedirect(object):

    def __init__(self, wsgi_app, codes, redirect_to):
        self.app = wsgi_app
        # Transform codes to str for comparison
        self.codes = tuple([str(x) for x in codes])
        self.redirect_to = redirect_to

    def __call__(self, environ, start_response):
        status, headers, app_iter, exc_info = call_wsgi_application(self.app,
            environ, catch_exc_info=True)

        if status[:3] in self.codes:
            start_response('302 Found', [('Location', self.redirect_to)])
            return []

        start_response(status, headers, exc_info)
        return app_iter

Hope this will help someone

Evgenyt