Skip to content

Commit b264a10

Browse files
committed
- Added scalariform
- Separate creation and storage of mail tokens (thanks @normenmueller) - Upgrade to Play 2.3.3 (thanks @benmccann)
1 parent 73d7c85 commit b264a10

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+628
-675
lines changed

ChangeLog

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
master -
2+
- Added scalariform
3+
- Separate creation and storage of mail tokens (thanks @normenmueller)
4+
- Upgrade to Play 2.3.3 (thanks @benmccann)
25
- Updated GoogleProvider to use the new Google endpoints (see https://developers.google.com/+/api/auth-migration#timetable)
36
- Code is now compatible with Play 2.3
47
- Added SecureSocial.currentUser to support Websockets

module-code/app/securesocial/controllers/LoginApi.scala

+32-32
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package securesocial.controllers
1919
import org.joda.time.DateTime
2020
import securesocial.core._
2121
import play.api.mvc.Action
22-
import scala.concurrent.{ExecutionContext, Future}
22+
import scala.concurrent.{ ExecutionContext, Future }
2323
import securesocial.core.SignUpEvent
2424
import securesocial.core.AuthenticationResult.Authenticated
2525
import securesocial.core.LoginEvent
@@ -50,44 +50,44 @@ trait BaseLoginApi[U] extends SecureSocial[U] {
5050

5151
def authenticate(providerId: String, builderId: String) = Action.async { implicit request =>
5252
import ExecutionContext.Implicits.global
53-
val result = for (
54-
builder <- env.authenticatorService.find(builderId) ;
55-
provider <- env.providers.get(providerId) if provider.isInstanceOf[ApiSupport]
56-
) yield {
57-
provider.asInstanceOf[ApiSupport].authenticateForApi.flatMap {
58-
case authenticated: Authenticated =>
59-
val profile = authenticated.profile
60-
env.userService.find(profile.providerId, profile.userId).flatMap {
61-
maybeExisting =>
62-
val mode = if (maybeExisting.isDefined) SaveMode.LoggedIn else SaveMode.SignUp
63-
env.userService.save(authenticated.profile, mode).flatMap {
64-
userForAction =>
65-
logger.debug(s"[securesocial] user completed authentication: provider = ${profile.providerId}, userId: ${profile.userId}, mode = $mode")
66-
val evt = if (mode == SaveMode.LoggedIn) new LoginEvent(userForAction) else new SignUpEvent(userForAction)
67-
// we're not using a session here .... review this.
68-
Events.fire(evt)
69-
builder.fromUser(userForAction).map { authenticator =>
70-
val token = TokenResponse(authenticator.id, authenticator.expirationDate)
71-
Ok(Json.toJson(token))
72-
}
73-
}
74-
}
75-
case failed: AuthenticationResult.Failed =>
76-
Future.successful(BadRequest(Json.toJson(Map("error" -> failed.error))).as("application/json"))
77-
case other =>
78-
// todo: review this status
79-
logger.error(s"[securesocial] unexpected result from authenticateForApi: $other")
80-
Future.successful(InternalServerError(Json.toJson(Map("error" -> "unexpected internal error"))).as("application/json"))
81-
}
53+
val result = for (
54+
builder <- env.authenticatorService.find(builderId);
55+
provider <- env.providers.get(providerId) if provider.isInstanceOf[ApiSupport]
56+
) yield {
57+
provider.asInstanceOf[ApiSupport].authenticateForApi.flatMap {
58+
case authenticated: Authenticated =>
59+
val profile = authenticated.profile
60+
env.userService.find(profile.providerId, profile.userId).flatMap {
61+
maybeExisting =>
62+
val mode = if (maybeExisting.isDefined) SaveMode.LoggedIn else SaveMode.SignUp
63+
env.userService.save(authenticated.profile, mode).flatMap {
64+
userForAction =>
65+
logger.debug(s"[securesocial] user completed authentication: provider = ${profile.providerId}, userId: ${profile.userId}, mode = $mode")
66+
val evt = if (mode == SaveMode.LoggedIn) new LoginEvent(userForAction) else new SignUpEvent(userForAction)
67+
// we're not using a session here .... review this.
68+
Events.fire(evt)
69+
builder.fromUser(userForAction).map { authenticator =>
70+
val token = TokenResponse(authenticator.id, authenticator.expirationDate)
71+
Ok(Json.toJson(token))
72+
}
73+
}
74+
}
75+
case failed: AuthenticationResult.Failed =>
76+
Future.successful(BadRequest(Json.toJson(Map("error" -> failed.error))).as("application/json"))
77+
case other =>
78+
// todo: review this status
79+
logger.error(s"[securesocial] unexpected result from authenticateForApi: $other")
80+
Future.successful(InternalServerError(Json.toJson(Map("error" -> "unexpected internal error"))).as("application/json"))
8281
}
83-
result.getOrElse(Future.successful(NotFound.as("application/json")))
82+
}
83+
result.getOrElse(Future.successful(NotFound.as("application/json")))
8484
}
8585

8686
def logout = Action.async { implicit request =>
8787
import securesocial.core.utils._
8888
import ExecutionContext.Implicits.global
8989
env.authenticatorService.fromRequest(request).flatMap {
90-
case Some(authenticator) => Ok("").discardingAuthenticator(authenticator)
90+
case Some(authenticator) => Ok("").discardingAuthenticator(authenticator)
9191
case None => Future.successful(Ok(""))
9292
}
9393
}

module-code/app/securesocial/controllers/LoginPage.scala

+5-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ import securesocial.core.utils._
2121
import play.api.Play
2222
import Play.current
2323
import providers.UsernamePasswordProvider
24-
import scala.concurrent.{ExecutionContext, Future}
25-
24+
import scala.concurrent.{ ExecutionContext, Future }
2625

2726
/**
2827
* A default Login controller that uses BasicProfile as the user type.
@@ -34,8 +33,7 @@ class LoginPage(override implicit val env: RuntimeEnvironment[BasicProfile]) ext
3433
/**
3534
* The trait that defines the login page controller
3635
*/
37-
trait BaseLoginPage[U] extends SecureSocial[U]
38-
{
36+
trait BaseLoginPage[U] extends SecureSocial[U] {
3937
private val logger = play.api.Logger("securesocial.controllers.LoginPage")
4038

4139
/**
@@ -49,12 +47,12 @@ trait BaseLoginPage[U] extends SecureSocial[U]
4947
*/
5048
def login = UserAwareAction { implicit request =>
5149
val to = ProviderControllerHelper.landingUrl
52-
if ( request.user.isDefined ) {
50+
if (request.user.isDefined) {
5351
// if the user is already logged in just redirect to the app
5452
logger.debug("User already logged in, skipping login page. Redirecting to %s".format(to))
55-
Redirect( to )
53+
Redirect(to)
5654
} else {
57-
if ( SecureSocial.enableRefererAsOriginalUrl ) {
55+
if (SecureSocial.enableRefererAsOriginalUrl) {
5856
SecureSocial.withRefererAsOriginalUrl(Ok(env.viewTemplates.getLoginPage(UsernamePasswordProvider.loginForm)))
5957
} else {
6058
Ok(env.viewTemplates.getLoginPage(UsernamePasswordProvider.loginForm))

module-code/app/securesocial/controllers/MailTokenBasedOperations.scala

+21-26
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@
1616
*/
1717
package securesocial.controllers
1818

19-
import securesocial.core.SecureSocial
20-
import scala.concurrent.{ExecutionContext, Future}
21-
import play.api.mvc.RequestHeader
22-
import play.api.i18n.Messages
19+
import java.util.UUID
20+
21+
import org.joda.time.DateTime
22+
import play.api.Play
2323
import play.api.data.Form
2424
import play.api.data.Forms._
2525
import play.api.data.validation.Constraints._
26+
import play.api.i18n.Messages
27+
import play.api.mvc.{ RequestHeader, SimpleResult }
28+
import securesocial.core.SecureSocial
2629
import securesocial.core.providers.MailToken
27-
import scala.Some
28-
import play.api.mvc.SimpleResult
29-
import java.util.UUID
30-
import org.joda.time.DateTime
31-
import play.api.Play
30+
31+
import scala.concurrent.Future
3232

3333
/**
3434
* The base controller for password reset and password change operations
@@ -42,8 +42,8 @@ abstract class MailTokenBasedOperations[U] extends SecureSocial[U] {
4242
val DefaultDuration = 60
4343
val TokenDuration = Play.current.configuration.getInt(TokenDurationKey).getOrElse(DefaultDuration)
4444

45-
val startForm = Form (
46-
Email -> email.verifying( nonEmpty )
45+
val startForm = Form(
46+
Email -> email.verifying(nonEmpty)
4747
)
4848

4949
/**
@@ -57,11 +57,7 @@ abstract class MailTokenBasedOperations[U] extends SecureSocial[U] {
5757
val now = DateTime.now
5858

5959
Future.successful(MailToken(
60-
UUID.randomUUID().toString
61-
, email.toLowerCase
62-
, now
63-
, now.plusMinutes(TokenDuration)
64-
, isSignUp = isSignUp
60+
UUID.randomUUID().toString, email.toLowerCase, now, now.plusMinutes(TokenDuration), isSignUp = isSignUp
6561
))
6662
}
6763

@@ -76,17 +72,16 @@ abstract class MailTokenBasedOperations[U] extends SecureSocial[U] {
7672
* @return the action result
7773
*/
7874
protected def executeForToken(token: String, isSignUp: Boolean,
79-
f: MailToken => Future[SimpleResult])
80-
(implicit request: RequestHeader): Future[SimpleResult] =
81-
{
82-
import ExecutionContext.Implicits.global
83-
env.userService.findToken(token).flatMap {
84-
case Some(t) if !t.isExpired && t.isSignUp == isSignUp => f(t)
85-
case _ =>
86-
val to = if ( isSignUp ) env.routes.signUpUrl else env.routes.resetPasswordUrl
87-
Future.successful(Redirect(to).flashing(Error -> Messages(BaseRegistration.InvalidLink)))
75+
f: MailToken => Future[SimpleResult])(implicit request: RequestHeader): Future[SimpleResult] =
76+
{
77+
import scala.concurrent.ExecutionContext.Implicits.global
78+
env.userService.findToken(token).flatMap {
79+
case Some(t) if !t.isExpired && t.isSignUp == isSignUp => f(t)
80+
case _ =>
81+
val to = if (isSignUp) env.routes.signUpUrl else env.routes.resetPasswordUrl
82+
Future.successful(Redirect(to).flashing(Error -> Messages(BaseRegistration.InvalidLink)))
83+
}
8884
}
89-
}
9085

9186
/**
9287
* The result sent after the start page is handled

module-code/app/securesocial/controllers/PasswordChange.scala

+14-15
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import play.api.data.Forms._
2424
import securesocial.core.providers.utils.PasswordValidator
2525
import play.api.i18n.Messages
2626
import scala.Some
27-
import scala.concurrent.{Await, ExecutionContext, Future}
27+
import scala.concurrent.{ Await, ExecutionContext, Future }
2828

2929
/**
3030
* A default PasswordChange controller that uses the BasicProfile as the user type
@@ -37,7 +37,7 @@ class PasswordChange(override implicit val env: RuntimeEnvironment[BasicProfile]
3737
* A trait that defines the password change functionality
3838
*
3939
* @tparam U the user object type
40-
**/
40+
*/
4141
trait BasePasswordChange[U] extends SecureSocial[U] {
4242
val CurrentPassword = "currentPassword"
4343
val InvalidPasswordMessage = "securesocial.passwordChange.invalidPassword"
@@ -55,7 +55,7 @@ trait BasePasswordChange[U] extends SecureSocial[U] {
5555

5656
/** The redirect target of the handlePasswordChange action. */
5757
def onHandlePasswordChangeGoTo = Play.current.configuration.getString(onPasswordChangeGoTo).getOrElse(
58-
securesocial.controllers.routes.PasswordChange.page().url
58+
securesocial.controllers.routes.PasswordChange.page().url
5959
)
6060

6161
/**
@@ -67,13 +67,13 @@ trait BasePasswordChange[U] extends SecureSocial[U] {
6767
*/
6868
def checkCurrentPassword[A](suppliedPassword: String)(implicit request: SecuredRequest[A]): Future[Boolean] = {
6969
import ExecutionContext.Implicits.global
70-
env.userService.passwordInfoFor(request.user).map {
71-
case Some(info) =>
72-
env.passwordHashers.get(info.hasher).exists {
73-
_.matches(info, suppliedPassword)
74-
}
75-
case None => false
76-
}
70+
env.userService.passwordInfoFor(request.user).map {
71+
case Some(info) =>
72+
env.passwordHashers.get(info.hasher).exists {
73+
_.matches(info, suppliedPassword)
74+
}
75+
case None => false
76+
}
7777
}
7878

7979
private def execute[A](f: Form[ChangeInfo] => Future[SimpleResult])(implicit request: SecuredRequest[A]): Future[SimpleResult] = {
@@ -87,12 +87,11 @@ trait BasePasswordChange[U] extends SecureSocial[U] {
8787
}),
8888
NewPassword ->
8989
tuple(
90-
Password1 -> nonEmptyText.verifying( PasswordValidator.constraint ),
90+
Password1 -> nonEmptyText.verifying(PasswordValidator.constraint),
9191
Password2 -> nonEmptyText
9292
).verifying(Messages(BaseRegistration.PasswordsDoNotMatch), passwords => passwords._1 == passwords._2)
9393

94-
)((currentPassword, newPassword) => ChangeInfo(currentPassword, newPassword._1))
95-
((changeInfo: ChangeInfo) => Some("", ("", "")))
94+
)((currentPassword, newPassword) => ChangeInfo(currentPassword, newPassword._1))((changeInfo: ChangeInfo) => Some("", ("", "")))
9695
)
9796

9897
env.userService.passwordInfoFor(request.user).flatMap {
@@ -123,9 +122,9 @@ trait BasePasswordChange[U] extends SecureSocial[U] {
123122
*/
124123
def handlePasswordChange = SecuredAction.async { implicit request =>
125124
execute { form: Form[ChangeInfo] =>
126-
form.bindFromRequest()(request).fold (
125+
form.bindFromRequest()(request).fold(
127126
errors => Future.successful(BadRequest(env.viewTemplates.getPasswordChangePage(errors))),
128-
info => {
127+
info => {
129128
val newPasswordInfo = env.currentHasher.hash(info.newPassword)
130129
import ExecutionContext.Implicits.global
131130
implicit val userLang = request2lang(request)

module-code/app/securesocial/controllers/PasswordReset.scala

+21-20
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ trait BasePasswordReset[U] extends MailTokenBasedOperations[U] {
4545
val PasswordUpdated = "securesocial.password.passwordUpdated"
4646
val ErrorUpdatingPassword = "securesocial.password.error"
4747

48-
val changePasswordForm = Form (
48+
val changePasswordForm = Form(
4949
BaseRegistration.Password ->
5050
tuple(
51-
BaseRegistration.Password1 -> nonEmptyText.verifying( PasswordValidator.constraint ),
51+
BaseRegistration.Password1 -> nonEmptyText.verifying(PasswordValidator.constraint),
5252
BaseRegistration.Password2 -> nonEmptyText
5353
).verifying(Messages(BaseRegistration.PasswordsDoNotMatch), passwords => passwords._1 == passwords._2)
5454
)
@@ -106,25 +106,26 @@ trait BasePasswordReset[U] extends MailTokenBasedOperations[U] {
106106
def handleResetPassword(token: String) = Action.async { implicit request =>
107107
import scala.concurrent.ExecutionContext.Implicits.global
108108
executeForToken(token, false, {
109-
t => changePasswordForm.bindFromRequest.fold(errors =>
109+
t =>
110+
changePasswordForm.bindFromRequest.fold(errors =>
110111
Future.successful(BadRequest(env.viewTemplates.getResetPasswordPage(errors, token))),
111-
p =>
112-
env.userService.findByEmailAndProvider(t.email, UsernamePasswordProvider.UsernamePassword).flatMap {
113-
case Some(profile) =>
114-
val hashed = env.currentHasher.hash(p._1)
115-
for (
116-
updated <- env.userService.save(profile.copy(passwordInfo = Some(hashed)), SaveMode.PasswordChange);
117-
deleted <- env.userService.deleteToken(token)
118-
) yield {
119-
env.mailer.sendPasswordChangedNotice(profile)
120-
val eventSession = Events.fire(new PasswordResetEvent(updated)).getOrElse(request.session)
121-
confirmationResult().withSession(eventSession).flashing(Success -> Messages(PasswordUpdated))
122-
}
123-
case _ =>
124-
logger.error("[securesocial] could not find user with email %s during password reset".format(t.email))
125-
Future.successful(confirmationResult().flashing(Error -> Messages(ErrorUpdatingPassword)))
126-
}
127-
)
112+
p =>
113+
env.userService.findByEmailAndProvider(t.email, UsernamePasswordProvider.UsernamePassword).flatMap {
114+
case Some(profile) =>
115+
val hashed = env.currentHasher.hash(p._1)
116+
for (
117+
updated <- env.userService.save(profile.copy(passwordInfo = Some(hashed)), SaveMode.PasswordChange);
118+
deleted <- env.userService.deleteToken(token)
119+
) yield {
120+
env.mailer.sendPasswordChangedNotice(profile)
121+
val eventSession = Events.fire(new PasswordResetEvent(updated)).getOrElse(request.session)
122+
confirmationResult().withSession(eventSession).flashing(Success -> Messages(PasswordUpdated))
123+
}
124+
case _ =>
125+
logger.error("[securesocial] could not find user with email %s during password reset".format(t.email))
126+
Future.successful(confirmationResult().flashing(Error -> Messages(ErrorUpdatingPassword)))
127+
}
128+
)
128129
})
129130
}
130131
}

0 commit comments

Comments
 (0)