Daniel
Daniel

Reputation: 157

How can I disable the CSRF filter on Play 2.6?

I've been trying to use Postman with my Play Framework API, but I keep running into problems related to the CSRF Filter.

I've browsed a few forums (including SO) looking for a fix to this, and the proverbial advice seems to be adding:

play.filters.disabled+=play.filters.csrf.CSRFFilter

to the application.conf file.

I've tried performing that fix, but even when I do so, I continue to get this error in the console logs:

[warn] p.filters.CSRF - [CSRF] Check failed because no token found in headers for /auth/logout

Where /auth/logout is a POST request with the Authorization cookie set as a JWT.

I've tried a number of alternative fixes, such as setting play.filters.disabled to [] or null, allowing all hosts through the CORS filter, various combinations of all 3, etc, but ultimately the same error appears in my logs.

The only thing that's made a change to the application at all is setting the CSRF token as a cookie instead of in the session, which changes the error to:

[warn] p.filters.CSRF - [CSRF] Check failed because none/none for /auth/logout

This gives me the comfort of knowing at least that the application.conf is being loaded correctly, but it still doesn't fix the problem.

Is there a correct way to disable the CSRF filter that I'm not doing properly? Is there another way to allow Postman to work through the CSRF filter?

Upvotes: 3

Views: 1922

Answers (2)

Daniel
Daniel

Reputation: 157

Ok, I figured out the issue, but it was a bit tricky to dig up the source of the issue.

When I had added macwire to the project for dependency injection, I had to define a custom application loader, which needed a custom AppComponents class. My declaration for the AppComponents class looked something like this:

class AppComponents(context: Context) extends BuiltInComponentsFromContext(context) with MyModule with AssetsComponents with I18nComponents with play.filters.HttpFiltersComponents

As is now apparent, play.filters.HttpFiltersComponents has the following field:

def httpFilters: Seq[EssentialFilter] = Seq(csrfFilter, securityHeadersFilter, allowedHostsFilter)

Where csrfFilter, securityHeadersFilter, and allowedHostsFilter are effectively hard-coded values. I guess when using a custom ApplicationLoader, it ignores the http filters set in the application.conf file (which seems obvious as I write this).

A current workaround/fix that I'm using is to set val httpFilters: Seq[EssentialFilter] = Seq(securityHeadersFilter, allowedHostsFilter), instead of the default HttpFiltersComponents field. I'll probably modify this a bit to read the filters in from the configuration file, but for now this gets around the problem.

TL;DR: Added a custom ApplicationLoader when integrating MacWire, didn't realize this would shadow the fields in the config file.

EDIT

The final code in my ApplicationLoader for configuring the HTTP filters with macwire looks as follows, in case anyone else needs it. It uses almost the exact same code as HttpFiltersComponents, but with macwire instead of Guice (undefined variables are inherited from BuiltInComponentsFromContext):

override lazy val httpFilters: Seq[EssentialFilter] = {
    val wiredInstance: Wired = wiredInModule(this)
    val classes: Seq[Class[EssentialFilter]] = {
        val disabledFilters = config.get[Seq[String]]("play.filters.disabled")
        val enabledFilters = config.get[Seq[String]]("play.filters.enabled").filterNot(disabledFilters.contains)
        try {
            for (filterClassName <- enabledFilters) yield {
                try {
                    environment.classLoader.loadClass(filterClassName).asInstanceOf[Class[EssentialFilter]]
                } catch {
                    case e: ClassNotFoundException =>
                      throw configuration.reportError("play.filters.enabled", s"Cannot load class $filterClassName", Some(e))
                }
            }
        } catch {
            case e: ConfigException.Null =>
                Nil
            case e: ConfigException.Missing =>
                Nil
        }
    }
    classes.map(x => wiredInstance.wireClassInstance(x))
}

Upvotes: 4

mkUltra
mkUltra

Reputation: 3068

Try add in your application.conf this code:

play.filters.hosts {
  allowed = ["."]
}

let me know in it's works for you. Check also official play documentation.

Upvotes: 0

Related Questions