/
UsernamePasswordProvider.scala
106 lines (94 loc) · 3.87 KB
/
UsernamePasswordProvider.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* Copyright 2012 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.providers
import play.api.data.Form
import play.api.data.Forms._
import securesocial.core._
import play.api.mvc.{PlainResult, Results, Result, Request}
import utils.{GravatarHelper, PasswordHasher}
import play.api.{Play, Application}
import Play.current
import com.typesafe.plugin._
import securesocial.controllers.TemplatesPlugin
import org.joda.time.DateTime
/**
* A username password provider
*/
class UsernamePasswordProvider(application: Application) extends IdentityProvider(application) {
override def id = UsernamePasswordProvider.UsernamePassword
def authMethod = AuthenticationMethod.UserPassword
val InvalidCredentials = "securesocial.login.invalidCredentials"
def doAuth[A]()(implicit request: Request[A]): Either[Result, SocialUser] = {
val form = UsernamePasswordProvider.loginForm.bindFromRequest()
form.fold(
errors => Left(badRequest(errors, request)),
credentials => {
val userId = UserId(credentials._1, id)
val result = for (
user <- UserService.find(userId) ;
pinfo <- user.passwordInfo ;
hasher <- Registry.hashers.get(pinfo.hasher) if hasher.matches(pinfo, credentials._2)
) yield (
Right(SocialUser(user))
)
result.getOrElse(
Left(badRequest(UsernamePasswordProvider.loginForm, request, Some(InvalidCredentials)))
)
}
)
}
private def badRequest[A](f: Form[(String,String)], request: Request[A], msg: Option[String] = None): PlainResult = {
Results.BadRequest(use[TemplatesPlugin].getLoginPage(request, f, msg))
}
def fillProfile(user: SocialUser) = {
GravatarHelper.avatarFor(user.email.get) match {
case Some(url) if url != user.avatarUrl => user.copy( avatarUrl = Some(url))
case _ => user
}
}
}
object UsernamePasswordProvider {
val UsernamePassword = "userpass"
private val Key = "securesocial.userpass.withUserNameSupport"
private val SendWelcomeEmailKey = "securesocial.userpass.sendWelcomeEmail"
private val EnableGravatarKey = "securesocial.userpass.enableGravatarSupport"
private val Hasher = "securesocial.userpass.hasher"
private val EnableTokenJob = "securesocial.userpass.enableTokenJob"
val loginForm = Form(
tuple(
"username" -> nonEmptyText,
"password" -> nonEmptyText
)
)
lazy val withUserNameSupport = current.configuration.getBoolean(Key).getOrElse(false)
lazy val sendWelcomeEmail = current.configuration.getBoolean(SendWelcomeEmailKey).getOrElse(true)
lazy val enableGravatar = current.configuration.getBoolean(EnableGravatarKey).getOrElse(true)
lazy val hasher = current.configuration.getString(Hasher).getOrElse(PasswordHasher.BCryptHasher)
lazy val enableTokenJob = current.configuration.getBoolean(EnableTokenJob).getOrElse(true)
}
/**
* A token used for reset password and sign up operations
*
* @param uuid the token id
* @param email the user email
* @param creationTime the creation time
* @param expirationTime the expiration time
* @param isSignUp a boolean indicating wether the token was created for a sign up action or not
*/
case class Token(uuid: String, email: String, creationTime: DateTime, expirationTime: DateTime, isSignUp: Boolean) {
def isExpired = expirationTime.isBeforeNow
}