Restrict permissions after token-based authentication - django

A site I am working on (using django) requires that users can access a subset of the functionality temporarily by following a URL sent by email, instead of having to login properly (i.e. with username and password).
I am, of course, aware of the potential security issues with this proposal. Therefore, the tokens included in the url are randomly generated and stored on the server (instead of hashing the username or something similar), and expire.
In addition, I would like to restrict the permissions of users accessing the site through such a token URL, so that they can only access some (very limited) information, while their credentials are required for any more substantial actions.
I had implemented this in a rather crude way: Briefly, instead of authenticating the user through the token, it is stored as a session variable, and the few views that recognize the token validate it. However, it would be great to have an extended solution: For example, a global user.has_token check would be brilliant. I can't imagine, however, how a more elegant solution might be achieved.
So my question is: How would you implement such a system? Is it, for example, possible to temporarily allocate or restrict permissions in django? Might a custom middleware be necessary here?
Any help would be much appreciated. Thanks a lot!
Edit: Following the discussion below, I would like to further specify the question: Would it be efficient to assign groups through a middleware on every page view? Would it be feasible to add properties to the user object at run-time (similar to the user.has_token example above)?

usings django groups you can restict access
below link gives you the example:
http://bradmontgomery.blogspot.com/2009/04/restricting-access-by-group-in-django.html

Related

How does token based authentication work?

I implement a web application (with Python+Django - to the extent that matters). Users can log in normally with username and password, but in addition I want to provide an API which users use to script the interaction with my site.
For the API authentication my plan was to do something like this:
In the database I create table with 'tokens' - i.e. random strings which point to the user database.
The user gets a token string.
For every API call the user passes the token string along with their request
In the API implementation the code:
Verify the token.
Log the correct user in and execute the API function as the user matching the token.
Log the user out again.
Return the result
Does this make sense? On the one hand it seems very simple - on the other hand it feels quite homemade, something I have heard is not recommended when it comes to security related topics?
I would wholeheartedly recommend looking at django-rest-framework
https://www.django-rest-framework.org/
It literally does all of that and more!
Nope, not a sales person, just a developer :)
It handles quite literally any use case you can think of, and I would be happy to discuss at great length any its not suitable for.
It handles:
Authentication
Parsing
Encoding
View or object level permissions
Object serialisation
Object creation
Object deletion
Automatically generated documentation
Several authentication methods, including custom managed methods
And a bunch of other stuff that makes writing API's in Django much easier
All in all it supports most if not all use cases.
EDIT
It is worth noting that there is a very good reason DRF has short lived access tokens. That is because of security.
Let's say a malicious actor gets hold of your short lived access token, thats a lot better than a "long life" one as you described.
It's worth weighing up security and ease of access, security and protecting your users should always paramount.
Futhermore, I would recommend taking a look at DRF Knox, which is recommended in the authentication section of the DRF docs:
https://github.com/James1345/django-rest-knox

Tracking unauthenticated users in Django

I need to track unregistered users in my Django website. This is for conversion optimization purposes (e.g. registration funnel, etc).
A method I've used so far is using IP address as a proxy for user_id. For various well-known reasons, this has led to fudged/unreliable results.
Can I sufficiently solve my problem via setting a session variable at server-side? An illustrative example would be great.
For example, currently I have a couple of ways in my head. One is doing request.session["temp_id"] = random.randint(1,1000000), and then tracking based on temp_id.
Another is setting a session variable every time an unauthorized user hits my web app's landing page, like so:
if not request.session.exists(request.session.session_key):
request.session.create()
From here on, I'll simply track them via request.session.session_key. Would this be a sound strategy? What major edge-cases (if any) do I need to be aware of?
Cookies are the simplest approach, but take into consideration that some users can have cookies turned off in their browsers.
So for those users you can use javascript local storage to set some data. This information will get deleted once you close the browser, but it's ok for funneling purposes. Still others can have javascript turned off.
Another approach would be to put custom data(key) in every link of the page when generating the template. in other words you would have the session_id stored in html page and send through url parameters at click. Something similar happens with csrf token. Look into that.

Django set django session cookies programmatically

