You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Kalle Korhonen <ka...@gmail.com> on 2009/06/16 07:36:13 UTC

Rememberme vs authentication

Shiro makes this artificial, strong separation between rememberme and
authentication. In the javadocs for RememberMeAuthenticationToken
(http://jsecurity.org/api/org/jsecurity/authc/RememberMeAuthenticationToken.html)
it is said that "Authentication is the process of proving you are who
you say you are". It is stated that rememberme is not considered an
authentication and implied that only using username/password can be
used for an "actual authentication". However, in practice there's no
way to know that whoever supplied the password is who they say they
are and passwords are generally not considered the strongest form of
authentication. Shiro's default rememberme implementation results in
no or very weak authentication, but there are alternatives that
results in stronger form of key-based authentication. Private/public
keys are often considered equally strong authentication to
username/password and for remember me, using rolling tokens (as
described for example at
http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/)
makes remembering the identity a much more secure process.

I've implemented rolling token-based remember cookies with Acegi in
the past, and now I'd like to do the same with Shiro. Considering the
view Shiro takes to rememberme, I wonder if it would make more sense
to implement a custom RememberMeManager or a custom authentication
filter for it. Current implementation doesn't allow you to authorize
the principal for anything when rememberMe is used, but I might like
to grant weaker roles to user that has been identified/authenticated
with a rolling token. I didn't find any built-in support for this type
of authentication so I'd also be interested in reviewing and possibly
reusing any existing code if somebody has already implemented
something like what I have in mind.

Kalle

Re: Rememberme vs authentication

Posted by Kalle Korhonen <ka...@gmail.com>.
On Wed, Jun 17, 2009 at 10:44 AM, Les Hazlewood<lh...@apache.org> wrote:
> Fair enough, although this does take quite a bit of effort to set up
> compared to the other approach, which I have to say I've used successfully
> on many commercial web sites with no ill-effect.  That doesn't mean the
> existing approach is the best it can be, it just means that, as is the case
> of so many things in the security world, that it hasn't been exploited yet
> on anything I've been involved with.  There is _always_ room for improvement
> in a security framework.
> So, do you think 1) this paradigm could be easily incorporated into the
> framework in a 'hands off' approach where it would work out of the box with
> no required configuration and 2) if so, should it be the default
> implementation used at startup?

No, I don't think it can be easily implemented in plain Shiro. The
reason is the same as to why Shiro's Realm API is read-only: since
Shiro cannot rely on any particular persistence model to exist, it's
difficult to implement any more complex server-side authentication,
identification or verification logic that would work out-of-the-box.
Since I'm not bound to these limitations (the security module I'm
working on requires JPA persistence) I can implement it fully as a
drop-in functionality - users of the library won't even need to know
how it works.

> If the onFailedLogin and onSuccessfulLogin methods are not suitable, I'd be
> more than happy to add a 'beforeLogin' method to the interface if you think
> that would be sufficient.  This would provide proper AOP-ish 'around advice'
> for an authentication attempt.
> Interestingly enough, both the RememberMeManager and the
> AuthenticationListener are nearly identical.  I think if we add a
> 'beforeLogin' method it should go into the AuthenticationListener interface
> and the RememberMeManager should just extend that interface.  Anyone have
> any objections on this?

Even adding onLogin won't help me since I want to do something after a
remembered identity was retrieved. But yes, I see a lot of custom
logic dealing specifically with rememberme when it mostly looks like
an authenticationListener (except for the added
getRememberedPrincipals). So I think making RememberMeManager extend
the AuthenticationListener is a good idea.

