Reputation: 157
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
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.
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
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