Skip to content
This repository has been archived by the owner on Sep 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #334 from akkie/storage-api-improvements
Browse files Browse the repository at this point in the history
Improve the storage API
  • Loading branch information
akkie committed Apr 30, 2015
2 parents 33662e1 + 53c4da9 commit 7163750
Show file tree
Hide file tree
Showing 36 changed files with 826 additions and 591 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## 2.0
## 3.0

- Update to Play 2.4
- Fix a lot of inconsistencies in the API

## 2.0 (2015-03-28)

- Use lazy val to initialize SecureRandom, so that initialization occurs also async
- Refactor authenticators and add BearerTokenAuthenticator, JWTAuthenticator, SessionAuthenticator and DummyAuthenticator
Expand Down
29 changes: 20 additions & 9 deletions silhouette-testkit/app/com/mohiva/play/silhouette/test/Fakes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,35 @@ class FakeAuthenticatorDAO[T <: StorableAuthenticator] extends AuthenticatorDAO[
var data: mutable.HashMap[String, T] = mutable.HashMap()

/**
* Saves the authenticator.
* Finds the authenticator for the given ID.
*
* @param authenticator The authenticator to save.
* @return The saved auth authenticator.
* @param id The authenticator ID.
* @return The found authenticator or None if no authenticator could be found for the given ID.
*/
def save(authenticator: T): Future[T] = {
def find(id: String): Future[Option[T]] = {
Future.successful(data.get(id))
}

/**
* Adds a new authenticator.
*
* @param authenticator The authenticator to add.
* @return The added authenticator.
*/
def add(authenticator: T): Future[T] = {
data += (authenticator.id -> authenticator)
Future.successful(authenticator)
}

/**
* Finds the authenticator for the given ID.
* Updates an already existing authenticator.
*
* @param id The authenticator ID.
* @return The found authenticator or None if no authenticator could be found for the given ID.
* @param authenticator The authenticator to update.
* @return The updated authenticator.
*/
def find(id: String): Future[Option[T]] = {
Future.successful(data.get(id))
def update(authenticator: T): Future[T] = {
data += (authenticator.id -> authenticator)
Future.successful(authenticator)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,13 @@ class FakesSpec extends PlaySpecification with JsonMatchers {
}
}

"The `save` method of the `FakeAuthenticatorDAO`" should {
"save an authenticator" in {
val loginInfo = LoginInfo("test", "test")
val authenticator = new FakeAuthenticator(loginInfo)
val dao = new FakeAuthenticatorDAO[FakeAuthenticator]()

await(dao.save(authenticator)) must be equalTo authenticator
}
}

"The `find` method of the `FakeAuthenticatorDAO`" should {
"return an authenticator for the given ID" in {
val loginInfo = LoginInfo("test", "test")
val authenticator = new FakeAuthenticator(loginInfo, "test")
val dao = new FakeAuthenticatorDAO[FakeAuthenticator]()

await(dao.save(authenticator))
await(dao.add(authenticator))

await(dao.find("test")) must beSome(authenticator)
}
Expand All @@ -71,13 +61,33 @@ class FakesSpec extends PlaySpecification with JsonMatchers {
}
}

"The `add` method of the `FakeAuthenticatorDAO`" should {
"add an authenticator" in {
val loginInfo = LoginInfo("test", "test")
val authenticator = new FakeAuthenticator(loginInfo)
val dao = new FakeAuthenticatorDAO[FakeAuthenticator]()

await(dao.add(authenticator)) must be equalTo authenticator
}
}

"The `update` method of the `FakeAuthenticatorDAO`" should {
"update an authenticator" in {
val loginInfo = LoginInfo("test", "test")
val authenticator = new FakeAuthenticator(loginInfo)
val dao = new FakeAuthenticatorDAO[FakeAuthenticator]()

await(dao.update(authenticator)) must be equalTo authenticator
}
}

"The `remove` method of the `FakeAuthenticatorDAO`" should {
"remove an authenticator" in {
val loginInfo = LoginInfo("test", "test")
val authenticator = new FakeAuthenticator(loginInfo, "test")
val dao = new FakeAuthenticatorDAO[FakeAuthenticator]()

await(dao.save(authenticator))
await(dao.add(authenticator))
await(dao.find("test")) must beSome(authenticator)
await(dao.remove("test"))
await(dao.find("test")) must beNone
Expand Down
21 changes: 21 additions & 0 deletions silhouette/app/com/mohiva/play/silhouette/api/AuthInfo.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright 2015 Mohiva Organisation (license at mohiva dot com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mohiva.play.silhouette.api

/**
* A marker trait for authentication information.
*/
trait AuthInfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Copyright 2015 Mohiva Organisation (license at mohiva dot com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mohiva.play.silhouette.api.repositories

import com.mohiva.play.silhouette.api.{ AuthInfo, LoginInfo }

import scala.concurrent.Future
import scala.reflect.ClassTag

/**
* A trait that provides the means to persist authentication information for the Silhouette module.
*
* If the application supports the concept of "merged identities", i.e., the same user being
* able to authenticate through different providers, then make sure that the auth info for
* every linked login info gets stored separately.
*/
trait AuthInfoRepository {

/**
* Finds the auth info which is linked with the specified login info.
*
* @param loginInfo The linked login info.
* @param tag The class tag of the auth info.
* @tparam T The type of the auth info to handle.
* @return The found auth info or None if no auth info could be found for the given login info.
*/
def find[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Option[T]]

/**
* Adds new auth info for the given login info.
*
* @param loginInfo The login info for which the auth info should be saved.
* @param authInfo The auth info to save.
* @tparam T The type of the auth info to handle.
* @return The saved auth info.
*/
def add[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[T]

/**
* Updates the auth info for the given login info.
*
* @param loginInfo The login info for which the auth info should be updated.
* @param authInfo The auth info to update.
* @tparam T The type of the auth info to handle.
* @return The updated auth info.
*/
def update[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[T]

/**
* Removes the auth info for the given login info.
*
* @param loginInfo The login info for which the auth info should be removed.
* @param tag The class tag of the auth info.
* @tparam T The type of the auth info to handle.
* @return A future to wait for the process to be completed.
*/
def remove[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Unit]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright 2015 Mohiva Organisation (license at mohiva dot com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mohiva.play.silhouette.api

/**
* Provides repositories used by the API to persist entities.
*/
package object repositories {}

This file was deleted.

21 changes: 11 additions & 10 deletions silhouette/app/com/mohiva/play/silhouette/api/util/CacheLayer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,14 @@
package com.mohiva.play.silhouette.api.util

import scala.concurrent.Future
import scala.concurrent.duration.Duration
import scala.reflect.ClassTag

/**
* A trait which provides a cache API.
*/
trait CacheLayer {

/**
* Save a value in cache.
*
* @param key The item key under which the value should be saved.
* @param value The value to save.
* @param expiration Expiration time in seconds (0 second means eternity).
* @return The value saved in cache.
*/
def save[T](key: String, value: T, expiration: Int = 0): Future[T]

/**
* Finds a value in the cache.
*
Expand All @@ -42,6 +33,16 @@ trait CacheLayer {
*/
def find[T: ClassTag](key: String): Future[Option[T]]

/**
* Save a value in cache.
*
* @param key The item key under which the value should be saved.
* @param value The value to save.
* @param expiration Expiration time in seconds (0 second means eternity).
* @return The value saved in cache.
*/
def save[T](key: String, value: T, expiration: Duration = Duration.Inf): Future[T]

/**
* Remove a value from the cache.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
package com.mohiva.play.silhouette.api.util

import com.mohiva.play.silhouette.api.services.AuthInfo
import com.mohiva.play.silhouette.api.AuthInfo

/**
* The password details.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class BearerTokenAuthenticatorService(
* @return The serialized authenticator value.
*/
def init(authenticator: BearerTokenAuthenticator)(implicit request: RequestHeader) = {
dao.save(authenticator).map { a =>
dao.add(authenticator).map { a =>
a.id
}.recover {
case e => throw new AuthenticatorInitializationException(InitError.format(ID, authenticator), e)
Expand Down Expand Up @@ -199,7 +199,7 @@ class BearerTokenAuthenticatorService(
* @return The original or a manipulated result.
*/
def update(authenticator: BearerTokenAuthenticator, result: Result)(implicit request: RequestHeader) = {
dao.save(authenticator).map { a =>
dao.update(authenticator).map { a =>
AuthenticatorResult(result)
}.recover {
case e => throw new AuthenticatorUpdateException(UpdateError.format(ID, authenticator), e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class CookieAuthenticatorService(
* @return The serialized authenticator value.
*/
def init(authenticator: CookieAuthenticator)(implicit request: RequestHeader) = {
dao.save(authenticator).map { a =>
dao.add(authenticator).map { a =>
Cookie(
name = settings.cookieName,
value = a.id,
Expand Down Expand Up @@ -231,7 +231,7 @@ class CookieAuthenticatorService(
* @return The original or a manipulated result.
*/
def update(authenticator: CookieAuthenticator, result: Result)(implicit request: RequestHeader) = {
dao.save(authenticator).map { a =>
dao.update(authenticator).map { a =>
AuthenticatorResult(result)
}.recover {
case e => throw new AuthenticatorUpdateException(UpdateError.format(ID, authenticator), e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class JWTAuthenticatorService(
* @return The serialized authenticator value.
*/
def init(authenticator: JWTAuthenticator)(implicit request: RequestHeader) = {
dao.fold(Future.successful(authenticator))(_.save(authenticator)).map { a =>
dao.fold(Future.successful(authenticator))(_.add(authenticator)).map { a =>
serialize(a)(settings)
}.recover {
case e => throw new AuthenticatorInitializationException(InitError.format(ID, authenticator), e)
Expand Down Expand Up @@ -354,7 +354,7 @@ class JWTAuthenticatorService(
* @return The original or a manipulated result.
*/
def update(authenticator: JWTAuthenticator, result: Result)(implicit request: RequestHeader) = {
dao.fold(Future.successful(authenticator))(_.save(authenticator)).map { a =>
dao.fold(Future.successful(authenticator))(_.update(authenticator)).map { a =>
AuthenticatorResult(result.withHeaders(settings.headerName -> serialize(a)(settings)))
}.recover {
case e => throw new AuthenticatorUpdateException(UpdateError.format(ID, authenticator), e)
Expand Down
Loading

0 comments on commit 7163750

Please sign in to comment.