> If you think this is a good approach and would allow you to do what you
> need, please open a Jira issue and I'd be more than happy to push it
> through.  If this won't allow you to do what you desire, please let me know
> why not and we can see how other mechanisms might be made available to do
> what you need.  At the end of the day, you have the ability to create
> Subject instances however you want via a custom implementation of the
> SubjectFactory interface (which is still in flux and might change to reflect

I was going to write that I think my best short term approach is to
override the DefaultSecurityManager which I didn't particularly like
because it would have created a lock-in for users, but yes I see that
SubjectFactory is new and might be exactly the extension point I need.
I can use the default RememberMeManager exactly as intended and keep
the rolling tokens separate, then use a custom SubjectFactory that
will do the token reading and comparison and invalidate the remembered
identity as needed. Thanks for that - I've been using 0.9 javadocs so
I missed SubjectFactory but I'm looking at trunk source now.

Kalle

Re: Rememberme vs authentication

Posted by Les Hazlewood <lh...@apache.org>.
>
> Still not seeing the difference? Ok, let's take a real world example.
> Bank of America's website remembers your username on that computer
> (ip) only. If you move to a different location (say you suddenly
> changed countries), it'll ask you a simple security question *before*
> it gives you a chance to type in your password - so the "remember me"
> works as an extra security feature rather than weaker form of
> security. Obviously simply accepting the given client-side identity is
> not enough. If you type in the wrong password, the implementation can
> invalidate your remembered identity on the server. If somebody
> intercepts your identity cookie it won't be valid anymore on the next
> try. You can also better protect against systematic attacks since the
> assigned key is unique (rather than the same encrypted identity) so
> all keys can be invalidated at once.


Fair enough, although this does take quite a bit of effort to set up
compared to the other approach, which I have to say I've used successfully
on many commercial web sites with no ill-effect.  That doesn't mean the
existing approach is the best it can be, it just means that, as is the case
of so many things in the security world, that it hasn't been exploited yet
on anything I've been involved with.  There is _always_ room for improvement
in a security framework.

So, do you think 1) this paradigm could be easily incorporated into the
framework in a 'hands off' approach where it would work out of the box with
no required configuration and 2) if so, should it be the default
implementation used at startup?

Are you suggesting I'd do something like
> SecurityUtils.getSubject().login() as part of
> RememberMeManager.getRememberedPrincipals()? That doesn't sound like
> the right approach to me.


I completely agree and goes to what I was saying about an authenticated
state vs a remembered state - I think an automatic login calls that are not
manually initiated by a human is (usually) a bad thing.


> I mean I don't see how  RememberMeManager
> interface can be used directly since it doesn't support
> onLogin(PrincipalCollection subjectPrincipals) (because rememberme is
> strictly limited to identity). Obviously I can hack Shiro anyway I
> like (and believe me, I have) but don't you think that the design
> dictates that in this case it'd be better just to implement a custom
> SecurityManager that incorporates some aspects of RememberMeManager?
> If not, how would you implement this using the RememberMeManager?


If the onFailedLogin and onSuccessfulLogin methods are not suitable, I'd be
more than happy to add a 'beforeLogin' method to the interface if you think
that would be sufficient.  This would provide proper AOP-ish 'around advice'
for an authentication attempt.

Interestingly enough, both the RememberMeManager and the
AuthenticationListener are nearly identical.  I think if we add a
'beforeLogin' method it should go into the AuthenticationListener interface
and the RememberMeManager should just extend that interface.  Anyone have
any objections on this?

If you think this is a good approach and would allow you to do what you
need, please open a Jira issue and I'd be more than happy to push it
through.  If this won't allow you to do what you desire, please let me know
why not and we can see how other mechanisms might be made available to do
what you need.  At the end of the day, you have the ability to create
Subject instances however you want via a custom implementation of the
SubjectFactory interface (which is still in flux and might change to reflect
a Map argument, much like the SessionFactory interface looks like now).

Also, if you have to do any more 'hacking' :) and things aren't
readily/easily available for you to override custom behavior, by all means
please continue to post feedback here.  I feel that's one of the most
important things to achieve in the project (where possible of course and
when the solutions are not rare edge-cases).

Cheers,

Les

Re: Rememberme vs authentication

Posted by Kalle Korhonen <ka...@gmail.com>.
On Tue, Jun 16, 2009 at 1:38 PM, Les Hazlewood<lh...@apache.org> wrote:
> I just wanted to be very clear to most readers and users of the framework
> that auto-login - where the end-user is automatically logged in without
> their required interaction, is usually a really, really bad idea.  It is not
> something that should be done by default (and is why we don't do it by
> default).

Certainly, especially if you are given exactly the same permissions.

> My point was this doesn't matter much if the programmer uses Shiro's API
> properly.  If the API is being used correctly, it would protect certain site
> areas depending on their state (anonymous, remembered, and/or
.. snip ..
> <shiro:guest/>
> <shiro:user/>
> <shiro:authenticated/>
> There are tags that represent the inverse of these as well.

I hope JSP tags are a thing of past by now :)

> But if you disagree that this doesn't provide the same end-goal as what the
> article advocates, albeit in a different way, I'd certainly like to hear
> your thoughts on why - if there is something that can be added to the
> framework to make lives easier for people, it probably should be
> incorporated :)

