All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalatra.auth.strategy.BasicAuthStrategy.scala Maven / Gradle / Ivy

package org.scalatra
package auth
package strategy

import java.util.Locale
import javax.servlet.http.{ HttpServletRequest, HttpServletResponse }

import net.iharder.Base64
import org.scalatra.util.RicherString._

import scala.io.Codec

trait RemoteAddress { self: ScentryStrategy[_] =>

  import org.scalatra.auth.strategy.BasicAuthStrategy._

  protected def remoteAddress(implicit request: HttpServletRequest) = {
    val proxied = request.getHeader("X-FORWARDED-FOR")
    val res = if (proxied.nonBlank) proxied else request.getRemoteAddr
    res
  }
}

/**
 * Provides a hook for the basic auth strategy
 *
 * for more details on usage check:
 * https://gist.github.com/732347
 */
trait BasicAuthSupport[UserType <: AnyRef] { self: (ScalatraBase with ScentrySupport[UserType]) =>

  def realm: String

  protected def basicAuth()(implicit request: HttpServletRequest, response: HttpServletResponse) = {
    val baReq = new BasicAuthStrategy.BasicAuthRequest(request)
    if (!baReq.providesAuth) {
      response.setHeader("WWW-Authenticate", "Basic realm=\"%s\"" format realm)
      halt(401, "Unauthenticated")
    }
    if (!baReq.isBasicAuth) {
      halt(400, "Bad Request")
    }
    scentry.authenticate("Basic")
  }

}

object BasicAuthStrategy {

  private val AUTHORIZATION_KEYS = List("Authorization", "HTTP_AUTHORIZATION", "X-HTTP_AUTHORIZATION", "X_HTTP_AUTHORIZATION")
  class BasicAuthRequest(r: HttpServletRequest) {

    def parts = authorizationKey map { r.getHeader(_).split(" ", 2).toList } getOrElse Nil
    def scheme: Option[String] = parts.headOption.map(sch => sch.toLowerCase(Locale.ENGLISH))
    def params = parts.lastOption

    private def authorizationKey = AUTHORIZATION_KEYS.find(r.getHeader(_) != null)

    def isBasicAuth = (false /: scheme) { (_, sch) => sch == "basic" }
    def providesAuth = authorizationKey.isDefined

    private[this] var _credentials: Option[(String, String)] = None
    def credentials = {
      if (_credentials.isEmpty)
        _credentials = params map { p =>
          (null.asInstanceOf[(String, String)] /: new String(Base64.decode(p), Codec.UTF8.charSet).split(":", 2)) { (t, l) =>
            if (t == null) (l, null) else (t._1, l)
          }
        }
      _credentials
    }
    def username = credentials map { _._1 } getOrElse null
    def password = credentials map { _._2 } getOrElse null
  }
}
abstract class BasicAuthStrategy[UserType <: AnyRef](protected val app: ScalatraBase, realm: String)
    extends ScentryStrategy[UserType]
    with RemoteAddress {

  private[this] val REMOTE_USER = "REMOTE_USER"

  implicit def request2BasicAuthRequest(r: HttpServletRequest) = new BasicAuthStrategy.BasicAuthRequest(r)

  protected def challenge = "Basic realm=\"%s\"" format realm

  override def isValid(implicit request: HttpServletRequest) = request.isBasicAuth && request.providesAuth

  def authenticate()(implicit request: HttpServletRequest, response: HttpServletResponse) =
    validate(request.username, request.password)

  protected def getUserId(user: UserType)(implicit request: HttpServletRequest, response: HttpServletResponse): String
  protected def validate(userName: String, password: String)(implicit request: HttpServletRequest, response: HttpServletResponse): Option[UserType]

  override def afterSetUser(user: UserType)(implicit request: HttpServletRequest, response: HttpServletResponse) {
    response.setHeader(REMOTE_USER, getUserId(user))
  }

  override def unauthenticated()(implicit request: HttpServletRequest, response: HttpServletResponse) {
    app halt Unauthorized(headers = Map("WWW-Authenticate" -> challenge))
  }

  override def afterLogout(user: UserType)(implicit request: HttpServletRequest, response: HttpServletResponse) {
    response.setHeader(REMOTE_USER, "")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy