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! 👍