I implemented a custom OAuth adapter using Django-allauth, in order to start from an existing codebase (this is a Django 1.9 project). The idea is that my django users are authenticated through the Authorization Code flow. The Oauth flow is working fine, and I can log in properly into my django app.
I have a weird problem with sessions and having multiple sessions for one user and I'm trying to track down a specific behaviour either from Django or Django-allauth. For some reason each user can only have one active session at a time and it's bothering me because I don't know at which point is the original session invalidated/flushed and I have nothing in place to logout users in the first place.
This is what I do:
* I log into my django app using the OAuth Authorization Code flow in browser A, access a resource, modify it. When I refresh browser A I'm still logged in and my modifications are saved.
* I log into my django app using the OAuth Authorization Code flow in browser B, I access the same resource (loading the modifications I did on browser A), modify it. When I refresh browser B I'm still logged in and my modifications are saved. (So at this point everything is happening as expected)
* Now I refresh browser A. What I would expect would be that I'm still logged in, as I have literally no logout support and in my tests the session doesn't expire for quite a while. I should be able to refresh, still be logged, and see whatever I did on browser B. But for some reason, I'm logged out (request user is AnonymousUser), and the session has been completely flushed at some point (but when?).
I've set up logs on the user_logged_in and user_logged_out signals as well as on my OAuth flow, and from what I can tell, user_logged_out is never sent (and anyway the django logout should not invalidate every other session related to the user, shouldn't it?). There doesn't seem to be any request.session.flush() anywhere within the django-allauth code.
It may be that I'm missing a fundamental point in Django-allauth or even Django itself, I don't know.
Does anyone have any idea about this?
Related
When logging out a user with Flask-Login, is there a way to log out all sessions that user may have (Ex: in different browsers, different devices, etc)?
Flask-Login stores user_id in Flask session which is client-side session, the data stores in cookie file in users browser. Hereby you can't delete cookies in all devices and browsers of the client.
Nevertheless you can use server-side sessions instead with the help e.g. Redis and Flask-Session extension for Flask. Server side session will solve problem with removing or manipulating (imagine admin gave or removed user's rights) user session simultaneously for any user's browser or device.
https://pythonhosted.org/Flask-Session/
As Artiom said in his answer, Flask-Login by default uses Flask session which is client side, and you won't be able to delete all those cookies from other clients.
However, there is a way to prevent other clients from logging in. Flask-Login relies on user_loader callback function to fetch the user from your cache, this function gets called on every HTTP request coming from the user's client.
What you can do is on logout, you delete this particular user from this cache. That way when any client (phone, other browser,etc..) used by this user try to access your page. Flask-Login won't find the user in the cache and will redirect them to the login page.
Where I work currently there are many Django projects, each running on their own VPS, and each is running under their own subdomain (foo.example.com, bar.example.com, ...) as shown in the following diagram:
What I want to do is to have a central Django Server that manages all the login process (authorization and authentication) for each application, and when a user logins in foo.example.com and then goes to bar.example.com, his session keeps active and doesn't need to enter credentials again (user/password), the same if the user logs out, he couldn't see anything on the other projects until he logins in again.
Similar as what Google does when you login on gmail.com and go to youtube.com or blogger.com (or more similar to what I want to do: you login in google.com and go to drive.google.com, photos.google.com, calendar.google.com) or any other Google's site, your session keeps active.
Is there any django-package or any other way that would help me accomplish it?
I would use the django rest framework and login with that. This will install a session cookie, which you can check every time the user opens a page that they need to be logged in for. Once the cookie expires, or django expires the cookie, the user is logged out, and pages should not be served to them if your authentication checks are good. This means that if they log in to the django server anywhere, they remain logged in, even on your page, just like with facebook or google. When they log out of the django server, anywhere, they will be logged out of your remote pages as well.
You can read more about the django rest framework authentication here.
I could not comment on #shaihulud comment because I don't have up to 50 reputations. To answer the question, I wrote an article that addresses that, for anyone that might run into this problem in the future, you can find the article here
I'm looking to set up Django to use OAuth2 to authenticate users for a service that I'm running, but I'm having a bit of difficulty understanding how the tokens are passed around.
I've been working my way through this tutorial: https://django-oauth-toolkit.readthedocs.org/en/0.7.0/tutorial/tutorial_01.html. I've been able to get a server up and running as the OAuth provider, and it seems to be working as it should. I'm able to log in to it and set up an application. The difficulty I'm having is figuring out how the various tokens are passed around.
Suppose that my OAuth provider is sitting on one server - let's call this Provider.com - and my service that I'm wanting authenticated is on service.com. When a user first tries to make a request to the service, they first need to authenticate against the Provider. So they click on a login button which directs them to Provider.com. They enter their credentials. If everything is set up correctly on the server, they should be presented with a prompt that gives them a chance to allow or deny Service.com from accessing their account on Provider.com. Supposing that they click Allow, they are then redirected to Service.com, and are given a token. On future calls to Service.com, they pass in the token, and are, in theory, able to make authenticated calls.
The problem I'm having understanding is this: At what point do the Provider and the Service communicate? If a call comes in to the Service, how does it know that the authentication token passed in with the call is valid? There's know way it could know that a particular token is valid unless: A) it recognizes that same token from a previous call which was also authenticated or B) it talks to the OAuth 2 provider and verifies the authenticity of the token.
A diagram like the one found here shows the process in the browser:
At the end of this, it has the Client App sending the authentication code, client id, and client secret to the OAuth2 provider. In the previously mentioned tutorial, it isn't really clear how this is actually done. In the tutorial, the provider and the service are on the same machine, and it would appear that they also share the same database.
This this brings about my question: How does one host a Django-based OAuth provider on a separate server than the resource/service being accessed? Is this possible?
From this other post, it indicates that this might not be possible: https://stackoverflow.com/a/26656538/1096385 Is that indeed the case, at least with the existing Django OAuth2 provider framework?
It depends on the oauth2 flow you're using. It seems like you're using authentication code.
In that case:
service.com sends the browser to provider.com for user authentication (uri contains service.com client_id and redirect_uri)
User authenticates on provider.com, then the browser is redirected to service.com's redirect_uri with a ?code parameter.
On your server side, handle this code parameter and ask for a token with it.
See https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#web-server-apps
I have a website that essentially requires that the user be logged in to see anything. If they are not logged in then they are redirected to the front page and a login form.
I currently use Django's standard authentication and test for authentication server-side before returning the page.
I now want to add Facebook login and authentication. Does this mean that I need to make a server-side call to Facebook and verify authentication every single time that a user navigates to any page? It seems that this will add quite a number of calls and potential page delays.
Or, is this not really a concern (Facebook call is fast) or is there some other clever way that I am missing? Somehow move the call client-side where I believe that Facebook uses caching?
I've looked at some of the Django/Facebook packages, but none seem to explain the overall strategy, which is what I'm looking to understand. The tutorials that I have looked at describe how to login, but don't worry about what happens once a user logs out of Facebook.
Basically, the user logs in once using facebook (this will make a request to facebook).
once is logged in, it will behave just as a normal django user (most apps create a Django User for each facebook user)
Only when the access token is expired (the "password" for using the facebook data) than you will need to make a connection to facebook again.
Ill recommend you to use Python Social Auth which basically does everything for you.
login_required can be used as decorator in django, but a login.html with user/password is restricted by app.
#login_required
def myview(request):
...
now i want to display a button in login.html to redirect user to other site's oauth flow.
the site fix my callback url static. And user/password are not needed now.
so how to redirect user to last request(maybe post with data), after callback from oauth server?
should session/cookies be used to store request object?
You can attach session information to an anonymous user's session in Django; everybody gets a session cookie, anonymous or not. That data is kept after the user logs in.
If your session data is stored in the database, though, then it will take up more and more space over time, and you will want to have a periodic task that clears out the old sessions.
But should you be saving POST data for later replay?
In certain cases, this may be okay -- when you know for certain that the POST request is idempotent, has already been run once, and that the data is just being used to generate the correct page for the user to see.
You probably shouldn't implement this as a generic solution, though. If a GET request can be constructed that redirects through OAuth and then automatically POSTs as the authenticated user, then you likely have a major CSRF hole on your hands.