casualjim
12/28/2012 - 5:40 PM

Session token strategy example for scalatra auth (scentry)

Session token strategy example for scalatra auth (scentry)

package org.example
package auth

import org.scalatra.auth.ScentryStrategy
import org.scalatra.{CookieSupport, ScalatraBase}

trait RedisClient {
  def get(key: String): Option[String]
}


object User {
  def apply(userString: String) = // create user from string stored in redis
}
case class User(id: Int, login: String, password: String, token: String = UUID.create.toString)

object UsersDao {

  private[this] val client: RedisClient = // create redis client here
  def fromToken(token: String): Option[User] = client.get("users:*:token", token) map User

  def fromLoginPassword(login: String, password: String) = client.get("users:*:login", login) map User filter (_.password == password)
  
}

object SessionTokenStrategy {
  val HeaderKey = "X-API-KEY"
  val ParamsKey = "api_key"
  val CookieKey = "scalatra.auth"
}
class SessionTokenStrategy(protected val app: ScalatraBase with CookieSupport) extends ScentryStrategy[User] {
  import SessionTokenStrategy._

  override def isValid: Boolean =
    ((app.request.header(HeaderKey) orElse app.params.get(ParamsKey) orElse app.cookies.get(CookieKey)) flatMap (_.blankOption)).isDefined

  def authenticate(): Option[User] = {
    val token = (app.request.header(HeaderKey) orElse app.params.get(ParamsKey) orElse app.cookies.get(CookieKey)) flatMap (_.blankOption)
    token flatMap { UsersDao.fromToken(token) }
  }
}

class PasswordStrategy(protected val app: ScalatraBase) extends ScentryStrategy[User] {
  override def isValid = app.params.get("login").isDefined && app.params.get("password").isDefined
  def authenticate(): Option[User] = UsersDao.fromLoginPassword(app.params("login"), app.params("password"))
}

trait MyAuthentication extends ScentrySupport[User] {
  protected def fromSession = { case id: String ⇒ UsersDao.fromToken }
  protected def toSession = { case usr: User ⇒ usr.token }

  /**
   * Registers authentication strategies.
   */
  override protected def configureScentry {
    val authCookieOptions = CookieOptions(httpOnly = true)
    scentry.store = new CookieAuthStore(self)(authCookieOptions) {
      override def set(value: String) {
        super.set(value)
        response.headers("X-SCALATRA-AUTH") = value
      }

      override def get: String = {
        val cookie = super.get
        if (cookie == null || cookie.trim.isEmpty) request.header("X-SCALATRA-AUTH").orNull
        else cookie
      }

      override def invalidate() {
        cookies.update(Scentry.scentryAuthKey, "")(authCookieOptions.copy(maxAge = 0))
        response.headers("X-SCALATRA-AUTH") = null
      }
    }
    scentry.unauthenticated { unauthenticated() }
  }
  override protected def registerAuthStrategies = {
    scentry.register("user_password", _ ⇒ new PasswordStrategy(self))
    scentry.register("session_token", _ ⇒ new SessionTokenStrategy(self))
  }

}