How often is load_user called in Flask Login? - flask

I know the function load_user is used to load a user entry from a database of the developer's choosing.
#login_manager.user_loader
def load_user(user_id):
return User.get(user_id) # DB agnostic
For me, it seems that it tries to load the user on every http request. This would make sense since HTTP is stateless. However, I thought Flask-Login allows for a session to hold onto the user until logout or login and the session cookie changes.
So basically, how often is load_user called, and what triggers it? Specifically, from the browser's perspective?
Some on my team are observing that the user is staying signed in for too long. I suspect either the session/token is not being cleared or there are multiple signed instances of the same user account as the db attempts to called User.get, or we are not protecting routes correctly with login_required.

Related

When do django AUTHENTICATION_CLASSES run with respect to Middleware

I see there is a django.contrib.auth.middleware.AuthenticationMiddleware but reading the documentation I don't think it determines when auth is actually auth is run. Does auth happen before or after middleware? Can that ordering be changed?
The authentication process and AuthenticationMiddleware unfortunately have little to do with each other. Authentication as a process is the practice of verifying credentials. In order to not have to do this for each request, one can create a "login session", which associates the browser with an authentication process that happened in the past. For the end user this is transparent as a "login process". This results in a "logged in user" and AuthenticationMiddleware puts this logged in user on the request object as request.user or if no login process has occurred, then the AnonymousUser.
In Django, authentication is done by whatever calls django.contrib.auth.authenticate and the login process by django.contrib.auth.login. In a vanilla installation this is done by django.contrib.auth.views.LoginView, which isn't hooked up to any url, except the admin login.
Authentication backends are not middleware. They are sources of truth for authentication data that is queried by the authenticate function. It's list is executed in order defined by the settings and the first one that returns True wins.
I think in the past the intention was for the authentication middleware to do more, but as it stands, a better name would be CurrentUserMiddleware.
No fixed place
You seem to think there is one spot where authentication backends are called on each request. This isn't the case, but depending on the authentication method, it can be. For example, Django Rest Framework's token authentication sends a token header on each request, which is authenticated each time in the view.
In theory, one can create a middleware that authenticates and sets the authenticated user each time, especially with token based auth, as they send credentials with each request. It's just unpractical, because it becomes harder and less explicit to exclude views from the process.

How to setup OpenID to work with load balancer?

