nickw444 / flask-ldap3-login

LDAP3 Logins for Flask/Flask-Login

Home Page:http://flask-ldap3-login.readthedocs.org/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

LDAPForm never gets validated

codeshard opened this issue · comments

Greetings @nickw444:
I have a AD with Zentyal and I'm able to login using flask-ldap3-login, and using the configuration you suggested in the docs, I'm not able to reproduce #21, so, I've no idea why, 'cause ldap3 works perfectly with MS Windows AD.
Now, I'm facing a different problem, I'm getting this error:
TypeError: 'NoneType' object is not callable
Here is my configuration:

#: LDAP
        self.LDAP_HOST = '192.168.1.1'
        self.LDAP_PORT = 636
        self.LDAP_USE_SSL = True
        self.LDAP_READONLY = True
        self.LDAP_USER_OBJECT_FILTER = '(objectCategory=organizationalPerson)'
        self.LDAP_USER_SEARCH_SCOPE = 'SUBTREE'
        self.LDAP_SEARCH_FOR_GROUPS = True
        self.LDAP_GROUP_OBJECT_FILTER = '(objectClass=group)'
        self.LDAP_GROUP_SEARCH_SCOPE = 'SUBTREE'
        self.LDAP_GROUP_MEMBERS_ATTR = 'member'
        self.LDAP_BASE_DN = 'OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu'
        self.LDAP_BIND_USER_DN = 'CN=usuario,OU=Users,OU=Users_Servicios_Lin,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu'
        self.LDAP_BIND_USER_PASSWORD = 'f4ncyp4ssw0rd'
        self.LDAP_USER_LOGIN_ATTR = 'sAMAccountName'

And following step by step the docs, I wrote this view:

@users_blueprint.route('/', methods=['GET', 'POST'])
def login():
    form = LDAPLoginForm()
    if form.validate_on_submit():
        login_user(form.user)
        return redirect('/dashboard')
    return render_template('users/main.jinja2', title=r'Inicio de Sesión', form=form)

and in the template:

{% block content %}
    {{ get_flashed_messages() }}
    {{ form.errors }}
    <form method="POST">
        <label>Username{{ form.username() }}</label>
        <label>Password{{ form.password() }}</label>
        {{ form.submit() }}
        {{ form.hidden_tag() }}
    </form>
{% endblock %}

Here is some debug output:

20170622-17:04PM DEBUG: Validating LDAPLoginForm against LDAP
20170622-17:04PM DEBUG: Opening connection with bind user 'CN=usuario,OU=Users,OU=Users_Servicios_Lin,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu'
20170622-17:04PM DEBUG: Successfully bound to LDAP as 'CN=usuario,OU=Users,OU=Users_Servicios_Lin,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu' for search_bind method
20170622-17:04PM DEBUG: Performing an LDAP Search using filter '(&(objectCategory=organizationalPerson)(sAMAccountName=codeshard))', base 'OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu', and scope 'SUBTREE'
20170622-17:04PM DEBUG: Opening connection with bind user 'CN=Ozkar L. Garcell,OU=Users_Admins,OU=IT,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu'
20170622-17:04PM DEBUG: Directly binding a connection to a server with user:'CN=Ozkar L. Garcell,OU=Users_Admins,OU=IT,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu'
20170622-17:04PM DEBUG: Authentication was successful for user 'codeshard'
20170622-17:04PM DEBUG: Searching for groups for specific user with filter '(&(objectClass=group)(member=CN=Ozkar L. Garcell,OU=Users_Admins,OU=IT,OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu))' , base 'OU=HLG,DC=ad,DC=hlg,DC=cuba,DC=cu' and scope 'SUBTREE'
20170622-17:04PM DEBUG: Destroying connection at <0x7fc3ba969128>
20170622-17:04PM INFO: 127.0.0.1 - - [22/Jun/2017 17:04:17] "POST / HTTP/1.1" 500
(...)
File "/home/codeshard/.virtualenvs/flaskeable/lib/python3.5/site-packages/flask_ldap3_login/forms.py", line 44, in validate_ldap
    result.user_groups
TypeError: 'NoneType' object is not callable

I made a small debug and the result var have all the attrs, this part:

self.user = ldap_mgr._save_user(
                result.user_dn,
                result.user_id,
                result.user_info,
                result.user_groups
            )

So, I've no idea what's going on. Any help will be appreciated.
Best regards

Hey @codeshard with that small traceback, I am able to deduce that it's nothing to do with the result vars, but rather _save_user being None (hence None is not callable).

None is the initial value of this.

You should be able to resolve this issue by using the @manager.save_user decorator to provide a callback:

# 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

(source: basic application example)

In the end it was a conceptual error of mine, I declared a dictionary to store in memory the logged in users, but in the end I needed to persist users in a table in a database, so my function was looking for the dictionary and this dictionary doesn't exists.

This is how I implemented the functions:

from app import db
from app.models import User

@login_manager.user_loader
def load_user(user_id):
    try:
        return User.query.get(user_id)
    except:
        return None


@ldap_manager.save_user
def save_user(dn, username, data, memberships):
    if User.query.filter_by(username=username).first():
        user = User.query.filter_by(username=username).first()
    else:
        user = User(data['title'], data['department'], data['mail'], username, data['givenName'], data['sn'])
        db.session.add(user)
        db.session.commit()
    return user

where db is a SQLALchemy instance.

Thanks for your answers and great flask app btw!
I will close the issue.

Awesome, glad you got it sorted! 👍