Multi-tenant Centralized Authentication Server - django

I am trying to create a centralized authentication server for multiple Django apps (APIs). I've seen posts/recommendations but none fit exactly what I am looking for.
Overview:
Users can be associated to one or multiple projects
Users have same credentials to all projects they are associated to
Use JSON Web Tokens - use payload to add user data, sub-domain (project) to route to, role, etc
Sub-domain will not be used for login. All users will login to same site and will be routed to project they are associated to (or given list if there are multiple). SSO is optional.
Questions/uncertainties:
Q: Should the authentication tokens be created on the authentication server or on each project? ie) Each user having one auth token for all projects or have one auth token for each project?
Q: Roles will be stored in each app. I would like to send the roles along with the authentication token in the JWT. Should this data be redundantly stored on the authentication server? Another other way would be for the authentication server to access the project databases. What is the best way to handle this? Users will have different roles for each project.
Q: Auth server will have basic user information (email/username, password, first/last name, etc). Since foreign keys can't be used between databases I can use a user proxy based on usernames to create the user on each project. Do the app servers need to have access to which authentication tokens are valid?
Taking advantage of pre-existing software:
Another approach I had in mind was to use django-tenant-schemas which takes advantage of Postgres schemas where each one of my projects would be a schema (currently using MYSQL databases). Does it make sense to take advantage of this?
Can I take advantage of an IdP service to offload some of the authentication? Does this easily tie into the Django auth layer?

Your question seems to be multiple so I would split the answer too:
ABOUT THE USERS
Since your users are not part of your "mutitencancy model" you have two options here:
Replicate your user data among the different tenant databases (via triggers and what not).
Write your own authentication middleware that verifies users in the right database (lets call it root database since now on). You can use user ids to from the root database and verify manually that they match, which is a bad idea.
That means your database schema will be something like this:
root database (all common data here)
project 1 database (with it's own user data or referencing root)
project 2 database (with it's own user data or referencing root)
Now for authentication tokens
You have the same options as above:
Keep them in the root database and write your own middleware.
Replicate them.
How to implement the whole thing
Since your use case is pretty particular, you may encounter some resistance from existing software. But creating your own multitenant solution is not that hard

Related

Should I use JWT or Sessions for my eCommerce website?

I'm building an eCommerce website for a personal project. It uses React for the front-end and a REST API running on django for the back-end. I want the user to be able to add items to a shopping cart and place an order without the need for an account.
For guest users, using a session/cookie to store info is great, but when it comes to logged in users, I would want to use the database to store items in a cart. That would require creating a user and giving them an auth token so they can perform necessary actions.
So should I use session/cookie authentication or is there a better way to achieve what I want using JWT?
Both approach can work very well. However, I am currently working on something similar and I would personally recommend the simpler option which is the classic session approach. JWT tokens can be harder to maintain and sometimes insecure if not done correctly. Also, JWT tokens will not persists between logins.
In both ways, I don't see why one would be better to create and maintain a cart except maybe that a session system can actually store the complete cart in the session itself. You can then implement sessions controllers at the API level.
ex: GET "https://{host}/api/cart" returns the items in the session's cart.
# Django session
request.session['cart_id'] = cartId
# JWT Tokens
jwt.encode({‘cart_id’: cartId} ...
little note.. It can be harder to setup the sessions if you are working on localhost for react and a remote server for your API. (The cookies are generally set per domain).
I am using JWT, and I think if you are using a database, you can create a generated JWTby user then store it in the database, you can control the availability of your jwt, in parameters, and I find the best way to secure your APIs, is to add the JWT token to the headers.
I would use Cognito authentication and integrate it with react and the backend api. It will help to manage the users outside the application.
If you’ll be hosting your application in AWS, Check out AWS Cognito, it’s an identity and a user pool service. Their free tier is quiet generous. That, together with AWS Amplify which is perfect for React, will give you out-of-the-box auth and user management.

How to map one social account to several user account with django-allauth

I need to map one social account (created on a Django server with django-oauth-toolkit) to several different logins in a Django website. I already managed to connect and the server passes all allowed accounts so that the client connects as one of them.
I'd like to add the possibility to prompt for the choice of which of the accounts should be used. I'm currently connecting the user in the pre_social_login method of the account adapter.
The only idea I have is to persist in the session the available accounts and redirect to a page to select the preferred one. I'd like to understand if there's a better way.

Django Open ID - Assign permissions to users who have never logged in by email

I'm using django-auth with the django-auth-openid extension to use OpenID (specifically, Google) to log users into my site. I have a user base of about 90 who will be using the site. All of them have Google accounts, and will be using them to access the site. Since the user base is set (there is no registration allowed, only admins can add users), I already have an exhaustive list of all of my users, including their email addresses and other information. How can I allow these users to login with their Gmail addresses without making them register first? Essentially, I'd like to make django-auth-openid match OpenID Gmail addresses to rows in the existing django-auth Users table. Is this possible?
Thanks!
I ended up using the python-social-auth library (which has Django support built in). The documentation for use with Django isn't great, but between the docs and the provided example it was relatively easy to integrate it with my existing django-auth setup. After that, I just deleted the 'create_user' pipeline from the SOCIAL_AUTH_PIPELINE tuple in my settings, and, that way, only users with existing OpenID connections were allowed in (no new registrations occurred from OpenID logins). This meant, though, that I had to create those connections (between OpenID identifiers and Users) manually, but that was pretty easy to do just using the Django Python shell.

OAuth-Based Authentication Scheme

I have an application that is run on multiple user systems, and using OAuth, allows the users to log in via Facebook, Twitter, etc. The entire point of the user logging in is to get settings and actions that the same user made while logged in on other computers, as identified by logging in with the same OAuth provider + provider user id. The application itself is written in C++ using Qt.
My question is this: how can I save the settings that a user made, and allow them to retrieve it in a secure way? I have a centralized server that I can store information using MySql tables, but I'm not sure the best way to have the user application prompt the server, and receive the data stored for that user.
Any ideas or places you could point me towards?
There are several ways I could think of with this, all have trade offs:
Generally I would store the data in mysql using some kind of string or object encryption/serialization method. I do not use Qt much but http://qt-project.org/wiki/Simple_encryption has some examples of very simple encryption that could be used.
Then the question becomes: What do you use as the key? I would go either with the key provided by OAuth for that user (which could be an issue if users de-authorize the app but still want access to this data) or some other user provided key (which is counter to using OAuth in the first place).
Another option is to go with Qt Users session http://qt-project.org/doc/qt-4.8/qtwebkit-guide-cache.html
This would maybe remove the need to encrypt since it should only be accessible within the users scope.
NOTE: Based on comments below it seems the issue is more about securing communication with the MySQL versus the data inside of MySQL. Waiting on user comments to revise my answer.

Django - Two auth system completely separated in the same project

I have a project using django. And now the need for having to completely separated auth system(with different tables, authentication back-end, users, user-info etc) comes in scene.
Is there any way to make django instead of setting request.user, sets request.myotherappuser?
What about the default auth system, can I still use it to authenticate those 'new users' and also log them in?
Thanks in advance.
I'm assuming from your phrase "authenticate those 'new users' and also log them in" that you have some legacy system from which you wish to authenticate people?
Why not write a custom authentication backend that logs people in against the old backend, and then also creates them a "new" account in django.contrib.auth?
You could also create an extension to the user model using Dj1.5 that allows you to reference the "old" table like request.user.myappotheruser.