Re: temporarily log in as another user

2009-05-26 Thread Dave Brueck

On May 14, 1:17 pm, Sam Chuparkoff  wrote:
> On Wed, 2009-05-13 at 05:21 -0700, DaveBrueckwrote:
> > Has anyone in this group implemented any sort of login-as-another-user
> > functionality with Django?
>
> I implemented "sticky superuser logins" about a year ago (the last
> time I worked with django until now), so I can attest it is a neat
> trick, at least for demos. But I probably don't undertand it
> anymore. And unfortunately, a brief look at the code shows some
> changes since django-gis r7229, which I was using then.
>
> I was working under the premise that the only special priviledge the
> superuser retains after changing effective id to another user is the
> ability to login as another user without a password. But nothing
> prevents granting other special powers. Anyhow I too suspect someone
> else has thought about this, no?
>
> My approach was to hack a new SUPERUSER_SESSION_KEY and
> SUPERUSER_BACKEND_SESSION_KEY into contrib/auth/__init__.py , and add
> a new 'superuser' attribute in AuthenticationMiddleware. I guessed
> this wasn't the most clever way but didn't want to confuse myself too
> much, because I still had a logical consequences to deal with. If
> you're interested in seeing some of this code, reply directly.

Thanks for the reply Sam. For the sake of writing this down somewhere,
here's what I ended up doing:

1) Created a new authentication backend that authenticates based on a
user ID:

class LoginAsBackend(ModelBackend):
'''Special-case backend for when the admin needs to login as
another user'''
def authenticate(self, id=None, curUser=None, forReals=False,
**kwargs):
# we require a few extra args just to prevent the accidental
use of this backend
# in other contexts
if id is None or not forReals or curUser is None:
return None

try:
return User.objects.get(id=id)
except User.DoesNotExist:
return None

2) Mark the user's session when we login as another user:

user = authenticate(id=id, curUser=r.user, forReals=True) # this
calls our special backends.LoginAsBackend
assert user
login(r, user)
r.session['was_admin'] = True

3) Use a special decorator on all views that are viewable by site
admins:

def admin_required(func):
def decorated(req, *args, **kwargs):
if req.user.has_perm('is_admin') or req.session.get
('was_admin'):
return func(req, *args, **kwargs)
return HttpResponseRedirect(settings.LOGIN_URL)
return decorated


It's not the prettiest solution, but it seems to work.
Take care,
-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
-~--~~~~--~~--~--~---



Re: temporarily log in as another user

2009-05-14 Thread Sam Chuparkoff

On Wed, 2009-05-13 at 05:21 -0700, Dave Brueck wrote:
> Has anyone in this group implemented any sort of login-as-another-user
> functionality with Django?

I implemented "sticky superuser logins" about a year ago (the last
time I worked with django until now), so I can attest it is a neat
trick, at least for demos. But I probably don't undertand it
anymore. And unfortunately, a brief look at the code shows some
changes since django-gis r7229, which I was using then.

I was working under the premise that the only special priviledge the
superuser retains after changing effective id to another user is the
ability to login as another user without a password. But nothing
prevents granting other special powers. Anyhow I too suspect someone
else has thought about this, no?

My approach was to hack a new SUPERUSER_SESSION_KEY and
SUPERUSER_BACKEND_SESSION_KEY into contrib/auth/__init__.py , and add
a new 'superuser' attribute in AuthenticationMiddleware. I guessed
this wasn't the most clever way but didn't want to confuse myself too
much, because I still had a logical consequences to deal with. If
you're interested in seeing some of this code, reply directly.

sdc



--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: temporarily log in as another user

2009-05-13 Thread Dave Brueck

Has anyone in this group implemented any sort of login-as-another-user
functionality with Django? Maybe if I at least know it's possible
it'll steer me in the right direction.

On May 2, 8:42 am, Dave Brueck  wrote:
> 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
-~--~~~~--~~--~--~---



temporarily log in as another user

2009-05-02 Thread Dave Brueck

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
-~--~~~~--~~--~--~---