Skip to content

Instantly share code, notes, and snippets.

@rossabaker
Created November 3, 2010 02:06
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rossabaker/660701 to your computer and use it in GitHub Desktop.
Save rossabaker/660701 to your computer and use it in GitHub Desktop.
trait AuthenticationSupport
        extends ScentrySupport[ApiUser]
                with FlashMapSupport
                with CookieSupport
                with Logging { self: ScalatraKernel =>
  before { scentry.authenticate('RememberMe) }
  override protected def registerAuthStrategies = {
    scentry.registerStrategy('UserPassword, app => new UserPasswordStrategy(app))
    scentry.registerStrategy('RememberMe, app => new RememberMeStrategy(app))
  }
  protected def fromSession = {
    case id: String => { /* Serialize user from session */ }
  }
  protected def toSession = {
    case usr: ApiUser => usr.id
  }
}
object RememberMeStrategy {
  class RememberMeStrategy(protected val app: ScalatraKernelProxy)
          extends ScentryStrategy[ApiUser] with Logging {
    val COOKIE_KEY = "scentry.auth.remember"
    private val oneWeek = 7 * 24 * 3600
    override def valid_? = {
      app.cookies(COOKIE_KEY).isDefined
    }
    override def afterAuthenticate(winningStrategy: Symbol, user: ApiUser) = {
      log debug "Executing after authenticate in remember me strategy with winning strategy [%s] and user [%s]".format(winningStrategy, user)
      if (winningStrategy == 'RememberMe ||
              (winningStrategy == 'UserPassword && checkbox2boolean(app.params.get("remember").getOrElse("")))) {
        log debug "Remembering user [%s]".format(user.email)
        // val token = fetchTokenFromBackend
        // app.cookies.update(COOKIE_KEY, token, CookieOptions( path = "/", maxAge = oneWeek ))
      }
    }
    def authenticate_! = {
      log debug "Authenticating in Remember me strategy"
      app.cookies(COOKIE_KEY) flatMap { token =>
        log debug "Authenticating with token [%s]".format(token)
        // Validate remember me token here
      }
    }
    override def beforeLogout(user: ApiUser) = {
      // Perform backend cleanup on logout
      app.cookies(COOKIE_KEY) foreach { _ => app.cookies.update(COOKIE_KEY, null) }
      log info "Removed cookie for user [%s]".format(user)
    }
  }
}
object UserPasswordStrategy {
  class UserPasswordStrategy(protected val app: ScalatraKernelProxy)
          extends ScentryStrategy[ApiUser]
          with Logging
  {
    private def email = app.params.get("email")
    private def password = app.params.get("password")
    private def remoteAddress ={
      val proxied = app.request.getHeader("X-FORWARDED-FOR")
      val res = if (proxied.nonBlank_?) proxied else app.request.getRemoteAddr
      log debug "The remote address is: %s".format(res)
      res
    }
    override def valid_? = {
      email.isDefined && password.isDefined
    }
    override def authenticate_! = {
      log debug "Authenticating in UserPasswordStrategy with: %s, %s, %s".format(email, password, remoteAddress)
      // perform authentication against database here
    }
  }
  trait UserPasswordMixin { self: ScalatraServlet =>
    before {
      log info "Executing before filter in user password filter"
    }
    get("/signup") {
      redirectIfAuthenticated_!
      // Show signup view
    }
    post( "/signup") {
      // Perform signup and redirect to login
    }
    get("/confirm/:token?") {
      redirectIfAuthenticated_!
      val token = params("token")
      if (token.blank_?) {
        flash.update("error", "The token is missing from the url.")
        redirect("/")
      } else {
        // perform confirmation logic here
        redirect("/")
      }
    }
    get("/login") {
      redirectIfAuthenticated_!
      // Show login view here
    }
    post("/login") {
      authenticate
      redirectIfAuthenticated_!
      flash.update("error", "There was a problem with your username and/or password.")
      redirect("/login")
    }
    get("/logout") {
      // logout logic here
      flash.update("success", "You have been logged out")
      redirectIfAuthenticated_!
      redirect("/")
    }
    get("/forgot") {
      redirectIfAuthenticated_!
      // show forgot password form
    }
    post("/forgot") {
      redirectIfAuthenticated_!
      // Create email and send
    }
    get("/reset/:token?") {
      def missingToken = {
        flash.update("error", "The token is missing from the url.")
        redirect("/")
      }
      redirectIfAuthenticated_!
      params.get("token") match {
        case None => missingToken
        case Some(token) => if (token.blank_?) {
          missingToken
        } else {
          // Verify the token
        }
      }
    }
    post("/reset") {
      redirectIfAuthenticated_!
      // Perform logic here to reset the password
    }
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment