Providing a Custom Request Extractor


#1

Hello,

I am currently trying to define a Custom Request Extractor. I can see the default Request Handlers, and have read the following: https://www.silhouette.rocks/v4.0/docs/providers#section-define-custom-request-extractors

I am a bit confused however as to the specific point at which the implicit should be provided.

Any help is greatly appreciated.

Liam.


#2

Hi,

at which point in the authentication flow do you try to use another request extractor? Maybe you could provide some code?

Best regards,
Christian


#3

Hi Akkie,

Thanks for taking the time to respond.
The general flow of what I am trying to achieve is:

A user signs in, which generates a JWT token and embeds it in a Play Session. The Token is then extracted from the Session on every subsequent request to authenticate the user using the JWTAuthenticator. (This is where I would I need the custom Request Extractor)

The following is an example of an endpoint I would wish to secure. It can be assumed that at this point a user has signed up/logged in, and that they are redirected to this endpoint immediately after.

def index = silhouette.SecuredAction.async { implicit request =>
    Future.successful(Ok(views.html.index("Home",Some(UserView.fromUser(request.identity)))))
}

In the default implementation, Silhouette at this point looks for the token in the headers, and although I see there are ways of specifying where to look for the token via the Request Parts config options, I do not see one which would be suitable for my use case (hence the need for the custom extractor which will look into the play session and return the token from there.)

I have chosen the JWT solution because of the possibility of embedding access right via the Custom Claims Field, which I would hope to do moving forward.

If it helps, my wiring for the SilhouetteModule is as follows (with some trimming):


def configure() {
    bind[Silhouette[DefaultEnv]].to[SilhouetteProvider[DefaultEnv]]
    bind[UnsecuredErrorHandler].to[CustomUnsecuredErrorHandler]
    bind[SecuredErrorHandler].to[CustomSecuredErrorHandler]
    bind[UserService]
    bind[UserDAO]
    bind[CacheLayer].to[PlayCacheLayer]
    bind[IDGenerator].toInstance(new SecureRandomIDGenerator())
    bind[PasswordHasher].toInstance(new BCryptPasswordHasher)
    bind[FingerprintGenerator].toInstance(new DefaultFingerprintGenerator(false))
    bind[EventBus].toInstance(EventBus())
    bind[Clock].toInstance(Clock())
    bind[DelegableAuthInfoDAO[PasswordInfo]].to[PasswordInfoDAO]
    bind[DelegableAuthInfoDAO[OAuth1Info]].to[OAuth1InfoDAO]
    bind[DelegableAuthInfoDAO[OAuth2Info]].to[OAuth2InfoDAO]
    bind[DelegableAuthInfoDAO[OpenIDInfo]].to[OpenIDInfoDAO]
    bind[AuditService].asEagerSingleton
  }

@Provides
def provideEnvironment(
    userService: UserService,
    authenticatorService: AuthenticatorService[JWTAuthenticator],
    eventBus: EventBus
  ): Environment[DefaultEnv] = {

    Environment[DefaultEnv](
      userService,
      authenticatorService,
      Seq(),
      eventBus
    )

  }

@Provides
def provideAuthenticatorService(@Named("authenticator-crypter") crypter: Crypter,
                                  idGenerator: IDGenerator,
                                  configuration: Configuration,
                                  clock: Clock): AuthenticatorService[JWTAuthenticator] = {

    val config = configuration.underlying.as[JWTAuthenticatorSettings]("silhouette.authenticator")
    val encoder = new CrypterAuthenticatorEncoder(crypter)
    new JWTAuthenticatorService (
      clock = clock,
      authenticatorEncoder = encoder,
      idGenerator = idGenerator,
      repository = None,
      settings = config
    )
  }

Thanks for any information/help.
Liam.


#4

Hi,

thanks for the detailed description of your issue :+1:.

It’s currently not possible to use custom request extractors for the retrieval of the authenticator. And I don’t think that I’ll fix this because in the next version or maybe the next after the next version the authenticators will be completely rewritten.

As a workaround, you could store the access rights in a cookie or directly in a session. You could also create a pull request which supports the retrieval from a session or a cookie in the default extractor.

Sorry that I cannot give you a better answer here.

Best regards,
Christian