You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Animesh Jain <an...@itasveer.com> on 2008/12/15 10:57:48 UTC

super user

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

Re: super user

Posted by Les Hazlewood <lh...@apache.org>.
Hi Animesh,

Yep, I created a new thread on the jsecurity-dev list because it entails the
implementation details on how we go about creating that functionality, as
opposed to how to use it or enable it (which would be better suited to the
user list).

If you'd like to follow along, please do join that list too.

Cheers,

Les

On Thu, Dec 18, 2008 at 9:50 AM, Animesh Jain <an...@itasveer.com> wrote:

> I just noticed (saw Les's post on Grails-user) that the discussion moved on
> to jsecurity-dev, I'll go join that list. . For others' reference
>
> http://markmail.org/message/hnex52p2puw2pip5
>
> - Animesh
>
>
> On Tue, Dec 16, 2008 at 1:06 AM, Jeremy Haile <jh...@fastmail.fm> wrote:
>
>> If you were trying to make it transparent then it would be more like
>> // This would return the user ID that the current user is running as
>> (whether it's themselves or a "run as" user)
>> String userId = ((UserPrincipal)subject.getPrincipal()).getUserId();
>>
>> In your logging code - if you wanted to log the actual user ID (not the
>> "run as" user ID) you would do:
>> String authenticatedUserId =
>> ((UserPrincipal)subject.getPrincipal()).getAuthenticatedUserId();
>>
>> I'd compare it to:
>> User user = getUser( ((UserPrincipal)subject.getPrincipal()).getUserId()
>> );
>>
>> But actually in my code it just looks like this - so it really doesn't
>> matter much if there's a few more characters:
>> User user = userManager.getCurrentUser();
>>
>> Plus, my principal already has more than one ID encapsulated in it.
>>
>>
>> On Dec 15, 2008, at 2:29 PM, Les Hazlewood wrote:
>>
>> On Mon, Dec 15, 2008 at 2:18 PM, Jeremy Haile <jh...@fastmail.fm> wrote:
>>
>>> Well, I think you could structure it so the programmers making calls on
>>> the subject don't have to know and still follow the approach where
>>> everything is encapsulated in the principal.  Just depends on how your
>>> principal encapsulates the information.
>>>
>>
>>> I like the Principal approach because it seems simpler, more transparent
>>> (i.e. no proxy classes pulling data from the session, etc.), and requires
>>> less overriding/etc to accomplish since you just implement the logic in your
>>> realm and return a principal that encapsulates any necessary information.
>>>
>>
>> So how do you deal with user-specific functionality pertaining to the
>> logged in user?  Do you do something like this?
>>
>> UserIdentity identity = (UserIdentity)Subject.getPrincipal();
>> Long userId;
>> if ( identity.isAssumed() ) {
>>     userId = identity.getAssumedId();
>> } else {
>>     userId = identity.getId();
>> }
>>
>> User user = getUser(userId);
>> System.out.println( "Welcome " + user.getGivenName() + "!" );
>>
>> Compare that to this:
>>
>> User user = getUser( (Long)Subject.getPrincipal() );
>> System.out.println( "Welcome " + user.getGivenName() + "!" );
>>
>> Thanks for any clarity - I'm still trying to understand your approach...
>>
>>
>>>
>>> I too like hearing about other approaches to this problem though.
>>>
>>>
>>>
>>> On Dec 15, 2008, at 1:53 PM, Les Hazlewood wrote:
>>>
>>> But this approach requires the GUI programmer (or the one making calls on
>>> the subject) to 'know' about this 'run as' check, everywhere in the
>>> application, right?  Doesn't that sound a little invasive as to opposed to
>>> just calling Subject.getPrincipal() in all locations?
>>>
>>> I surface this only for clarity - I'm not shooting down any approaches.
>>> I just haven't seen a way to 1) offer transparent 'run as' functionality
>>> while 2) still retaining accurate traceability.
>>>
>>> My solution achieves both points, but I'm very open to any suggestions on
>>> how else it may be done - if there is a cleaner way, etc.  If there's
>>> anything else up your sleeves, I'm all ears ;)
>>>
>>> On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm>wrote:
>>>
>>>> Another "clean" way to do this would be to do it similar to my approach,
>>>> but actually have the principal object have the assumed identity AND actual
>>>> identity.  In most cases these would be the same, but in a "super user"
>>>> situation, they could be different.
>>>> Most (non-auditing) code that needs to determine who the current user is
>>>> would always retrieve the principal and use the "assumed identity".  Any
>>>> auditing or event logging code could then log both of these fields by
>>>> examining the principal.
>>>>
>>>>
>>>> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>>>>
>>>> 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 <jh...@fastmail.fm>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
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>

Re: super user

Posted by Animesh Jain <an...@itasveer.com>.
I just noticed (saw Les's post on Grails-user) that the discussion moved on
to jsecurity-dev, I'll go join that list. . For others' reference

http://markmail.org/message/hnex52p2puw2pip5

- Animesh

On Tue, Dec 16, 2008 at 1:06 AM, Jeremy Haile <jh...@fastmail.fm> wrote:

> If you were trying to make it transparent then it would be more like
> // This would return the user ID that the current user is running as
> (whether it's themselves or a "run as" user)
> String userId = ((UserPrincipal)subject.getPrincipal()).getUserId();
>
> In your logging code - if you wanted to log the actual user ID (not the
> "run as" user ID) you would do:
> String authenticatedUserId =
> ((UserPrincipal)subject.getPrincipal()).getAuthenticatedUserId();
>
> I'd compare it to:
> User user = getUser( ((UserPrincipal)subject.getPrincipal()).getUserId() );
>
> But actually in my code it just looks like this - so it really doesn't
> matter much if there's a few more characters:
> User user = userManager.getCurrentUser();
>
> Plus, my principal already has more than one ID encapsulated in it.
>
>
> On Dec 15, 2008, at 2:29 PM, Les Hazlewood wrote:
>
> On Mon, Dec 15, 2008 at 2:18 PM, Jeremy Haile <jh...@fastmail.fm> wrote:
>
>> Well, I think you could structure it so the programmers making calls on
>> the subject don't have to know and still follow the approach where
>> everything is encapsulated in the principal.  Just depends on how your
>> principal encapsulates the information.
>>
>
>> I like the Principal approach because it seems simpler, more transparent
>> (i.e. no proxy classes pulling data from the session, etc.), and requires
>> less overriding/etc to accomplish since you just implement the logic in your
>> realm and return a principal that encapsulates any necessary information.
>>
>
> So how do you deal with user-specific functionality pertaining to the
> logged in user?  Do you do something like this?
>
> UserIdentity identity = (UserIdentity)Subject.getPrincipal();
> Long userId;
> if ( identity.isAssumed() ) {
>     userId = identity.getAssumedId();
> } else {
>     userId = identity.getId();
> }
>
> User user = getUser(userId);
> System.out.println( "Welcome " + user.getGivenName() + "!" );
>
> Compare that to this:
>
> User user = getUser( (Long)Subject.getPrincipal() );
> System.out.println( "Welcome " + user.getGivenName() + "!" );
>
> Thanks for any clarity - I'm still trying to understand your approach...
>
>
>>
>> I too like hearing about other approaches to this problem though.
>>
>>
>>
>> On Dec 15, 2008, at 1:53 PM, Les Hazlewood wrote:
>>
>> But this approach requires the GUI programmer (or the one making calls on
>> the subject) to 'know' about this 'run as' check, everywhere in the
>> application, right?  Doesn't that sound a little invasive as to opposed to
>> just calling Subject.getPrincipal() in all locations?
>>
>> I surface this only for clarity - I'm not shooting down any approaches.  I
>> just haven't seen a way to 1) offer transparent 'run as' functionality while
>> 2) still retaining accurate traceability.
>>
>> My solution achieves both points, but I'm very open to any suggestions on
>> how else it may be done - if there is a cleaner way, etc.  If there's
>> anything else up your sleeves, I'm all ears ;)
>>
>> On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm>wrote:
>>
>>> Another "clean" way to do this would be to do it similar to my approach,
>>> but actually have the principal object have the assumed identity AND actual
>>> identity.  In most cases these would be the same, but in a "super user"
>>> situation, they could be different.
>>> Most (non-auditing) code that needs to determine who the current user is
>>> would always retrieve the principal and use the "assumed identity".  Any
>>> auditing or event logging code could then log both of these fields by
>>> examining the principal.
>>>
>>>
>>> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>>>
>>> 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 <jh...@fastmail.fm>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
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>

Re: super user

Posted by Jeremy Haile <jh...@fastmail.fm>.
If you were trying to make it transparent then it would be more like

// This would return the user ID that the current user is running as  
(whether it's themselves or a "run as" user)
String userId = ((UserPrincipal)subject.getPrincipal()).getUserId();

In your logging code - if you wanted to log the actual user ID (not  
the "run as" user ID) you would do:
String authenticatedUserId =  
((UserPrincipal)subject.getPrincipal()).getAuthenticatedUserId();

I'd compare it to:
User user =  
getUser( ((UserPrincipal)subject.getPrincipal()).getUserId() );

But actually in my code it just looks like this - so it really doesn't  
matter much if there's a few more characters:
User user = userManager.getCurrentUser();

Plus, my principal already has more than one ID encapsulated in it.


On Dec 15, 2008, at 2:29 PM, Les Hazlewood wrote:

> On Mon, Dec 15, 2008 at 2:18 PM, Jeremy Haile <jh...@fastmail.fm>  
> wrote:
> Well, I think you could structure it so the programmers making calls  
> on the subject don't have to know and still follow the approach  
> where everything is encapsulated in the principal.  Just depends on  
> how your principal encapsulates the information.
>
> I like the Principal approach because it seems simpler, more  
> transparent (i.e. no proxy classes pulling data from the session,  
> etc.), and requires less overriding/etc to accomplish since you just  
> implement the logic in your realm and return a principal that  
> encapsulates any necessary information.
>
> So how do you deal with user-specific functionality pertaining to  
> the logged in user?  Do you do something like this?
>
> UserIdentity identity = (UserIdentity)Subject.getPrincipal();
> Long userId;
> if ( identity.isAssumed() ) {
>     userId = identity.getAssumedId();
> } else {
>     userId = identity.getId();
> }
>
> User user = getUser(userId);
> System.out.println( "Welcome " + user.getGivenName() + "!" );
>
> Compare that to this:
>
> User user = getUser( (Long)Subject.getPrincipal() );
> System.out.println( "Welcome " + user.getGivenName() + "!" );
>
> Thanks for any clarity - I'm still trying to understand your  
> approach...
>
>
> I too like hearing about other approaches to this problem though.
>
>
>
> On Dec 15, 2008, at 1:53 PM, Les Hazlewood wrote:
>
>> But this approach requires the GUI programmer (or the one making  
>> calls on the subject) to 'know' about this 'run as' check,  
>> everywhere in the application, right?  Doesn't that sound a little  
>> invasive as to opposed to just calling Subject.getPrincipal() in  
>> all locations?
>>
>> I surface this only for clarity - I'm not shooting down any  
>> approaches.  I just haven't seen a way to 1) offer transparent 'run  
>> as' functionality while 2) still retaining accurate traceability.
>>
>> My solution achieves both points, but I'm very open to any  
>> suggestions on how else it may be done - if there is a cleaner way,  
>> etc.  If there's anything else up your sleeves, I'm all ears ;)
>>
>> On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm>  
>> wrote:
>> Another "clean" way to do this would be to do it similar to my  
>> approach, but actually have the principal object have the assumed  
>> identity AND actual identity.  In most cases these would be the  
>> same, but in a "super user" situation, they could be different.
>>
>> Most (non-auditing) code that needs to determine who the current  
>> user is would always retrieve the principal and use the "assumed  
>> identity".  Any auditing or event logging code could then log both  
>> of these fields by examining the principal.
>>
>>
>> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>>
>>> 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 <jh...@fastmail.fm>  
>>> 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
>>>
>>>
>>
>>
>
>


Re: super user

Posted by Les Hazlewood <lh...@apache.org>.
On Mon, Dec 15, 2008 at 2:18 PM, Jeremy Haile <jh...@fastmail.fm> wrote:

> Well, I think you could structure it so the programmers making calls on the
> subject don't have to know and still follow the approach where everything is
> encapsulated in the principal.  Just depends on how your principal
> encapsulates the information.
>

> I like the Principal approach because it seems simpler, more transparent
> (i.e. no proxy classes pulling data from the session, etc.), and requires
> less overriding/etc to accomplish since you just implement the logic in your
> realm and return a principal that encapsulates any necessary information.
>

So how do you deal with user-specific functionality pertaining to the logged
in user?  Do you do something like this?

UserIdentity identity = (UserIdentity)Subject.getPrincipal();
Long userId;
if ( identity.isAssumed() ) {
    userId = identity.getAssumedId();
} else {
    userId = identity.getId();
}

User user = getUser(userId);
System.out.println( "Welcome " + user.getGivenName() + "!" );

Compare that to this:

User user = getUser( (Long)Subject.getPrincipal() );
System.out.println( "Welcome " + user.getGivenName() + "!" );

Thanks for any clarity - I'm still trying to understand your approach...


>
> I too like hearing about other approaches to this problem though.
>
>
>
> On Dec 15, 2008, at 1:53 PM, Les Hazlewood wrote:
>
> But this approach requires the GUI programmer (or the one making calls on
> the subject) to 'know' about this 'run as' check, everywhere in the
> application, right?  Doesn't that sound a little invasive as to opposed to
> just calling Subject.getPrincipal() in all locations?
>
> I surface this only for clarity - I'm not shooting down any approaches.  I
> just haven't seen a way to 1) offer transparent 'run as' functionality while
> 2) still retaining accurate traceability.
>
> My solution achieves both points, but I'm very open to any suggestions on
> how else it may be done - if there is a cleaner way, etc.  If there's
> anything else up your sleeves, I'm all ears ;)
>
> On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm> wrote:
>
>> Another "clean" way to do this would be to do it similar to my approach,
>> but actually have the principal object have the assumed identity AND actual
>> identity.  In most cases these would be the same, but in a "super user"
>> situation, they could be different.
>> Most (non-auditing) code that needs to determine who the current user is
>> would always retrieve the principal and use the "assumed identity".  Any
>> auditing or event logging code could then log both of these fields by
>> examining the principal.
>>
>>
>> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>>
>> 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 <jh...@fastmail.fm> 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
>>>>
>>>
>>>
>>
>>
>
>

Re: super user

Posted by Jeremy Haile <jh...@fastmail.fm>.
Well, I think you could structure it so the programmers making calls  
on the subject don't have to know and still follow the approach where  
everything is encapsulated in the principal.  Just depends on how your  
principal encapsulates the information.

I like the Principal approach because it seems simpler, more  
transparent (i.e. no proxy classes pulling data from the session,  
etc.), and requires less overriding/etc to accomplish since you just  
implement the logic in your realm and return a principal that  
encapsulates any necessary information.

I too like hearing about other approaches to this problem though.


On Dec 15, 2008, at 1:53 PM, Les Hazlewood wrote:

> But this approach requires the GUI programmer (or the one making  
> calls on the subject) to 'know' about this 'run as' check,  
> everywhere in the application, right?  Doesn't that sound a little  
> invasive as to opposed to just calling Subject.getPrincipal() in all  
> locations?
>
> I surface this only for clarity - I'm not shooting down any  
> approaches.  I just haven't seen a way to 1) offer transparent 'run  
> as' functionality while 2) still retaining accurate traceability.
>
> My solution achieves both points, but I'm very open to any  
> suggestions on how else it may be done - if there is a cleaner way,  
> etc.  If there's anything else up your sleeves, I'm all ears ;)
>
> On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm>  
> wrote:
> Another "clean" way to do this would be to do it similar to my  
> approach, but actually have the principal object have the assumed  
> identity AND actual identity.  In most cases these would be the  
> same, but in a "super user" situation, they could be different.
>
> Most (non-auditing) code that needs to determine who the current  
> user is would always retrieve the principal and use the "assumed  
> identity".  Any auditing or event logging code could then log both  
> of these fields by examining the principal.
>
>
> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>
>> 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 <jh...@fastmail.fm>  
>> 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
>>
>>
>
>


