I have a Pyramid application which recently upgraded its login view to
do CSRF checking. I set 'require_csrf=True' in the view config. I
didn't set any of the configurator options for csrf so it defaults to
session storage, which is 'pyramid_redis_sessions'.

The application works fine but when I ran py.test to see if any tests
were out of date, all the functional tests broke with this error:

AppError: Bad Response: 400 Bad CSRF Origin (not 200 OK or 3xx
redirect for https://localhost:90/login)
400 Bad CSRF Origin
Access is denied. The server can not verify that the origin or
referrer of your request matches the current site. Either your browser
supplied the wrong Origin or Referrer or it did not supply one at all.
Referer checking failed - https://localhost:80/login does not match
any trusted origins.

My test fixture, common login function, and test look like this:

# Fixture
app = pyramid.paster.get_app(ini_file)
extra_environ = {"wsgi.url_scheme": "https"}
apptest = webtest.TestApp(app, extra_environ=extr_environ)
# Test
login(apptest, USERNAME)
# Login function
apptest.reset()   # Clear any existing cookies.
res = apptest.get("/login", status=200)
form = res.forms["login"]
form["username"] = USERNAME
form["password"] = PASSWORD
res = form.submit()
assert b"Invalid username or password." not in res

This seems to be a different error from a token mismatch or missing
token. There is a session with a key "_csrft_" so it seems to have a
token that should work. Looking at the source code for
"pyramid/csrf.py" in the "check_csrf_origin()" function, it talks
about an "Origin" header and trusted origins and a config setting to
add trusted origins. I added a setting:

pyramid.csrf_trusted_origins = localhost:80

and that made the test succeed. But is that the most robust approach?
And why do I have to do this?  There is no 'localhost' server or port
80 running -- it's a figment of WebTest's imagination. So it could
just as easily be "foo:999999". But whatever WebTest's default is,
shouldn't it be the same across tests and shouldn't that be enough for
the CSRF checker? What is the trusted origin it's expecting?

Perhaps it's a mismatch between the https scheme and port 80. I think
I set HTTPS because the cookies are HTTPS only and they wouldn't go
through otherwise. But how do you set the port in the WSGI
environment? And again, why should I have to?

Another option would be to disable CSRF checking during tests. That
would require defining a setting and passing it through multiple
layers to the view registration, and again is less than ideal because
I'd rather have CSRF checking work rather than be bypassed in tests.

So what's the best way forward?

-- 
Mike Orr <[email protected]>

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/CAH9f%3DuqL2TFMrYkAEU7fnyn%2BXJOaKs3DO%2BBsYRzNEVmskFTWBQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to