How can I add persistence to Play Silhouette password hasher registry?

363 Views Asked by At

I'm looking at the Play Silhouette seed example:

https://github.com/mohiva/play-silhouette-seed

It is clear how to add persistence to UserDAO and AuthTokenDAO because they have in memory implementations UserDAOImpl and AuthTokenDAOImpl which you can override and provide database implementations like MongoUserDAOImpl and MongoAuthTokenDAOImpl.

However I'm puzzled by where hashed passwords are stored. There is no DAO for this in the example.

This is the point where the user submits a registration password:

https://github.com/mohiva/play-silhouette-seed/blob/master/app/controllers/SignUpController.scala#L80

val authInfo = passwordHasherRegistry.current.hash(data.password)

How can I add persistence to passwordHasherRegistry?

2

There are 2 best solutions below

3
On BEST ANSWER

You probably don't need to add persistence to passwordHasherRegistry. passwordHasherRegistry is an object that contains a list of current and historical hash functions used to hash the password so you can verify it.

According to the Persistence docs page to persist hashed password information you should provide implementation of AuthInfoRepository trait. You may use DelegableAuthInfoRepository that delegates the work to instance(s) of DelegableAuthInfoDAO. See also Silhouette Persistence ReactiveMongo GitHub repository that provides some Mongo-based implementation MongoAuthInfoDAO

0
On

Based on the suggestion by @SergGr I used https://github.com/mohiva/play-silhouette-persistence-reactivemongo module to implement password persistence.

The documentation of the module shows how to construct a DAO instance:

val dao = new MongoAuthInfoDAO[PasswordInfo](reactiveMongoApi, config)

The original example binds DAO as follows:

bind[DelegableAuthInfoDAO[PasswordInfo]].toInstance(new InMemoryAuthInfoDAO[PasswordInfo])

It is tempting to simply replace this with

bind[DelegableAuthInfoDAO[PasswordInfo]].toInstance(new MongoAuthInfoDAO[PasswordInfo](reactiveMongoApi, config))

and try to inject the required parameters as

class SilhouetteModule @Inject() (reactiveMongoApi: ReactiveMongoApi, configuration: Configuration) extends AbstractModule with ScalaModule

This will compile, and it seems that it makes sense. However this will result in a runtime error, because the injection cannot be performed. It seems we are trying to inject something before having set up the injector correctly.

The solution is to remove this binding alltogether and rely solely on

@Provides
def providePasswordInfoDAO(reactiveMongoApi: ReactiveMongoApi, config: Configuration): DelegableAuthInfoDAO[PasswordInfo] = {
  implicit lazy val format = Json.format[PasswordInfo]
  new MongoAuthInfoDAO[PasswordInfo](reactiveMongoApi, config)
}

This is in the documentation but it is not emphasized that you should use this instead of trying to create an instance yourself.

On little caveat is that the implementation creates a collection auth.PasswordInfo and if you try to check it in the mongo shell with db.auth.PasswordInfo.find(), you will get an error. The dot in the name is a problem, so you have to use db["auth.PasswordInfo"].find().