Django Test Client and Subdomains - python

I'm trying to figure out how to make the Django test client play nice with my app that puts each user on it's own subdomain. i.e. each account has account1.myapp.com, account2.myapp.com.
A user could be members of multiple subdomains (similar basecamp's model) so i handle which subdomain the request is being issued against in middleware.
As I'm writing my unit tests, I realized that all requests are issued to "http://testserver" which my middleware then redirects and the subsequent 302 is not followed as it's determined to be an external request.
Anyone aware of a way to enable this with the test client? I'm currently hacking a bit in django to enable it.

in your tests, when using the client, add the HTTP_HOST parameter:
response = c.post(reverse('my-url'), data={}, HTTP_HOST='account1.myapp.com')
on your middleware now you should see the host changed!

Related

Add Django endpoint that doesn't require database connection

I have a typical Django project that uses PostgreSQL as it's database backend. I need to set up a specific endpoint (/status/) that works even when the connection to the database is lost. The actual code is very simple (just returns the response directly without touching the DB) but when the DB is down I still get OperationalError when calling this endpoint. This is because I use some pieces of middleware that attempt to contact the database, e.g. session middleware and auth middleware. Is there any way to implement such /status/ endpoint? I could theoretically implement this as a piece of middleware and put it before any other middleware but that seems as kind of hack.
Up to my knowledge no.
If some Middlewares requires a database and you enabled them then they will be used for each request.
I did not read about a way of conditionally executing middlewares depending on the request's url.
So up to my knowledge a normal djangoview will not be able to handle such a status page.
The only solution, that I can imagine is your suggestion to implement a middleware, that is handled first, shortcuts all the other middlewares and returns the result.

Sharing authenticated users between Django and django-rest-framework in the same project

I have a Django project that will ultimately consist of three apps. Two of which will be "normal" Django apps, the third is a djangorestframework app. I also plan on creating a desktop client for the project at some point.
I want the rest app to be the only entity communicating with the database. Hence I use requests to communicate with the rest endpoints from the views of the "normal" Django apps and I will do the same for the desktop client. I want all apps to be accessible only for authenticated users, so I'm using Django's authentication backend.
My question is how to pass on the authenticated user/session from the pure Django apps to the rest endpoints when using requests in the views.
I managed to authenticate on the rest API using request's HTTPBasicAuth, but that requires me to have the user's password at hand in plain text. Sure, I could create a technical user to do these requests. But that would also mean that each and every request would need to go through authentication first and that doesn't feel like the best approach.
I have tried to extract the session cookie from the request object that is provided to the views and pass it on through requests.get, but did not manage to put it into the requests.get call the right way.
As of now, using requests and the established sessions looks like my best bet, especially since that will be the way the desktop client will do things, too. So I'm currently looking for the right way to provide requests.get with the session cookie, but I'm certainly open for better solutions.
You should use tokens.
Basically any kind of authentication out of your django project should be managed with secure tokens.
And yes, authentication check should happen everytime you send a request. To make it faster, you can store tokens in memory. (You can use redis or maybe even load your db on memory or ... ) but this is the right and common way to it. Even django does this check everytime using it's builtin functions.
DRF docs recommended some few packages to manage these tokens:
DRF: Third party packages
I used knox for many projects and it's pretty good.
Basically to authenticate your users over all of your projects or microservices, you have to take the token from user, set it as header or ... for your request to the main database or authentication project.
Most of the apps use token in headers which you can simply add to all of your requests calls:
Requests docs: Custom Headers

How can I randomize csrf token for django admin

I've just got vulnerability report that came from pentesters for my Django project. The report says my Django app is vulnerable to the BREACH ATTACK. SSL is active, cookies are flagged as secure, session cookies are set as secure. HTTP Compressions closed by the sysadmin it is controlled from the Nginx that I have no access. So gzip is closed. Now I want to randomize csrf token for per client-side request for the django admin, especially for the login page. Is there a way to do this in settings.py in a simple way or do I have to write custom admin view? What is the best practice for this issue?

Heroku router logging format

I've recently deployed a Flask app on Heroku. It provides an API on top of an existing API and requires a confidential API key for the original service from the user. The app is really just a few forms, the values of which are passed with ajax to a specific URL on the server. Nothing fancy. I take steps to not store confidential information in the app and want no traces of it anywhere within the app.
Looking at the logs from heroku logs --source heroku, the heroku router process stores all HTTP requests for the app, including those requests that include the confidential information.
Is there a way to specify the log format for the heroku process so as to not store the URL served?
As other commenters mentioned, it is a bad practice to put confidential info in a URL. These could get cached or logged by a number of systems (e.g. routers, proxy servers, caches) on the roundtrip to the server. There are a couple ways to solve this:
Put them in a the Authorization header. This is probably the most common way authentication is handled for REST-based APIs.
Put them in the POST body. This works to get it out of the URL, but is a little weird semantically to say that your are POSTing the credentials to some resource (if this a REST API), unless it is a login call.

POST request to Tastypie returns a non-SSL Location Header

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.

Categories

Resources