Still not seeing the difference? Ok, let's take a real world example.
Bank of America's website remembers your username on that computer
(ip) only. If you move to a different location (say you suddenly
changed countries), it'll ask you a simple security question *before*
it gives you a chance to type in your password - so the "remember me"
works as an extra security feature rather than weaker form of
security. Obviously simply accepting the given client-side identity is
not enough. If you type in the wrong password, the implementation can
invalidate your remembered identity on the server. If somebody
intercepts your identity cookie it won't be valid anymore on the next
try. You can also better protect against systematic attacks since the
assigned key is unique (rather than the same encrypted identity) so
all keys can be invalidated at once.

>> Ok, so it's clear that Shiro's rememberme is only to used for
>> remembering the identity.
>
> That's the default yes - but not limited to that.  The developer can do
> whatever he likes by implementing the RememberMeManager interface.  You're
... snip ...
> Same with Shiro - we just provide a nice default that works assuming you use
> the API correctly.  The developer can certainly override this if they desire
> by providing their own RememberMeManager implementation.

Are you suggesting I'd do something like
SecurityUtils.getSubject().login() as part of
RememberMeManager.getRememberedPrincipals()? That doesn't sound like
the right approach to me. I mean I don't see how  RememberMeManager
interface can be used directly since it doesn't support
onLogin(PrincipalCollection subjectPrincipals) (because rememberme is
strictly limited to identity). Obviously I can hack Shiro anyway I
like (and believe me, I have) but don't you think that the design
dictates that in this case it'd be better just to implement a custom
SecurityManager that incorporates some aspects of RememberMeManager?
If not, how would you implement this using the RememberMeManager?

Kalle

Re: Rememberme vs authentication

Posted by Les Hazlewood <lh...@apache.org>.
>
> > It is most certainly not artificial.  Authentication is the act of
> verifying
> > who you are who you say you are by supplying credentials that verify your
> > identity - the type of credentials (password, public/private key pair,
> etc)
> > are irrelevant and up to what the system architect/administrator deems as
> > appropriate.
>
> Sure, but it depends on your viewpoint. Shiro takes the approach that
> remember should not supply any credentials, but I see it as a line
> where different authentication/identifying mechanisms could supply
> some credentials that vary in their strength.


That's Shiro's _default_ assumption.  Any developer can change this if they
want to ;)  Which is obviously what you're asking.

I just wanted to be very clear to most readers and users of the framework
that auto-login - where the end-user is automatically logged in without
their required interaction, is usually a really, really bad idea.  It is not
something that should be done by default (and is why we don't do it by
default).

That being said, Shiro is definitely flexible and will allow you to override
almost anything you want.  If one wants to shoot themselves in the foot,
then they're free to do so (I'm not implying you're doing this, I'm just
making a point that the framework is not inherently limited to only the case
of "remember only my identity" - that's just the default approach for the
same exact reasons your article points out and is sufficient for 95% of use
cases).


> >>
> http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
> )
> >> makes remembering the identity a much more secure process.
> > I just read that article, and I fail to see how it is any better than
> > Shiro's default approach.  Those cookies are valid for only a current
> > session, just as Shiro's 'authenticated' state is only valid for a single
> > session.  In fact, Premises #1, #2, and #3 are exactly why our
> > implementation functions the way it does! :)  And because we don't store
> > passwords in the rememberMe cookie, Premises #2 and #3 aren't even valid
> for
> > Shiro.
>
> Oh I think you need to re-read the article until you see the
> difference and agree that its at least stronger form of identification
> than Shiro's default approach :) It's stronger because the server
> issues you a key that is good for one time access only. Compare this
> to Shiro - you are only storing the identity on the client side and
> the server didn't issue you any key to compare to. It is also stronger
> because all of the rolling tokens can be invalidated on the server,
> for example when you successfully use username/password authentication
> or change a password on the server. Finally, it's stronger because the
> server decides if the remembered identity is expired - not the client.


My point was this doesn't matter much if the programmer uses Shiro's API
properly.  If the API is being used correctly, it would protect certain site
areas depending on their state (anonymous, remembered, and/or
authenticated).  This, ultimately, is the end-goal of the article to which
you linked and what is important.  Yes, the random ID does give the server a
little more control over the entire process, but it is mostly unnecessary
when using the API correctly.

For example, the developer should do something like this:

if ( currentSubject.isAuthenticated() ) {
    spendUsersMoney();
}

and never this:

if ( currentSubject.getPrincipal() != null ) {
    spendUsersMoney();
}

There are JSP tags that execute the same logic based on these 3 states:
anonymous, a user (either remembered or authenticated), and authenticated,
respectively:

