From be4079c41e5808ea12d316e9c9d04a58381e6c78 Mon Sep 17 00:00:00 2001 From: Rustam Kildiev Date: Wed, 13 Apr 2016 12:43:34 +0300 Subject: [PATCH] minimum support for Play 2.5 --- .../app/securesocial/controllers/Assets.scala | 2 +- .../securesocial/controllers/LoginPage.scala | 21 ++-- .../MailTokenBasedOperations.scala | 36 +++--- .../controllers/PasswordChange.scala | 35 +++--- .../controllers/PasswordReset.scala | 12 +- .../controllers/ProviderController.scala | 15 ++- .../controllers/Registration.scala | 15 ++- .../controllers/ViewsPlugin.scala | 35 ++++-- .../securesocial/core/IdentityProvider.scala | 31 +++-- .../securesocial/core/OAuth2Provider.scala | 14 ++- .../app/securesocial/core/SecureSocial.scala | 107 ++++++++-------- .../authenticator/CookieAuthenticator.scala | 45 ++++--- .../HttpHeaderAuthenticator.scala | 12 +- .../core/authenticator/IdGenerator.scala | 14 ++- .../core/java/BasePasswordHasher.java | 28 ----- .../core/java/BaseUserService.java | 118 +++++++++--------- .../java/DefaultSecuredActionResponses.java | 35 +++--- .../securesocial/core/java/SecureSocial.java | 52 ++++---- .../app/securesocial/core/java/Secured.java | 111 ++++++++-------- .../core/java/SecuredActionResponses.java | 11 +- .../app/securesocial/core/java/UserAware.java | 82 ++++++------ .../core/providers/DropboxProvider.scala | 9 +- .../providers/UsernamePasswordProvider.scala | 22 ++-- .../core/providers/WeiboProvider.scala | 14 ++- .../core/providers/utils/Mailer.scala | 49 +++++--- .../core/providers/utils/PasswordHasher.scala | 26 ++-- .../providers/utils/PasswordValidator.scala | 17 +-- .../core/services/CacheService.scala | 23 +++- .../core/services/HttpService.scala | 16 ++- .../core/services/RoutesService.scala | 21 +++- module-code/build.sbt | 4 +- module-code/conf/securesocial.routes | 32 ++--- project/Common.scala | 8 +- project/plugins.sbt | 2 +- .../demo/app/controllers/Application.java | 10 +- .../demo/app/service/InMemoryUserService.java | 37 +++--- samples/java/demo/javaDemo.sbt | 4 +- samples/scala/demo/app/Global.scala | 65 +++++----- samples/scala/demo/scalaDemo.sbt | 2 - 39 files changed, 664 insertions(+), 528 deletions(-) delete mode 100644 module-code/app/securesocial/core/java/BasePasswordHasher.java diff --git a/module-code/app/securesocial/controllers/Assets.scala b/module-code/app/securesocial/controllers/Assets.scala index 9266fd253..39f99da17 100644 --- a/module-code/app/securesocial/controllers/Assets.scala +++ b/module-code/app/securesocial/controllers/Assets.scala @@ -1,3 +1,3 @@ package securesocial.controllers -object Assets extends controllers.AssetsBuilder(play.api.http.LazyHttpErrorHandler) \ No newline at end of file +class Assets extends controllers.AssetsBuilder(play.api.http.LazyHttpErrorHandler) \ No newline at end of file diff --git a/module-code/app/securesocial/controllers/LoginPage.scala b/module-code/app/securesocial/controllers/LoginPage.scala index f57ea3ce8..7b0607c4e 100644 --- a/module-code/app/securesocial/controllers/LoginPage.scala +++ b/module-code/app/securesocial/controllers/LoginPage.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -18,13 +18,13 @@ package securesocial.controllers import javax.inject.Inject +import play.api.Application +import play.filters.csrf.CSRFAddToken import securesocial.core._ +import securesocial.core.providers.UsernamePasswordProvider import securesocial.core.utils._ -import play.api.Play -import Play.current -import providers.UsernamePasswordProvider -import scala.concurrent.{ ExecutionContext, Future } -import play.filters.csrf._ + +import scala.concurrent.Future /** * A default Login controller that uses BasicProfile as the user type. @@ -44,8 +44,12 @@ trait BaseLoginPage extends SecureSocial { */ val onLogoutGoTo = "securesocial.onLogoutGoTo" + @Inject + implicit var CSRFAddToken: CSRFAddToken = null + /** * Renders the login page + * * @return */ def login = CSRFAddToken { @@ -71,6 +75,9 @@ trait BaseLoginPage extends SecureSocial { } } + @Inject + var application: Application = null + /** * Logs out the user by clearing the credentials from the session. * The browser is redirected either to the login page or to the page specified in the onLogoutGoTo property. @@ -79,7 +86,7 @@ trait BaseLoginPage extends SecureSocial { */ def logout = UserAwareAction.async { implicit request => - val redirectTo = Redirect(Play.configuration.getString(onLogoutGoTo).getOrElse(env.routes.loginPageUrl)) + val redirectTo = Redirect(application.configuration.getString(onLogoutGoTo).getOrElse(env.routes.loginPageUrl)) val result = for { user <- request.user authenticator <- request.authenticator diff --git a/module-code/app/securesocial/controllers/MailTokenBasedOperations.scala b/module-code/app/securesocial/controllers/MailTokenBasedOperations.scala index 82da9aa39..af11820b4 100644 --- a/module-code/app/securesocial/controllers/MailTokenBasedOperations.scala +++ b/module-code/app/securesocial/controllers/MailTokenBasedOperations.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -17,18 +17,17 @@ package securesocial.controllers import java.util.UUID +import javax.inject.Inject import org.joda.time.DateTime -import play.api.Play +import play.api.Application import play.api.data.Form import play.api.data.Forms._ import play.api.data.validation.Constraints._ import play.api.i18n.Messages -import play.api.mvc.{ RequestHeader, Result } +import play.api.mvc.{RequestHeader, Result} import securesocial.core.SecureSocial import securesocial.core.providers.MailToken -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current import scala.concurrent.Future @@ -42,7 +41,9 @@ abstract class MailTokenBasedOperations extends SecureSocial { val Email = "email" val TokenDurationKey = "securesocial.userpass.tokenDuration" val DefaultDuration = 60 - val TokenDuration = Play.current.configuration.getInt(TokenDurationKey).getOrElse(DefaultDuration) + @Inject + implicit var application: Application = null + val TokenDuration = application.configuration.getInt(TokenDurationKey).getOrElse(DefaultDuration) val startForm = Form( Email -> email.verifying(nonEmpty) @@ -51,7 +52,7 @@ abstract class MailTokenBasedOperations extends SecureSocial { /** * Creates a token for mail based operations * - * @param email the email address + * @param email the email address * @param isSignUp a boolean indicating if the token is used for a signup or password reset operation * @return a MailToken instance */ @@ -67,22 +68,21 @@ abstract class MailTokenBasedOperations extends SecureSocial { * Helper method to execute actions where a token needs to be retrieved from * the backing store * - * @param token the token id + * @param token the token id * @param isSignUp a boolean indicating if the token is used for a signup or password reset operation - * @param f the function that gets invoked if the token exists - * @param request the current request + * @param f the function that gets invoked if the token exists + * @param request the current request * @return the action result */ protected def executeForToken(token: String, isSignUp: Boolean, - f: MailToken => Future[Result])(implicit request: RequestHeader): Future[Result] = - { - env.userService.findToken(token).flatMap { - case Some(t) if !t.isExpired && t.isSignUp == isSignUp => f(t) - case _ => - val to = if (isSignUp) env.routes.startSignUpUrl else env.routes.startResetPasswordUrl - Future.successful(Redirect(to).flashing(Error -> Messages(BaseRegistration.InvalidLink))) - } + f: MailToken => Future[Result])(implicit request: RequestHeader): Future[Result] = { + env.userService.findToken(token).flatMap { + case Some(t) if !t.isExpired && t.isSignUp == isSignUp => f(t) + case _ => + val to = if (isSignUp) env.routes.startSignUpUrl else env.routes.startResetPasswordUrl + Future.successful(Redirect(to).flashing(Error -> Messages(BaseRegistration.InvalidLink))) } + } /** * The result sent after the start page is handled diff --git a/module-code/app/securesocial/controllers/PasswordChange.scala b/module-code/app/securesocial/controllers/PasswordChange.scala index b74707bf0..12394c286 100644 --- a/module-code/app/securesocial/controllers/PasswordChange.scala +++ b/module-code/app/securesocial/controllers/PasswordChange.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -18,18 +18,17 @@ package securesocial.controllers import javax.inject.Inject -import securesocial.core._ -import securesocial.core.SecureSocial._ -import play.api.mvc.Result -import play.api.Play +import play.api.Application import play.api.data.Form import play.api.data.Forms._ +import play.api.i18n.Messages +import play.api.mvc.Result +import play.filters.csrf.{CSRFCheck, _} +import securesocial.core.SecureSocial._ +import securesocial.core._ import securesocial.core.providers.utils.PasswordValidator -import play.api.i18n.{ I18nSupport, Messages } -import scala.concurrent.{ Await, ExecutionContext, Future } -import play.filters.csrf._ -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current + +import scala.concurrent.{Await, Future} /** * A default PasswordChange controller that uses the BasicProfile as the user type @@ -57,15 +56,18 @@ trait BasePasswordChange extends SecureSocial { */ val onPasswordChangeGoTo = "securesocial.onPasswordChangeGoTo" + @Inject + implicit var application: Application = null /** The redirect target of the handlePasswordChange action. */ - def onHandlePasswordChangeGoTo = Play.current.configuration.getString(onPasswordChangeGoTo).getOrElse( + def onHandlePasswordChangeGoTo = application.configuration.getString(onPasswordChangeGoTo).getOrElse( securesocial.controllers.routes.PasswordChange.page().url ) /** * checks if the supplied password matches the stored one + * * @param suppliedPassword the password entered in the form - * @param request the current request + * @param request the current request * @tparam A the type of the user object * @return a future boolean */ @@ -104,6 +106,9 @@ trait BasePasswordChange extends SecureSocial { } } + @Inject + implicit var CSRFAddToken: CSRFAddToken = null + /** * Renders the password change page * @@ -119,6 +124,9 @@ trait BasePasswordChange extends SecureSocial { } } + @Inject + implicit var CSRFCheck: CSRFCheck = null + /** * Handles form submission from the password change page * @@ -132,7 +140,6 @@ trait BasePasswordChange extends SecureSocial { info => { val newPasswordInfo = env.currentHasher.hash(info.newPassword) val userLang = request2lang(request) - implicit val messages = applicationMessages env.userService.updatePasswordInfo(request.user, newPasswordInfo).map { case Some(u) => env.mailer.sendPasswordChangedNotice(u)(request, userLang) @@ -152,6 +159,6 @@ trait BasePasswordChange extends SecureSocial { * The class used in the form * * @param currentPassword the user's current password - * @param newPassword the new password + * @param newPassword the new password */ case class ChangeInfo(currentPassword: String, newPassword: String) diff --git a/module-code/app/securesocial/controllers/PasswordReset.scala b/module-code/app/securesocial/controllers/PasswordReset.scala index 1fed9040c..2eb98c7f8 100644 --- a/module-code/app/securesocial/controllers/PasswordReset.scala +++ b/module-code/app/securesocial/controllers/PasswordReset.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -21,14 +21,12 @@ import javax.inject.Inject import play.api.data.Form import play.api.data.Forms._ import play.api.i18n.Messages -import play.filters.csrf._ import play.api.mvc.Action +import play.filters.csrf.{CSRFCheck, _} import securesocial.core._ import securesocial.core.providers.UsernamePasswordProvider import securesocial.core.providers.utils.PasswordValidator import securesocial.core.services.SaveMode -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current import scala.concurrent.Future @@ -57,6 +55,9 @@ trait BasePasswordReset extends MailTokenBasedOperations { ).verifying(Messages(BaseRegistration.PasswordsDoNotMatch), passwords => passwords._1 == passwords._2) ) + @Inject + implicit var CSRFAddToken: CSRFAddToken = null + /** * Renders the page that starts the password reset flow */ @@ -67,6 +68,9 @@ trait BasePasswordReset extends MailTokenBasedOperations { } } + @Inject + implicit var CSRFCheck: CSRFCheck = null + /** * Handles form submission for the start page */ diff --git a/module-code/app/securesocial/controllers/ProviderController.scala b/module-code/app/securesocial/controllers/ProviderController.scala index d7e6332b8..14f960ca7 100644 --- a/module-code/app/securesocial/controllers/ProviderController.scala +++ b/module-code/app/securesocial/controllers/ProviderController.scala @@ -17,15 +17,14 @@ package securesocial.controllers import javax.inject.Inject -import play.api.Play + +import play.api.Application import play.api.i18n.Messages import play.api.mvc._ import securesocial.core._ import securesocial.core.authenticator.CookieAuthenticator import securesocial.core.services.SaveMode import securesocial.core.utils._ -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current import scala.concurrent.Future @@ -39,7 +38,8 @@ class ProviderController @Inject() (override implicit val env: RuntimeEnvironmen * A trait that provides the means to authenticate users for web applications */ trait BaseProviderController extends SecureSocial { - import securesocial.controllers.ProviderControllerHelper.{ logger, toUrl } + + import securesocial.controllers.ProviderControllerHelper.{logger, toUrl} /** * The authentication entry point for GET requests @@ -173,10 +173,13 @@ object ProviderControllerHelper { * * @return */ - def landingUrl = Play.configuration.getString(onLoginGoTo).getOrElse( - Play.configuration.getString(ApplicationContext).getOrElse(Root) + def landingUrl = application.configuration.getString(onLoginGoTo).getOrElse( + application.configuration.getString(ApplicationContext).getOrElse(Root) ) + @Inject + implicit var application: Application = null + /** * Returns the url that the user should be redirected to after login * diff --git a/module-code/app/securesocial/controllers/Registration.scala b/module-code/app/securesocial/controllers/Registration.scala index e3a720c94..d5e380e45 100644 --- a/module-code/app/securesocial/controllers/Registration.scala +++ b/module-code/app/securesocial/controllers/Registration.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -21,17 +21,15 @@ import javax.inject.Inject import play.api.data.Forms._ import play.api.data._ import play.api.i18n.Messages -import play.filters.csrf._ import play.api.mvc.Action +import play.filters.csrf.{CSRFCheck, _} import securesocial.core._ import securesocial.core.authenticator.CookieAuthenticator import securesocial.core.providers.UsernamePasswordProvider import securesocial.core.providers.utils._ import securesocial.core.services.SaveMode -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current -import scala.concurrent.{ Await, Future } +import scala.concurrent.{Await, Future} /** * A default Registration controller that uses the BasicProfile as the user type @@ -92,6 +90,9 @@ trait BaseRegistration extends MailTokenBasedOperations { val form = if (UsernamePasswordProvider.withUserNameSupport) formWithUsername else formWithoutUsername + @Inject + implicit var CSRFAddToken: CSRFAddToken = null + /** * Starts the sign up process */ @@ -106,6 +107,9 @@ trait BaseRegistration extends MailTokenBasedOperations { } } + @Inject + implicit var CSRFCheck: CSRFCheck = null + def handleStartSignUp = CSRFCheck { Action.async { implicit request => @@ -137,6 +141,7 @@ trait BaseRegistration extends MailTokenBasedOperations { /** * Renders the sign up page + * * @return */ def signUp(token: String) = CSRFAddToken { diff --git a/module-code/app/securesocial/controllers/ViewsPlugin.scala b/module-code/app/securesocial/controllers/ViewsPlugin.scala index a4eb789ce..0e704dcd2 100644 --- a/module-code/app/securesocial/controllers/ViewsPlugin.scala +++ b/module-code/app/securesocial/controllers/ViewsPlugin.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,13 +16,14 @@ */ package securesocial.controllers +import javax.inject.Inject + +import play.api.Application import play.api.data.Form -import play.api.i18n.Lang +import play.api.i18n.{Lang, Messages} import play.api.mvc.RequestHeader -import play.twirl.api.{ Html, Txt } -import securesocial.core.{ BasicProfile, RuntimeEnvironment } -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current +import play.twirl.api.{Html, Txt} +import securesocial.core.{BasicProfile, RuntimeEnvironment} /** * A trait that provides the pages for SecureSocial @@ -77,7 +78,7 @@ trait MailTemplates { /** * Returns the email sent when a user starts the sign up process * - * @param token the token used to identify the request + * @param token the token used to identify the request * @param request the current http request * @return a String with the text and/or html body for the email */ @@ -86,7 +87,7 @@ trait MailTemplates { /** * Returns the email sent when the user is already registered * - * @param user the user + * @param user the user * @param request the current request * @return a tuple with the text and/or html body for the email */ @@ -95,7 +96,7 @@ trait MailTemplates { /** * Returns the welcome email sent when the user finished the sign up process * - * @param user the user + * @param user the user * @param request the current request * @return a String with the text and/or html body for the email */ @@ -113,8 +114,8 @@ trait MailTemplates { /** * Returns the email sent to the user to reset the password * - * @param user the user - * @param token the token used to identify the request + * @param user the user + * @param token the token used to identify the request * @param request the current http request * @return a String with the text and/or html body for the email */ @@ -123,7 +124,7 @@ trait MailTemplates { /** * Returns the email sent as a confirmation of a password change * - * @param user the user + * @param user the user * @param request the current http request * @return a String with the text and/or html body for the email */ @@ -132,6 +133,9 @@ trait MailTemplates { } object ViewTemplates { + @Inject + implicit var application: Application = null + /** * The default views. */ @@ -163,18 +167,24 @@ object ViewTemplates { securesocial.views.html.passwordChange(form) } + @Inject + implicit var messages: Messages = null + override def getNotAuthorizedPage(implicit request: RequestHeader, lang: Lang): Html = { securesocial.views.html.notAuthorized() } } + } object MailTemplates { + /** * The default mails. */ class Default(env: RuntimeEnvironment) extends MailTemplates { implicit val implicitEnv = env + def getSignUpEmail(token: String)(implicit request: RequestHeader, lang: Lang): (Option[Txt], Option[Html]) = { (None, Some(securesocial.views.html.mails.signUpEmail(token))) } @@ -199,4 +209,5 @@ object MailTemplates { (None, Some(securesocial.views.html.mails.passwordChangedNotice(user))) } } + } \ No newline at end of file diff --git a/module-code/app/securesocial/core/IdentityProvider.scala b/module-code/app/securesocial/core/IdentityProvider.scala index 29277158c..4f6857de7 100644 --- a/module-code/app/securesocial/core/IdentityProvider.scala +++ b/module-code/app/securesocial/core/IdentityProvider.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,9 +16,12 @@ */ package securesocial.core -import play.api.mvc.{ Result, AnyContent, Request } -import play.api.Play -import concurrent.Future +import javax.inject.Inject + +import play.api.mvc.{AnyContent, Request, Result} +import play.api.{Application, Environment, Mode} + +import scala.concurrent.Future /** * Base class for all Identity Providers. @@ -31,6 +34,7 @@ abstract class IdentityProvider { /** * Subclasses need to implement this to specify the authentication method + * * @return */ def authMethod: AuthenticationMethod @@ -55,11 +59,16 @@ object IdentityProvider { private val logger = play.api.Logger("securesocial.core.IdentityProvider") val SessionId = "sid" + @Inject + implicit var application: Application = null + + @Inject + implicit var environment: Environment = null + // todo: do I want this here? val sslEnabled: Boolean = { - import Play.current - val result = current.configuration.getBoolean("securesocial.ssl").getOrElse(false) - if (!result && Play.isProd) { + val result = application.configuration.getBoolean("securesocial.ssl").getOrElse(false) + if (!result && environment.mode == Mode.Prod) { logger.warn( "[securesocial] IMPORTANT: Play is running in production mode but you did not turn SSL on for SecureSocial." + "Not using SSL can make it really easy for an attacker to steal your users' credentials and/or the " + @@ -71,12 +80,13 @@ object IdentityProvider { /** * Reads a property from the application.conf + * * @param property * @return */ def loadProperty(providerId: String, property: String, optional: Boolean = false): Option[String] = { val key = s"securesocial.$providerId.$property" - val result = Play.current.configuration.getString(key) + val result = application.configuration.getString(key) if (!result.isDefined && !optional) { logger.warn(s"[securesocial] Missing property: $key ") } @@ -96,6 +106,7 @@ object IdentityProvider { sealed trait AuthenticationResult object AuthenticationResult { + /** * A user denied access to their account while authenticating with an external provider (eg: Twitter) */ @@ -108,15 +119,18 @@ object AuthenticationResult { /** * Returned when the user was succesfully authenticated + * * @param profile the authenticated user profile */ case class Authenticated(profile: BasicProfile) extends AuthenticationResult /** * Returned when the authentication process failed for some reason. + * * @param error a description of the error */ case class Failed(error: String) extends AuthenticationResult + } /** @@ -127,6 +141,7 @@ object AuthenticationResult { trait ApiSupport { /** * Authenticates a user + * * @param request * @return */ diff --git a/module-code/app/securesocial/core/OAuth2Provider.scala b/module-code/app/securesocial/core/OAuth2Provider.scala index 8e647ce57..21008b875 100644 --- a/module-code/app/securesocial/core/OAuth2Provider.scala +++ b/module-code/app/securesocial/core/OAuth2Provider.scala @@ -18,15 +18,16 @@ package securesocial.core import _root_.java.net.URLEncoder import _root_.java.util.UUID +import javax.inject.Inject -import play.api.Play -import play.api.libs.json.{ JsError, JsSuccess, JsValue, Json } +import play.api.Application +import play.api.libs.json.{JsError, JsSuccess, JsValue, Json} import play.api.libs.ws.WSResponse import play.api.mvc._ -import securesocial.core.services.{ CacheService, HttpService, RoutesService } +import securesocial.core.services.{CacheService, HttpService, RoutesService} import scala.collection.JavaConversions._ -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} trait OAuth2Client { val settings: OAuth2Settings @@ -166,6 +167,7 @@ abstract class OAuth2Provider( /** * Defines the request format for api authentication requests + * * @param email the user email * @param info the OAuth2Info as returned by some Oauth2 service on the client side (eg: JS app) */ @@ -231,6 +233,8 @@ object OAuth2Settings { val ClientId = "clientId" val ClientSecret = "clientSecret" val Scope = "scope" + @Inject + implicit var application: Application = null /** * Helper method to create an OAuth2Settings instance from the properties file. @@ -248,7 +252,7 @@ object OAuth2Settings { clientId <- loadProperty(id, OAuth2Settings.ClientId) clientSecret <- loadProperty(id, OAuth2Settings.ClientSecret) } yield { - val config = Play.current.configuration + val config = application.configuration val scope = loadProperty(id, OAuth2Settings.Scope, optional = true) val authorizationUrlParams: Map[String, String] = config.getObject(propertyKey + OAuth2Settings.AuthorizationUrlParams).map { o => diff --git a/module-code/app/securesocial/core/SecureSocial.scala b/module-code/app/securesocial/core/SecureSocial.scala index e91e69811..deb1e4655 100644 --- a/module-code/app/securesocial/core/SecureSocial.scala +++ b/module-code/app/securesocial/core/SecureSocial.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,19 +16,19 @@ */ package securesocial.core -import play.api.mvc._ +import javax.inject.Inject + +import play.api.Application +import play.api.http.HeaderNames import play.api.i18n.Messages import play.api.libs.json.Json -import play.api.http.HeaderNames -import securesocial.core.SecureSocial.{ RequestWithUser, SecuredRequest } -import scala.concurrent.{ ExecutionContext, Future } +import play.api.mvc.{Result, _} import play.twirl.api.Html - -import securesocial.core.utils._ +import securesocial.core.SecureSocial.{RequestWithUser, SecuredRequest} import securesocial.core.authenticator._ -import play.api.mvc.Result -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current +import securesocial.core.utils._ + +import scala.concurrent.{ExecutionContext, Future} /** * Provides the actions that can be used to protect controllers and retrieve the current user @@ -37,15 +37,19 @@ import play.api.Play.current */ trait SecureSocial extends Controller { implicit val env: RuntimeEnvironment + implicit def executionContext: ExecutionContext = env.executionContext protected val notAuthenticatedJson = Unauthorized(Json.toJson(Map("error" -> "Credentials required"))).as(JSON) + @Inject + implicit var messages: Messages = null + protected def notAuthenticatedResult[A](implicit request: Request[A]): Future[Result] = { Future.successful { render { case Accepts.Json() => notAuthenticatedJson case Accepts.Html() => Redirect(env.routes.loginPageUrl). - flashing("error" -> Messages("securesocial.loginRequired")) + flashing("error" -> messages("securesocial.loginRequired")) .withSession(request.session + (SecureSocial.OriginalUrlKey -> request.uri)) case _ => Unauthorized("Credentials required") } @@ -53,7 +57,9 @@ trait SecureSocial extends Controller { } protected val notAuthorizedJson = Forbidden(Json.toJson(Map("error" -> "Not authorized"))).as(JSON) + protected def notAuthorizedPage()(implicit request: RequestHeader): Html = env.viewTemplates.getNotAuthorizedPage + protected def notAuthorizedResult[A](implicit request: Request[A]): Future[Result] = { Future.successful { render { @@ -76,6 +82,7 @@ trait SecureSocial extends Controller { /** * Creates a secured action + * * @param authorize an Authorize object that checks if the user is authorized to invoke the action */ def apply[A](authorize: Authorization[env.U]) = new SecuredActionBuilder(Some(authorize)) @@ -93,34 +100,32 @@ trait SecureSocial extends Controller { private val logger = play.api.Logger("securesocial.core.SecuredActionBuilder") def invokeSecuredBlock[A](authorize: Option[Authorization[env.U]], request: Request[A], - block: SecuredRequest[A, env.U] => Future[Result]): Future[Result] = - { - env.authenticatorService.fromRequest(request).flatMap { - case Some(authenticator) if authenticator.isValid => - authenticator.touch.flatMap { updatedAuthenticator => - val user = updatedAuthenticator.user - if (authorize.isEmpty || authorize.get.isAuthorized(user, request)) { - block(SecuredRequest(user, updatedAuthenticator, request)).flatMap { - _.touchingAuthenticator(updatedAuthenticator) - } - } else { - notAuthorizedResult(request) + block: SecuredRequest[A, env.U] => Future[Result]): Future[Result] = { + env.authenticatorService.fromRequest(request).flatMap { + case Some(authenticator) if authenticator.isValid => + authenticator.touch.flatMap { updatedAuthenticator => + val user = updatedAuthenticator.user + if (authorize.isEmpty || authorize.get.isAuthorized(user, request)) { + block(SecuredRequest(user, updatedAuthenticator, request)).flatMap { + _.touchingAuthenticator(updatedAuthenticator) } + } else { + notAuthorizedResult(request) } - case Some(authenticator) if !authenticator.isValid => - logger.debug("[securesocial] user tried to access with invalid authenticator : '%s'".format(request.uri)) - notAuthenticatedResult(request).flatMap { _.discardingAuthenticator(authenticator) } - case None => - logger.debug("[securesocial] anonymous user trying to access : '%s'".format(request.uri)) - notAuthenticatedResult(request) - } + } + case Some(authenticator) if !authenticator.isValid => + logger.debug("[securesocial] user tried to access with invalid authenticator : '%s'".format(request.uri)) + notAuthenticatedResult(request).flatMap {_.discardingAuthenticator(authenticator)} + case None => + logger.debug("[securesocial] anonymous user trying to access : '%s'".format(request.uri)) + notAuthenticatedResult(request) } + } override def invokeBlock[A](request: Request[A], - block: (SecuredRequest[A, env.U]) => Future[Result]): Future[Result] = - { - invokeSecuredBlock(authorize, request, block) - } + block: (SecuredRequest[A, env.U]) => Future[Result]): Future[Result] = { + invokeSecuredBlock(authorize, request, block) + } } /** @@ -137,20 +142,20 @@ trait SecureSocial extends Controller { override protected implicit def executionContext: ExecutionContext = env.executionContext override def invokeBlock[A](request: Request[A], - block: (RequestWithUser[A, env.U]) => Future[Result]): Future[Result] = - { - env.authenticatorService.fromRequest(request).flatMap { - case Some(authenticator) if authenticator.isValid => - authenticator.touch.flatMap { - a => block(RequestWithUser(Some(a.user), Some(a), request)) - } - case Some(authenticator) if !authenticator.isValid => - block(RequestWithUser(None, None, request)).flatMap(_.discardingAuthenticator(authenticator)) - case None => - block(RequestWithUser(None, None, request)) - } + block: (RequestWithUser[A, env.U]) => Future[Result]): Future[Result] = { + env.authenticatorService.fromRequest(request).flatMap { + case Some(authenticator) if authenticator.isValid => + authenticator.touch.flatMap { + a => block(RequestWithUser(Some(a.user), Some(a), request)) + } + case Some(authenticator) if !authenticator.isValid => + block(RequestWithUser(None, None, request)).flatMap(_.discardingAuthenticator(authenticator)) + case None => + block(RequestWithUser(None, None, request)) } + } } + } object SecureSocial { @@ -168,6 +173,7 @@ object SecureSocial { /** * Saves the referer as original url in the session if it's not yet set. + * * @param result the result that maybe enhanced with an updated session * @return the result that's returned to the client */ @@ -187,6 +193,7 @@ object SecureSocial { /** * Gets the referer URI from the implicit request + * * @return the path and query string of the referer path and query */ def refererPathAndQuery[A](implicit request: Request[A]): Option[String] = { @@ -199,9 +206,11 @@ object SecureSocial { } } + @Inject + implicit var application: Application = null + val enableRefererAsOriginalUrl = { - import play.api.Play - Play.current.configuration.getBoolean("securesocial.enableRefererAsOriginalUrl").getOrElse(false) + application.configuration.getBoolean("securesocial.enableRefererAsOriginalUrl").getOrElse(false) } /** @@ -210,7 +219,7 @@ object SecureSocial { * gives you will be enough. * * @param request the current request - * @param env the current environment + * @param env the current environment * @return a future with an option user */ def currentUser(implicit request: RequestHeader, env: RuntimeEnvironment, executionContext: ExecutionContext): Future[Option[env.U]] = { diff --git a/module-code/app/securesocial/core/authenticator/CookieAuthenticator.scala b/module-code/app/securesocial/core/authenticator/CookieAuthenticator.scala index 2602032a8..feca23aa5 100644 --- a/module-code/app/securesocial/core/authenticator/CookieAuthenticator.scala +++ b/module-code/app/securesocial/core/authenticator/CookieAuthenticator.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,25 +16,27 @@ */ package securesocial.core.authenticator +import javax.inject.Inject + import org.joda.time.DateTime -import play.api.mvc.{ Cookie, Result, DiscardingCookie, RequestHeader } +import play.api.Application +import play.api.mvc.{Cookie, DiscardingCookie, RequestHeader, Result} import securesocial.core.IdentityProvider -import scala.concurrent.{ ExecutionContext, Future } -import play.api.Play + +import scala.concurrent.Future /** * A Cookie based authenticator. This authenticator puts an id an a cookie that is then used to track authenticated * users. Since the cookie only has the id for this authenticator the rest of the data is stored using an * instance of the AuthenticatorStore. * - * @param id the authenticator id - * @param user the user this authenticator is associated with + * @param id the authenticator id + * @param user the user this authenticator is associated with * @param expirationDate the expiration date - * @param lastUsed the last time the authenticator was used - * @param creationDate the authenticator creation time - * @param store the authenticator store where instances of this authenticator are persisted + * @param lastUsed the last time the authenticator was used + * @param creationDate the authenticator creation time + * @param store the authenticator store where instances of this authenticator are persisted * @tparam U the user type (defined by the application using the module) - * * @see AuthenticatorStore * @see RuntimeEnvironment */ @@ -123,12 +125,14 @@ case class CookieAuthenticator[U](id: String, user: U, expirationDate: DateTime, /** * An authenticator builder. It can create an Authenticator instance from an http request or from a user object * - * @param store the store where instances of the CookieAuthenticator class are persisted. + * @param store the store where instances of the CookieAuthenticator class are persisted. * @param generator a session id generator * @tparam U the user object type */ class CookieAuthenticatorBuilder[U](store: AuthenticatorStore[CookieAuthenticator[U]], generator: IdGenerator) extends AuthenticatorBuilder[U] { + import store.executionContext + val id = CookieAuthenticator.Id /** @@ -164,7 +168,8 @@ class CookieAuthenticatorBuilder[U](store: AuthenticatorStore[CookieAuthenticato } object CookieAuthenticator { - import play.api.Play.current + @Inject + implicit var application: Application = null // todo: create settings object val Id = "cookie" @@ -187,17 +192,17 @@ object CookieAuthenticator { val DefaultIdleTimeout = 30 val DefaultAbsoluteTimeout = 12 * 60 - lazy val cookieName = Play.application.configuration.getString(CookieNameKey).getOrElse(DefaultCookieName) - lazy val cookiePath = Play.application.configuration.getString(CookiePathKey).getOrElse( - Play.configuration.getString(ApplicationContext).getOrElse(DefaultCookiePath) + lazy val cookieName = application.configuration.getString(CookieNameKey).getOrElse(DefaultCookieName) + lazy val cookiePath = application.configuration.getString(CookiePathKey).getOrElse( + application.configuration.getString(ApplicationContext).getOrElse(DefaultCookiePath) ) - lazy val cookieDomain = Play.application.configuration.getString(CookieDomainKey) + lazy val cookieDomain = application.configuration.getString(CookieDomainKey) lazy val cookieSecure = IdentityProvider.sslEnabled - lazy val cookieHttpOnly = Play.application.configuration.getBoolean(CookieHttpOnlyKey).getOrElse(DefaultCookieHttpOnly) - lazy val idleTimeout = Play.application.configuration.getInt(IdleTimeoutKey).getOrElse(DefaultIdleTimeout) - lazy val absoluteTimeout = Play.application.configuration.getInt(AbsoluteTimeoutKey).getOrElse(DefaultAbsoluteTimeout) + lazy val cookieHttpOnly = application.configuration.getBoolean(CookieHttpOnlyKey).getOrElse(DefaultCookieHttpOnly) + lazy val idleTimeout = application.configuration.getInt(IdleTimeoutKey).getOrElse(DefaultIdleTimeout) + lazy val absoluteTimeout = application.configuration.getInt(AbsoluteTimeoutKey).getOrElse(DefaultAbsoluteTimeout) lazy val absoluteTimeoutInSeconds = absoluteTimeout * 60 - lazy val makeTransient = Play.application.configuration.getBoolean(TransientKey).getOrElse(true) + lazy val makeTransient = application.configuration.getBoolean(TransientKey).getOrElse(true) val discardingCookie: DiscardingCookie = { DiscardingCookie(cookieName, cookiePath, cookieDomain, cookieSecure) diff --git a/module-code/app/securesocial/core/authenticator/HttpHeaderAuthenticator.scala b/module-code/app/securesocial/core/authenticator/HttpHeaderAuthenticator.scala index 01310f06a..f57ae348b 100644 --- a/module-code/app/securesocial/core/authenticator/HttpHeaderAuthenticator.scala +++ b/module-code/app/securesocial/core/authenticator/HttpHeaderAuthenticator.scala @@ -16,9 +16,11 @@ */ package securesocial.core.authenticator +import javax.inject.Inject + import org.joda.time.DateTime -import play.api.Play -import play.api.mvc.{ Result, _ } +import play.api.Application +import play.api.mvc.{Result, _} import scala.concurrent.Future @@ -34,7 +36,6 @@ import scala.concurrent.Future * @param creationDate the authenticator creation time * @param store the authenticator store where instances of this authenticator are persisted * @tparam U the user type (defined by the application using the module) - * * @see AuthenticatorStore * @see RuntimeEnvironment */ @@ -120,7 +121,8 @@ class HttpHeaderAuthenticatorBuilder[U](store: AuthenticatorStore[HttpHeaderAuth } object HttpHeaderAuthenticator { - import play.api.Play.current + @Inject + implicit var application: Application = null // todo: create settings object val Id = "token" @@ -129,7 +131,7 @@ object HttpHeaderAuthenticator { // default values val DefaultHeaderName = "X-Auth-Token" - lazy val headerName = Play.application.configuration.getString(HeaderNameKey).getOrElse(DefaultHeaderName) + lazy val headerName = application.configuration.getString(HeaderNameKey).getOrElse(DefaultHeaderName) // using the same properties than the CookieBased authenticator for now. lazy val idleTimeout = CookieAuthenticator.idleTimeout lazy val absoluteTimeout = CookieAuthenticator.absoluteTimeout diff --git a/module-code/app/securesocial/core/authenticator/IdGenerator.scala b/module-code/app/securesocial/core/authenticator/IdGenerator.scala index e63218ac6..c75fada44 100644 --- a/module-code/app/securesocial/core/authenticator/IdGenerator.scala +++ b/module-code/app/securesocial/core/authenticator/IdGenerator.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,10 +16,14 @@ */ package securesocial.core.authenticator -import scala.concurrent.Future import java.security.SecureRandom +import javax.inject.Inject + +import play.api.Application import play.api.libs.Codecs +import scala.concurrent.Future + /** * An Authenticator Id generator. */ @@ -28,6 +32,7 @@ trait IdGenerator { } object IdGenerator { + /** * The default id generator */ @@ -37,7 +42,9 @@ object IdGenerator { val random = new SecureRandom() val DefaultSizeInBytes = 128 val IdLengthKey = "securesocial.idLengthInBytes" - val IdSizeInBytes = play.api.Play.current.configuration.getInt(IdLengthKey).getOrElse(DefaultSizeInBytes) + @Inject + implicit var application: Application = null + val IdSizeInBytes = application.configuration.getInt(IdLengthKey).getOrElse(DefaultSizeInBytes) /** * Generates a new id using SecureRandom @@ -53,4 +60,5 @@ object IdGenerator { } } } + } \ No newline at end of file diff --git a/module-code/app/securesocial/core/java/BasePasswordHasher.java b/module-code/app/securesocial/core/java/BasePasswordHasher.java deleted file mode 100644 index aeac951c9..000000000 --- a/module-code/app/securesocial/core/java/BasePasswordHasher.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss - * - * 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 securesocial.core.java; - -import securesocial.core.providers.utils.PasswordHasher; - -/** - * Base class for all password hashers written in Java. - * - * This is deprecated, extend PasswordHasher directly. - */ -@Deprecated -public abstract class BasePasswordHasher extends PasswordHasher { -} diff --git a/module-code/app/securesocial/core/java/BaseUserService.java b/module-code/app/securesocial/core/java/BaseUserService.java index 9a3a690fb..cd407de65 100644 --- a/module-code/app/securesocial/core/java/BaseUserService.java +++ b/module-code/app/securesocial/core/java/BaseUserService.java @@ -1,24 +1,21 @@ /** * Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss - * + *

* 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 - * + *

+ * 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 securesocial.core.java; -import play.libs.F; import play.libs.Scala; -import scala.*; import scala.Option; import scala.concurrent.Future; import securesocial.core.BasicProfile; @@ -27,13 +24,15 @@ import securesocial.core.services.SaveMode; import securesocial.core.services.UserService; -import java.lang.Boolean; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +import static scala.compat.java8.FutureConverters.toScala; /** * A base user service for developers that want to write their UserService in Java. - * + *

* Note: You need to implement all the doXXX methods below. - * */ public abstract class BaseUserService implements UserService { protected BaseUserService() { @@ -46,31 +45,31 @@ protected BaseUserService() { */ @Override public Future> find(String providerId, String userId) { - return doFind(providerId, userId).map(new F.Function>() { + return toScala(doFind(providerId, userId).thenApplyAsync(new Function>() { @Override - public Option apply(BasicProfile user) throws Throwable { + public Option apply(BasicProfile user) { return Scala.Option(user); } - }).wrapped(); + })); } /** * Finds an Identity by email and provider id. - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation. * - * @param email - the user email + * @param email - the user email * @param providerId - the provider id * @return */ @Override public Future> findByEmailAndProvider(String email, String providerId) { - return doFindByEmailAndProvider(email, providerId).map(new F.Function>() { - public Option apply(BasicProfile user) throws Throwable { + return toScala(doFindByEmailAndProvider(email, providerId).thenApplyAsync(new Function>() { + public Option apply(BasicProfile user) { return Scala.Option(user); } - }).wrapped(); + })); } /** @@ -81,44 +80,44 @@ public Option apply(BasicProfile user) throws Throwable { */ @Override public Future save(BasicProfile user, SaveMode mode) { - return doSave(user, mode).wrapped(); + return toScala(doSave(user, mode)); } /** * Links the current user Identity to another * * @param current The Identity of the current user - * @param to The Identity that needs to be linked to the current user + * @param to The Identity that needs to be linked to the current user */ @Override public Future link(U current, BasicProfile to) { - return doLink(current, to).wrapped(); + return toScala(doLink(current, to)); } @Override public Future> passwordInfoFor(U user) { - return doPasswordInfoFor(user).map(new F.Function>() { + return toScala(doPasswordInfoFor(user).thenApplyAsync(new Function>() { @Override - public Option apply(PasswordInfo passwordInfo) throws Throwable { + public Option apply(PasswordInfo passwordInfo) { return Scala.Option(passwordInfo); } - }).wrapped(); + })); } @Override public Future> updatePasswordInfo(U user, PasswordInfo info) { - return doUpdatePasswordInfo(user, info).map(new F.Function>() { + return toScala(doUpdatePasswordInfo(user, info).thenApplyAsync(new Function>() { @Override - public Option apply(BasicProfile basicProfile) throws Throwable { + public Option apply(BasicProfile basicProfile) { return Scala.Option(basicProfile); } - }).wrapped(); + })); } /** * Saves a token. This is needed for users that * are creating an account in the system instead of using one in a 3rd party system. - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * @@ -127,17 +126,17 @@ public Option apply(BasicProfile basicProfile) throws Throwable { */ @Override public Future saveToken(MailToken mailToken) { - return doSaveToken(Token.fromScala(mailToken)).map(new F.Function() { + return toScala(doSaveToken(Token.fromScala(mailToken)).thenApplyAsync(new Function() { @Override - public MailToken apply(Token token) throws Throwable { + public MailToken apply(Token token) { return token.toScala(); } - }).wrapped(); + })); } /** * Finds a token - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * @@ -146,18 +145,18 @@ public MailToken apply(Token token) throws Throwable { */ @Override public Future> findToken(String token) { - return doFindToken(token).map(new F.Function>() { + return toScala(doFindToken(token).thenApplyAsync(new Function>() { @Override - public Option apply(Token token) throws Throwable { - MailToken scalaToken = token != null ? token.toScala() : null; + public Option apply(Token token) { + MailToken scalaToken = token != null ? token.toScala() : null; return Scala.Option(scalaToken); } - }).wrapped(); + })); } /** * Deletes a token - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * @@ -165,21 +164,20 @@ public Option apply(Token token) throws Throwable { */ @Override public Future> deleteToken(String uuid) { - return doDeleteToken(uuid).map(new F.Function>() { + return toScala(doDeleteToken(uuid).thenApplyAsync(new Function>() { @Override - public Option apply(Token token) throws Throwable { - MailToken scalaToken = token != null ? token.toScala() : null; + public Option apply(Token token) { + MailToken scalaToken = token != null ? token.toScala() : null; return Scala.Option(scalaToken); } - }).wrapped(); + })); } /** * Deletes all expired tokens - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation - * */ @Override public void deleteExpiredTokens() { @@ -192,76 +190,76 @@ public void deleteExpiredTokens() { * * @param user */ - public abstract F.Promise doSave(BasicProfile user, SaveMode mode); + public abstract CompletionStage doSave(BasicProfile user, SaveMode mode); /** * Saves a token - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * * @param token */ - public abstract F.Promise doSaveToken(Token token); + public abstract CompletionStage doSaveToken(Token token); /** * Links the current user Identity to another * * @param current The Identity of the current user - * @param to The Identity that needs to be linked to the current user + * @param to The Identity that needs to be linked to the current user */ - public abstract F.Promise doLink(U current, BasicProfile to); + public abstract CompletionStage doLink(U current, BasicProfile to); /** * Finds the user in the backing store. + * * @return an Identity instance or null if no user matches the specified id */ - public abstract F.Promise doFind(String providerId, String userId); + public abstract CompletionStage doFind(String providerId, String userId); - public abstract F.Promise doPasswordInfoFor(U user); + public abstract CompletionStage doPasswordInfoFor(U user); - public abstract F.Promise doUpdatePasswordInfo(U user, PasswordInfo info); + public abstract CompletionStage doUpdatePasswordInfo(U user, PasswordInfo info); /** * Finds a token - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * * @param tokenId the token id * @return a Token instance or null if no token matches the specified id */ - public abstract F.Promise doFindToken(String tokenId); + public abstract CompletionStage doFindToken(String tokenId); /** * Finds an identity by email and provider id. - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation. * - * @param email - the user email + * @param email - the user email * @param providerId - the provider id * @return an Identity instance or null if no user matches the specified id */ - public abstract F.Promise doFindByEmailAndProvider(String email, String providerId); + public abstract CompletionStage doFindByEmailAndProvider(String email, String providerId); /** * Deletes a token - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation * * @param uuid the token id */ - public abstract F.Promise doDeleteToken(String uuid); + public abstract CompletionStage doDeleteToken(String uuid); /** * Deletes all expired tokens - * + *

* Note: If you do not plan to use the UsernamePassword provider just provide en empty * implementation - * */ public abstract void doDeleteExpiredTokens(); } diff --git a/module-code/app/securesocial/core/java/DefaultSecuredActionResponses.java b/module-code/app/securesocial/core/java/DefaultSecuredActionResponses.java index 00ed7acdd..ee6142433 100644 --- a/module-code/app/securesocial/core/java/DefaultSecuredActionResponses.java +++ b/module-code/app/securesocial/core/java/DefaultSecuredActionResponses.java @@ -1,31 +1,31 @@ /** * Copyright 2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss - * + *

* 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 - * + *

+ * 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 securesocial.core.java; import com.fasterxml.jackson.databind.node.ObjectNode; -import play.api.i18n.Messages; -import play.api.Play; -import play.libs.F; import play.libs.Json; import play.mvc.Controller; import play.mvc.Http; import play.mvc.Result; import play.twirl.api.Html; +import javax.inject.Inject; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + /** * The default responses sent when the invoker is not authenticated or authorized to execute a protected * action. @@ -33,35 +33,38 @@ * @see securesocial.core.java.SecuredActionResponses */ public class DefaultSecuredActionResponses extends Controller implements SecuredActionResponses { + @Inject + play.api.i18n.Messages messages = null; + public Html notAuthorizedPage(Http.Context ctx) { return securesocial.views.html.notAuthorized.render(ctx._requestHeader(), ctx.lang(), SecureSocial.env()); } - public F.Promise notAuthenticatedResult(Http.Context ctx) { + public CompletionStage notAuthenticatedResult(Http.Context ctx) { Http.Request req = ctx.request(); Result result; - if ( req.accepts("text/html")) { + if (req.accepts("text/html")) { ctx.flash().put("error", play.i18n.Messages.get("securesocial.loginRequired")); ctx.session().put(SecureSocial.ORIGINAL_URL, ctx.request().uri()); result = redirect(SecureSocial.env().routes().loginPageUrl(ctx._requestHeader())); - } else if ( req.accepts("application/json")) { + } else if (req.accepts("application/json")) { ObjectNode node = Json.newObject(); node.put("error", "Credentials required"); result = unauthorized(node); } else { result = unauthorized("Credentials required"); } - return F.Promise.pure(result); + return CompletableFuture.completedFuture(result); } - public F.Promise notAuthorizedResult(Http.Context ctx) { + public CompletionStage notAuthorizedResult(Http.Context ctx) { Http.Request req = ctx.request(); Result result; - if ( req.accepts("text/html")) { + if (req.accepts("text/html")) { result = forbidden(notAuthorizedPage(ctx)); - } else if ( req.accepts("application/json")) { + } else if (req.accepts("application/json")) { ObjectNode node = Json.newObject(); node.put("error", "Not authorized"); result = forbidden(node); @@ -69,6 +72,6 @@ public F.Promise notAuthorizedResult(Http.Context ctx) { result = forbidden("Not authorized"); } - return F.Promise.pure(result); + return CompletableFuture.completedFuture(result); } } diff --git a/module-code/app/securesocial/core/java/SecureSocial.java b/module-code/app/securesocial/core/java/SecureSocial.java index 7364a6621..dbb221f07 100644 --- a/module-code/app/securesocial/core/java/SecureSocial.java +++ b/module-code/app/securesocial/core/java/SecureSocial.java @@ -1,33 +1,35 @@ /** -* Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss -* -* 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. -* -*/ + * Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss + *

+ * 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 securesocial.core.java; import play.api.mvc.RequestHeader; -import play.libs.F; -import play.libs.HttpExecution; +import play.libs.concurrent.HttpExecution; import play.mvc.Http; import scala.Option; import scala.concurrent.ExecutionContext; import securesocial.core.RuntimeEnvironment; import securesocial.core.SecureSocial$; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + /** -* -*/ + * + */ public class SecureSocial { /** * The user key @@ -54,7 +56,7 @@ public static RuntimeEnvironment env() { * @param env the environment * @return the current user object or null if there isn't one available */ - public static F.Promise currentUser(RuntimeEnvironment env) { + public static CompletionStage currentUser(RuntimeEnvironment env) { return currentUser(env, HttpExecution.defaultContext()); } @@ -67,20 +69,20 @@ public static F.Promise currentUser(RuntimeEnvironment env) { * @param executor an ExecutionContext * @return the current user object or null if there isn't one available */ - public static F.Promise currentUser(RuntimeEnvironment env, ExecutionContext executor) { + public static CompletionStage currentUser(RuntimeEnvironment env, ExecutionContext executor) { RequestHeader requestHeader = Http.Context.current()._requestHeader(); if (requestHeader == null || env == null) { - return F.Promise.promise(null); + return CompletableFuture.supplyAsync(null); } else { scala.concurrent.Future scalaFuture = SecureSocial$.MODULE$.currentUser(requestHeader, env, executor); - F.Function, Object> mapFunction = new F.Function, Object>() { + Function, Object> mapFunction = new Function, Object>() { @Override - public Object apply(Option objectOption) throws Throwable { + public Object apply(Option objectOption) { return objectOption.isDefined() ? objectOption.get() : null; } }; - return F.Promise.wrap(scalaFuture).map(mapFunction); + return scala.compat.java8.FutureConverters.toJava(scalaFuture).thenApplyAsync(mapFunction); } } } diff --git a/module-code/app/securesocial/core/java/Secured.java b/module-code/app/securesocial/core/java/Secured.java index a6c4b3eb9..a3f2e20df 100644 --- a/module-code/app/securesocial/core/java/Secured.java +++ b/module-code/app/securesocial/core/java/Secured.java @@ -1,22 +1,20 @@ /** * Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss - * + *

* 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 - * + *

+ * 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 securesocial.core.java; -import play.libs.F; import play.mvc.Action; import play.mvc.Http; import play.mvc.Result; @@ -26,17 +24,20 @@ import securesocial.core.authenticator.Authenticator; import javax.inject.Inject; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +import static scala.compat.java8.FutureConverters.toJava; /** * Protects an action with SecureSocial - * + *

* Sample usage: * - * @SecuredAction - * public static Result index() { - * User user = (User) ctx().args.get(SecureSocial.USER_KEY); - * return ok("Hello " + user.displayName); - * } + * @SecuredAction public static Result index() { + * User user = (User) ctx().args.get(SecureSocial.USER_KEY); + * return ok("Hello " + user.displayName); + * } */ public class Secured extends Action { @@ -50,55 +51,61 @@ public Secured(RuntimeEnvironment env) throws Throwable { } static void initEnv(RuntimeEnvironment env) throws IllegalAccessException, InstantiationException { - if ( SecureSocial.env() == null ) { + if (SecureSocial.env() == null) { Http.Context.current().args.put("securesocial-env", env); } } @Override - public F.Promise call(final Http.Context ctx) throws Throwable { - initEnv(env); - authorizationInstance = configuration.authorization().newInstance(); - responses = configuration.responses().newInstance(); - return F.Promise.wrap(env.authenticatorService().fromRequest(ctx._requestHeader())).flatMap( - new F.Function>, F.Promise>() { - @Override - public F.Promise apply(Option> authenticatorOption) throws Throwable { - if (authenticatorOption.isDefined() && authenticatorOption.get().isValid()) { - final Authenticator authenticator = authenticatorOption.get(); - Object user = authenticator.user(); - if (authorizationInstance.isAuthorized(user, configuration.params())) { - return F.Promise.wrap(authenticator.touch()).flatMap(new F.Function>() { - @Override - public F.Promise apply(Authenticator touched) throws Throwable { - ctx.args.put(SecureSocial.USER_KEY, touched.user()); - return F.Promise.wrap(touched.touching(ctx)).flatMap(new F.Function>() { - @Override - public F.Promise apply(scala.runtime.BoxedUnit unit) throws Throwable { - return delegate.call(ctx); - } - }); - } - }); + public CompletionStage call(final Http.Context ctx) { + Exception exception; + try { + initEnv(env); + authorizationInstance = configuration.authorization().newInstance(); + responses = configuration.responses().newInstance(); + return toJava(env.authenticatorService().fromRequest(ctx._requestHeader())).thenComposeAsync( + new Function>, CompletionStage>() { + @Override + public CompletionStage apply(Option> authenticatorOption) { + if (authenticatorOption.isDefined() && authenticatorOption.get().isValid()) { + final Authenticator authenticator = authenticatorOption.get(); + Object user = authenticator.user(); + if (authorizationInstance.isAuthorized(user, configuration.params())) { + return toJava(authenticator.touch()).thenComposeAsync(new Function>() { + @Override + public CompletionStage apply(Authenticator touched) { + ctx.args.put(SecureSocial.USER_KEY, touched.user()); + return toJava(touched.touching(ctx)).thenComposeAsync(new Function>() { + @Override + public CompletionStage apply(scala.runtime.BoxedUnit unit) { + return delegate.call(ctx); + } + }); + } + }); + } else { + return responses.notAuthorizedResult(ctx); + } } else { - return responses.notAuthorizedResult(ctx); - } - } else { - if (authenticatorOption.isDefined()) { - return F.Promise.wrap(authenticatorOption.get().discarding(ctx)).flatMap( - new F.Function>() { - @Override - public F.Promise apply(BoxedUnit unit) throws Throwable { - return responses.notAuthenticatedResult(ctx); + if (authenticatorOption.isDefined()) { + return toJava(authenticatorOption.get().discarding(ctx)).thenComposeAsync( + new Function>() { + @Override + public CompletionStage apply(BoxedUnit unit) { + return responses.notAuthenticatedResult(ctx); + } } - } - ); + ); + } + return responses.notAuthenticatedResult(ctx); } - return responses.notAuthenticatedResult(ctx); } } - } - ); + ); + } catch (IllegalAccessException | InstantiationException e) { + exception = e; + } + throw new RuntimeException(exception); } -} \ No newline at end of file +} diff --git a/module-code/app/securesocial/core/java/SecuredActionResponses.java b/module-code/app/securesocial/core/java/SecuredActionResponses.java index cd01d5b30..bac37482e 100644 --- a/module-code/app/securesocial/core/java/SecuredActionResponses.java +++ b/module-code/app/securesocial/core/java/SecuredActionResponses.java @@ -16,10 +16,11 @@ */ package securesocial.core.java; -import play.twirl.api.Html; -import play.libs.F; import play.mvc.Http; import play.mvc.Result; +import play.twirl.api.Html; + +import java.util.concurrent.CompletionStage; /** * An interface that defines the responses that will be sent wheen the invoker is not authenticated or @@ -29,6 +30,8 @@ */ public interface SecuredActionResponses { Html notAuthorizedPage(Http.Context ctx); - F.Promise notAuthenticatedResult(Http.Context ctx); - F.Promise notAuthorizedResult(Http.Context ctx); + + CompletionStage notAuthenticatedResult(Http.Context ctx); + + CompletionStage notAuthorizedResult(Http.Context ctx); } diff --git a/module-code/app/securesocial/core/java/UserAware.java b/module-code/app/securesocial/core/java/UserAware.java index 1ffc4cfe4..cf40ccc91 100644 --- a/module-code/app/securesocial/core/java/UserAware.java +++ b/module-code/app/securesocial/core/java/UserAware.java @@ -1,22 +1,20 @@ /** * Copyright 2012-2014 Jorge Aliss (jaliss at gmail dot com) - twitter: @jaliss - * + *

* 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 - * + *

+ * 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 securesocial.core.java; -import play.libs.F; import play.mvc.Action; import play.mvc.Http; import play.mvc.Result; @@ -24,21 +22,23 @@ import securesocial.core.RuntimeEnvironment; import securesocial.core.authenticator.Authenticator; -import static play.libs.F.Promise; import javax.inject.Inject; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + +import static scala.compat.java8.FutureConverters.toJava; /** * An action that puts the current user in the context if there's one available. This is useful in * public actions that need to access the user information if there's one logged in. - * + *

* Sample usage: * - * @UserAwareAction - * public static Result index() { - * User user = (User) ctx().args.get(SecureSocial.USER_KEY); - * String name = user == null ? "guest" : user.displayName; - * return ok("Hello " + name); - * } + * @UserAwareAction public static Result index() { + * User user = (User) ctx().args.get(SecureSocial.USER_KEY); + * String name = user == null ? "guest" : user.displayName; + * return ok("Hello " + name); + * } * @see securesocial.core.java.UserAwareAction */ public class UserAware extends Action { @@ -50,32 +50,38 @@ public UserAware(RuntimeEnvironment env) throws Throwable { } @Override - public F.Promise call(final Http.Context ctx) throws Throwable { - Secured.initEnv(env); - return F.Promise.wrap(env.authenticatorService().fromRequest(ctx._requestHeader())).flatMap( - new F.Function>, Promise>() { - @Override - public Promise apply(Option> authenticatorOption) throws Throwable { - if (authenticatorOption.isDefined() && authenticatorOption.get().isValid()) { - Authenticator authenticator = authenticatorOption.get(); - return F.Promise.wrap(authenticator.touch()).flatMap(new F.Function>() { - @Override - public Promise apply(Authenticator touched) throws Throwable { - ctx.args.put(SecureSocial.USER_KEY, touched.user()); - return F.Promise.wrap(touched.touching(ctx)).flatMap(new F.Function>() { - @Override - public Promise apply(scala.runtime.BoxedUnit unit) throws Throwable { - return delegate.call(ctx); - } - }); - } - }); - } else { - return delegate.call(ctx); + public CompletionStage call(final Http.Context ctx) { + Exception exeption; + try { + Secured.initEnv(env); + return toJava(env.authenticatorService().fromRequest(ctx._requestHeader())).thenComposeAsync( + new Function>, CompletionStage>() { + @Override + public CompletionStage apply(Option> authenticatorOption) { + if (authenticatorOption.isDefined() && authenticatorOption.get().isValid()) { + Authenticator authenticator = authenticatorOption.get(); + return toJava(authenticator.touch()).thenComposeAsync(new Function>() { + @Override + public CompletionStage apply(Authenticator touched) { + ctx.args.put(SecureSocial.USER_KEY, touched.user()); + return toJava(touched.touching(ctx)).thenComposeAsync(new Function>() { + @Override + public CompletionStage apply(scala.runtime.BoxedUnit unit) { + return delegate.call(ctx); + } + }); + } + }); + } else { + return delegate.call(ctx); + } } } - } - ); + ); + } catch (IllegalAccessException | InstantiationException e) { + exeption = e; + } + throw new RuntimeException(exeption); } } \ No newline at end of file diff --git a/module-code/app/securesocial/core/providers/DropboxProvider.scala b/module-code/app/securesocial/core/providers/DropboxProvider.scala index 9541fb040..186f1c978 100644 --- a/module-code/app/securesocial/core/providers/DropboxProvider.scala +++ b/module-code/app/securesocial/core/providers/DropboxProvider.scala @@ -18,10 +18,12 @@ */ package securesocial.core.providers -import play.api.libs.ws.WS +import javax.inject.Inject + +import play.api.libs.ws.WSClient import securesocial.core._ import securesocial.core.providers.DropboxProvider._ -import securesocial.core.services.{ CacheService, RoutesService } +import securesocial.core.services.{CacheService, RoutesService} import scala.concurrent.Future @@ -32,11 +34,12 @@ class DropboxProvider(routesService: RoutesService, cacheService: CacheService, client: OAuth2Client) extends OAuth2Provider(routesService, client, cacheService) { + @Inject + var WS: WSClient = null private val Logger = play.api.Logger("securesocial.core.providers.DropboxProvider") override val id = DropboxProvider.Dropbox override def fillProfile(info: OAuth2Info): Future[BasicProfile] = { - import play.api.Play.current val accessToken = info.accessToken WS.url(DropboxProvider.Api).withHeaders("Authorization" -> s"Bearer $accessToken").get().map { response => diff --git a/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala b/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala index 76dc9e5e4..93a94331e 100644 --- a/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala +++ b/module-code/app/securesocial/core/providers/UsernamePasswordProvider.scala @@ -16,18 +16,20 @@ */ package securesocial.core.providers +import javax.inject.Inject + import org.joda.time.DateTime -import play.api.Play.current +import play.Application import play.api.data.Form import play.api.data.Forms._ import play.api.mvc._ import securesocial.controllers.ViewTemplates -import securesocial.core.AuthenticationResult.{ Authenticated, NavigationFlow } +import securesocial.core.AuthenticationResult.{Authenticated, NavigationFlow} import securesocial.core._ import securesocial.core.providers.utils.PasswordHasher -import securesocial.core.services.{ AvatarService, UserService } +import securesocial.core.services.{AvatarService, UserService} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.{ExecutionContext, Future} /** * A username password provider @@ -107,6 +109,8 @@ class UsernamePasswordProvider[U](userService: UserService[U], } object UsernamePasswordProvider { + @Inject + var current: Application = null val UsernamePassword = "userpass" private val Key = "securesocial.userpass.withUserNameSupport" private val SendWelcomeEmailKey = "securesocial.userpass.sendWelcomeEmail" @@ -121,11 +125,11 @@ object UsernamePasswordProvider { ) ) - lazy val withUserNameSupport = current.configuration.getBoolean(Key).getOrElse(false) - lazy val sendWelcomeEmail = current.configuration.getBoolean(SendWelcomeEmailKey).getOrElse(true) - lazy val hasher = current.configuration.getString(Hasher).getOrElse(PasswordHasher.id) - lazy val enableTokenJob = current.configuration.getBoolean(EnableTokenJob).getOrElse(true) - lazy val signupSkipLogin = current.configuration.getBoolean(SignupSkipLogin).getOrElse(false) + lazy val withUserNameSupport = current.configuration.getBoolean(Key, false) + lazy val sendWelcomeEmail = current.configuration.getBoolean(SendWelcomeEmailKey, true) + lazy val hasher = current.configuration.getString(Hasher, PasswordHasher.id) + lazy val enableTokenJob = current.configuration.getBoolean(EnableTokenJob, true) + lazy val signupSkipLogin = current.configuration.getBoolean(SignupSkipLogin, false) } /** diff --git a/module-code/app/securesocial/core/providers/WeiboProvider.scala b/module-code/app/securesocial/core/providers/WeiboProvider.scala index c8ca540ca..8a6c5d73f 100644 --- a/module-code/app/securesocial/core/providers/WeiboProvider.scala +++ b/module-code/app/securesocial/core/providers/WeiboProvider.scala @@ -1,6 +1,6 @@ /** * Copyright 2013 wuhaixing (wuhaixing at gmail dot com) - weibo: @数据水墨 - * qiuzhanghua (qiuzhanghua at gmail.com) - weibo: qiuzhanghua + * qiuzhanghua (qiuzhanghua at gmail.com) - weibo: qiuzhanghua * 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 @@ -16,11 +16,13 @@ */ package securesocial.core.providers -import play.api.libs.ws.{ WS, WSResponse } +import javax.inject.Inject + +import play.api.libs.ws.{WSClient, WSResponse} import securesocial.core._ -import securesocial.core.services.{ CacheService, RoutesService } +import securesocial.core.services.{CacheService, RoutesService} -import scala.concurrent.{ ExecutionContext, Future } +import scala.concurrent.Future /** * A Weibo provider @@ -30,6 +32,9 @@ class WeiboProvider(routesService: RoutesService, cacheService: CacheService, client: OAuth2Client) extends OAuth2Provider(routesService, client, cacheService) { + + @Inject + val WS: WSClient = null val GetAuthenticatedUser = "https://api.weibo.com/2/users/show.json?uid=%s&access_token=%s" val AccessToken = "access_token" val Message = "error" @@ -97,7 +102,6 @@ class WeiboProvider(routesService: RoutesService, } def getEmail(accessToken: String): Future[Option[String]] = { - import play.api.Play.current WS.url(GetUserEmail.format(accessToken)).get().map { response => val me = response.json (me \ Message).asOpt[String] match { diff --git a/module-code/app/securesocial/core/providers/utils/Mailer.scala b/module-code/app/securesocial/core/providers/utils/Mailer.scala index 47d203871..538eb0f0e 100644 --- a/module-code/app/securesocial/core/providers/utils/Mailer.scala +++ b/module-code/app/securesocial/core/providers/utils/Mailer.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,30 +16,45 @@ */ package securesocial.core.providers.utils -import play.api.PlayConfig -import play.api.i18n.{ Lang, Messages } -import play.api.libs.concurrent.Akka +import javax.inject.Inject + +import akka.actor.ActorSystem +import play.api.Application +import play.api.i18n.Lang import play.api.mvc.RequestHeader -import play.twirl.api.{ Txt, Html } +import play.i18n.Messages +import play.twirl.api.{Html, Txt} import securesocial.controllers.MailTemplates import securesocial.core.BasicProfile -import play.api.i18n.Messages.Implicits._ -import play.api.Play.current + /** * A helper trait to send email notifications */ trait Mailer { def sendAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) + def sendSignUpEmail(to: String, token: String)(implicit request: RequestHeader, lang: Lang) + def sendWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) + def sendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang) + def sendUnkownEmailNotice(email: String)(implicit request: RequestHeader, lang: Lang) + def sendPasswordChangedNotice(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) + def sendEmail(subject: String, recipient: String, body: (Option[Txt], Option[Html])) } object Mailer { + import play.api.libs.mailer._ + + @Inject + implicit var current: Application = null + @Inject + implicit var messages: Messages = null + /** * The default mailer implementation * @@ -57,34 +72,34 @@ object Mailer { override def sendAlreadyRegisteredEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getAlreadyRegisteredEmail(user) - sendEmail(Messages(AlreadyRegisteredSubject), user.email.get, txtAndHtml) + sendEmail(messages.at(AlreadyRegisteredSubject), user.email.get, txtAndHtml) } override def sendSignUpEmail(to: String, token: String)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getSignUpEmail(token) - sendEmail(Messages(SignUpEmailSubject), to, txtAndHtml) + sendEmail(messages.at(SignUpEmailSubject), to, txtAndHtml) } override def sendWelcomeEmail(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getWelcomeEmail(user) - sendEmail(Messages(WelcomeEmailSubject), user.email.get, txtAndHtml) + sendEmail(messages.at(WelcomeEmailSubject), user.email.get, txtAndHtml) } override def sendPasswordResetEmail(user: BasicProfile, token: String)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getSendPasswordResetEmail(user, token) - sendEmail(Messages(PasswordResetSubject), user.email.get, txtAndHtml) + sendEmail(messages.at(PasswordResetSubject), user.email.get, txtAndHtml) } override def sendUnkownEmailNotice(email: String)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getUnknownEmailNotice() - sendEmail(Messages(UnknownEmailNoticeSubject), email, txtAndHtml) + sendEmail(messages.at(UnknownEmailNoticeSubject), email, txtAndHtml) } override def sendPasswordChangedNotice(user: BasicProfile)(implicit request: RequestHeader, lang: Lang) { val txtAndHtml = mailTemplates.getPasswordChangedNoticeEmail(user) - sendEmail(Messages(PasswordResetOkSubject), user.email.get, txtAndHtml) + sendEmail(messages.at(PasswordResetOkSubject), user.email.get, txtAndHtml) } override def sendEmail(subject: String, recipient: String, body: (Option[Txt], Option[Html])) { @@ -95,10 +110,16 @@ object Mailer { logger.debug(s"[securesocial] sending email to $recipient") logger.debug(s"[securesocial] mail = [$body]") - Akka.system.scheduler.scheduleOnce(1.seconds) { + @Inject + implicit var actorSystem: ActorSystem = null + @Inject + implicit var MailerPlugin: MailerClient = null + + actorSystem.scheduler.scheduleOnce(1.seconds) { val mail = Email(subject, fromAddress, Seq(recipient), body._1.map(txt => txt.body), body._2.map(html => html.body)) MailerPlugin.send(mail) } } } + } \ No newline at end of file diff --git a/module-code/app/securesocial/core/providers/utils/PasswordHasher.scala b/module-code/app/securesocial/core/providers/utils/PasswordHasher.scala index 45443749c..7c9943dff 100644 --- a/module-code/app/securesocial/core/providers/utils/PasswordHasher.scala +++ b/module-code/app/securesocial/core/providers/utils/PasswordHasher.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,8 +16,11 @@ */ package securesocial.core.providers.utils -import securesocial.core.PasswordInfo +import javax.inject.Inject + import org.mindrot.jbcrypt._ +import play.api.Application +import securesocial.core.PasswordInfo /** * A trait that defines the password hasher interface @@ -40,7 +43,7 @@ abstract class PasswordHasher { /** * Checks whether a supplied password matches the hashed one * - * @param passwordInfo the password retrieved from the backing store (by means of UserService) + * @param passwordInfo the password retrieved from the backing store (by means of UserService) * @param suppliedPassword the password supplied by the user trying to log in * @return true if the password matches, false otherwise. */ @@ -53,16 +56,10 @@ object PasswordHasher { /** * The default password hasher based on BCrypt. */ - class Default(logRounds: Int) extends PasswordHasher { - /** - * Creates an instance with logRounds set to the value specified in - * securesocial.passwordHasher.bcrypt.rounds or to a default 10 if the property is not - * defined. - */ - def this() = this({ - val app = play.api.Play.current - app.configuration.getInt(Default.RoundsProperty).getOrElse(Default.Rounds) - }) + class Default extends PasswordHasher { + @Inject + implicit var application: Application = null + val logRounds: Int = application.configuration.getInt(Default.RoundsProperty).getOrElse(Default.Rounds) /** * The hasher id @@ -84,7 +81,7 @@ object PasswordHasher { /** * Checks if a password matches the hashed version * - * @param passwordInfo the password retrieved from the backing store (by means of UserService) + * @param passwordInfo the password retrieved from the backing store (by means of UserService) * @param suppliedPassword the password supplied by the user trying to log in * @return true if the password matches, false otherwise. */ @@ -97,4 +94,5 @@ object PasswordHasher { val Rounds = 10 val RoundsProperty = "securesocial.passwordHasher.bcrypt.rounds" } + } \ No newline at end of file diff --git a/module-code/app/securesocial/core/providers/utils/PasswordValidator.scala b/module-code/app/securesocial/core/providers/utils/PasswordValidator.scala index d2498b856..ee1fb90a5 100644 --- a/module-code/app/securesocial/core/providers/utils/PasswordValidator.scala +++ b/module-code/app/securesocial/core/providers/utils/PasswordValidator.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,7 +16,10 @@ */ package securesocial.core.providers.utils -import play.api.data.validation.{ Constraint, Invalid, Valid } +import javax.inject.Inject + +import play.api.Application +import play.api.data.validation.{Constraint, Invalid, Valid} import securesocial.core.RuntimeEnvironment /** @@ -52,11 +55,10 @@ object PasswordValidator { * The minimum length can be configured setting a minimumPasswordLength property for userpass. * Defaults to 8 if not specified. */ - class Default(requiredLength: Int) extends PasswordValidator { - def this() = this({ - val app = play.api.Play.current - app.configuration.getInt(Default.PasswordLengthProperty).getOrElse(Default.Length) - }) + class Default extends PasswordValidator { + @Inject + implicit var application: Application = null + val requiredLength = application.configuration.getInt(Default.PasswordLengthProperty).getOrElse(Default.Length) override def validate(password: String): Either[(String, Seq[Any]), Unit] = { if (password.length >= requiredLength) { @@ -71,4 +73,5 @@ object PasswordValidator { val PasswordLengthProperty = "securesocial.userpass.minimumPasswordLength" val InvalidPasswordMessage = "securesocial.signup.invalidPassword" } + } diff --git a/module-code/app/securesocial/core/services/CacheService.scala b/module-code/app/securesocial/core/services/CacheService.scala index c059a32a6..9f942e5fe 100644 --- a/module-code/app/securesocial/core/services/CacheService.scala +++ b/module-code/app/securesocial/core/services/CacheService.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,7 +16,13 @@ */ package securesocial.core.services -import scala.concurrent.{ ExecutionContext, Future } +import javax.inject.Inject + +import play.api.Application +import play.api.cache.CacheApi + +import scala.concurrent.duration.Duration +import scala.concurrent.{ExecutionContext, Future} /** * An interface for the Cache API @@ -38,19 +44,24 @@ object CacheService { * A default implementation for the CacheService based on the Play cache. */ class Default(implicit val executionContext: ExecutionContext) extends CacheService { - import play.api.cache.Cache + import scala.reflect.ClassTag - import play.api.Play.current + + @Inject + implicit var application: Application = null + @Inject + implicit var Cache: CacheApi = null override def set[T](key: String, value: T, ttlInSeconds: Int): Future[Unit] = - Future.successful(Cache.set(key, value, ttlInSeconds)) + Future.successful(Cache.set(key, value, Duration(ttlInSeconds, "s"))) override def getAs[T](key: String)(implicit ct: ClassTag[T]): Future[Option[T]] = Future.successful { - Cache.getAs[T](key) + Cache.get[T](key) } override def remove(key: String): Future[Unit] = Future.successful { Cache.remove(key) } } + } diff --git a/module-code/app/securesocial/core/services/HttpService.scala b/module-code/app/securesocial/core/services/HttpService.scala index 30aa55e6b..73af28af5 100644 --- a/module-code/app/securesocial/core/services/HttpService.scala +++ b/module-code/app/securesocial/core/services/HttpService.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,12 +16,18 @@ */ package securesocial.core.services +import javax.inject.Inject + +import play.api.Application +import play.api.libs.ws.WSClient + import scala.concurrent.ExecutionContext /** * A mockable interface for the http client */ trait HttpService { + import play.api.libs.ws.WSRequest def url(url: String): WSRequest @@ -33,10 +39,14 @@ object HttpService { * A default implementation for HttpService based on the Play WS client. */ class Default(implicit val executionContext: ExecutionContext) extends HttpService { - import play.api.Play.current - import play.api.libs.ws.WS + @Inject + implicit var application: Application = null + @Inject + implicit var WS: WSClient = null + import play.api.libs.ws.WSRequest def url(url: String): WSRequest = WS.url(url) } + } diff --git a/module-code/app/securesocial/core/services/RoutesService.scala b/module-code/app/securesocial/core/services/RoutesService.scala index 25e8a616a..cceae90b1 100644 --- a/module-code/app/securesocial/core/services/RoutesService.scala +++ b/module-code/app/securesocial/core/services/RoutesService.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -16,7 +16,10 @@ */ package securesocial.core.services -import play.api.mvc.{ Call, RequestHeader } +import javax.inject.Inject + +import play.api.Application +import play.api.mvc.{Call, RequestHeader} import securesocial.core.IdentityProvider /** @@ -88,20 +91,27 @@ trait RoutesService { * The url to start an authentication flow with the given provider */ def authenticationUrl(provider: String, redirectTo: Option[String] = None)(implicit req: RequestHeader): String + def faviconPath: Call + def jqueryPath: Call + def bootstrapCssPath: Call + def customCssPath: Option[Call] } object RoutesService { + /** * The default RoutesService implementation. It points to the routes * defined by the built in controllers. */ class Default extends RoutesService { private val logger = play.api.Logger("securesocial.core.DefaultRoutesService") - lazy val conf = play.api.Play.current.configuration + @Inject + implicit var application: Application = null + lazy val conf = application.configuration val FaviconKey = "securesocial.faviconPath" val JQueryKey = "securesocial.jqueryPath" @@ -175,23 +185,27 @@ object RoutesService { /** * Loads the Favicon to use from configuration, using a default one if not provided + * * @return the path to Favicon file to use */ override val faviconPath = valueFor(FaviconKey, DefaultFaviconPath) /** * Loads the Jquery file to use from configuration, using a default one if not provided + * * @return the path to Jquery file to use */ override val jqueryPath = valueFor(JQueryKey, DefaultJqueryPath) /** * Loads the Bootstrap CSS file to use from configuration, using a default one if not provided + * * @return the path to Bootstrap CSS file to use */ override val bootstrapCssPath = valueFor(BootstrapCssKey, DefaultBootstrapCssPath) /** * Loads the Custom Css file to use from configuration. If there is none define, none will be used + * * @return Option containing a custom css file or None */ override val customCssPath: Option[Call] = { @@ -200,4 +214,5 @@ object RoutesService { path } } + } \ No newline at end of file diff --git a/module-code/build.sbt b/module-code/build.sbt index ce821a4d6..a22fcad98 100644 --- a/module-code/build.sbt +++ b/module-code/build.sbt @@ -1,12 +1,10 @@ -import play.sbt.PlayImport.PlayKeys._ - name := "SecureSocial" version := Common.version scalaVersion := Common.scalaVersion -crossScalaVersions := Seq("2.11.7", "2.10.5") +crossScalaVersions := Seq("2.11.8") //PlayKeys.generateRefReverseRouter := false diff --git a/module-code/conf/securesocial.routes b/module-code/conf/securesocial.routes index bb076eba2..5dfbe3486 100644 --- a/module-code/conf/securesocial.routes +++ b/module-code/conf/securesocial.routes @@ -1,28 +1,28 @@ # Login page -GET /login @securesocial.controllers.LoginPage.login -GET /logout @securesocial.controllers.LoginPage.logout +GET /login @securesocial.controllers.LoginPage.login +GET /logout @securesocial.controllers.LoginPage.logout # Registration routes -GET /signup @securesocial.controllers.Registration.startSignUp -POST /signup @securesocial.controllers.Registration.handleStartSignUp -GET /signup/:mailToken @securesocial.controllers.Registration.signUp(mailToken) -POST /signup/:mailToken @securesocial.controllers.Registration.handleSignUp(mailToken) +GET /signup @securesocial.controllers.Registration.startSignUp +POST /signup @securesocial.controllers.Registration.handleStartSignUp +GET /signup/:mailToken @securesocial.controllers.Registration.signUp(mailToken) +POST /signup/:mailToken @securesocial.controllers.Registration.handleSignUp(mailToken) # Reset password -GET /reset @securesocial.controllers.PasswordReset.startResetPassword -POST /reset @securesocial.controllers.PasswordReset.handleStartResetPassword -GET /reset/:mailToken @securesocial.controllers.PasswordReset.resetPassword(mailToken) -POST /reset/:mailToken @securesocial.controllers.PasswordReset.handleResetPassword(mailToken) +GET /reset @securesocial.controllers.PasswordReset.startResetPassword +POST /reset @securesocial.controllers.PasswordReset.handleStartResetPassword +GET /reset/:mailToken @securesocial.controllers.PasswordReset.resetPassword(mailToken) +POST /reset/:mailToken @securesocial.controllers.PasswordReset.handleResetPassword(mailToken) # Change Password -GET /password @securesocial.controllers.PasswordChange.page -POST /password @securesocial.controllers.PasswordChange.handlePasswordChange +GET /password @securesocial.controllers.PasswordChange.page +POST /password @securesocial.controllers.PasswordChange.handlePasswordChange # Authentication entry points for all providers -GET /authenticate/:provider @securesocial.controllers.ProviderController.authenticate(provider, redirectTo: Option[String]) -POST /authenticate/:provider @securesocial.controllers.ProviderController.authenticateByPost(provider, redirectTo: Option[String]) +GET /authenticate/:provider @securesocial.controllers.ProviderController.authenticate(provider, redirectTo: Option[String]) +POST /authenticate/:provider @securesocial.controllers.ProviderController.authenticateByPost(provider, redirectTo: Option[String]) -POST /api/authenticate/:provider @securesocial.controllers.LoginApi.authenticate(provider, builder = "token") +POST /api/authenticate/:provider @securesocial.controllers.LoginApi.authenticate(provider, builder = "token") -GET /assets/*file securesocial.controllers.Assets.at(path = "/public/lib/securesocial/securesocial", file) +GET /assets/*file @securesocial.controllers.Assets.at(path = "/public/lib/securesocial/securesocial", file) diff --git a/project/Common.scala b/project/Common.scala index 4eaf2bfb0..61f08e6f7 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -1,7 +1,9 @@ object Common { - def version = "master-SNAPSHOT" - def playVersion = System.getProperty("play.version", "2.4.4") - def scalaVersion = System.getProperty("scala.version", "2.11.7") + def version = "master-SNAPSHOT" + + def playVersion = System.getProperty("play.version", "2.5.1") + + def scalaVersion = System.getProperty("scala.version", "2.11.8") } diff --git a/project/plugins.sbt b/project/plugins.sbt index 0cf99b2bf..c4fb7fb73 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,7 +5,7 @@ logLevel := Level.Warn resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releases/" // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.4.2")) +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % System.getProperty("play.version", "2.5.1")) // Add Scalariform addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") diff --git a/samples/java/demo/app/controllers/Application.java b/samples/java/demo/app/controllers/Application.java index e95ed6b0e..35c800ab7 100644 --- a/samples/java/demo/app/controllers/Application.java +++ b/samples/java/demo/app/controllers/Application.java @@ -18,7 +18,6 @@ import com.google.inject.Inject; import play.Logger; -import play.libs.F; import play.mvc.Controller; import play.mvc.Result; import securesocial.core.BasicProfile; @@ -30,6 +29,9 @@ import views.html.index; import views.html.linkResult; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + /** * A sample controller @@ -96,10 +98,10 @@ public Result linkResult() { /** * Sample use of SecureSocial.currentUser. Access the /current-user to test it */ - public F.Promise currentUser() { - return SecureSocial.currentUser(env).map( new F.Function() { + public CompletionStage currentUser() { + return SecureSocial.currentUser(env).thenApplyAsync(new Function() { @Override - public Result apply(Object maybeUser) throws Throwable { + public Result apply(Object maybeUser) { String id; if ( maybeUser != null ) { diff --git a/samples/java/demo/app/service/InMemoryUserService.java b/samples/java/demo/app/service/InMemoryUserService.java index af399f3c0..74835ba1b 100644 --- a/samples/java/demo/app/service/InMemoryUserService.java +++ b/samples/java/demo/app/service/InMemoryUserService.java @@ -17,17 +17,18 @@ package service; import play.Logger; -import play.libs.F; import securesocial.core.BasicProfile; import securesocial.core.PasswordInfo; -import securesocial.core.services.SaveMode; import securesocial.core.java.BaseUserService; import securesocial.core.java.Token; import securesocial.core.providers.UsernamePasswordProvider; +import securesocial.core.services.SaveMode; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; /** * A Sample In Memory user service in Java @@ -42,7 +43,7 @@ public class InMemoryUserService extends BaseUserService { private HashMap tokens = new HashMap(); @Override - public F.Promise doSave(BasicProfile profile, SaveMode mode) { + public CompletionStage doSave(BasicProfile profile, SaveMode mode) { DemoUser result = null; if (mode == SaveMode.SignUp()) { result = new DemoUser(profile); @@ -74,11 +75,11 @@ public F.Promise doSave(BasicProfile profile, SaveMode mode) { } else { throw new RuntimeException("Unknown mode"); } - return F.Promise.pure(result); + return CompletableFuture.completedFuture(result); } @Override - public F.Promise doLink(DemoUser current, BasicProfile to) { + public CompletionStage doLink(DemoUser current, BasicProfile to) { DemoUser target = null; for ( DemoUser u: users.values() ) { @@ -101,17 +102,17 @@ public F.Promise doLink(DemoUser current, BasicProfile to) { } } if (!alreadyLinked) target.identities.add(to); - return F.Promise.pure(target); + return CompletableFuture.completedFuture(target); } @Override - public F.Promise doSaveToken(Token token) { + public CompletionStage doSaveToken(Token token) { tokens.put(token.uuid, token); - return F.Promise.pure(token); + return CompletableFuture.completedFuture(token); } @Override - public F.Promise doFind(String providerId, String userId) { + public CompletionStage doFind(String providerId, String userId) { if(logger.isDebugEnabled()){ logger.debug("Finding user " + userId); } @@ -126,27 +127,27 @@ public F.Promise doFind(String providerId, String userId) { } } - return F.Promise.pure(found); + return CompletableFuture.completedFuture(found); } @Override - public F.Promise doPasswordInfoFor(DemoUser user) { + public CompletionStage doPasswordInfoFor(DemoUser user) { throw new RuntimeException("doPasswordInfoFor is not implemented yet in sample app"); } @Override - public F.Promise doUpdatePasswordInfo(DemoUser user, PasswordInfo info) { + public CompletionStage doUpdatePasswordInfo(DemoUser user, PasswordInfo info) { throw new RuntimeException("doUpdatePasswordInfo is not implemented yet in sample app"); } @Override - public F.Promise doFindToken(String tokenId) { - return F.Promise.pure(tokens.get(tokenId)); + public CompletionStage doFindToken(String tokenId) { + return CompletableFuture.completedFuture(tokens.get(tokenId)); } @Override - public F.Promise doFindByEmailAndProvider(String email, String providerId) { + public CompletionStage doFindByEmailAndProvider(String email, String providerId) { BasicProfile found = null; for ( DemoUser u: users.values() ) { @@ -158,12 +159,12 @@ public F.Promise doFindByEmailAndProvider(String email, String pro } } - return F.Promise.pure(found); + return CompletableFuture.completedFuture(found); } @Override - public F.Promise doDeleteToken(String uuid) { - return F.Promise.pure(tokens.remove(uuid)); + public CompletionStage doDeleteToken(String uuid) { + return CompletableFuture.completedFuture(tokens.remove(uuid)); } @Override diff --git a/samples/java/demo/javaDemo.sbt b/samples/java/demo/javaDemo.sbt index 8d965018c..7529ea86d 100644 --- a/samples/java/demo/javaDemo.sbt +++ b/samples/java/demo/javaDemo.sbt @@ -1,5 +1,3 @@ -import PlayKeys._ - name := "java-demo" version := Common.version @@ -12,7 +10,7 @@ libraryDependencies ++= Seq("ws.securesocial" %% "securesocial" % version.value, resolvers += Resolver.sonatypeRepo("snapshots") -javacOptions ++= Seq("-source", "1.6", "-target", "1.6", "-encoding", "UTF-8", "-Xlint:-options") +javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-encoding", "UTF-8", "-Xlint:-options") scalacOptions := Seq("-encoding", "UTF-8", "-Xlint", "-deprecation", "-unchecked", "-feature") diff --git a/samples/scala/demo/app/Global.scala b/samples/scala/demo/app/Global.scala index 5fe0f598c..ff93f0c98 100644 --- a/samples/scala/demo/app/Global.scala +++ b/samples/scala/demo/app/Global.scala @@ -5,7 +5,7 @@ * 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 + * 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, @@ -14,41 +14,38 @@ * limitations under the License. * */ + import controllers.CustomRoutesService -import java.lang.reflect.Constructor import securesocial.core.RuntimeEnvironment -import service.{ DemoUser, MyEventListener, InMemoryUserService } +import service.{DemoUser, InMemoryUserService, MyEventListener} -object Global extends play.api.GlobalSettings { +/** + * The runtime environment for this sample app. + */ +class MyRuntimeEnvironment extends RuntimeEnvironment.Default { + type U = DemoUser + override implicit val executionContext = play.api.libs.concurrent.Execution.defaultContext + override lazy val routes = new CustomRoutesService() + override lazy val userService: InMemoryUserService = new InMemoryUserService() + override lazy val eventListeners = List(new MyEventListener()) +} - /** - * The runtime environment for this sample app. - */ - class MyRuntimeEnvironment extends RuntimeEnvironment.Default { - type U = DemoUser - override implicit val executionContext = play.api.libs.concurrent.Execution.defaultContext - override lazy val routes = new CustomRoutesService() - override lazy val userService: InMemoryUserService = new InMemoryUserService() - override lazy val eventListeners = List(new MyEventListener()) +/** + * An implementation that checks if the controller expects a RuntimeEnvironment and + * passes the instance to it if required. + * + * This can be replaced by any DI framework to inject it differently. + * + * @param controllerClass + * @tparam A + * @return + */ +/* def getControllerInstance[A](controllerClass: Class[A]): A = { + val instance = controllerClass.getConstructors.find { c => + val params = c.getParameterTypes + params.length == 1 && params(0) == classOf[RuntimeEnvironment[DemoUser]] + }.map { + _.asInstanceOf[Constructor[A]].newInstance(MyRuntimeEnvironment) } - - /** - * An implementation that checks if the controller expects a RuntimeEnvironment and - * passes the instance to it if required. - * - * This can be replaced by any DI framework to inject it differently. - * - * @param controllerClass - * @tparam A - * @return - */ - /* def getControllerInstance[A](controllerClass: Class[A]): A = { - val instance = controllerClass.getConstructors.find { c => - val params = c.getParameterTypes - params.length == 1 && params(0) == classOf[RuntimeEnvironment[DemoUser]] - }.map { - _.asInstanceOf[Constructor[A]].newInstance(MyRuntimeEnvironment) - } - instance.getOrElse(super.getControllerInstance(controllerClass)) - }*/ -} + instance.getOrElse(super.getControllerInstance(controllerClass)) +}*/ \ No newline at end of file diff --git a/samples/scala/demo/scalaDemo.sbt b/samples/scala/demo/scalaDemo.sbt index f479aa254..c4d20c591 100644 --- a/samples/scala/demo/scalaDemo.sbt +++ b/samples/scala/demo/scalaDemo.sbt @@ -1,5 +1,3 @@ -import PlayKeys._ - name := "scala-demo" version := Common.version