casualjim
10/3/2011 - 11:35 PM

auth_support.scala

package backchat
package web
package auth

import org.scalatra.auth.ScentryStrategy
import org.scalatra.ScalatraKernel
import model.User

class BackchatHeaderAuth(protected val app: ScalatraKernel, name: String) extends ScentryStrategy[User] {

  override def isValid = true

  def authenticateKey(key: String): Option[User]  = User.authenticateWithApiKey(key).toOption

  /**
   * Authenticates a user by validating the key read from the authorization header.
   */
  def authenticate() = {
    BackchatHeaderAuth(app, name) flatMap (authenticateKey _)
  }

  /**
   * Called when authentication failed. Sets a challenge header on the response.
   */
  override def unauthenticated() {
    val challenge = """%s realm="%s API""" format (name, name)
    app.response.setHeader("WWW-Authenticate", challenge)
    app.halt(401, "Unauthorized")
  }
}

object BackchatHeaderAuth {


  class OptionableString(s: String) {
    def toOption = if(s == null || s.trim.isEmpty) None else Some(s)
  }
  
  private implicit def string2optionable(s: String) = new OptionableString(s)

  def apply(app: ScalatraKernel, name: String) =
    (app.request.getHeader("Authorization").toOption
      map (_.trim)
      filter (_.toUpperCase(ENGLISH).startsWith(name.toUpperCase(ENGLISH) + " "))
      map (_.substring(name.length + 1)))

}
package backchat
package web
package auth

import model.User
import org.scalatra.auth.{ ScentryConfig, ScentrySupport }
import org.scalatra.ScalatraKernel
import org.scalatra.auth.strategy.BasicAuthSupport

/**
 * Base trait for apps that need authentication support.
 *
 * @see [[backchat.model.User]]
 */
trait AuthenticationSupport extends ScentrySupport[User] with BasicAuthSupport[User] { self: ScalatraKernel ⇒

  val realm = Config.serviceName
  protected def contextPath = request.getContextPath

  protected def fromSession = { case id: String ⇒ User.find(id) openOr null }
  protected def toSession = { case usr: User ⇒ usr.id.toString }

  protected val scentryConfig = (new ScentryConfig {}).asInstanceOf[ScentryConfiguration]

  override protected def configureScentry {
    scentry.unauthenticated {
      scentry.strategies.get('BackchatHeader) foreach { _.unauthenticated() }
    }
  }

  /**
   * Registers authentication strategies.
   */
  override protected def registerAuthStrategies = {
    scentry.registerStrategy('BackchatHeader, app ⇒ new BackchatHeaderAuth(app))
  }

}