Skip to content

Instantly share code, notes, and snippets.

@mawaldne
Last active January 22, 2020 19:37
Show Gist options
  • Save mawaldne/065ab8566e1de6db33cc947d166e4680 to your computer and use it in GitHub Desktop.
Save mawaldne/065ab8566e1de6db33cc947d166e4680 to your computer and use it in GitHub Desktop.
Token Authentication example for Scalatra
package yourpackage
import org.scalatra.auth.strategy.BasicAuthSupport
import org.scalatra.auth.{ScentryConfig, ScentryStrategy, ScentrySupport}
import org.scalatra.{ScalatraBase, Unauthorized}
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
import java.util.Locale
class TokenAuthRequest(r: HttpServletRequest) {
private val AUTHORIZATION_KEYS = List("Authorization", "HTTP_AUTHORIZATION", "X-HTTP_AUTHORIZATION", "X_HTTP_AUTHORIZATION")
def parts = authorizationKey map {
r.getHeader(_).split(" ", 2).toList
} getOrElse Nil
def scheme: Option[String] = parts.headOption.map(sch => sch.toLowerCase(Locale.ENGLISH))
def token: String = parts.lastOption getOrElse ""
private def authorizationKey = AUTHORIZATION_KEYS.find(r.getHeader(_) != null)
def isTokenAuth = (false /: scheme) { (_, sch) => sch == "token" }
def providesAuth = authorizationKey.isDefined
}
trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] {
self: ScalatraBase =>
val realm = "Token Authentication"
protected def fromSession: PartialFunction[String, User] = {
case id: String => User(id)
}
protected def toSession: PartialFunction[User, String] = {
case usr: User => usr.id
}
protected val scentryConfig: ScentryConfiguration = new ScentryConfig {}.asInstanceOf[ScentryConfiguration]
override protected def configureScentry(): Unit = {
scentry.unauthenticated {
scentry.strategies("Token").unauthenticated()
}
}
override protected def registerAuthStrategies(): Unit = {
scentry.register("Token", app => new TokenAuthStrategy(app, realm))
}
// verifies if the request is a token request
protected def auth()(implicit request: HttpServletRequest, response: HttpServletResponse) = {
val tokenReq = new TokenAuthRequest(request)
if (!tokenReq.providesAuth) halt(401, "Unauthenticated")
if (!tokenReq.isTokenAuth) halt(400, "Bad Request")
scentry.authenticate("Token")
}
}
class TokenAuthStrategy(protected override val app: ScalatraBase, realm: String) extends ScentryStrategy[User] {
implicit def request2TokenAuthRequest(r: HttpServletRequest) = new TokenAuthRequest(r)
protected def validate(userName: String, password: String): Option[User] = if (userName == "scalatra" && password == "scalatra") Some(User("scalatra"))
else None
protected def getUserId(user: User): String = user.id
override def isValid(implicit request: HttpServletRequest) = request.isTokenAuth && request.providesAuth
// catches the case that we got none user
override def unauthenticated()(implicit request: HttpServletRequest, response: HttpServletResponse) {
app halt Unauthorized()
}
// overwrite required authentication request
def authenticate()(implicit request: HttpServletRequest, response: HttpServletResponse): Option[User] = validate(request.token)
protected def validate(token: String): Option[User] = {
// validate the token here and return
if (token == "FOOTOKEN") Some(User("scalatra"))
else None
}
}
case class User(id: String)
@mawaldne
Copy link
Author

Heres a route I have setup:

class SomeController extends ScalatraFilter with AuthenticationSupport with LazyLogging {
  get("/status") {
    auth.get
    Ok(s"works")
  }
}

Then you can curl your route with:

curl -v -H 'Authorization: Token FOOTOKEN' http://localhost:9000/status

Obviously change the token to be whatever you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment