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

Improve the storage API #334

Merged
merged 1 commit into from
Apr 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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