|
Play Framework/Scala example source code file (csrf.scala)
The csrf.scala Play Framework example source code
/*
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package play.filters.csrf
import play.api.mvc._
import play.api._
import play.api.mvc.Results._
import play.api.libs.Crypto
import play.core.j.JavaHelpers
private[csrf] object CSRFConf {
def c = Play.maybeApplication.map(_.configuration).getOrElse(Configuration.empty)
def TokenName: String = c.getString("csrf.token.name").getOrElse("csrfToken")
def CookieName: Option[String] = c.getString("csrf.cookie.name")
def SecureCookie: Boolean = c.getBoolean("csrf.cookie.secure").getOrElse(Session.secure)
def PostBodyBuffer: Long = c.getBytes("csrf.body.bufferSize").getOrElse(102400L)
def SignTokens: Boolean = c.getBoolean("csrf.sign.tokens").getOrElse(true)
val UnsafeMethods = Set("POST")
val UnsafeContentTypes = Set("application/x-www-form-urlencoded", "text/plain", "multipart/form-data")
val HeaderName = "Csrf-Token"
val HeaderNoCheck = "nocheck"
def defaultCreateIfNotFound(request: RequestHeader) = {
// If the request isn't accepting HTML, then it won't be rendering a form, so there's no point in generating a
// CSRF token for it.
(request.method == "GET" || request.method == "HEAD") && (request.accepts("text/html") || request.accepts("application/xml+xhtml"))
}
/**
* This is used by the noarg constructor of CSRFFilter, so that Java developers can select an error handler.
*/
def defaultJavaErrorHandler: CSRF.ErrorHandler = {
c.getString("csrf.error.handler").map { className =>
val clazz = try {
Play.maybeApplication.get.classloader.loadClass(className)
} catch {
case c: ClassNotFoundException => throw new RuntimeException("Could not find CSRF error handler " + className, c)
}
if (classOf[CSRFErrorHandler].isAssignableFrom(clazz)) {
import play.mvc.Http.{ Context => JContext }
val errorHandler = clazz.newInstance().asInstanceOf[CSRFErrorHandler]
new CSRF.ErrorHandler {
def handle(req: RequestHeader, msg: String) = {
val ctx = JavaHelpers.createJavaContext(req)
JContext.current.set(ctx)
try {
errorHandler.handle(msg).toScala
} finally {
JContext.current.remove()
}
}
}
} else if (classOf[CSRF.ErrorHandler].isAssignableFrom(clazz)) {
clazz.newInstance().asInstanceOf[CSRF.ErrorHandler]
} else {
throw new RuntimeException(s"Error handler must implement ${classOf[CSRFErrorHandler]} or ${classOf[CSRF.ErrorHandler]}")
}
}.getOrElse(CSRF.DefaultErrorHandler)
}
def defaultErrorHandler = CSRF.DefaultErrorHandler
def defaultTokenProvider = {
if (SignTokens) {
CSRF.SignedTokenProvider
} else {
CSRF.UnsignedTokenProvider
}
}
}
object CSRF {
private[csrf] val filterLogger = play.api.Logger("play.filters")
/**
* A CSRF token
*/
case class Token(value: String)
object Token {
val RequestTag = "CSRF_TOKEN"
implicit def getToken(implicit request: RequestHeader): Token = {
CSRF.getToken(request).getOrElse(sys.error("Missing CSRF Token"))
}
}
// Allows the template helper to access it
def TokenName = CSRFConf.TokenName
import CSRFConf._
/**
* Extract token from current request
*/
def getToken(request: RequestHeader): Option[Token] = {
// First check the tags, this is where tokens are added if it's added to the current request
val token = request.tags.get(Token.RequestTag)
// Check cookie if cookie name is defined
.orElse(CookieName.flatMap(n => request.cookies.get(n).map(_.value)))
// Check session
.orElse(request.session.get(TokenName))
if (SignTokens) {
// Extract the signed token, and then resign it. This makes the token random per request, preventing the BREACH
// vulnerability
token.flatMap(Crypto.extractSignedToken)
.map(token => Token(Crypto.signToken(token)))
} else {
token.map(Token.apply)
}
}
/**
* A token provider, for generating and comparing tokens.
*
* This abstraction allows the use of randomised tokens.
*/
trait TokenProvider {
/** Generate a token */
def generateToken: String
/** Compare two tokens */
def compareTokens(tokenA: String, tokenB: String): Boolean
}
object SignedTokenProvider extends TokenProvider {
def generateToken = Crypto.generateSignedToken
def compareTokens(tokenA: String, tokenB: String) = Crypto.compareSignedTokens(tokenA, tokenB)
}
object UnsignedTokenProvider extends TokenProvider {
def generateToken = Crypto.generateToken
def compareTokens(tokenA: String, tokenB: String) = Crypto.constantTimeEquals(tokenA, tokenB)
}
/**
* This trait handles the CSRF error.
*/
trait ErrorHandler {
/** Handle a result */
def handle(req: RequestHeader, msg: String): Result
}
object DefaultErrorHandler extends ErrorHandler {
def handle(req: RequestHeader, msg: String) = Forbidden(msg)
}
}
/**
* Default global, use this if CSRF is your only Filter
*/
object Global extends WithFilters(new CSRFFilter()) with GlobalSettings
Other Play Framework source code examplesHere is a short list of links related to this Play Framework csrf.scala source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.