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))
}
}