<shiro:guest/>
<shiro:user/>
<shiro:authenticated/>

There are tags that represent the inverse of these as well.

But if you disagree that this doesn't provide the same end-goal as what the
article advocates, albeit in a different way, I'd certainly like to hear
your thoughts on why - if there is something that can be added to the
framework to make lives easier for people, it probably should be
incorporated :)

Ok, so it's clear that Shiro's rememberme is only to used for
> remembering the identity.


That's the default yes - but not limited to that.  The developer can do
whatever he likes by implementing the RememberMeManager interface.  You're
probably a super user in this regard and know exactly how you want things to
work - its just I think people should ask themselves if the above approach
is not usable before going down that road - most of the time it is not
necessary and could even cause a security hole.  It is typically a bad thing
to perform sensitive operations without explicitly requiring human
interaction to verify identity, so we don't enable this by default on
purpose.

Let's forget about the rememberme for now
> and I'll rephrase the problem: how do I best implement authentication
> logic based on disposable server issued keys so that client doesn't
> have to go through a particular authentication point?
>
> > Based on what I've read in that article, Shiro already does what you
> > require.  I'm wondering if this is just confusion based on Acegi-related
> > preconceptions?
>
> Certainly not. Acegi doesn't take any stand on how strong any
> particular authentication/identification mechanism is - it's all left
> up to the developer.


Same with Shiro - we just provide a nice default that works assuming you use
the API correctly.  The developer can certainly override this if they desire
by providing their own RememberMeManager implementation.

Please let us know if you have any questions about your implementation or
any other ideas that might make RememberMe better.  I for one am definitely
open to suggestions!

Cheers,

Les

Re: Rememberme vs authentication

Posted by Kalle Korhonen <ka...@gmail.com>.
On Tue, Jun 16, 2009 at 6:50 AM, Les Hazlewood<lh...@apache.org> wrote:
> I think your comments are based on maybe previous Acegi use and there is
> possible confusion as to the differences between the two projects.
> First and foremost, Shiro's rememberMe cookie does not store credentials
> (passwords, keys, etc).  It can never be used to find a user's password.
> Only identity (principals), such as a username, is stored.  Premises #2 and
> #3 in your linked article on rolling tokens does not apply to Shiro.

Yes, not confused really, just asking for confirmation.

> It is most certainly not artificial.  Authentication is the act of verifying
> who you are who you say you are by supplying credentials that verify your
> identity - the type of credentials (password, public/private key pair, etc)
> are irrelevant and up to what the system architect/administrator deems as
> appropriate.

Sure, but it depends on your viewpoint. Shiro takes the approach that
remember should not supply any credentials, but I see it as a line
where different authentication/identifying mechanisms could supply
some credentials that vary in their strength.

>> http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/)
>> makes remembering the identity a much more secure process.
> I just read that article, and I fail to see how it is any better than
> Shiro's default approach.  Those cookies are valid for only a current
> session, just as Shiro's 'authenticated' state is only valid for a single
> session.  In fact, Premises #1, #2, and #3 are exactly why our
> implementation functions the way it does! :)  And because we don't store
> passwords in the rememberMe cookie, Premises #2 and #3 aren't even valid for
> Shiro.

Oh I think you need to re-read the article until you see the
difference and agree that its at least stronger form of identification
than Shiro's default approach :) It's stronger because the server
issues you a key that is good for one time access only. Compare this
to Shiro - you are only storing the identity on the client side and
the server didn't issue you any key to compare to. It is also stronger
because all of the rolling tokens can be invalidated on the server,
for example when you successfully use username/password authentication
or change a password on the server. Finally, it's stronger because the
server decides if the remembered identity is expired - not the client.

> Also, when a user logs out - the rememberMe cookie is invalidated.  The
> article's approach and Shiro's approach are _very_ similar.

I don't want to make this yes/no argument, but if you claim that I
don't think you fully understood the article.

>> I wonder if it would make more sense
>> to implement a custom RememberMeManager or a custom authentication
>> filter for it. Current implementation doesn't allow you to authorize
>> the principal for anything when rememberMe is used,
> I'm confused by this statement.  If you are 'remembered' with Shiro, you can
> most certainly be authorized (remembered user X is allowed/not allowed to do
> action y).  Authorization is based solely on identity (which is retained by
> rememberMe) - not based on your authentication state.

Ok, so it's clear that Shiro's rememberme is only to used for
remembering the identity. Let's forget about the rememberme for now
and I'll rephrase the problem: how do I best implement authentication
logic based on disposable server issued keys so that client doesn't
have to go through a particular authentication point?

