OAuth2 Resource Server using Silhouette

80 views
Skip to first unread message

Adrian

unread,
Sep 9, 2016, 10:50:09 AM9/9/16
to Silhouette
Hello,

I'm implementing an OAuth2 resource service (RS).

It's basically a Rest Service which uses an HTTP header for authorization :
Authorization: Bearer mF_9.B5f-4.1JqM


See http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#authz-header
In a first time, this will be an opaque token, so my RS needs to call an OAuth introspection endpoint to retrieve information (most notably caller id and granted OAuth scopes).
https://tools.ietf.org/html/rfc7662

I didn't found OOB support for this scenario in Silhouette (correct me if I'm wrong please !).

I'm trying to implement this flow with Silhouette, but I'm wondering if I'm on the right path.

I'm thinking of extending from RequestProvider.
I'll inject an IdentityService into RequestProvider.
When my RequestProvider.authenticate method is called :
 1. I'll get the token from Authorization HTTP Header.
 2. I'll call the introspect Url
 3. I'll build a User from introspect Url response.
 4. I'll build a LoginInfo with my RequestProvider id and the token.
 4. And I'll call identityService.save(loginInfo, user)

Is it the good way to implement this flow with Silhouette ?
Or is there a better way ?

Thanks,
Adrian

Christian Kaps

unread,
Sep 10, 2016, 3:04:08 AM9/10/16
to Silhouette
Hi,

as noted in the RFC, you should use two tokens to prevent token scanning. The token send in the header is used for authentication against the endpoint(RS), so that only authorized clients can access the endpoint(RS). And the introspection token should be send in a POST request to the introspection endpoint. I'm not sure you have this considered in your scenario?

With this in mind I see the following possibility. I think the request provider is the best place to implement the functionality for the introspection call. For authentication you could use an authenticator provided by Silhouette. The problem is that you cannot use both together in a secured action because if a valid authenticator was found the request provider will not be executed. Using a filter wont't work, because if a client isn't authenticated the secured action used in the filter would use the request provider without authentication. It would bypass the authentication mechanism because the secured action tries first to authenticate with an authenticator and if this fails it would use the request provider. Instead you could also inject the authenticator service into your request provider. So you can handle authentication with the authenticator service and if the client has successful authenticated you could introspect the token. Please note that the bearer or JWT token authenticators, provided by Silhouette, doesn't support the Authorization: Bearer scheme. But I think I will implement this in the next days.

Does this make sense to you?

Best regards,
Christian

Adrian

unread,
Sep 10, 2016, 2:16:14 PM9/10/16
to Silhouette
Thanks for your reply Christian.

My code is working now (just tested it with an OAuth Authorization Server).
I've pushed it to github.

The problem I'm having is how I can make available the OAuth Scopes to my application controllers in a good way ?

My requestHandler code is really ugly :

 1. I'm injecting the identityService into requestHandler :
    as in https://github.com/gonzalad/sample-rs/blob/master/app/org/gonzalad/play/silhouette/impl/providers/OAuth2BearerTokenProvider.scala#L46
 2. requestHandler just gets the access token value from Authorization HTTP Header, and calls identityService.retrieve.
 3. identityService calls introspect endpoint to retrieve all the access token claims, and populates the identity (with access token OAuth scopes)
    as in https://github.com/gonzalad/sample-rs/blob/master/app/org/gonzalad/play/silhouette/impl/providers/OAuth2BearerIntrospectIdentityService.scala#L44

This flow allows me to create SecuredAction to check for an existing OAuth scope :
https://github.com/gonzalad/sample-rs/blob/master/app/controllers/SecuredController.scala#L23
https://github.com/gonzalad/sample-rs/blob/master/app/security/AdminRights.scala

Thanks,
Adrian

P.S. sorry, I didn't inject authenticator service into requestHandler (I didn't understood how my controller could then have access to the OAuth scopes)

Adrian

unread,
Sep 10, 2016, 6:23:20 PM9/10/16
to Silhouette
> The problem I'm having is how I can make available the OAuth Scopes to my application controllers in a good way ?

Perhaps by injecting a AuthInfoRepository in my RequestHandler :
 * requestHandler would create a custom OAuth2BearerTokenIno after calling the introspectUri (this info will contain scopes and accessToken value).
 * it will create a LoginInfo with providerKey = accessToken value.
 * it will save those 2 informations inside AuthInfoRepository.

Then, the microservice developper will just need to create it's own UserService.
He'll need to inject the AuthInfoRepository into its UserService, retrieve the OAuth2BearerTokenIno based on the loginInfo and convert OAuth2BearerTokenIno into whatever User class he wants.

Perhaps this is better since it allows RequestHandler and IdentityService separation, my RequestHandler would then be reusable between multiple applications.

But I believe I'm always missing something with AuthenticatorService :(

Thanks,
Adrian
Reply all
Reply to author
Forward
0 new messages