Using this
request.url_root+ attributes["footer"]["district_link"]
in jinja on a page that is https:// gives me a url that has http:// which is causing problems. Is there a way to use this request that preserves this so it will be http:// on a page that uses http and https on a page that uses https?
The backend is using flask if that is relevant here
Is your app proxied behind something like nginx?
If so you will need to use something like ProxyFix to add headers that include this information.
You can read more about proxy configuration in the flask docs on proxy setups.
Once you have ProxyFix working you can make use of the X-Forwarded-Proto header (for example). There's some more helpful info in this answer.
Related
I have a Flask application that is running behind an NGINX reverse proxy. In one of my functions I need to construct a URL to a different service and I wish to match the HTTP scheme to whatever the NGINX entry scheme is. So if NGINX is reverse proxying an https request, I'd like to generate a url like https://my_other_service. But if NGINX reverse proxies an http I'd like it to be http://my_other_service.
The flask.url_for function is able to automatically determine the proxy scheme when I use it for endpoints in the same app so I figure this must be possible, but in my case the url I'm generating is not an endpoint in the current Flask app.
How can I determine the proxy scheme inside a flask app?
As described on this question, you can directly tell url_for to use a specific scheme when generating a URL:
url_for('secure_thingy',
_external=True,
_scheme='https',
viewarg1=1, ...)
The problem, of course, is that you don't necessarily know whether the URL should be https or not. If it's running behind Nginx in production, it must be https. If it's running on localhost for local development, perhaps https wouldn't work.
One solution would be to just have a configuration setting for your app on what scheme to use. In your development environment, it would be set to http. In your production environment, you'd use https. That's what I would do.
An alternative is to tell Nginx to pass along a special header which you could then use to alter the scheme.
There are instructions on adding headers on the Nginx site, so here's an example:
location /some/path/ {
proxy_set_header X-Force-Https "yes";
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
Then in your Flask code, only pass _scheme='https' to url_for if request.headers.get('X-Force-Https', None) == 'yes'.
That's a more automatic solution, but will require you to modify your production web server environment.
I have a java server sending out a request where the path contains the hostname.
OTOH I've got an ancient django server (1.8) that figures (wrongly) that the hostname is part of the path, and always returns a 404.
Assuming that sending properly formed requests from java side is not possible, how would I go about modifying the request URL to something that can be properly redirected to, without actually redirecting? (a 30x is also unacceptable in this case).
I ended up doing a rewrite in nginx (using proxy_pass).
I couldn't solve this at the application level in any feasible way.
In the Google App Engine standard environment, if you use urllib to make HTTPS requests, you'll get an AppEnginePlatformWarning which says you're using urlfetch instead of sockets.
I found the warning annoying, so I disabled it.
# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
# squelch warning
requests.packages.urllib3.disable_warnings(
requests.packages.urllib3.contrib.appengine.AppEnginePlatformWarning
)
My question is - is there a good reason to switch to sockets? Specifically what is wrong with using urlfetch?
There's nothing wrong with using urlfetch, in fact it is the recommended method for issuing outbound HTTP(S) requests on GAE. From Issuing HTTP(S) Requests (emphasis on requests-related note mine):
App Engine uses the URL Fetch service to issue outbound HTTP(S)
requests.
For details about how the URL Fetch service is implemented and which
headers are sent in a URL Fetch request, see Outbound Requests.
Issuing an HTTP request
To issue an outbound HTTP request, use the urlfetch.fetch
method. For improved code portability, you can also use the Python
standard libraries urllib, urllib2, or httplib to issue HTTP
requests. When you use these libraries in App Engine, they perform
HTTP requests using App Engine's URL Fetch service. You can also use
the third-party requests library as long as you configure it to use
URLFetch.
The sockets support is rather the problematic one in GAE, it comes with a fairly long list of limitations and restrictions, see Sockets Python API Overview, in particular the Limitations and restrictions section.
The warning you see is not from GAE, it's from the 3rd-party requests library you use, which is why I highlighted the note in the above quote. IMHO it's safe to simply ignore/mask the warning in a GAE context.
I am developing a WSGI middleware application (Python 2.7) using Werkzeug. This app works within a SAML SSO environment and needs a SAML token to be accessed.
The middleware also performs requests to other applications in the same SAML environment, acting on behalf of the logged in user. In order to do that without the need of user feedback, I need to forward the SAML session cookie that I can get from the WSGI environment to requests that I am performing using the Requests library.
My issue is that the cookies that I get from WSGI/Werkzeug can only be parsed as http.cookies.SimpleCooke , while Requests accepts cookielib.CookieJar instances.
I have not found a way to cleanly forward these session cookies without resorting to shameful hacks such as parsing the raw content of the set-cookie headers.
Any suggestions?
Thanks,
gm
Cookies are just HTTP headers. Just use pull the cookie value from http.cookies.SimpleCookie, and add it to your requests session's cookie jar.
Not a hack. :)
I am doing a POST request to my Tastypie api, which creates a resource.
It normally returns the resource uri, through the Location header in the response.
The problem I'm having is the Location header contains a non-ssl url, even though my initial request (and the whole of my application) is under https.
From my request headers:
URL: https://example.com/api/v1/resource/
From my response headers:
Location: http://example.com/api/v1/resource/80/
Because this is a reusable application that is not always running under ssl, I do not want to hardcode an ugly string replace. Also, there is already a 301 redirect in place, from http to https, but I do not want the redirect to happen.
All help appreciated!
Update:
This actually didn't have anything to do with Tastypie, it was because of the servers/proxy configuration. See answer below for resolution details.
The reason is simple: seemingly request.is_secure() returns False in your case, so the URL is constructed using http instead of https.
There are couple of solutions, but you should first find what caused request.is_secure() to return False. I bet you are running behind some proxy or load balancer. If you did not change the logic behind URL generation, then this is probably the cause of your issue.
To fix that, you can take a look at SECURE_PROXY_SSL_HEADER setting in Django, which defines headers that indicate the SSL connection established with the proxy or load balancer:
If your Django app is behind a proxy, though, the proxy may be "swallowing" the fact that a request is HTTPS, using a non-HTTPS connection between the proxy and Django. In this case, is_secure() would always return False -- even for requests that were made via HTTPS by the end user.
In this situation, you'll want to configure your proxy to set a custom HTTP header that tells Django whether the request came in via HTTPS, and you'll want to set SECURE_PROXY_SSL_HEADER so that Django knows what header to look for.
But if you are designing a reusable app and the above is correct in your case, just make sure it is not something different. If you are sure this is the case, then leave that to the user - the headers responsible for secure request indication should be set explicitly, only by the programmer who uses your app. Otherwise this could mean a security issue.