Re: super user

Posted by Les Hazlewood <le...@hazlewood.com>.
But this approach requires the GUI programmer (or the one making calls on
the subject) to 'know' about this 'run as' check, everywhere in the
application, right?  Doesn't that sound a little invasive as to opposed to
just calling Subject.getPrincipal() in all locations?

I surface this only for clarity - I'm not shooting down any approaches.  I
just haven't seen a way to 1) offer transparent 'run as' functionality while
2) still retaining accurate traceability.

My solution achieves both points, but I'm very open to any suggestions on
how else it may be done - if there is a cleaner way, etc.  If there's
anything else up your sleeves, I'm all ears ;)

On Mon, Dec 15, 2008 at 11:14 AM, Jeremy Haile <jh...@fastmail.fm> wrote:

> Another "clean" way to do this would be to do it similar to my approach,
> but actually have the principal object have the assumed identity AND actual
> identity.  In most cases these would be the same, but in a "super user"
> situation, they could be different.
> Most (non-auditing) code that needs to determine who the current user is
> would always retrieve the principal and use the "assumed identity".  Any
> auditing or event logging code could then log both of these fields by
> examining the principal.
>
>
> On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:
>
> 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 <jh...@fastmail.fm> 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
>>>
>>
>>
>
>

Re: super user

Posted by Jeremy Haile <jh...@fastmail.fm>.
Another "clean" way to do this would be to do it similar to my  
approach, but actually have the principal object have the assumed  
identity AND actual identity.  In most cases these would be the same,  
but in a "super user" situation, they could be different.

Most (non-auditing) code that needs to determine who the current user  
is would always retrieve the principal and use the "assumed  
identity".  Any auditing or event logging code could then log both of  
these fields by examining the principal.


On Dec 15, 2008, at 10:32 AM, Les Hazlewood wrote:

> 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 <jh...@fastmail.fm>  
> 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
>
>


Re: super user

Posted by Les Hazlewood <lh...@apache.org>.
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 <jh...@fastmail.fm> 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
>>
>
>

Re: super user

Posted by Jeremy Haile <jh...@fastmail.fm>.
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