4

I develop and maintain a customer portal, written in Perl/Catalyst. We make use of the Catalyst authentication plugins (w/ an LDAP storage backend, coupled with a few deny_unless rules to ensure the right people have the right group membership).

It's often that in managing a customer's permissions, we have the need to test out a user's settings before we hand things over. Currently, our only recourse is to reset a user's password and log in ourselves, but this is less than ideal, particularly if the user has already set their own passwords, etc.

My question is this: for Catalyst, has anyone come across a method of impersonating a user account such that, given the correct super-admin privileges, one could impersonate another account temporarily while testing out a setting, and then back out once done?

If not in Catalyst, then how have people approached this in other frameworks, or their own custom solutions? Admittedly, this is something that introduces a potentially egregious attack vector for a web application, but if forced to implement, how have people approached design for this? Perhaps some serious cookie-session-fu? Or possibly an actualID/effectiveID system?

Kaiden
  • 308
  • 2
  • 6

1 Answers1

5

We use a custom authenticator controller, a custom user class (MyApp::Core::User) and several realms:

package MyApp::Controller::Auth;
...
sub surrogate : Local {
    my ( $self, $c ) = @_;
    my $p = $c->req->params;
    my $actual_user = $c->user; # save it for later

    try {
        $c->authenticate({ id=>$p->{surrogate_id} }, 'none');
        $c->session->{user} = new MyApp::Core::User( 
             active_user    => $actual_user, 
             effective_user => $c->user );
        $c->stash->{json} = { success => \1, msg => "Login Ok" };
    } catch {
        $c->stash->{json} = { success => \0, msg => "Invalid User" };
    };
    $c->forward('View::JSON');  
}

In myapp.conf I use something like this:

<authentication>
    default_realm ldap
    <realms>
        <ldap>
             # ldap realm config stuff here
        </local>
        <none>
            <credential>
                class Password
                password_field password
                password_type none
            </credential>
            <store>
                class Null
            </store>
        </none>
     </realms>
</authentication>

That way we're creating a normal Catalyst user object, but wrapping it around our custom user class for more control. I probably could have created an specialized realm for surrogating, but I've chosen using my own user class instead. It was done a while back and I can recall why we did it that way.

ojosilva
  • 1,984
  • 2
  • 15
  • 21
  • Oh man, that's pretty clever. I suppose then that you could lock down access to the special surrogate controller, and you'd be able to impersonate a user until you decided to log off or otherwise terminate your session. I like that a lot. Thanks for sharing. – Kaiden Feb 27 '11 at 23:52
  • Yup, I didn't specify the authorization control to the surrogate controller in my answer. You can use whatever your have elsewhere in your app. It's actually pretty cool to have the ability to surrogate inside an app, useful for debugging user issues. Just make sure you log who is impersonating who, in case the system is abused by powerusers. – ojosilva Feb 28 '11 at 00:26