> Based on what I've read in that article, Shiro already does what you
> require.  I'm wondering if this is just confusion based on Acegi-related
> preconceptions?

Certainly not. Acegi doesn't take any stand on how strong any
particular authentication/identification mechanism is - it's all left
up to the developer. Shiro instead implements custom logic for
rememberme, i.e. just for the "remember my identity only" case.

Kalle

Re: Rememberme vs authentication

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

I think your comments are based on maybe previous Acegi use and there is
possible confusion as to the differences between the two projects.

First and foremost, Shiro's rememberMe cookie does not store credentials
(passwords, keys, etc).  It can never be used to find a user's password.
Only identity (principals), such as a username, is stored.  Premises #2 and
#3 in your linked article on rolling tokens does not apply to Shiro.

Shiro makes this artificial, strong separation between rememberme and
> authentication. In the javadocs for RememberMeAuthenticationToken
> (
> http://jsecurity.org/api/org/jsecurity/authc/RememberMeAuthenticationToken.html
> )
> it is said that "Authentication is the process of proving you are who
> you say you are". It is stated that rememberme is not considered an
> authentication and implied that only using username/password can be
> used for an "actual authentication".


It is most certainly not artificial.  Authentication is the act of verifying
who you are who you say you are by supplying credentials that verify your
identity - the type of credentials (password, public/private key pair, etc)
are irrelevant and up to what the system architect/administrator deems as
appropriate.

When you are only remembered, you haven't authenticated anything.  By the
very definition of authentication, there can be no confusion as to whether
or not a simply 'remembered' user is authenticated or not.  Any framework
that does not make this distinction is just plain wrong, and the
amazon.comexample shows a very real use case of why this is important.

Shiro makes no requirement that passwords are used to authenticate, and they
have no relationship to rememberMe functionality at all - users can
authenticate by whatever means they desire, such as public/private key
pairs.  The RememberMeAuthenticationToken and its parent interface
explicitly have no notions of usernames and/or passwords for this reason.


> However, in practice there's no
> way to know that whoever supplied the password is who they say they
> are and passwords are generally not considered the strongest form of
> authentication. Shiro's default rememberme implementation results in
> no or very weak authentication,


The correct statement is "Shiro's default rememberMe implementation results
in no authentication" - on purpose.  And again, Shiro's default rememberMe
implementation makes no assumptions about whether or not passwords are good
enough - the application configuration does.

When you are remembered, by default, you are not automatically authenticated
- and never should considered as such just by the very definition of the
word.  Indeed, because Shiro does not retain credentials in rememberMe, it
_can't_ automatically authenticate the remembered user (a good thing).

The application developer decides what state is 'good enough' for his
application by performing the appropriate checks, and because Shiro
distinguisihes between the different states, the developer can do this
easily.  It is not something cludged together as an afterthought in the
framework.

That is,

currentSubject.isAuthenticated() == true:  provided correct credentials
during the current session
currentSubject.getPrincipal() != null: provided correct credentials during
the current session OR during a previous session and they are currently
'remembered' from a previous session
currentSubject.getPrincipal() == null: anonymous user - hasn't authenticated
yet and is not rememebered.


> but there are alternatives that
> results in stronger form of key-based authentication. Private/public
> keys are often considered equally strong authentication to
> username/password and for remember me, using rolling tokens (as
> described for example at
>
> http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
> )
> makes remembering the identity a much more secure process.


I just read that article, and I fail to see how it is any better than
Shiro's default approach.  Those cookies are valid for only a current
session, just as Shiro's 'authenticated' state is only valid for a single
session.  In fact, Premises #1, #2, and #3 are exactly why our
implementation functions the way it does! :)  And because we don't store
passwords in the rememberMe cookie, Premises #2 and #3 aren't even valid for
Shiro.

Also, when a user logs out - the rememberMe cookie is invalidated.  The
article's approach and Shiro's approach are _very_ similar.


> I wonder if it would make more sense
> to implement a custom RememberMeManager or a custom authentication
> filter for it. Current implementation doesn't allow you to authorize
> the principal for anything when rememberMe is used,


I'm confused by this statement.  If you are 'remembered' with Shiro, you can
most certainly be authorized (remembered user X is allowed/not allowed to do
action y).  Authorization is based solely on identity (which is retained by
rememberMe) - not based on your authentication state.

Based on what I've read in that article, Shiro already does what you
require.  I'm wondering if this is just confusion based on Acegi-related
preconceptions?

Best,

Les