This is pretty cool - I like seeing how people come up with their respective
solutions.  It is interesting to see others' thought process for solving
these things.

I do this functionality as well in my applications, but I humbly offer my
solution as a little more elegant and 'traceable' from a security
perspective.

The purpose of 'run as' functionality is almost always to see things exactly
as that particular user would see things, so you can verify their
experience, or to perform logic as that individual.  But it is still
important in secure applications (IMHO) to never lose track of who is
actually performing the button clicks, especially if they've assumed someone
else's identity.

And if it ever comes to government or financial related applications or any
application that has to adhere to government regulations or oversight, you
always want to be able to show any government official/reviewer, "Although
it appears User X did this, it was _really_ User Y - don't blame User X".

Here's how I solve this problem:

A user logs in with their own username and password always.
They perform some sort of user search, which then shows a paginated results
page.

If the current user has the "assumeIdentity" permission, only then is an
additional 'assume identity' link available on each line-item that is shown
in the results page.  If they don't have this permission, they never see the
link and thus can't click on it.

The current user (if permitted) clicks the 'assume identity' link, which
sends a request to the server and then adds the target user's identity (in
our system a Long primary key of the assumed User) to the current user's
session.  Our session table in the database has a 'assumed_identity' column
that is a foreign key to the user's table.

We also have event tracking in place, where any operation deemed as
noteworthy is logged and has a foreign key back to the sessions table.

Therefore, we can always tell for *every* action (logged event) which
session it was attributed to.  Then, if the entry in the sessions table has
an assumed identity, then we know that the event was really attributed to
the 'owning' or original user, not the user of the assumed identity.

In our application, the Subject.getPrincipal() method returns the user's
long ID primary key.  We added a little Subject wrapper/proxy around the
existing Subject implementation that first checks the session, and if there
is an assumed identity, returns that.  If there is no assumed identity, it
returns the id of the user that actually authenticated as normal.

This is to ensure that all application functionality built around the
Subject.getPrincipal code still returns the expected data so further
information can be looked up (user name, first name, etc).  Works perfectly
if there is an assumed identity or not, but the session always 'remember's
who the 'real' user is executing the logic for traceability purposes.

I hope that gives some insight how this works :)  I've always wanted to add
this in a clean way to JSecurity.  Maybe it should be a 1.0 feature...

On Mon, Dec 15, 2008 at 9:18 AM, Jeremy Haile <[email protected]> wrote:

> Animesh,
>
> You can definitely support super user authentication with JSecurity - we do
> this in our application.  The way we do it is by having our realm accept
> multiple types of tokens - a regular UsernamePasswordToken and also a
> SuperUserToken.  The SuperUserToken contains an additional field called
> "runAsUser".  (in other words, it has a username, password, and a "run as
> username" property)
>
> The realm will then authenticate the normal username and password, but
> return back the principal of the "run as user".  Since our realm extends
> from AuthorizingRealm, it simply returns an instance of
> SimpleAuthenticationInfo that contains the principal of the "run as user"
> but the credentials of the user who is authenticating.
>
> Since this is potentially a very dangerous feature, we only enable it for
> accounts that have the admin flag set on them and ensure that the password
> for this account is very secure, limited, and changed on a regular basis.
>  This functionality is also only available from a secret URL that we don't
> link to in any way.
>
> Here's an excerpt code snippet from our codebase:
>
> User user = userManager.getActiveUserByEmail( organizationId,
> token.getUsername());
> if( user == null ) {
>    throw new UnknownAccountException( "No user account found for [" +
> token.getUsername() + "] for org ID [" + organizationId + "]" );
> }
>
>  if( token instanceof SuperUserToken ) {
>            if( !user.isAdmin() ) {
>                final String message = "Attempt to login as superuser by
> non-admin account: [" + token.getUsername() + "]";
>                log.error(message);
>                throw new UnauthorizedException( message );
>            }
>
>            Contact runAsContact = contactManager.getContactByEmail(
> ((SuperUserToken)token).getRunAsEmail() );
>            if( runAsContact == null ) {
>                throw new UnknownAccountException( "No user found with email
> [" + ((SuperUserToken)token).getRunAsEmail() + "]" );
>            }
>            UserPrincipal runAsPrincipal = new
> UserPrincipal(runAsContact.getUser().getId(), runAsContact.getId());
>            return new SimpleAuthenticationInfo( runAsPrincipal,
> user.getEncryptedPassword(), getName() );
>
>  } else {
>  // Do regular authentication here...
> }
>
> Let me know if you have any questions or problems with this approach.
>
> Jeremy Haile
>
>
>
>
> On Dec 15, 2008, at 4:57 AM, Animesh Jain wrote:
>
>  Hi
>>
>> Is there some way to create a super user sort of entity which can
>> authenticate itself as any subject it wants. It probably is not desired to
>> have such functionality but I'm wondering if there's some way to achieve
>> that if needed.
>>
>> Kind regards
>> Animesh
>>
>
>

Reply via email to