Authenticate with Flask-LDAP3-Login based on group membership

Question:

I’m new to Flask and I’m trying out Flask-LDAP3-Login.

I’ve followed the documentation here and i have it working which is great: https://flask-ldap3-login.readthedocs.io/en/latest/index.html

How would i go about authenticating a user based on whether they are a member of a specific group? I see the docs mention group filtering but i’m not sure how to put it all together.

Asked By: br0cky

||

Answers:

Do you have a ldap server ? if not go to https://www.openldap.org/ and follow instructions on how to install openldap server
if you prefer a docker container then go here
https://github.com/osixia/docker-openldap and follow steps to get the container up and running
then go here https://ldap3.readthedocs.io/tutorial.html

pip install ldap3 on the machine which has your python env or another python container (same bridge network as your ldap container)

open python console and type the following commands

>>> from ldap3 import Server, Connection, ALL
>>> server = Server('ipa.demo1.freeipa.org')
>>> conn = Connection(server)
>>> conn.bind()
True 

first with this free ldap server ipa.demo1.freeipa.org
and then with your own ldap server ip address

Answered By: user17970

If anyone is curious, i solved this myself doing the following:

First, i integrated flask-ldap3-login with Flask-SQLAlchemy using steps here – https://github.com/nickw444/flask-ldap3-login/issues/26

My save user method now looks like this:

@ldap_manager.save_user
def save_user(dn, username, data, memberships):
    id=int(data.get("uidNumber"))
    if 'group-goes-here' in data.get("memberOf"):
        user=User.query.filter_by(id=id).first()
        if not user:
            user=User(
                id=int(id),
                dn=dn,
                username=username,
                email=data['mail'],
                firstname=data['givenName'],
                lastname=data['sn']
            )
            db.session.add(user)
            db.session.commit()

        return user

So basically provided the user enters valid LDAP credentials it goes to AD to retrieve their group memberships and its a simple if ‘group-goes-here’ in data.get(“memberOf”): determines whether to save the user in my User model and return it back to the handler.

@auth.route('/login', methods=['GET', 'POST'])
def login():
    # Redirect users who are not logged in.
    form = LDAPLoginForm()
    if form.validate_on_submit():
        if form.user:
            login_user(form.user)
        else:
            flash('Login Failed', 'warning')
            return redirect(url_for('auth.login'))
        return redirect(url_for('main.home'))

Hope this helps!

Answered By: br0cky

The LDAP_USER_OBJECT_FILTER can be used to check group membership. If a user is not found within the group, an authentication fail will be produced. This is taken from the flask-ldap3-login docs:

Specifies what object filter to apply when searching for users. Defaults to ‘(objectclass=person)’


Matching direct members of a group:

app.config['LDAP_USER_OBJECT_FILTER'] = '(objectclass=person)(memberOf=<DN of Group>)'

For nested group membership you can use LDAP_MATCHING_RULE_IN_CHAIN:

app.config['LDAP_USER_OBJECT_FILTER'] = '(objectclass=person)(memberOf:1.2.840.113556.1.4.1941:=<DN of Group>)'

The Microsoft Search Filter Syntax docs state:

This is a special "extended" match operator that walks the chain of ancestry in objects all the way to the root until it finds a match.

Answered By: Enzyme4776