From 5f16014f69f7a1857a30c030076306bc36a45565 Mon Sep 17 00:00:00 2001 From: akkie Date: Wed, 12 Feb 2014 22:14:54 +0100 Subject: [PATCH] Fixes #104 --- .../contrib/daos/OAuth1InfoDAO.scala | 43 ++++ .../contrib/daos/OAuth2InfoDAO.scala | 43 ++++ .../contrib/daos/PasswordInfoDAO.scala | 43 ++++ .../services/DefaultAuthInfoService.scala | 92 ++++++++ .../contrib/utils/BCryptPasswordHasher.scala | 3 +- .../core/providers/CredentialsProvider.scala | 13 +- .../core/providers/OAuth1Provider.scala | 3 +- .../core/providers/OAuth2Provider.scala | 3 +- .../core/providers/SocialProvider.scala | 6 +- .../core/services/AuthInfoService.scala | 11 +- .../core/utils/PasswordHasher.scala | 11 +- build.sbt | 1 + .../services/DefaultAuthInfoServiceSpec.scala | 223 ++++++++++++++++++ .../core/providers/OAuth1ProviderSpec.scala | 2 +- .../core/providers/OAuth2ProviderSpec.scala | 2 +- 15 files changed, 478 insertions(+), 21 deletions(-) create mode 100644 app/com/mohiva/play/silhouette/contrib/daos/OAuth1InfoDAO.scala create mode 100644 app/com/mohiva/play/silhouette/contrib/daos/OAuth2InfoDAO.scala create mode 100644 app/com/mohiva/play/silhouette/contrib/daos/PasswordInfoDAO.scala create mode 100644 app/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoService.scala create mode 100644 test/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoServiceSpec.scala diff --git a/app/com/mohiva/play/silhouette/contrib/daos/OAuth1InfoDAO.scala b/app/com/mohiva/play/silhouette/contrib/daos/OAuth1InfoDAO.scala new file mode 100644 index 000000000..3a1ade6bf --- /dev/null +++ b/app/com/mohiva/play/silhouette/contrib/daos/OAuth1InfoDAO.scala @@ -0,0 +1,43 @@ +/** + * Copyright 2014 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.contrib.daos + +import com.mohiva.play.silhouette.core.LoginInfo +import com.mohiva.play.silhouette.core.providers.OAuth1Info +import scala.concurrent.Future + +/** + * The DAO to store the OAuth1 information. + */ +trait OAuth1InfoDAO { + + /** + * Saves the OAuth1 info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The OAuth1 info to save. + * @return The saved OAuth1 info or None if the OAuth1 info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: OAuth1Info): Future[Option[OAuth1Info]] + + /** + * Finds the OAuth1 info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved OAuth1 info or None if no OAuth1 info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[OAuth1Info]] +} diff --git a/app/com/mohiva/play/silhouette/contrib/daos/OAuth2InfoDAO.scala b/app/com/mohiva/play/silhouette/contrib/daos/OAuth2InfoDAO.scala new file mode 100644 index 000000000..31301f0af --- /dev/null +++ b/app/com/mohiva/play/silhouette/contrib/daos/OAuth2InfoDAO.scala @@ -0,0 +1,43 @@ +/** + * Copyright 2014 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.contrib.daos + +import com.mohiva.play.silhouette.core.LoginInfo +import com.mohiva.play.silhouette.core.providers.OAuth2Info +import scala.concurrent.Future + +/** + * The DAO to store the OAuth2 information. + */ +trait OAuth2InfoDAO { + + /** + * Saves the OAuth2 info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The OAuth2 info to save. + * @return The saved OAuth2 info or None if the OAuth2 info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: OAuth2Info): Future[Option[OAuth2Info]] + + /** + * Finds the OAuth2 info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved OAuth2 info or None if no OAuth2 info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[OAuth2Info]] +} diff --git a/app/com/mohiva/play/silhouette/contrib/daos/PasswordInfoDAO.scala b/app/com/mohiva/play/silhouette/contrib/daos/PasswordInfoDAO.scala new file mode 100644 index 000000000..2c610b7f9 --- /dev/null +++ b/app/com/mohiva/play/silhouette/contrib/daos/PasswordInfoDAO.scala @@ -0,0 +1,43 @@ +/** + * Copyright 2014 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.contrib.daos + +import com.mohiva.play.silhouette.core.LoginInfo +import com.mohiva.play.silhouette.core.providers.PasswordInfo +import scala.concurrent.Future + +/** + * The DAO to store the password information. + */ +trait PasswordInfoDAO { + + /** + * Saves the password info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The password info to save. + * @return The saved password info or None if the password info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: PasswordInfo): Future[Option[PasswordInfo]] + + /** + * Finds the password info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved password info or None if no password info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[PasswordInfo]] +} diff --git a/app/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoService.scala b/app/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoService.scala new file mode 100644 index 000000000..7737f2d70 --- /dev/null +++ b/app/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoService.scala @@ -0,0 +1,92 @@ +/** + * Copyright 2014 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.contrib.services + +import javax.inject.Inject +import scala.reflect.ClassTag +import scala.concurrent.Future +import scala.concurrent.ExecutionContext.Implicits.global +import com.mohiva.play.silhouette.core.LoginInfo +import com.mohiva.play.silhouette.core.services.{ AuthInfo, AuthInfoService } +import com.mohiva.play.silhouette.core.providers.{ OAuth2Info, OAuth1Info, PasswordInfo } +import com.mohiva.play.silhouette.contrib.daos.{ OAuth2InfoDAO, OAuth1InfoDAO, PasswordInfoDAO } +import DefaultAuthInfoService._ + +/** + * An implementation of the auth info service which stores the different auth info instances with the help of + * different DAOs. + * + * Due the nature of the different auth information it is hard to persist the data in a single data structure, + * expect the data gets stored in a serialized format. With this implementation it is possible to store the + * different auth info in different backing stores. If we speak of a relational database, then the auth info + * can be stored in different tables. And the tables represents the internal data structure of each auth info + * object. + * + * @param passwordInfoDAO The password info DAO implementation. + * @param oauth1InfoDAO The OAuth1 info DAO implementation. + * @param oauth2InfoDAO The OAuth2 info DAO implementation. + */ +class DefaultAuthInfoService @Inject() ( + passwordInfoDAO: PasswordInfoDAO, + oauth1InfoDAO: OAuth1InfoDAO, + oauth2InfoDAO: OAuth2InfoDAO) extends AuthInfoService { + + /** + * Saves auth info. + * + * This method gets called when a user logs in(social auth) or registers. This is the change + * to persist the auth info for a provider in the backing store. 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. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The auth info to save. + * @return The saved auth info or None if the auth info couldn't be saved. + */ + def save[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[Option[T]] = authInfo match { + case a: PasswordInfo => passwordInfoDAO.save(loginInfo, a).map(_.map(_.asInstanceOf[T])) + case a: OAuth1Info => oauth1InfoDAO.save(loginInfo, a).map(_.map(_.asInstanceOf[T])) + case a: OAuth2Info => oauth2InfoDAO.save(loginInfo, a).map(_.map(_.asInstanceOf[T])) + case a => throw new Exception(SaveError.format(a.getClass)) + } + + /** + * Retrieves 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. + * @return The retrieved auth info or None if no auth info could be retrieved for the given login info. + */ + def retrieve[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Option[T]] = tag match { + case a if a.runtimeClass == classOf[PasswordInfo] => passwordInfoDAO.find(loginInfo).map(_.map(_.asInstanceOf[T])) + case a if a.runtimeClass == classOf[OAuth1Info] => oauth1InfoDAO.find(loginInfo).map(_.map(_.asInstanceOf[T])) + case a if a.runtimeClass == classOf[OAuth2Info] => oauth2InfoDAO.find(loginInfo).map(_.map(_.asInstanceOf[T])) + case a => throw new Exception(RetrieveError.format(a.runtimeClass)) + } +} + +/** + * The companion object. + */ +object DefaultAuthInfoService { + + /** + * The error messages. + */ + val SaveError = "Cannot save auth info of type: %s" + val RetrieveError = "Cannot search for auth info of type: %s" +} diff --git a/app/com/mohiva/play/silhouette/contrib/utils/BCryptPasswordHasher.scala b/app/com/mohiva/play/silhouette/contrib/utils/BCryptPasswordHasher.scala index 36cae4752..3ddace606 100644 --- a/app/com/mohiva/play/silhouette/contrib/utils/BCryptPasswordHasher.scala +++ b/app/com/mohiva/play/silhouette/contrib/utils/BCryptPasswordHasher.scala @@ -19,7 +19,8 @@ */ package com.mohiva.play.silhouette.contrib.utils -import com.mohiva.play.silhouette.core.utils.{ PasswordInfo, PasswordHasher } +import com.mohiva.play.silhouette.core.utils.PasswordHasher +import com.mohiva.play.silhouette.core.providers.PasswordInfo import org.mindrot.jbcrypt.BCrypt import BCryptPasswordHasher._ diff --git a/app/com/mohiva/play/silhouette/core/providers/CredentialsProvider.scala b/app/com/mohiva/play/silhouette/core/providers/CredentialsProvider.scala index 101208bb8..36bfebb9b 100644 --- a/app/com/mohiva/play/silhouette/core/providers/CredentialsProvider.scala +++ b/app/com/mohiva/play/silhouette/core/providers/CredentialsProvider.scala @@ -22,8 +22,8 @@ package com.mohiva.play.silhouette.core.providers import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global import com.mohiva.play.silhouette.core._ -import com.mohiva.play.silhouette.core.services.AuthInfoService -import com.mohiva.play.silhouette.core.utils.{ PasswordHasher, PasswordInfo } +import com.mohiva.play.silhouette.core.services.{ AuthInfo, AuthInfoService } +import com.mohiva.play.silhouette.core.utils.PasswordHasher /** * A provider for authenticating with credentials. @@ -86,3 +86,12 @@ object CredentialsProvider { * @param password The password to authenticate with. */ case class Credentials(identifier: String, password: String) + +/** + * The password details. + * + * @param hasher The ID of the hasher used to hash this password. + * @param password The hashed password. + * @param salt The optional salt used when hashing. + */ +case class PasswordInfo(hasher: String, password: String, salt: Option[String] = None) extends AuthInfo diff --git a/app/com/mohiva/play/silhouette/core/providers/OAuth1Provider.scala b/app/com/mohiva/play/silhouette/core/providers/OAuth1Provider.scala index 4cb174fae..a8185149f 100644 --- a/app/com/mohiva/play/silhouette/core/providers/OAuth1Provider.scala +++ b/app/com/mohiva/play/silhouette/core/providers/OAuth1Provider.scala @@ -28,6 +28,7 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.util.{ Success, Failure, Try } import com.mohiva.play.silhouette.core._ import com.mohiva.play.silhouette.core.utils.{ HTTPLayer, CacheLayer } +import com.mohiva.play.silhouette.core.services.AuthInfo import OAuth1Provider._ /** @@ -193,4 +194,4 @@ case class OAuth1Settings( * @param token The consumer token. * @param secret The consumer secret. */ -case class OAuth1Info(token: String, secret: String) +case class OAuth1Info(token: String, secret: String) extends AuthInfo diff --git a/app/com/mohiva/play/silhouette/core/providers/OAuth2Provider.scala b/app/com/mohiva/play/silhouette/core/providers/OAuth2Provider.scala index ae20a86cc..5288410d7 100644 --- a/app/com/mohiva/play/silhouette/core/providers/OAuth2Provider.scala +++ b/app/com/mohiva/play/silhouette/core/providers/OAuth2Provider.scala @@ -29,6 +29,7 @@ import play.api.libs.functional.syntax._ import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global import com.mohiva.play.silhouette.core.utils.{ HTTPLayer, CacheLayer } +import com.mohiva.play.silhouette.core.services.AuthInfo import com.mohiva.play.silhouette.core._ import OAuth2Provider._ @@ -236,4 +237,4 @@ case class OAuth2Info( accessToken: String, tokenType: Option[String] = None, expiresIn: Option[Int] = None, - refreshToken: Option[String] = None) + refreshToken: Option[String] = None) extends AuthInfo diff --git a/app/com/mohiva/play/silhouette/core/providers/SocialProvider.scala b/app/com/mohiva/play/silhouette/core/providers/SocialProvider.scala index a6a746118..84132433a 100644 --- a/app/com/mohiva/play/silhouette/core/providers/SocialProvider.scala +++ b/app/com/mohiva/play/silhouette/core/providers/SocialProvider.scala @@ -15,18 +15,18 @@ */ package com.mohiva.play.silhouette.core.providers -import play.api.mvc.{ SimpleResult, RequestHeader } import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global +import play.api.mvc.{ SimpleResult, RequestHeader } import com.mohiva.play.silhouette.core.{ LoginInfo, Provider } -import com.mohiva.play.silhouette.core.services.AuthInfoService +import com.mohiva.play.silhouette.core.services.{ AuthInfo, AuthInfoService } /** * The base interface for all social providers. * * @tparam A The type of the auth info. */ -trait SocialProvider[A] extends Provider { +trait SocialProvider[A <: AuthInfo] extends Provider { /** * Authenticates the user and fills the profile information. diff --git a/app/com/mohiva/play/silhouette/core/services/AuthInfoService.scala b/app/com/mohiva/play/silhouette/core/services/AuthInfoService.scala index a245850c4..fd04ad126 100644 --- a/app/com/mohiva/play/silhouette/core/services/AuthInfoService.scala +++ b/app/com/mohiva/play/silhouette/core/services/AuthInfoService.scala @@ -19,6 +19,7 @@ */ package com.mohiva.play.silhouette.core.services +import scala.reflect.ClassTag import scala.concurrent.Future import com.mohiva.play.silhouette.core.LoginInfo @@ -41,13 +42,19 @@ trait AuthInfoService { * @param authInfo The auth info to save. * @return The saved auth info or None if the auth info couldn't be saved. */ - def save[T](loginInfo: LoginInfo, authInfo: T): Future[Option[T]] + def save[T <: AuthInfo](loginInfo: LoginInfo, authInfo: T): Future[Option[T]] /** * Retrieves 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. * @return The retrieved auth info or None if no auth info could be retrieved for the given login info. */ - def retrieve[T](loginInfo: LoginInfo): Future[Option[T]] + def retrieve[T <: AuthInfo](loginInfo: LoginInfo)(implicit tag: ClassTag[T]): Future[Option[T]] } + +/** + * A marker trait for authentication information. + */ +trait AuthInfo diff --git a/app/com/mohiva/play/silhouette/core/utils/PasswordHasher.scala b/app/com/mohiva/play/silhouette/core/utils/PasswordHasher.scala index 57fb93e9d..c8cb9af00 100644 --- a/app/com/mohiva/play/silhouette/core/utils/PasswordHasher.scala +++ b/app/com/mohiva/play/silhouette/core/utils/PasswordHasher.scala @@ -19,6 +19,8 @@ */ package com.mohiva.play.silhouette.core.utils +import com.mohiva.play.silhouette.core.providers.PasswordInfo + /** * A trait that defines the password hasher interface. */ @@ -48,12 +50,3 @@ trait PasswordHasher { */ def matches(passwordInfo: PasswordInfo, suppliedPassword: String): Boolean } - -/** - * The password details. - * - * @param hasher The ID of the hasher used to hash this password. - * @param password The hashed password. - * @param salt The optional salt used when hashing. - */ -case class PasswordInfo(hasher: String, password: String, salt: Option[String] = None) diff --git a/build.sbt b/build.sbt index 3feeba964..6f31e5d4b 100644 --- a/build.sbt +++ b/build.sbt @@ -16,6 +16,7 @@ licenses := Seq("Apache License" -> url("https://github.com/mohiva/play-silhouet libraryDependencies ++= Seq( cache, "org.mindrot" % "jbcrypt" % "0.3m", + "javax.inject" % "javax.inject" % "1", "org.mockito" % "mockito-core" % "1.9.5" % "test" ) diff --git a/test/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoServiceSpec.scala b/test/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoServiceSpec.scala new file mode 100644 index 000000000..80fc5a089 --- /dev/null +++ b/test/com/mohiva/play/silhouette/contrib/services/DefaultAuthInfoServiceSpec.scala @@ -0,0 +1,223 @@ +/** + * Copyright 2014 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.contrib.services + +import org.specs2.specification.Scope +import play.api.test.PlaySpecification +import scala.collection.mutable +import scala.concurrent.Future +import com.mohiva.play.silhouette.core.LoginInfo +import com.mohiva.play.silhouette.core.providers.{ PasswordInfo, OAuth2Info, OAuth1Info } +import com.mohiva.play.silhouette.contrib.daos.{ OAuth2InfoDAO, OAuth1InfoDAO, PasswordInfoDAO } +import com.mohiva.play.silhouette.core.services.AuthInfo +import DefaultAuthInfoService._ + +/** + * Test case for the [[com.mohiva.play.silhouette.contrib.services.DefaultAuthInfoService]] trait. + */ +class DefaultAuthInfoServiceSpec extends PlaySpecification { + + "The save method" should { + "save the PasswordInfo in the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + + await(service.save(loginInfo, passwordInfo)) must beSome(passwordInfo) + passwordInfoDAO.data.apply(loginInfo) must be equalTo passwordInfo + } + + "save the OAuth1Info in the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + + await(service.save(loginInfo, oauth1Info)) must beSome(oauth1Info) + oauth1InfoDAO.data.apply(loginInfo) must be equalTo oauth1Info + } + + "save the OAuth2Info in the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + + await(service.save(loginInfo, oauth2Info)) must beSome(oauth2Info) + oauth2InfoDAO.data.apply(loginInfo) must be equalTo oauth2Info + } + + "throw an Exception if an unsupported type was given" in new Context { + val loginInfo = LoginInfo("credentials", "1") + + await(service.save(loginInfo, new UnsupportedInfo)) must throwA[Exception].like { + case e => e.getMessage must startWith(SaveError.format("")) + } + } + } + + "The retrieve method" should { + "retrieve the PasswordInfo from the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + passwordInfoDAO.data += (loginInfo -> passwordInfo) + + await(service.retrieve[PasswordInfo](loginInfo)) must beSome(passwordInfo) + } + + "retrieve the OAuth1Info from the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + oauth1InfoDAO.data += (loginInfo -> oauth1Info) + + await(service.retrieve[OAuth1Info](loginInfo)) must beSome(oauth1Info) + } + + "retrieve the OAuth2Info from the correct DAO" in new Context { + val loginInfo = LoginInfo("credentials", "1") + oauth2InfoDAO.data += (loginInfo -> oauth2Info) + + await(service.retrieve[OAuth2Info](loginInfo)) must beSome(oauth2Info) + } + + "throw an Exception if an unsupported type was given" in new Context { + val loginInfo = LoginInfo("credentials", "1") + + await(service.retrieve[UnsupportedInfo](loginInfo)) must throwA[Exception].like { + case e => e.getMessage must startWith(RetrieveError.format("")) + } + } + } + + /** + * The context. + */ + trait Context extends Scope { + + /** + * The DAOs. + */ + val passwordInfoDAO = new PasswordInfoDAOImpl + val oauth1InfoDAO = new OAuth1InfoDAOImpl + val oauth2InfoDAO = new OAuth2InfoDAOImpl + + /** + * The auth info. + */ + val passwordInfo = PasswordInfo("test.hasher", "test.password") + val oauth1Info = OAuth1Info("test.token", "test.secret") + val oauth2Info = OAuth2Info("test.token") + + /** + * The cache instance to store the different auth information instances. + */ + val service = new DefaultAuthInfoService(passwordInfoDAO, oauth1InfoDAO, oauth2InfoDAO) + } + + /** + * An unsupported auth info. + */ + class UnsupportedInfo extends AuthInfo + + /** + * The DAO to store the password information. + */ + class PasswordInfoDAOImpl extends PasswordInfoDAO { + + /** + * The data store for the password info. + */ + var data: mutable.HashMap[LoginInfo, PasswordInfo] = mutable.HashMap() + + /** + * Saves the password info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The password info to save. + * @return The saved password info or None if the password info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: PasswordInfo): Future[Option[PasswordInfo]] = { + data += (loginInfo -> authInfo) + Future.successful(Some(authInfo)) + } + + /** + * Finds the password info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved password info or None if no password info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[PasswordInfo]] = { + Future.successful(Option(data.apply(loginInfo))) + } + } + + /** + * The DAO to store the OAuth1 information. + */ + class OAuth1InfoDAOImpl extends OAuth1InfoDAO { + + /** + * The data store for the OAuth1 info. + */ + var data: mutable.HashMap[LoginInfo, OAuth1Info] = mutable.HashMap() + + /** + * Saves the OAuth1 info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The OAuth1 info to save. + * @return The saved OAuth1 info or None if the OAuth1 info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: OAuth1Info): Future[Option[OAuth1Info]] = { + data += (loginInfo -> authInfo) + Future.successful(Some(authInfo)) + } + + /** + * Finds the OAuth1 info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved OAuth1 info or None if no OAuth1 info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[OAuth1Info]] = { + Future.successful(Option(data.apply(loginInfo))) + } + } + + /** + * The DAO to store the OAuth2 information. + */ + class OAuth2InfoDAOImpl extends OAuth2InfoDAO { + + /** + * The data store for the OAuth2 info. + */ + var data: mutable.HashMap[LoginInfo, OAuth2Info] = mutable.HashMap() + + /** + * Saves the OAuth2 info. + * + * @param loginInfo The login info for which the auth info should be saved. + * @param authInfo The OAuth2 info to save. + * @return The saved OAuth2 info or None if the OAuth2 info couldn't be saved. + */ + def save(loginInfo: LoginInfo, authInfo: OAuth2Info): Future[Option[OAuth2Info]] = { + data += (loginInfo -> authInfo) + Future.successful(Some(authInfo)) + } + + /** + * Finds the OAuth2 info which is linked with the specified login info. + * + * @param loginInfo The linked login info. + * @return The retrieved OAuth2 info or None if no OAuth2 info could be retrieved for the given login info. + */ + def find(loginInfo: LoginInfo): Future[Option[OAuth2Info]] = { + Future.successful(Option(data.apply(loginInfo))) + } + } +} diff --git a/test/com/mohiva/play/silhouette/core/providers/OAuth1ProviderSpec.scala b/test/com/mohiva/play/silhouette/core/providers/OAuth1ProviderSpec.scala index ce69084ae..6ba4d5b15 100644 --- a/test/com/mohiva/play/silhouette/core/providers/OAuth1ProviderSpec.scala +++ b/test/com/mohiva/play/silhouette/core/providers/OAuth1ProviderSpec.scala @@ -29,7 +29,7 @@ import com.mohiva.play.silhouette.core.AuthenticationException import OAuth1Provider._ /** - * Test case for the [[com.mohiva.play.silhouette.core.providers.OAuth1ProviderSpec]] class. + * Test case for the [[com.mohiva.play.silhouette.core.providers.OAuth1Provider]] class. * * These tests will be additionally executed before every OAuth1 provider spec. */ diff --git a/test/com/mohiva/play/silhouette/core/providers/OAuth2ProviderSpec.scala b/test/com/mohiva/play/silhouette/core/providers/OAuth2ProviderSpec.scala index 35510b1bc..e9dd45284 100644 --- a/test/com/mohiva/play/silhouette/core/providers/OAuth2ProviderSpec.scala +++ b/test/com/mohiva/play/silhouette/core/providers/OAuth2ProviderSpec.scala @@ -30,7 +30,7 @@ import com.mohiva.play.silhouette.core.{ AuthenticationException, AccessDeniedEx import OAuth2Provider._ /** - * Test case for the [[com.mohiva.play.silhouette.core.providers.OAuth2ProviderSpec]] class. + * Test case for the [[com.mohiva.play.silhouette.core.providers.OAuth2Provider]] class. * * These tests will be additionally executed before every OAuth2 provider spec. */