Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Remember Me feature #276

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import providers.utils.RoutesHelper
import securesocial.core.LoginEvent
import securesocial.core.AccessDeniedException
import scala.Some

import securesocial.core.providers.UsernamePasswordProvider

/**
* A controller to provide the authentication entry point
Expand Down Expand Up @@ -107,17 +107,21 @@ object ProviderController extends Controller
}
}

def completeAuthentication(user: Identity, session: Session)(implicit request: RequestHeader): PlainResult = {
if ( Logger.isDebugEnabled ) {
def completeAuthentication(user: Identity, session: Session)(implicit request: Request[AnyContent]): PlainResult = {
if (Logger.isDebugEnabled) {
Logger.debug("[securesocial] user logged in : [" + user + "]")
}

val withSession = Events.fire(new LoginEvent(user)).getOrElse(session)
Authenticator.create(user) match {
case Right(authenticator) => {
val form = UsernamePasswordProvider.loginForm.bindFromRequest()
val rememberCookie = form.fold(error => None, credentials => credentials.remember)
Redirect(toUrl).withSession(withSession -
SecureSocial.OriginalUrlKey -
IdentityProvider.SessionId -
OAuth1Provider.CacheKey).withCookies(authenticator.toCookie)
OAuth1Provider.CacheKey).withCookies(authenticator.toCookie(rememberCookie))

}
case Left(error) => {
// improve this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import securesocial.core.{Identity, SecuredRequest, SocialUser}
import play.api.data.Form
import securesocial.controllers.Registration.RegistrationInfo
import securesocial.controllers.PasswordChange.ChangeInfo
import securesocial.core.providers.UsernamePasswordProvider.LoginInfo


/**
Expand All @@ -44,7 +45,7 @@ trait TemplatesPlugin extends Plugin {
* @tparam A
* @return
*/
def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)], msg: Option[String] = None): Html
def getLoginPage[A](implicit request: Request[A], form: Form[LoginInfo], msg: Option[String] = None): Html

