Is this anyhow possible to access the request object from within the django admin's authenticate() in custom auth backend?
The reason for this is I want to keep and re-use the user's password (or a Kerberos ticket - not sure yet) to authorize an operation in another system, which uses the same LDAP backend. For this purpose I wanted to use request.session - but it doesn't seem to be accessible, at least not the easy way.
If there's any other possibility to pass a value from the auth to the model, I'd be happy to get a suggestion as well.
Thanks.
I believe it's a bad idea to store raw password in session for security reasons, but some ideas (just ideas, never tried it):
Access session directly https://docs.djangoproject.com/en/1.10/topics/http/sessions/#using-sessions-out-of-views
Make sure your session won't be flushed by django.contrib.auth.login. See details in implementation.
user_logged_in signal has access to request and user object.
user_logged_in.send(sender=user.__class__, request=request, user=user)
Looks like you can add attribute to user object inside authentication backend method and later attach it to session.
Related
Basically, I am implementing the following functionality where the Front end will send signed JWTs to the backend. If the backend is able to decode and hence validate the Token (i.e. the signature, claims, audience, etc), then it will give access to the protected API resources:
Now the users already exist in Azure AD (so I don't want to have to create/manage users in the Django DB as well). So essentially all I want to do is protect the Django Restful API endpoints with validated Access Tokens. I was looking at Custom Authentication (by extending rest_framework.authentication.BaseAuthentication) but it seems that the authenticate method expects a User to be matched (Hence Users to exist) and returned for a successful authentication (I would like to just pass if JWT validation is a success or raise Exception is there is an error).
Django docs:
Either way, authenticate() should check the credentials it gets and return a user object that matches those credentials if the credentials are valid. If they’re not valid, it should return None.
I have achieved my desired flow (i.e. having no Django Users) using method_decorator but this does not seem like a correct pattern for authentication:
class ComponentViewSet(viewsets.ModelViewSet):
queryset = Component.objects.all()
serializer_class = ComponentSerializer
#method_decorator(validate_jwt)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
Django docs also state that:
The Django admin is tightly coupled to the Django User object. The best way to deal with this is to create a Django User object for each user that exists for your backend (e.g., in your LDAP directory, your external SQL database, etc.).You can either write a script to do this in advance or your authenticate method can do it the first time a user logs in.
I have also done a separate implementation of the Custom Authentication by creating Users on the fly in the authenticate method just as the documentation recommended.
So my question is, is having Users exist in Django a strongly recommended design (or must according to the docs) even when you have a centrally managed Authentication system like LDAP/AD etc? Or is it also common not to use the Users model and use some other kind of implementation (for example the method decorator I used) when you don't intend to hold any kind of User information in the backend because I see it as redundant? Are there any advantages of duplicating a users database in the Django backend if it is strongly recommended. And do these users also require passwords if they extend django.contrib.auth.models.User?
Rather than needing to use a decorator on every method, just make your own authentication backend. When a view calls authenticate(), Django calls all backends specified in AUTHENTICATION_BACKENDS until one doesn't return None.
In regards to storing users, Django assumes by default that you want to store session data in the backend, to not require login. If you're fine with reauthenticating on every request, then you can feasibly just return a new instance of BaseUser object, without saving to the database, although other Django functionality might break in unexpected ways.
You might want to explore creating your own user model based on AbstractUser or even AbstractBaseUser. If you're not getting a new token on every request, it makes sense to store the token in the user model, along with a when_authenticated, time_to_expiry, etc.
A new user OR a returning user who's when_authenticated + time_to_expiry < now() access token will be validated with the auth server. On success, update the necessary time fields, along with current_access_token. Subsequent requests within your refresh window merely have to do a fast equality check, as opposed to another request to the server.
This will save your auth server from lots of requests, speed up your API (no auth server validation on every call), and still let you use some of the awesome functionality Django lets you have with users.
Currently I implemented a login routine for the website I am working on, according to This Tutorial.
Also I am not authenticating the user with djangos own system, because I am using authentication against the LDAP of my company (django-auth-ldap).
Currently I am using a general user to login to the database, which has universal access to all data, which also gives full access to any user logging in to the website.
To avoid that I would like to know how I can connect to the database as the individual user, who just logged in to the website.
Thanks in advance and sorry for bad english
Restricting user access to functionality and authenticating with the DB are handled separately in Django. You might be able to read the privileges of your users from the DB and map them to Django permissions but this is non-trivial (about Permissions see https://docs.djangoproject.com/en/2.1/topics/auth/default/#permissions-and-authorization).
In a UI/UX that has functionalities restricted depending on authorization, the frontend and backend need to be aware that permissions need to be checked and missing authorization needs to be communicated in some way or other to the user.
Example:
Users in group A are allowed to delete X. They see the "delete" button and there might also be an AJAX call that can delete X.
Users in group B are not allowed to delete X. They do not see the delete button and the AJAX call that can delete X needs to check for that permission and/or user group membership.
If you are only using a DB level authorization layer than - how would you know if the "delete" button should be displayed and for what to check in the AJAX call?
hi!
If I'm getting your problem correctly, the user you are creating is a Super User every time right?
Well if you are using Django auth.User model, you can just make User_object.is_super to False and then restrict the access of users though if-else in view! (User_object is the object of the auth.User model)
Does that made any sense?
//BTW, a side-note, a mistake I made while making my first custom user model: make sure to store your passwords hashed using Django hashes and salts!
I apologize in advance for asking a rather cryptic question. However, I did not understand it despite going through a lot of material. It would be great if you could shed some light on this.
What is the purpose of a request_loader in flask-login? How does it interact with the user_loader decorator?
If I am using a token based authentication system (I am planning on sending the token to my angularJS front end, storing the token there and sending that token in the authorization-token header), will I need a request_loader or will a user_loader (where I check the auth header and see if the user exists) suffice?
From the Flask-Login documentation:
Sometimes you want to login users without using cookies, such as using
header values or an api key passed as a query argument. In these cases,
you should use the request_loader callback. This callback should
behave the same as your user_loader callback, except that it accepts
the Flask request instead of a user_id.
So, to answer your question, they both serve the same function for Flask-Login. They are both used to load the user. request_loader, however, is appropriate for custom logins.
Here's a great tutorial I found that utilizes request_loader to take advantage of token based authentication (The post is not my own, I'm merely sharing the link): http://gouthamanbalaraman.com/blog/minimal-flask-login-example.html
I need to make this clear.
This is the reason why you shoud use request_loader with flask_login.
There will be a lot of #login_required from flask_login used in your api to guard the request access.
You need to make a request to pass the check of auth.
And there will be a lot of current_user imported from flask_login,
Your app need to use them to let the request act as the identity of the current_user.
There are two ways to achieve the above with flask_login.
Using user_loader makes the request to be OK for #login_required.
It is often used for UI logins from browser.
It will store session cookies to the browser and use them to auth later.
So you need to login only once and the session will keep for a time.
Using request_loader will also be OK with #login_required.
But it is often used with api_key or basic auth.
For example used by other apps to interact with your flask app.
There will be no session cookies,
so you need to provide the auth info every time you send request.
With both user_loader and request_loader,
now you got 2 ways of auth for the same api,
protected by #login_required,
and with current_user usable,
which is really smart.
To verify users with Flask-Login's session_id for frontend requests through Angular, you must set the withCredentials configuration flag to true.
That is, if you are using Angular's $http.post(url,data [,config]) or $http.get(url [,config]), make sure the config object contains the property withCredentials set to true. This will instruct the browser to use its cookies in the same way it would for a full-on page visit.
For example,
$http.post('/api/login',{username:'myusername',password:'mypassword'},{withCredentials:true})
will post the data {username:'myusername',password:'mypassword'} to your site/app's /api/login route and, if you're using Flask-Login and are logged in, Flask will know.
You can set this behavior for all $http service requests by setting
$httpProvider.defaults.withCredentials=true
somewhere in your app. Currently, I have that line of code in my app.config block, which seems appropriate to me:
var myApp = angular.module('myApp');
myApp.config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;
});
(Since this post is about Flask, folks may want to send form data through Angular in such a way that it can be found in request.form, which has a similar solution, fyi.)
I am using Flask-Security to build a web app that has a public REST API. I am trying to figure out how to add user registration and login using REST calls only.
It is fairly easy to create a user using user_datastore.create_user. But how can I then login the user, using a REST call?
If flask_security.utils.login_user took username+password or a token as an argument, it would be easy, but it takes a user object instead?
The documentation shows how to register and login using forms and views, but I need to be able to register and login from an IOS device (using RESTkit).
You will either want to use flask_security.decorators.auth_token_required along with SECURITY_TOKEN_AUTHENTICATION_KEY or SECURITY_TOKEN_AUTHENTICATION_HEADER (depending on whether you want to pass the token in the URL or in a header) or you can override flask_security.core.UserMixin.get_auth_token for your User class and Flask-Security will do the right thing.
[Writing an answer since I do not have enough credentials to comment on answer provided by Sean Vieira]
I looked a bit of Flask-Security code - it uses Flask-Login's LoginManager for this.
Flask-Login in turn expects the user to define token_loader (as well as implement get_auth_token in User class)
Does Flask-Security provide "default" token_loader functionality ? Otherwise - it is same as Flask-Login
Edit:
It turns out Flask-Security works just fine. I do not need to write my own token_loader.
I had security code in a separate file, and that is how "magic" broke.
I brought back the security code into myapp/init.py - and documented code "works"
Edit 2:
Refering to answer provided by Sean above. I don't think it is one or the other. One must use auth_token_required decorator.
Overriding get_auth_token in User class is optional, in case you want different implementation for token generation (I think)
Overriding get_auth_token in User class is not sufficient.
I was wondering if I could eliminate django session calls for specific views. For example, if I have a password reset form I don't want a call to the DB to check for a session or not. Thanks!
Sessions are lazily loaded: if you don't use the session during a request, Django won't load it.
This includes request.user: if you access it, it accesses the session to find the user. (It loads lazily, too--if you don't access request.user, it won't access the session, either.)
So, figure out what's accessing the session and eliminate it--and if you can't, at least you'll know why the session is being pulled in.