views:

216

answers:

4

I've made this decorator, which results in an infinite redirect loop.

The problem is this:

args[0].redirect(users.create_login_url(args[0].request.path))

It appears to be a perfectly valid URL. So why wouldn't it properly redirect?

def admin_only(handler, *args):

    def redirect_to_login(*args, **kwargs):
        return args[0].redirect(users.create_login_url(args[0].request.path))

    user = users.get_current_user()
    if user:
        if authorized(user):
            return handler(args[0])
        else:
            logging.warning('An unauthorized user has attempted to enter an authorized page')
            return redirect_to_login
    else:
        return redirect_to_login
A: 

Are you sure proper status code is being sent, you can use live http headers add-on for firefox to check whether 301 or 303 is being sent or not.

M. Utku ALTINKAYA
A: 

You should use firebug, or live http headers, or somesuch, to see what exactly is happening here. My guess: Your authorized() function is always returning false (even when a user is logged in), so it redirects to the login page, which (if the user is already logged in) immediately redirects the user back to your page, which redirects... you get the idea.

Nick Johnson
+2  A: 

It seems that you aren't defining your decorator properly.

A decorator is called only once every time you wrap a function with it; from then on the function that the decorator returned will be called. It seems that you (mistakenly) believe that the decorator function itself will be called every time.

Try something like this instead:

def redirect_to_login(*args, **kwargs):
    return args[0].redirect(users.create_login_url(args[0].request.path))

def admin_only(handler):
    def wrapped_handler(*args, **kwargs):    
        user = users.get_current_user()
        if user:
            if authorized(user):
                return handler(args[0])
            else:
                logging.warning('An unauthorized user has attempted '
                                'to enter an authorized page')
                return redirect_to_login(*args, **kwargs)
        else:
            return redirect_to_login(*args, **kwargs)

    return wrapped_handler

Note that in the above code, the decorator just defines a new function and returns it, and this new function itself does the relevant checks.

taleinat
A: 

The problem is actually when I use

return args[0].redirect(users.create_logout_url(args[0].request.uri))

This goes to the logout page, which then redirects to the current page. However, my logs show that the current page thinks I'm still logged in, even after the logging out is complete.

This is strange, since I haven't modified anything in the app engine users API.

jamtoday