Flask-login and LDAP
Solution 1
Flask-login does not depend or need any specific backend for users. You have to represent the user object and return an id. see this post for example
flask-login: can't understand how it works
Solution 2
You can do it in python with the LDAP module:
LDAP_SERVER = "yourldapserver"
LDAP_PORT = 390033 # your port
import ldap
def login(email, password):
ld = ldap.open(LDAP_SERVER, port=LDAP_PORT)
try:
ld.simple_bind_s(email, password)
except ldap.INVALID_CREDENTIALS:
return False
return True
Solution 3
Simple example of flask-login with ldap3.
from flask_ldap3_login.forms import LDAPLoginForm
from flask_ldap3_login import LDAP3LoginManager, AuthenticationResponse
from flask_login import LoginManager, login_user, UserMixin, current_user
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['DEBUG'] = 'True'
# Setup LDAP Configuration Variables. Change these to your own settings.
# Hostname of your LDAP Server
app.config['LDAP_PORT'] = 636
# Hostname of your LDAP Server
app.config['LDAP_HOST'] = 'ldap-name.com'
app.config['LDAP_USE_SSL'] = True
# Base DN of your directory
app.config['LDAP_BASE_DN'] = 'dc=Hostname,dc=com'
# Users DN to be prepended to the Base DN
app.config['LDAP_USER_DN'] = 'ou=people'
# Groups DN to be prepended to the Base DN
app.config['LDAP_GROUP_DN'] = 'cn=ldap-groupname,ou=groups'
# The RDN attribute for your user schema on LDAP
app.config['LDAP_USER_RDN_ATTR'] = 'uid'
# The Attribute you want users to authenticate to LDAP with.
app.config['LDAP_USER_LOGIN_ATTR'] = 'uid'
# The Username to bind to LDAP with
app.config['LDAP_BIND_USER_DN'] = 'uid'
# The Password to bind to LDAP with
app.config['LDAP_BIND_USER_PASSWORD'] = 'pwd'
login_manager = LoginManager(app) # Setup a Flask-Login Manager
ldap_manager = LDAP3LoginManager(app) # Setup a LDAP3 Login Manager.
# Create a dictionary to store the users in when they authenticate
# This example stores users in memory.
users = {}
# Declare an Object Model for the user, and make it comply with the
# flask-login UserMixin mixin.
class User(UserMixin):
def __init__(self, dn, username, data):
self.dn = dn
self.username = username
self.data = data
def __repr__(self):
return self.dn
def get_id(self):
return self.dn
# Declare a User Loader for Flask-Login.
# Simply returns the User if it exists in our 'database', otherwise
# returns None.
@login_manager.user_loader
def load_user(id):
if id in users:
return users[id]
return None
# Declare The User Saver for Flask-Ldap3-Login
# This method is called whenever a LDAPLoginForm() successfully validates.
# Here you have to save the user, and return it so it can be used in the
# login controller.
@ldap_manager.save_user
def save_user(dn, username, data, memberships):
user = User(dn, username, data)
users[dn] = user
return user,username
@app.route('/', methods=['GET', 'POST'])
def login():
# exists in LDAP.
form = LDAPLoginForm()
if form.validate_on_submit():
# Successfully logged in, We can now access the saved user object
# via form.user.
a = login
return redirect(url_for('mainpage'))
return render_template('login.html',form=form)
else:
return render_template('error.html')
Solution 4
self.id should be a string that is unique. it can be one of :
- cn (unique in LDAP)
- sAMAccountName (unique in the domain, it is like a unix login)
- mail (multivalued, one of them should/could be unique)
- ...
Just choose one, and wisely. I prefer the sAMAcountName for my own work. It requires you to do an LDAPSearch after ldap_bind.
The first bind without authentication (to find the DN) should be made with an applicative user to avoid information leaking (in case you are hacked).
Ldap connection are resources => use a context manager
with ldap.open(LDAP_SERVER, port=LDAP_PORT) as ld:
# do the search/bind/search here
monoceres
Updated on July 23, 2022Comments
-
monoceres almost 2 years
I'm developing a webapp with the flask framework as a backend and I need to provide authentication.
Since this is an in-house app to be used on our local domain I have chosen to authenticate user with their already present domain credentials.
The method I use is the
win32security.LogonUser
frompywin32
which returns a handle on successful login.I have tried to understand how flask-login works, but the
@login_manager.user_loader
callback makes me confused.It says I should provide an id which can be used to reload the user, however I have no database or persistent storage to provide this mapping from, since I'm only interesting in checking if the user pass authentication.
My User class looks like this:
class User(flask_login.UserMixin): def __init__(self,username): self.username = username self.id = ???
What to use an
id
, and how could this id map back to this instance? -
frlzjosh over 3 yearsI'm still confused on how we pass id's to login_manager? When do we call load_user or save_user to pass ldap's info into it?