The stack I'm currently using is:
Keycloak
flask
flask-oidc
nginx as load balancer
The set up I'm having is I have two instances of a service running (instance1, instance2). The issue I'm facing is:
A user uses web browser to authenticate by going to https://mycompany.com/auth/login
instance1 handles this request and redirects the user to Keycloak for authentication
Keycloak redirects the user back to the app using redirect url (https://mycompany.com/auth/auth_callback)
This time the load balancer routes the request to the redirect url to instance2. Here instance2 errors out with a response from Keycloak saying "{'error': 'invalid_grant', 'description': 'Incorrect redirect uri'}", which is very confusing because the redirect uri is correct.
I am not entirely sure why this set up is not working. But after reading through how openID works, I kind of suspect it has to do with the state parameter (https://auth0.com/docs/protocols/oauth2/oauth-state). Again, I am not entirely sure. But it has to be something that's only local to instance1, which instance2 doesn't have.
How do people tackle this issue ? Is this set up even possible?
From the documentation
Note that you should probably provide the library with a place to store the credentials it has retrieved for the user. These need to be stored in a place where the user themselves or an attacker can not get to them. To provide this, give an object that has setitem and getitem dict APIs implemented as second argument to the init() call. Without this, the library will only work on a single thread, and only retain sessions until the server is restarted.
It is referring to credentials_store option in OpenIDConnect instantiation. To support persisted login via multiple application instances, you will need a persisted shared datastore for this use case. You could use a share redis or dynamodb instance.
Implementation of this credentials_store is fairly simple, you can try something like,
class RedisOpenIdCredStore:
def __init__(self):
# Handle Redis instance initialisation here
pass
def __setitem__(self, key, value):
# Set item to redis
pass
def __getitem__(self, key):
# Fetch and return item from redis if present
pass
credential_store = RedisOpenIdCredStore()
oid_connect = OpenIDConnect(app, credential_store=credential_store, ...)

Understanding the Client's Responsibilities in OAuth 2.0

I've been trying to learn the inner workings of OAuth 2.0 in my own RESTful app, and I can't seem to find any good explanation of how my Javascript client handles the process.
At this point, I have the client (an Angular 2 SPA) ask the user for their username and password (running Django Rest Framework along with Django Oauth Toolkit). The client makes an AJAX post to the server (specifically to /o/token), and using the resource owner password credentials flow is authenticated and receives the response with the token.
Now, assuming I'm doing everything correctly up to this point, I'm unsure how to properly handle the token from that point forward.
At this point, I'm having my Angular app save the token in a variable and attach the authorization header (with the token) to the calls made to the API. This works as far as granting the correct permissions, but im having a hard time understanding how to maintain persistence of the header (so if the user navigates to a different page, the token is still callable). Initially I stored it in a cookie, but I have concerns with security.
So, first, am I understanding all this correctly? What kind of security concerns should I take into account here? And, of course, how can I save the token on the client?
Yes, you need to store access tokens as user session data because they should be persistent. For example if user leaves your site and then reopens he expects to see himself logged in.
It will be better if you make your sessions server-side: user-agent will store only session ID and all user data will be in your database. User don't need his access token, only your application does.
Instructions for implementation of server-side sessions for Django look pretty simple:
If you want to use a database-backed session, you need to add 'django.contrib.sessions' to your INSTALLED_APPS setting.
Once you have configured your installation, run manage.py migrate to install the single database table that stores session data.

How Can I retain session information once a user registers (Django)?

When a new user is created, I want to retain some of the information in their session
e.g. things a user has stored in their session I want to use once they have registered (or logged in).
I would use either a post_save signal on the user model (or an auth login signal), but it appears that the signals don't put the request, or session into the signal sent. It also seems I can't easily get the session from just the user.
I'm using Django 1.4
Edit: let me give an example.
The problem boils down to this - I may want to retain information for a user's activities before they login, but where do I store this information before they login? A good place would be a session (or I could link the data held in a db to the session, using the session a little like a makeshift user).
In any case, until they login, I can simply use their session like a user credential, and store information that persists so long as their cookie does (how else can could I reliably track an anonymous user?).
But once they register (or log-in), I want to move that information from the session, into the account properly. One good reason is that it would make sense to delete data from anonymous users periodically, whereas registered user's data would be persisted.
To do this I simply want access to the session (could be via the request) from a handler to the new-user signal, so I can make a one-off transfer from data in the session. But the new-user signal doesn't hold the session (or request).
If you're using django.contrib.sessions and django.contrib.auth for the job, the session data should be retained automatically after login.
Moreover, the user_logged_in signal is sent along with request actually.
Edit:
So use user_logged_in signal. It carries request. Pick some specific key to store unauthenticated user's data (e.g. "_anonymous_data"). If that key is set on request.session while handeling signal, simply rewrite data on request.user.get_profile() object, call save and del request.session["_anonymous_data"].
The code to retreive it could look something like:
if request.user.is_authenticated():
user_data = request.user.get_profile()
else:
user_data = requerst.session["_anonymous_data"]
It's only a scratch of course. You don't want to hardcode session keys or write such logic in views. If you need it application wide, embed it in some abstraction class which takes request in __init__.
you could try using sessions:
https://docs.djangoproject.com/en/dev/topics/http/sessions/?from=olddocs

Django Middleware + URL's

Can a middleware check to see if a value is in the url, such as an image id ("/image/152/"), and if it is then do some checks to make sure the current user has permission to view that image and if not redirect to another url?
I had to roll my own permissions for this site I am working on and I don't want to clog up almost every view I write for the whole site with the same code, so I thought a middleware would be a good idea for this, but I'm not sure how to go about doing it.
Yes, this is possible. The django middleware docs for process_request indicate that:
def process_request(self, request)
request is an HttpRequest object. This method is called on each request, before Django decides which view to execute.
process_request() should return either None or an HttpResponse object. If it returns None, Django will continue processing this request, executing any other middleware and, then, the appropriate view. If it returns an HttpResponse object, Django won't bother calling ANY other request, view or exception middleware, or the appropriate view; it'll return that HttpResponse.
The HttpRequest object has a path attribute that will give you the URL that was requested.
If you prefer, however, note that you can also extend Django's system for authentication backends to populate the user in the request with permissions based on any arbitrary criteria, such as perhaps your hand-rolled permissions scheme. This way, you can leverage the default authentication decorators (#permission_required and #user_passes_test), and other apps/the admin site will be able to honour your permissions as well. The User object and permissions created do not need to reside in Django's user/permission tables, and can be created virtually on login; I've had a fair amount of success with this.
See Writing an authentication backend if this appeals.
If you implement authorization (Permission system) in middleware, you will end up with two options:
Check URL and allow to access
Check URL and reject access
If your requirement is that much simple, it is fine, since you don't have to touch views.
But in general, Permission system is much complex than that, for example:
User can access FOO/show_all/
But, he can't see or access foo instance, i.e, FOO/show/foo_1/
Since, he can't access foo_1 instance, we should not show them in show_all
(all foo instances)
If you want implement above 3 together, I suggest you write your own custom authorization backend for Django. All you need to do is implement few methods (your specific logic) and attach as backend.