/**
* Returns the html for the signup page
Expand Down Expand Up @@ -165,7 +166,7 @@ trait TemplatesPlugin extends Plugin {
* @param application
*/
class DefaultTemplatesPlugin(application: Application) extends TemplatesPlugin {
override def getLoginPage[A](implicit request: Request[A], form: Form[(String, String)],
override def getLoginPage[A](implicit request: Request[A], form: Form[LoginInfo],
msg: Option[String] = None): Html =
{
securesocial.views.html.login(form, msg)
Expand Down
6 changes: 4 additions & 2 deletions module-code/app/securesocial/core/Authenticator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ case class Authenticator(id: String, identityId: IdentityId, creationDate: DateT
*
* @return a cookie instance
*/
def toCookie: Cookie = {
def toCookie(): Cookie = toCookie(None)
def toCookie(remeberMe : Option[Boolean]): Cookie = {
import Authenticator._
Cookie(
cookieName,
id,
if ( makeTransient ) Transient else Some(absoluteTimeoutInSeconds),
if ( remeberMe.getOrElse(makeTransient) ) Transient else Some(absoluteTimeoutInSeconds),

cookiePath,
cookieDomain,
secure = cookieSecure,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Play.current
import com.typesafe.plugin._
import securesocial.controllers.TemplatesPlugin
import org.joda.time.DateTime
import play.api.mvc.Session

/**
* A username password provider
Expand All @@ -43,11 +44,11 @@ class UsernamePasswordProvider(application: Application) extends IdentityProvide
form.fold(
errors => Left(badRequest(errors, request)),
credentials => {
val userId = IdentityId(credentials._1, id)
val userId = IdentityId(credentials.username, id)
val result = for (
user <- UserService.find(userId) ;
pinfo <- user.passwordInfo ;
hasher <- Registry.hashers.get(pinfo.hasher) if hasher.matches(pinfo, credentials._2)
hasher <- Registry.hashers.get(pinfo.hasher) if hasher.matches(pinfo,credentials.password)
) yield (
Right(SocialUser(user))
)
Expand All @@ -58,11 +59,12 @@ class UsernamePasswordProvider(application: Application) extends IdentityProvide
)
}

private def badRequest[A](f: Form[(String,String)], request: Request[A], msg: Option[String] = None): PlainResult = {
private def badRequest[A](f: Form[UsernamePasswordProvider.LoginInfo], request: Request[A], msg: Option[String] = None): PlainResult = {
Results.BadRequest(use[TemplatesPlugin].getLoginPage(request, f, msg))
}

def fillProfile(user: SocialUser) = {

def fillProfile(user: SocialUser) = {
GravatarHelper.avatarFor(user.email.get) match {
case Some(url) if url != user.avatarUrl => user.copy( avatarUrl = Some(url))
case _ => user
Expand All @@ -78,20 +80,37 @@ object UsernamePasswordProvider {
private val Hasher = "securesocial.userpass.hasher"
private val EnableTokenJob = "securesocial.userpass.enableTokenJob"
private val SignupSkipLogin = "securesocial.userpass.signupSkipLogin"
private val RememberMe = "securesocial.userpass.withRememberMe"


val loginForm = Form(
tuple(
case class LoginInfo(username: String, password: String, remember: Option[Boolean])

val loginFormWithRemember = Form[LoginInfo](
mapping(
"username" -> nonEmptyText,
"password" -> nonEmptyText
)
)
"password" -> nonEmptyText,
"remember" -> boolean) // binding
((username, password, remember) => LoginInfo(username, password, Some(remember)))
(info => Some(info.username, info.password, info.remember.getOrElse(false)))
)
val loginFormWithoutRemember = Form[LoginInfo](
mapping(
"username" -> nonEmptyText,
"password" -> nonEmptyText)
// binding
((username, password) => LoginInfo(username, password, None)) // unbinding
(info => Some(info.username, info.password)))

val loginForm = if (UsernamePasswordProvider.withRememberMe) loginFormWithRemember else loginFormWithoutRemember

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)
lazy val signupSkipLogin = current.configuration.getBoolean(SignupSkipLogin).getOrElse(false)
lazy val withRememberMe = current.configuration.getBoolean(RememberMe).getOrElse(false)

}

/**
Expand Down
2 changes: 1 addition & 1 deletion module-code/app/securesocial/views/login.scala.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(loginForm: Form[(String,String)], errorMsg: Option[String] = None)(implicit request: RequestHeader)
@(loginForm: Form[securesocial.core.providers.UsernamePasswordProvider.LoginInfo], errorMsg: Option[String] = None)(implicit request: RequestHeader)

@import helper._
@import securesocial.core.Registry
Expand Down
10 changes: 9 additions & 1 deletion module-code/app/securesocial/views/provider.scala.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@(providerId: String, loginForm: Option[Form[(String, String)]] = None)(implicit request: RequestHeader)
@(providerId: String, loginForm: Option[Form[securesocial.core.providers.UsernamePasswordProvider.LoginInfo]] = None)(implicit request: RequestHeader)

@import securesocial.core.Registry
@import securesocial.core.IdentityProvider
Expand Down Expand Up @@ -40,6 +40,14 @@
'_label -> Messages("securesocial.signup.password1"),
'class -> "input-xlarge"
)

@if( UsernamePasswordProvider.withRememberMe ) {
@helper.checkbox(
loginForm.get("remember"),
'_label -> Messages("securesocial.login.remember"),
'class -> "input-xlarge"
)
}

<div class="form-actions">
<button type="submit" class="btn btn-primary">@Messages("securesocial.login.title")</button>
Expand Down
1 change: 1 addition & 0 deletions module-code/conf/messages.zh-CN
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ securesocial.appName=Secure Social 2

# Login page
securesocial.login.title=登录
securesocial.login.remember=記住我
securesocial.login.instructions=用你在这里的账号或点击下面这些网站的图标登录
securesocial.login.accessDenied=你被拒绝访问你的账号。请允许用该账号登录。
securesocial.login.errorLoggingIn=在你登录时系统出错了,请再试一次。
Expand Down
1 change: 1 addition & 0 deletions samples/scala/demo/conf/securesocial.conf
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ securesocial {
# Enable username support, otherwise SecureSocial will use the emails as user names
#
withUserNameSupport=false
withRememberMe = false
sendWelcomeEmail=true
enableGravatarSupport=true
tokenDuration=60
Expand Down