Hi all,

I would like an admin user on my site to be able to temporarily
"become" a normal user and see the site as if logged in as that normal
user. However, I also need to retain one admin-related permission
after I become the normal user.

On my site there are admin users that aren't staff or superusers from
Django's perspective - instead they are users that belong to an admin
group and, by extension, have an 'app.is_admin' permission.

To support this "login as" functionality, I created a custom
authentication backend and added it to my list in settings.py. This
backend subclasses ModelBackend so that for the most part permissions
and so forth work normally, except that authentication happens purely
based on user ID:

class LoginAsBackend(ModelBackend):
    '''Special-case backend for when the admin needs to login as
another user'''
    def authenticate(self, id=None, **kwargs):
        try:
            return User.objects.get(id=id)
        except User.DoesNotExist:
            return None

    def has_perm(self, user, perm):
        # If we authenticated this user, then they are an admin
        if perm == 'app.is_admin' and user.backend ==
'app.backends.LoginAsBackend':
            return True

        # for other permissions, though, look them up from the usual
place
        return super(LoginAsBackend, self).has_perm(user, perm)

The overridden has_perm method is supposed to allow this user to
continue to be a site admin, otherwise as soon as you become the
normal user, you're effectively logged out as an admin, which means if
you need to look at the account for multiple users you'd have to re-
login using your own credentials each time.

The problem I'm having is that the above successfully gets me logged
in as the desired user, but I lose the knowledge that I used to be an
admin - when has_perm is called, the user object does not have a
backend property.

The view to become another user looks something like this:

@permission_required('app.is_admin', login_url='/user/noperm/')
def UserLoginAs(r, id):
    user = authenticate(id=id) # id is a user ID here
    assert user
    login(r, user)
    return HttpResponseRedirect('/')

Immediately after the login() call, user.backend *does* exist and does
have the name of my custom backend, but on any subsequent requests the
user object does not have backend set (probably because in a later
request, it's a different instance of the user object or something).

All of the site admin functionality is wrapped in permission_required
calls that require the app.is_admin permission, so I just need some
way for this user to have that permission - but only for the current
session. I don't want to actually give the user that permission since
it's temporary.

Is there some better way to do all this? Or am I on the right track
but just missing a step?

I also noticed that the user's session retains knowledge of which
backend was used (req.session['_auth_user_backend']) but I couldn't
figure out a good way to make use of that via permission_required.
Maybe I need to change all uses of permission_required to a custom
decorator that does what I need? (ugh)

Thanks for any help you can give me!
-Dave

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to