I am creating a saas, software as a service site with django.
Due to the project requirements the users are inside schemas/tenants, for that im using the fantastic django-tenant-schemas app, one user can have accounts inside different schemas (they share username and password) ... i want to let the user move throught the different schemas they are in more or less freely ... for that i have created a view where the user can select on what schema he wants to be on.
When i use an application wide cookie session that is when i have the cookie setting as ".domain.ext" (django documentation) that works fine but its NOT the behaviour we really want for our application.
What we really need is to be able to have different versions of the app on different browser tabs.
So we have to set the cookie configuration to "domain.ext", then everything breaks because the original view is on one tenant and the next view (where the just logged user really belongs) is inside other tenant then the old cookie is deleted.
So the question is how can i programmatically set the cookie correctly on the new view so the user that really belongs to that tenat is still authenticated.
Or is there any alternative approach we could use for that? Any examples?
EDIT TO CLARIFY as demanded:
Person A belongs to 2 schemas SH1 and SH2 on both of them he has the same username and password.
On every password change the password hash is replicated on all the schemas they belong to so they dont have to remember specific passwords or usernames.
When the person is logged on SH1 the url will be sh1.domain.com when he is logged on SH2 the url will be sh2.domain.com
So lets say the person is now logged on schema SH1, he decides to switch to schema SH2, to be able to do that i need the user to still been authenticated so that view has to be on the SH1 schema, but then its redirected to the new schema force authenticating the user but since the cookie is set as domain specific (default django behaviour) when the user lands on the next url sh1.domain.com/whatever the previous cookie is deleted and thus he has to log in again to be able to access.
If I'm understanding correctly, you want the ability to have the behavior of a cross-domain cookie, but without actually using a cross-domain cookie.
The immediate answer that comes to mind is "well, use a cross-domain cookie". This is pretty much the vanilla example of a situation where you'd want to use use a cross-domain cookie. Engineering a complex solution so that you can avoid using the simple solution never ends well :-) Unless there's some other constraint in play that you haven't revealed, I'd start by questioning whether you shouldn't just be doing this the easy way.
However, assuming there is a good reason (and, frankly, I'd be interested to know what that is), the problem you're going to face is that browser security is essentially trying to stop you doing exactly what you're proposing. You want to know, from domain SH2, whether something has happened to a cookie set on domain SH1. That's exactly the situation that cookie security policies are designed to prevent.
The only way you're going to be able to work around this is to have a third party that can share knowledge. When user A logs into SH1, you do password authentication as normal - but you also post a flag somewhere that says "User A is now on SH1". When A logs into SH2, you post the corresponding flag. If A goes back to SH1, you check against the central source of truth, discover that they're currently on SH2, and force a login.
You probably could do this by manipulating cookies and session keys, but I suspect an easier way would be to use an Authentication backend. What you'll be writing is an authentication backend that is very similar to Django's own backend - except that it will be making checks of cross-domain login status against the central source of truth.
How you implement that "source of truth" is up to you - an in memory cache, database table, or any other source of data will do. The key idea is that you're not trying to rewrite cookies so that the same cookie works on every site - you're keeping each site's cookies independent, but using Django's authentication infrastructure to keep the cookies synchronised as a user moves between domains.

Going about Implementing Authentication/Authorization using CouchDb as backend in Django

I need to store both authentication and authorization information in couchdb. I've used a similar method to this for implementing authentication. However, what do I need to implement authorization for users. I need that certain actions be called only by specific users. Will using the user_passes_test decorator be a good idea for this?
I am also looking to move the session store to a separate couchdb instance. Will this be a good idea? Can anyone give me pointers/examples on how to go about this.
I am new to both Python and Django.
To answer the first part of your question, all you need to implement is the "authenticate" method of your custom authentication backend. The Django docs have some decent examples of how you could implement an authentication backend.
In regard to your permissions question, it depends on the exact details of what types of permission checks you need. If your permissions model fits well with Django's existing permissions system, you can make make authorizations decisions based on data in couchdb by implementing the optional permission bits in your custom authentication backend. Again, the Django docs have details on how exactly to do this.
As far as the session store, I don't know enough about CouchDB's performance characteristics to say if you need to store session data in a separate instance or not. What I can tell you however is either way, the way you use a CouchDB instance as your session store is to use a custom session engine. With a quick look around, it looks like django-couchdb-utils can provide you with a session engine that you could drop in without too much work (might also have some other useful bits for you).

How should I manage username/password session information?

I have a website (the basic gist of which is described in this question), and I want to have some way to store the username and some information about the user consistently while they use the site (ie, upload and download data).
Right now, given a successful login, I was returning the hash of the password as well as any associated information. Anytime a user tries something, their username, hash, and so forth must match what's in the database. If the user logs out, their local Sinatra session has all information flushed.
I realize that this is a very naive approach. Is there a better way to handle user session information? The wikipedia entry on cookies mentions that a session uid is used instead of this other information; what is the advantage of that approach? I suspect that this approach is also vulnerable to other attacks, but since I verify everything that's done as it's done, I'm not sure what attacks I'm leaving myself open to.
Also, if/when I implement ssl, will these transactions be 'automagically' encrypted, or will I need to do something else to make sure that the strings are protected, if they need to be?
This is actually a very complicated issue. Just to illustrate, you have the problem of account lock-out: If you lock out based on failed attempts, how easy is it for an attacker to DOS your website?
I'll list a few best-practices to get you started:
Store Passwords Salted and Hashed alongside the Username and UserId. (You should also store the salt next to the hash.)
Disallow frequent bad-password attempts. (More frequent than once every few seconds).
If attempts are failing for any given user or any given IP address (more than 3 times a minute) require some form of human-validation, like a CAPTCHA. This allows you to prevent total DOS attacks.
If implementing an auto-login system, use a token authentication system.
For token authentication systems, use a Secure random number generator, send the plain token to the users, but Salt and Hash the token at the database.
Use TLS/SSL if possible, but don't rely on their security once the data is off-the-wire.
If your website is built in asp.net then you can use dot net securities.. which is really very good. and you can also use principle classes in it to make it more secure..