For web-scale scalability, most REST implementors prefer that REST APIs
should be stateless.  While you _can_ have REST APIs that use sessions,
most choose to remain stateless and authenticate on every request as a best
practice.

Assuming you'll authenticate every request, your token will be the data
you'll need to submit to Shiro on each request.

In security circles, this is known as a 'bearer token' - the data isn't
actual authentication principals+credentials, instead it is a token that
you automatically assume that the presenter of the token (aka 'holder' or
'bearer') is allowed to have it and you can trust it.  I should point out
that bearer tokens are less secure than other mechanisms, but I won't talk
about that here, as that is a different thread entirely.  But sometimes
(e.g. your case?) maybe they're the only mechanism that can be used.

Assuming you want to perform bearer token authentication In Shiro, you can
implement the AuthenticationToken interface, e.g.:

public class BearerAuthenticationToken implements AuthenticationToken {
    public BearerAuthenticationToken(String token) {...}
    ....
}

You can then create a Realm implementation that 'supports' this
BearerAuthenticationToken implementation.  This ensures that only this
Realm will process these types of authentication attempts:

public class BearerTokenRealm extends AuthorizingRealm /* or
AuthenticatingRealm */ {

    public BearerTokenRealm() {
        //this makes the supports(...) method return true only if the token
is an instanceof BAT:
        setAuthenticationTokenClass(BearerAuthenticationToken.class);
    }

    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
token) throws AuthenticationException {
        BearerAuthenticationToken bearerToken =
(BearerAuthenticationToken)token;

        //assert the bearerToken, and if valid, look up the account data
and return
        //an AuthenticationInfo instance representing that account.
    }
}

In my opinion, the String contents should be encrypted with AES-256
encryption using a private key known only to the application.  The
unencrypted value can be whatever you want - e.g. an account ID that you
can use to look up account information.

Next, you'll need to create an AuthenticatingFilter implementation that
knows how to extract the token from the HTTP Headers and construct a
BearerAuthenticationToken instance, e.g.:

BearerTokenAuthenticatingFilter extends AuthenticatingFilter {

    @Override
    public AuthenticationToken createToken(....) {

    }

}

You can look at the source code for Shiro's BasicHttpAuthenticationFilter
implementation to give you ideas when implementing your own
BearerTokenFilter:

http://svn.apache.org/repos/asf/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/authc/BasicHttpAuthenticationFilter.java

Finally, you can set up the filter and filter chain definitions in
shiro.ini (or equivalent in Spring or Guice, etc):

[main]

bearerAuthc = com.company.shiro.web.filter.BearerTokenAuthenticatingFilter

[urls]

/rest/** = ssl, noSessionCreation, bearerAuthc

I'd definitely use the SSL filter to enforce SSL to ensure the token cannot
be modified in transit.  This is one of a few security reasons why bearer
tokens must be secured in additional ways (e.g. they are not as strong as,
say, digest-based authentication that don't need SSL).

HTH!

--
Les Hazlewood | @lhazlewood
CTO, Stormpath | http://stormpath.com | @goStormpath | 888.391.5282
Stormpath wins GigaOM Structure Launchpad Award! http://bit.ly/MvZkMk


On Mon, Aug 6, 2012 at 2:28 PM, Sean Blaes <[email protected]> wrote:

>  I've been doing a ton of research on this and just want to validate the
> best approach before I move forward...
>
> My requirement is that I do token based authentication for a REST/Jersey
> service that is also integrated with Spring. This means that there is an
> "authenticate" service to which the username/password will be posted, which
> will respond with a string token. That token can be whatever I want. All
> other method request will pass the token in an HTTP header. This is the
> requirement because we support several existing clients and cannot expect
> them to change at our whim, and this is how the current service works that
> is using a home-grown auth framework.
>
> I'm looking at disabling session creation, as described at:
>
>
> https://cwiki.apache.org/confluence/display/SHIRO/Session+Management#SessionManagement-StatelessApplications%28Sessionless%29
>
> Specifically with
>
> /rest/** = noSessionCreation, anon
>
> The question then is how do I best store and retrieve the fact that the
> user with a given token has been authenticated? Should I just store it in
> ehcache and and retrieve it with a "remember me manager" upon each request?
> Or, do I need to implement a secondary realm that logs in by the stored
> auth token rather than the user/password. Lastly, I could keep sessions
> enabled but I really don't need anything from the session other than this
> token, I don't think.
>
> --
> Sean Blaes
> Sent with Sparrow <http://www.sparrowmailapp.com/?sig>
>
>

Reply via email to