Correction. 15. So I changed my code thus:
``extra_environ = {"HTTP_HOST": "localhost:443", "wsgi.url_scheme": "https"} apptest.webtest.TestApp(app, extra_environ=extra_environ)'' On Wed, Oct 11, 2017 at 3:51 PM, Mike Orr <sluggos...@gmail.com> wrote: > On Tue, Sep 26, 2017 at 8:14 AM, Michael Merickel <mmeri...@gmail.com> wrote: >>> What is the Origin header and shouldn't Pyramid/WebOb set it automatically >>> if it's becoming more important? >> >> 1) You can read the RFC about it or anything on google. >> 2) The Origin header is set by the client, not the server. >> >> If the origin matches the current domain (usually set by the host header) >> then the request is trusted by default and you do not need to modify >> anything. You have your app setup in such a way that your requests *look* >> like they are originating from another server instead of the domain hosting >> the content. Just configure your webtest requests such that the origin and >> host match and you'll be fine. >> >>> I still feel like there's a missing piece, something that needs to be >>> documented so that others don't fall into this same trap. >> >> If you would like to contribute some documentation on this once you figure >> it out I'm more than happy to review. It probably belongs in the testing >> chapter about how to use webtest. If you think webtest should set the >> origin/host the same by default then perhaps you could open an issue over >> there. > > OK, I've got something that works; I'll make a cookbook page for > testing with HTTPS-only cookies. I'll try to explain it precisely now > although it's a long journey through webtest.app, webob.request, > pyramid.csrf, and session cookies. To recap the situation: > > 1. The login form is CSRF-protected. (IT requirement.) > > 2. The app uses SessionAuthenticationPolicy and > pyramid_redis_sessions. Cookies are HTTPS-only (IT requirement.), so > setting 'redis.sessions.cookie_secure = true'. This tells the client > to send the cookie only with HTTPS requests (not HTTP). > > 3. All this is working fine in production. > > 4. The functional test logs in via a form. It uses WebTest. There is > no web server, just WebTest calling the WSGI app. > > 5. The test ran fine before implementing HTTPS cookies and CSRF protection. > > 6. HTTPS cookies broke the test, because WebTest emulates an HTTP > environment by default, so it won't transmit the cookie that indicates > the session containing the authenticated status. The login submit > fails. > > 7.I made the request "HTTPS" with an environ var: > > ``extra_environ = {"wsgi.url_scheme": "https"}``. > ``apptest = webtest.testApp(app, extra_environ=extra_environ}``. > That fixed #6. > > 8. I implemented CSRF checking, and now the login failed because the > "origin" (the client's domain) was different was different from what > the "server" expected. > > 9. Troubleshooting and this list revealed two workarounds: turn off > HTTPS-only cookies and revert to HTTP, or set the de facto host as a > trusted host. (Setting 'pyramid.csrf_trusted_origins = localhost:80'.) > > 10. However, I didn't want to make my test configuration so different > from the real one and lose some aspect of testing. Instead I wanted to > understand the underlying problem and fix it. > > 11. The problem is that in the form submission request, the referer > domain was different from the current domain. I don't have access to > the request; it's internal to WebTest. I put print statements in > 'pyramid.csrf' to determine what the request attributes were and what > the mismatch was. The actual domain was 'localhost' while the referer > had 'localhost:80'. It wasn't clear what code was calculating the > referer value or what it based it on. It didn't make sense because > didn't it know that 'localhost' is the same as 'localhost:80'? > > 12. Enlightenment came when I realized the referer was > "https://localhost:80", which is nonsense. The default HTTPS port is > 443, not 80. > > 13. I tried setting extra_environ "HTTP_PORT" : "443" but that didn't > work: the referer still had "https://localhost:80". > > 14. I tracked down the code to the > 'webob.request.BaseRequest.host_url' property. It looks first in > envvar 'HTTP_HOST' and falls back to 'SERVER_NAME' and 'SERVER_PORT'. > > 15. So I changed my code thus: > > ``extra_environ = {"HTTP_HOST": "443", "wsgi.url_scheme": "https"} > apptest.webtest.TestApp(app, extra_environ=extra_environ)'' > > Presto, it works! > > I'm not sure if 'webtest' should be smarter, or if so exactly how. But > at least this solves this underlying problem. > > Is there anything else I should do to more completely mimic an HTTPS request? > > > >> - Michael >> >> >> On Tue, Sep 26, 2017 at 12:52 AM, Mike Orr <sluggos...@gmail.com> wrote: >>> >>> On Mon, Sep 25, 2017 at 10:40 PM, Mike Orr <sluggos...@gmail.com> wrote: >>> > On Mon, Sep 25, 2017 at 9:00 PM, Mike Orr <sluggos...@gmail.com> wrote: >>> >> On Mon, Sep 25, 2017 at 5:47 PM, Michael Merickel <mmeri...@gmail.com> >>> >> wrote: >>> >>>> So what's the best way forward? >>> >>> >>> >>> I think you covered your options pretty well. >>> >>> >>> >>> 1) Set wsgi.url_scheme to "http" as origin checks are only done on >>> >>> https. >>> >>> 2) Set the pyramid.csrf_trusted_origins as you are doing now. >>> >>> 3) Disable csrf checking for your tests. >>> >>> >>> >>> I think it's just a helpful reminder that you would be wise to think >>> >>> about >>> >>> the origin header more these days as it's required by CORS requests >>> >>> and, of >>> >>> course, cross origin requests are the attack vector CSRF is helping to >>> >>> protect. >>> >> >>> >> It sounds like it needs documentation then. What is the Origin header >>> >> and shouldn't Pyramid/WebOb set it automatically if it's becoming more >>> >> important? >>> >> >>> >> #1 and #3 would make the test environment different from the real >>> >> environment. #2 raises the question of what is WebTest's Origin >>> >> header, what should it be, why are they different, and does something >>> >> need to be changed in the library? >>> > >>> > I guess the solution is #1, to roll back the HTTPS, because there is >>> > no HTTPS because there's no network server. That in turn will require >>> > a configuration that doesn't make the cookies HTTPS-only. >>> >>> (The browser got in a mood and did "Send" too quickly.) >>> >>> I still feel like there's a missing piece, something that needs to be >>> documented so that others don't fall into this same trap. The only >>> reason I set HTTPS-only and CSRF is our IT department asked us to do >>> this wherever feasible, and since it didn't make much difference >>> either way I went along with it. So presumably other people in other >>> organizations will be doing the same thing, and have the same thing >>> happen in their tests. >>> >>> >>> -- >>> Mike Orr <sluggos...@gmail.com> >>> >>> -- >>> 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 pylons-discuss+unsubscr...@googlegroups.com. >>> To post to this group, send email to pylons-discuss@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/pylons-discuss/CAH9f%3Duo%2BAYpm6-oS-vPLFg0Ek3gz1G2JDHcW2m0MmdH_X8zp4g%40mail.gmail.com. >>> For more options, visit https://groups.google.com/d/optout. >> >> >> -- >> 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 pylons-discuss+unsubscr...@googlegroups.com. >> To post to this group, send email to pylons-discuss@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/pylons-discuss/CAKdhhwFWJkrGFxOTkAyMDB61JkCm0%3D%3DwWONQ5V9U60D%3DAqV%3DXQ%40mail.gmail.com. >> >> For more options, visit https://groups.google.com/d/optout. > > > > -- > Mike Orr <sluggos...@gmail.com> -- Mike Orr <sluggos...@gmail.com> -- 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 pylons-discuss+unsubscr...@googlegroups.com. To post to this group, send email to pylons-discuss@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/pylons-discuss/CAH9f%3Duq_g7H%2BW1U%3DFp75%2B1NNHjCzPxKhgomEpAFsf1_utcw-sg%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.