Django websockets auth - django

I use tornado + sockjs for websockets and Django rest framework for main app.
Also I use rest-framework-jwt for auth on Django app.
Now I have to determine user in tornado. How I see it:
User send jwt in message when sockjs connected to tornado server.
Tornado server parse jwt and determine is valid jwt or not? But for this solution I have to read database. But this operation is sync which is not good, because tornado is async.
Also I thought use Celery. When user connected to tornado, tornado creats task for celery and in this task jwt will be parsed. In that case solution is not blocking tornado. But how then to notice user via websockets about check jwt?

UPDATE:
You shouldn't need to read database to validate a JWT. JWT is a signed token, all you need is the secret key to validate the JWT.
OLD ANSWER:
(Note: The diagram below is rather redundant for JWT, as a JWT is already a signed token and can be validated without needing to be saved anywhere. This diagram, however, works for cookie based auth.)
You can share auth tokens between Django and Tornado using a message broker (such as Redis):
Redis is fast and lightweight and you can connect with it asynchronously from Tornado.
There's no need for Celery here.

If will you use SQLAlchemy, to connect and handler database, you could use tornado-sqlalchemy to make the async query on the database and notify your user via WebSocket without break event loop of the tornado.
#coroutine
def open(self):
with self.make_session() as session:
jtw = request.params.get('authorization')
jwt_valid = yield self.check_jwt_valid(jwt, session)
if not jwt_valid:
self.write('JWT Inválid')
self.close()
#coroutine
def check_jwt_valid(self, jwt, session):
jwt_found = session.query(JWT_QUERY...).first()
return jwt_found

Related

user authentication using async websocket instead of django channels

I have a websocket service previously written using python websocket package which can access django models. Is it possible to check if the messages are coming from an authenticated user without using django channels?
Well, no answers, so you get to watch me at work.
I made an alternative login api rate limited to 3 requests per minute which would return the token if you send it a username and password.
I changed the django login template to include the token query
token query works before username and password is posted to the django server
token is retrieved before login and placed into browser's session storage
user logs in, websocket page is loaded, we've got the token in the session storage
websocket connection is created using the token in the session storage so webscoket server now has the token for authentication
use token for authentication to retrieve the account data on server side and route requests to the websocket object according to that.

Session with Django

In a Home page, i have a form login. in the view.index of the app "Home", after authenticate, i create the ssesion. And after, i call the app "Places" if the authenticate is okey,
request.session['user'] = username
request.session.set_expiry(900)
return HttpResponseRedirect('/places/')
in the settings of the project i configure the SESSION_SAVE_EVERY_REQUEST = True.
How can i send the session to all others pages of the project, and log out the user when the session is expired ?
HTTP is a request response protocol.
This means that the server has no way to to communicate to the client without the client initiating the conversation. So the only way to do something like this is native Django, is to have the client periodically check to see if the session is still ok.
One way to achieve this is with a background ajax call (perhaps using setInterval in javascript) which checks the session, and if it's not any good anymore (either by expiration or the user has been disabled etc) then redirect them back to the login page.
Another approaches could involve sending the expiry time to the client so that it only checks the session when it would have expired (though this wouldn't pick up on users being disabled) or having a websocket server which pushes this information to the client.

Django REST framework JWT checks user from database with every request

I'm using Django REST framework JWT library for authentication in my django application. And I thought the whole idea of using JSON Web Token Authentication was NOT having a database trip in every request.
But it still retrieves user's data (which is stored in the token's PAYLOAD) from database per request.
What am I doing wrong?
The webtoken mechanism and the server authentication internals are rather orthogonal.
The web token just allows the holder to say who they are. It is similar to holding a user's username and password, except the token can be revoked without the user having to learn a new password. This authentication technique has nothing to do with whether the server will do a database access.
If you wish to eliminate a DB access during authentication on the server, you can use some sort of authentication caching mechanism like django-cached_authentication_middleware.

Django-allauth, JWT, Oauth

I have an AngularJS Single Page Application that uses a Django backend API based on the Django Rest Framework. The API is protected via django-rest-framework-jwt. I would like to use django-allauth for account management and authentication on the server side.
I am just missing one single piece in the flow: How does my Oauth-Token from the client get transferred into a JWT-token? Basically, I would like to do as described here http://blog.wizer.fr/2013/11/angularjs-facebook-with-a-django-rest-api/ based on python-social-auth.
So my question is, how do I implement the ObtainAuthToken class from the link with django-allauth?
There are usually two login flows with social login: client-side ("Javascript SDK") and server-side. If your server needs to be authorised, it's usually a lot easier to go through the server-side flow. And that's also what all-auth does I think (and you didn't mention you use a frontend library like the blogpost you mentioned does).
Now the challenge is to provide the token from the server to the frontend. You would probably load the token in the HTML of the initialisation of the SPA, and then from Angular save the token client side (cookie, localStorage, etc.) so the session isn't lost on a refresh.
If you don't want the user to leave your app, you can open your /accounts/login/ or /accounts/signup/ url in a new window. In that new window they authorise your app, and your server receives the token upon return. There, you will have to generate a JWT token manually, and render that into the template so that javascript can access it. With js in that popup window, you can then communicate with your app that opened the popup and pass it the token – see this SO answer for an example – so it can save it.
Django-allauth provides signals that let you hook into the social login process. In your case, I would recommend subscribing to the allauth.socialaccount.signals.pre_social_login signal. The code will look something like this:
from allauth.socialaccount.signals import pre_social_login
#receiver(pre_social_login)
def create_jwt_token(sender, request, sociallogin, **kwargs):
# dig into the sociallogin object to find the new access token.
We used hello.js for O-Auth at the company I worked at.
You provide a shim on the Python end and get the refresh token and whatever other data needed once the user connects their social account.
We redirect them via Django to the page they attempted to access from their OAuth provider's page.
Each user still has their own email account which is needed for the JWT, but you could assume that whatever email is in the scope of their social account is their email then use django's functionality to create new users: User.objects.create(email=emailStringFromOauthData) etc.

Best way to pass Django session id in sockjs connection

Right now I have a Django-tornado-sockjs stack and want to be able to pass the session id from the site into a sockjs cnnection. What is the most secure way to pass the Django session id to my tornado backend? It sounds like people are recommending I store the session id in cookies and then send the data over when sockjs opens a connection. But isn't this less secure? It doesn't seem like Sockjs supports passing http-only cookies.
Any alternatives? At some point do I just have to accept I will have pass the encrypted session id though html or cookies and is there a real danger to this?
I'm far from a security expert but AFAIK requiring SSL for all auth requests is a baseline requirement to keep things secure if security is important.
We don't use session ids but instead generate an auth token on login, store it in redis which acts as the message queue between django and sockjs-tornado, and also pass it into the rendered page that establishes the sockjs connection via https. Then our sockjs-tornado process checks for the correct auth token in redis as part of the payload in a connection event.
We use haproxy to handle SSL uniformly across all the requests and dispatch to the appropriate backend which has been working great.