Giter Site home page Giter Site logo

nickw444 / flask-ldap3-login Goto Github PK

View Code? Open in Web Editor NEW
72.0 7.0 38.0 658 KB

LDAP3 Logins for Flask/Flask-Login

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

License: MIT License

Python 100.00%
python flask ldap ldap-library python3 python2 flask-extensions hacktoberfest

flask-ldap3-login's Introduction

Flask-LDAP3-Login

image

image

Latest Version

Flask LDAP3 Login allows you to easily integrate your flask app with an LDAP directory. It can be used as an extension to Flask-Login and can even be used with Flask-Principal for permission and privilege management.

Flask LDAP3 Login uses the ldap3 library, and maintains compatibility with those versions of Python supported by upstream.

Flask LDAP3 Login Will:
  • Allow you to query whether or not a user's credentials are correct
  • Query the directory for users details
  • Query the directory for group details
  • Query the directory for users group memberships
  • Provide a contextual ldap_manager.connection object (ldap3.Connection) which can be used in any flask request context. Useful for writing your own more advanced queries.
Flask LDAP3 Login Wont:
  • Provide a login/logout mechanism. You need to provide this with something like flask-login
  • Provide any extension to the application's session. User tracking and group tracking should be done via flask-login and flask-principal

View the Full Documentation at ReadTheDocs

flask-ldap3-login's People

Contributors

andrewjroth avatar arugifa avatar cgroschupp avatar cjchand avatar dependabot[bot] avatar dlsteve avatar eliasj avatar gmacon avatar heman avatar hugovk avatar m-bach avatar mwielgoszewski avatar nickw444 avatar northwestwitch avatar nsmcan avatar oisins avatar veritasimo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

flask-ldap3-login's Issues

Exception initializing a second app

If you initialize LDAP3LoginManager on a second app after using the connection on the first app it raises an exception:

Code to reproduce:

from flask import Flask
from flask_ldap3_login import LDAP3LoginManager

manager = LDAP3LoginManager()

app1 = Flask("one")
app1.config["LDAP_HOST"] = "localhost"
print("init one")
manager.init_app(app1)
with app1.app_context():
    print("connection one")
    manager.connection

app2 = Flask("two")
app2.config["LDAP_HOST"] = "localhost"
print("init two")
manager.init_app(app2)

output (on Python 3.7.0):

init one
connection one
init two
Traceback (most recent call last):
  File "repro.py", line 17, in <module>
    manager.init_app(app2)
  File ".../site-packages/flask_ldap3_login/__init__.py", line 77, in init_app
    self._server_pool.remove(s)
  File ".../site-packages/ldap3/core/pooling.py", line 285, in remove
    self.pool_states[connection].refresh()
  File ".../site-packages/ldap3/core/pooling.py", line 67, in refresh
    self.last_used_server = randint(0, len(self.servers) - 1)
  File ".../random.py", line 222, in randint
    return self.randrange(a, b+1)
  File ".../random.py", line 200, in randrange
    raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width))
ValueError: empty range for randrange() (0,0, 0)

It looks like the fix here is to store the necessary state on the app context instead of on LDAP3LoginManager.

I'll try to find some time soon to put together a PR for this; please let me know if you have any comments.

Edit: After discussing with the other engineers on my project, we've decided to drop the dependency on Flask-LDAP3-Login, so I likely won't be trying to find time to open a PR for this any more.

Users with different "sub OUs" not able to log in

I want two users to log in from 2 different sub OUs.

For example if I want both these 2 to authenticate
user1 dn: OU=Users,OU=subgroup1,OU=group1,OU=Users
user2 dn: OU=Users,OU=subgroup2,OU=group1,OU=Users

it doesnt work because I need the entire user DN in the config.
e.g config['LDAP_USER_DN'] = "OU=Users,OU=subgroup1,OU=group1,OU=Users"

Any way to work around this or perhaps fix it in a later patch?

MS Active Directory user credential validation failure

User credential validation against MS Active Directory (via NTLM) appears to always fail. From performing an element of troubleshooting, the bind is successful and I can see that the initial search for the user (needing to be validated) succeeds. However, the credential validation always fails with the following error:

No handlers could be found for logger "flask_ldap3_login"
AuthenticationResponseStatus.fail

Below is the configuration that is being used in the test script.


from flask_ldap3_login import LDAP3LoginManager

config = dict()

# Setup LDAP Configuration Variables. Change these to your own settings.
# All configuration directives can be found in the documentation.

# Hostname of your LDAP Server
config['LDAP_HOST'] = 'w.x.y.z'

# Base DN of your directory
config['LDAP_BASE_DN'] = 'dc=domain,dc=local'

config['LDAP_USER_DN'] = 'ou=OU2,ou=OU1'

# The RDN attribute for your user schema on LDAP
config['LDAP_USER_RDN_ATTR'] = 'CN'

# The Username to bind to LDAP with
config['LDAP_BIND_USER_DN'] = 'domain.local\\bind-username'

# Declares what ldap attribute corresponds to the username passed to any login method when performing a bind. 
config['LDAP_USER_LOGIN_ATTR'] = 'cn'

# Specifies what object filter to apply when searching for users.
config['LDAP_USER_OBJECT_FILTER'] = '(objectclass=user)'

# The Password to bind to LDAP with
config['LDAP_BIND_USER_PASSWORD'] = 'bind-password'

#Specifies what scope to search in when searching for a specific user.
config['LDAP_USER_SEARCH_SCOPE'] = 'SUBTREE'

#Specifies the LDAP bind type to use when binding to LDAP.
config['LDAP_BIND_AUTHENTICATION_TYPE'] = 'NTLM'

# Setup a LDAP3 Login Manager.
ldap_manager = LDAP3LoginManager()

# Init the mamager with the config since we aren't using an app
ldap_manager.init_config(config)

# Check if the credentials are correct
response = ldap_manager.authenticate('test-user', 'test-user-password')
print(response.status)

Drop support for Python 2.7

Upstream support for Python 2 will end on January 1, 2020, about four months from now.

Downloads from PyPI of flask-ldap3-login in the last 30 days:

python_version download_count
3.7 1,132
3.6 942
3.5 914
2.7 541
3.4 123
Total 3,652

AttributeError: module 'ldap3' has no attribute 'POOLING_STRATEGY_FIRST'

File ".....\Python\Python35\lib\site-packages\flask_ldap3_login\__init__.py", line 55, in __init__ ldap3.POOLING_STRATEGY_FIRST, AttributeError: module 'ldap3' has no attribute 'POOLING_STRATEGY_FIRST'
It looks like POOLING_STRATEGY_FIRST has been changed to FIRST in ldap3

This happens when initializing LDAP3LoginManager

app = Flask(__name__) ldap_manager = LDAP3LoginManager(app)

Use Fake LDAP in dev

First thanks for this package (the only flask ldap package that worked for me).

I was wondering if there is a way to use a Fake LDAP for testing authentication in Development mode ?

When implementing LDAP roles / groups, it gets trickier to test when authenticating against a real LDAP (need to create fake user and assign different roles / group and test manually.

I saw that this fake LDAP is present in the tests, maybe we could enable it when DEBUG is set to True in the Flask app config ?

Thanks !

A message for a misconfiguration

following a misconfiguration, I found when binding with the AD, the connection was successfully established,
but often when doing the search, it found that the type was not correct and it jumps and destroys the connection.
But he didn't tell me anything, what message can be put on it for a better guide?

DEBUG:flask_ldap3_login:Opening connection with bind user 'user'
DEBUG:flask_ldap3_login:Successfully bound to LDAP as 'user' for search_bind method
DEBUG:flask_ldap3_login:Performing an LDAP Search using filter '(&(objectclass=user)(sAMAccountName=user))', base 'dc=domain,dc=com', and scope 'SUBTREE'
DEBUG:flask_ldap3_login:Destroying connection at <0x7f8e95d9fb38>

'type': 'searchResRef'

Validation

AttributeError: module 'wtforms.validators' has no attribute 'Required

Hi I'm pretty new in python dev, but i got this error when trying to use the module.
i am using the code i get from the website.
it used to work before, but it stopped working.
i am on python 3.10 at the moment.

sorry if this is a noob question.

Traceback (most recent call last):
  File "/Users/drazali/dev/VIATOR/pythonProject/main.py", line 5, in <module>
    from flask_ldap3_login.forms import LDAPLoginForm
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/flask_ldap3_login/forms.py", line 15, in <module>
    class LDAPLoginForm(FlaskForm):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/flask_ldap3_login/forms.py", line 26, in LDAPLoginForm
    username = wtforms.StringField('Username', validators=[validators.Required()])
AttributeError: module 'wtforms.validators' has no attribute 'Required'

user data attributes are lists sometimes

I have code that extracts data from the user like so...

fname = data["givenName"]

this usually works fine and the value is a string.

Occasionally, the value is a list with a single string value.

This doesn't seem to be related to the particular user because it happens to my own accounts sometimes.

Not sure if this would be related to flask-ldap3-login or if it would be ldap3.

LDAP and local accounts

I am using the module in combination with the sqlalchemy module. As far as I can see it is not possible to have LDAP as well as local users. Is it planned or am I missing something?

get_user_groups() malforms CN causing false query results and empty user_groups

Issue

Long story short, I'm using LDAP3LoginManager.authenticate() to authenticate users. Bind, user search, and user authentication all work successfully, but the resulting user_groups is an empty list.

The issue seems to stem from this line:

safe_dn = ldap3.utils.conv.escape_filter_chars(dn)

Verification

Logs

Directly binding a connection to a server with user:'CN=LastName\, FirstName,...'
Authentication was successful for user 'username'
Searching for groups for specific user with filter '(&(objectclass=group)(member=CN=LastName\5c, FirstName...)'

Troubleshooting

  • Opened a python shell importing python-ldap3
  • Tested search query using the filter provided by flask_ldap3_login logs
    • This failed to return any results
  • Tested search query removing the 5c
    • Success

Returned group memberships is empty

I have the ldap database:

version: 1

dn: dc=br
objectClass: top
objectClass: dcObject
objectClass: organization
dc: br
o: SCS

dn: dc=com,dc=br
objectClass: domain
objectClass: top
dc: com

dn: cn=admin,dc=br
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

dn: dc=vfd,dc=com,dc=br
objectClass: domain
objectClass: top
dc: vfd

dn: ou=Groups,dc=vfd,dc=com,dc=br
objectClass: organizationalUnit
objectClass: top
ou: Groups

dn: ou=People,dc=vfd,dc=com,dc=br
objectClass: organizationalUnit
objectClass: top
ou: People

dn: cn=owncloud,ou=Groups,dc=vfd,dc=com,dc=br
objectClass: groupOfUniqueNames
objectClass: top
cn: owncloud
uniqueMember: uid=psycho,ou=People,dc=vfd,dc=com,dc=br

dn: uid=psycho,ou=People,dc=vfd,dc=com,dc=br
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: shadowAccount
objectClass: mailAccount
objectClass: posixAccount
objectClass: top
cn: Baltazar
gidNumber: 1000
homeDirectory: /home/psycho
sn: Tavares Vanderlei
uid: psycho
uidNumber: 1000
loginShell: /bin/bash

And the following config:

app=create_app(config={
	"SQLALCHEMY_DATABASE_URI" : 'sqlite:///test.db',
	"SECRET_KEY" : 'XXXXXXXXXXXXXXXXXX',
	"DEBUG" : True,
	"LDAP_HOST" : 'ldaps://localhost',
	# Base DN of your directory
	"LDAP_BASE_DN" : 'dc=br',
	# Users DN to be prepended to the Base DN
	"LDAP_USER_DN" : 'ou=People,dc=vfd,dc=com',
	# Groups DN to be prepended to the Base DN
	"LDAP_GROUP_DN" : 'ou=Groups,dc=vfd,dc=com',
	"LDAP_GROUP_OBJECT_FILTER" : '(objectClass=groupOfUniqueNames)',
	# The Username to bind to LDAP with
	"LDAP_BIND_USER_DN" : None,
	# The Password to bind to LDAP with
	"LDAP_BIND_USER_PASSWORD" : None,
	"LDAP_USER_SEARCH_SCOPE" : "SUBTREE",
	"LDAP_GROUP_SEARCH_SCOPE" : "SUBTREE",
	"LDAP_SEARCH_FOR_GROUPS" : True,
	"LDAP_GROUP_MEMBERS_ATTR" : "uniqueMember"
})

When I use the Flask-Ldap3-Login code:

@ldap_manager.save_user
def save_user(dn, username, data, memberships=None):
	print(memberships)
	...

The line print(memberships) print only []. The list had to contain the groups that user belonged, or I did not get it right?

The code for groups is working, i'm doing something wrong or maybe something more?

I need this to implement the flask-principal(or something like this). I'm holding myself to not use ldap's api directly. Is possible to help me in this? More people can have this error and need this. If someone help, i can generate the test code to serve as example.

User is found in AD OU Subtree but is not logged in - No AD/LDAP error

I am trying to authenticate users that are within an OU several levels deep in AD. Other users are inside a security group. LDAP search returns 'success' (I take a traffic capture and I see that the user is found inside the OU and security group); yet, the user does not get logged in. Could this be a bug or is my implementation wrong? Here's part of my config:

app.config['LDAP_USER_RDN_ATTR'] = 'cn'
app.config['LDAP_USER_LOGIN_ATTR'] = 'sAMAccountName'
app.config['LDAP_BASE_DN'] = 'DC=mydomoain,DC=com'
app.config['LDAP_GROUP_DN'] = 'OU=theou'
app.config['LDAP_USER_DN'] = 'OU=theou'
app.config['LDAP_USER_SEARCH_SCOPE'] = 'SUBTREE'

@login_manager.user_loader
def load_user(id):
    if id in users:
        return users[id]
    return None

@ldap_manager.save_user
def save_user(dn, username, data, memberships):
    user = User(dn, username, data)
    users[dn] = user
    return user

@app.route("/login", methods=['GET', 'POST'])
def login():
    form = LDAPLoginForm()
    if form.validate_on_submit():
        flash('Welcome, ' + form.username.data + '!', 'success')
        login_user(form.user)  # Tell flask-login to log them in.
        return redirect(url_for('myotherpage'))
    return render_template('login.html', form=form)

authentication and verify user part of ldap group

I am using APIs to verify credentials and also make sure user is part of either of two ldap groups to access the application. I enabled debugging and able to verify that user is authenticated successfully. However, when it is searching for the groups, I see the following and retrieves hundreds of users (maybe all users)

------------------
Searching for groups for specific user with filter '(&(objectclass=group)(member=CN=CHINNI,OU=Information_Services,OU=KMC,DC=Kids,DC=med))' , base 'cn=users,DC=Kids,DC=med' and scope 'LEVEL'
DEBUG:flask_ldap3_login:Searching for groups for specific user with filter '(&(objectclass=group)(member=CN=CHINNI,OU=Information_Services,OU=KMC,DC=Kids,DC=med))' , base 'cn=users,DC=Kids,DC=med' and scope 'LEVEL'
-----------------------------------------

When I print in save_user(dn, username, data, memberships), the memberships contains hundreds of users which I can't even see all of them as it is getting cutoff. I thought I will see groups (10 or so) that are user is part of. When I do same following filter in AD, I see only group names

(member=CN=CHINNI,OU=Information_Services,OU=KMC,DC=Kids,DC=med))' , base 'cn=users,DC=Kids,DC=med' and scope 'LEVEL'
-----------------

Appreciate help to understand what is this memberships means and how do I get only group names that user belongs so that I can iterate to make sure he is part of proper group. System freezes as it is getting all users.

Edited by @gmacon 2020-02-24: Literal formatting for log outputs.

Login user based on group membership

Hi there,

Just wondering how i would go about allowing login provided user is a member of a specific group? I've tried different filters but during testing it still logs me in even though i'm not a member of the group.

Thanks!

Only cn attribute is working

I'm recording this as an issue as I do not know where else to turn.

For context, I'm coding this against a Windows 2012 R2 Active Directory server. I am also using the sample application to get it working, before implementing it into my application.

I have this working as long as I set LDAP_USER_RDN_ATTR and LDAP_USER_LOGIN_ATTR to 'cn'. If I set it to 'sAMAccountName', then I only ever get 'Invalid Username/Password.

Any suggestions or recommendations on how I can get this code to recognize anything else other than the 'cn' attribute in AD?

Thank you in advance!!

Cannot integrate OpenLDAP

We currently swapped providers from MS Active Directory to OpenLDAP and now I cannot get it to connect. Everything is the same from the hierarchy to the creds being used to the server name.

Where can I find documentation on integration with OpenLDAP or is it not currently possible?

Inappropriate setup of Tls context within init_app() for default server.

Hi @HeMan ! Just wanted to highlight the following observation. In current version of the app there's an option to add LDAP server during plugin initialization if LDAP_ADD_SERVER is set to true. However, I was unable to use this shortcut because there's no way to pass Tls context for this default server. The most weird bit is the fact that it init_app passes LDAP_USE_SSL value, which forces LDAP to use certificate, but it can't be provided :) So it's catch-22.

I have to populate Server pool manually AFTER I create a Tls context with certificate which I then pass during Server object creation. I believe this can be easily fixed by introducing additional config variable, such as LDAP_SSL_CERT which will point to the file of the certificate to use when both LDAP_ADD_SERVER and LDAP_USE_SSL are set to True

So instead of this

        if app.config["LDAP_ADD_SERVER"]:
            self.add_server(
                hostname=app.config["LDAP_HOST"],
                port=app.config["LDAP_PORT"],
                use_ssl=app.config["LDAP_USE_SSL"],
                app=app,
            )

Do this

        if app.config["LDAP_ADD_SERVER"]:
            ldap3_tls_cts = None

            if app.config["LDAP_USE_SSL"] and app.config["LDAP_SSL_CERT"]:
                ldap3_tls_ctx = Tls(
                    validate=CERT_REQUIRED,
                    version=PROTOCOL_TLSv1,
                    ca_certs_file=app.config.get('LDAP_SSL_CERT'),
                    valid_names=app.config.get('LDAP_VALID_NAMES')
                )

            self.add_server(
                hostname=app.config["LDAP_HOST"],
                port=app.config["LDAP_PORT"],
                use_ssl=app.config["LDAP_USE_SSL"],
                app=app,
                tls_ctx=ldap3_tls_ctx
            )

I also use LDAP_VALID_NAMES to define a list of server's names as defined in the certificate in case there's mismatch
This one works like a charm for me, but of course I have to do this outside of your module.

If you agree with this, I can incorporate this into code as a pull request

Add license information to setup.py

I wanted to help add licensing information in setup.py as follows.

    license="MIT",
    classifiers=[
        "Intended Audience :: Developers",
        "Programming Language :: Python",
        "Environment :: Web Environment",
        "Framework :: Flask",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.5",
        "Programming Language :: Python :: 3.6",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3 :: Only",
    ],

It would help automatically parse for the license of this library.
Thank you.

DeprecationWarning: Required is going away in WTForms 3.0, use DataRequired

Hi,

After updating the Flask / Flask-WTF and WTForms i receive the following warning

2019-10-08 15:28:30,129 - INFO -  * Restarting with stat MainThread
/usr/local/lib/python3.7/site-packages/flask_wtf/recaptcha/widgets.py:5: DeprecationWarning: The import 'werkzeug.url_encode' is deprecated and will be removed in Werkzeug 1.0. Use 'from werkzeug.urls import url_encode' instead.
  from werkzeug import url_encode
/usr/local/lib/python3.7/site-packages/flask_ldap3_login/forms.py:26: DeprecationWarning: Required is going away in WTForms 3.0, use DataRequired
  username = wtforms.StringField('Username', validators=[validators.Required()])

If you think to fix it and to release a new build.

One user can't Authenticate; others can - Malformed Filter error

Using "flask-ldap3-login 0.9.14". All users who are members of the specified AD group are logged into my application except for those that have "()" in their first name in AD.

This is my configuration:

LDAP_USER_RDN_ATTR = 'cn'
LDAP_USER_LOGIN_ATTR = 'sAMAccountName'
LDAP_BASE_DN = 'DC=mydomain,DC=com'
LDAP_REQUIRED_GROUP = 'ou=helpdesk,dc=mydomain,dc=com'
LDAP_USER_SEARCH_SCOPE = 'SUBTREE'

Here's what I see in the logs:

UNSUCCESSFUL LOGIN

DEBUG:root:Validating LDAPLoginForm against LDAP
DEBUG:flask_ldap3_login:Opening connection with bind user '[email protected]'
DEBUG:flask_ldap3_login:Successfully bound to LDAP as '[email protected]' for search_bind method
DEBUG:flask_ldap3_login:Performing an LDAP Search using filter '(&(objectclass=person)(sAMAccountName=ebadu))', base 'DC=mydomain,DC=com', and scope 'SUBTREE'
DEBUG:flask_ldap3_login:Opening connection with bind user 'CN=Badu\, Ericka (EB),OU=HELPDESK,DC=mydomain,DC=com'
DEBUG:flask_ldap3_login:Directly binding a connection to a server with user:'CN=Badu\, ericka (EB),OU=HELPDESK,DC=mydomain,DC=com'
DEBUG:flask_ldap3_login:Authentication was successful for user 'ebadu'
DEBUG:flask_ldap3_login:Searching for groups for specific user with filter '(&(objectclass=group)(uniqueMember=CN=Badu\, Ericka (EB),OU=HELPDESK,DC=mydomain,DC=com))' , base 'DC=mydomain,DC=com' and scope 'LEVEL'
ERROR:flask_ldap3_login:malformed filter
DEBUG:flask_ldap3_login:Destroying connection at <0x7f8629604c50>
DEBUG:flask_ldap3_login:Destroying connection at <0x7f8628eabf98>

SUCCESSFUL LOGIN

DEBUG:root:Validating LDAPLoginForm against LDAP
DEBUG:flask_ldap3_login:Opening connection with bind user '[email protected]'
DEBUG:flask_ldap3_login:Successfully bound to LDAP as '[email protected]' for search_bind method
DEBUG:flask_ldap3_login:Performing an LDAP Search using filter '(&(objectclass=person)(sAMAccountName=mpeters))', base 'DC=mydomain,DC=com', and scope 'SUBTREE'
DEBUG:flask_ldap3_login:Opening connection with bind user 'CN=Peters\, Mike,OU=HELPDESK,DC=mydomain,DC=com'
DEBUG:flask_ldap3_login:Directly binding a connection to a server with user:'CN=Peters\, Mike,OU=HELPDESK,DC=mydomain,DC=com'
DEBUG:flask_ldap3_login:Authentication was successful for user 'mpeters'
DEBUG:flask_ldap3_login:Searching for groups for specific user with filter '(&(objectclass=group)(uniqueMember=CN=Peters\, Mike,OU=HELPDESK,DC=mydomain,DC=com))' , base 'DC=mydomain,DC=com' and scope 'LEVEL'
DEBUG:flask_ldap3_login:Destroying connection at <0x7f8629683828>
DEBUG:flask_ldap3_login:Destroying connection at <0x7f8628e91048>

Asked in SO https://stackoverflow.com/questions/53068554/ad-user-cannot-loging-to-flask-app-ldap3

Changing port for configuration

Nick - first, thanks for writing this. LDAP configuration is driving me nuts....

My school has limited resources and so IT is only able to help me so much. I have tried to use your LDAP3-LoginManager with no luck so far. I believe I have all the setting correct, but I cannot see a config dict option for changing/setting the port. Our school LDAP port is 636, so I do not know if that is the standard port or a different port than normal. Is there an LDAP_Port option for the config dict?

Thanks,

James Taylor

Unable to differentiate between broken connection and user not found

Because the ldap_manager.authenticate('username', 'password') method only returns success or fail, the application has no way of knowing if the issue is on the network or the user entered the wrong credentials. This is because all exceptions are caught on line 440 in __init__.py:

   try:
       connection.bind()
       debug("Successfully bound to LDAP as '{0}' for search_bind method".format(
               self.config.get('LDAP_BIND_USER_DN') or 'Anonymous'
       ))
   except Exception as e:  # <--- Here
       self.destroy_connection(connection)
       log.error(e)
       return AuthenticationResponse()

Would it be possible to reraise these exceptions or at least include them in the AuthenticationResponse object? Or am I just missing a way to get this information (except for the logs)?

Active Directory connection not possible

I am testing the connection to a Samba based AD. SIMPLE auth mechanism is disabled by default by samba.

When I try to use SASL, I receive an error, because no mechanism ('sasl_mechanism=') is given to the Connection object of the ldap3 module.

Am I doing something wrong? What is the best way to connect to an Active Directory Server?

Question - is START-TLS supported by flask-ldap3-login?

I tried today to connect to my ldap server with START-TLS and i got an "unable to open socket" Error.

flask_ldap3_login.authenticate_direct_bind +406 - ERROR - ('unable to open socket', [(LDAPSocketOpenError("('socket ssl wrapping error: EOF occurred in violation of protocol (_ssl.c:600)',)",)

The ldap Server provides only PLAIN ldap oder START-TLS ldap via Port 389. The ldaps Port 636 is not in use.

I used the Quickinstall TLS Version from the documention, but without luck.

ldap3 can connect to START-TLS based Server. It seems that your implementation is full-encrypted and didnt support START-TLS.

import ssl
from ldap3 import Server, Connection, Tls, ALL
from ldap3 import AUTO_BIND_NO_TLS, AUTO_BIND_TLS_BEFORE_BIND

host = 'someldapserver.with.starttls'
server = Server(host, port=389, get_info=ALL)

conn = Connection(server, auto_bind=True)
print(server.info)
print("Plain 1\n",conn)
conn.start_tls()
print("START-TLS 2\n", conn)
conn.unbind()

tls_configuration = Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1_2)
server = Server(host, port=389, use_ssl=False, tls=tls_configuration, get_info=ALL)
conn = Connection(server, auto_bind=False)
conn.open()
conn.start_tls()
# print(server.info)
print("START-TLS again\n",conn)
conn.unbind()
python testtls.py 
DSA info (from DSE):
  Supported LDAP versions: 3
  Naming contexts: 
    ou=somewhere,o=something,c=somedomain
    cn=log
  Supported controls: 
    1.2.826.0.1.3344810.2.3 - Matched Values - Control - RFC3876
    1.2.840.113556.1.4.1339 - Domain scope - Control - MICROSOFT
    1.2.840.113556.1.4.1340 - Search options - Control - MICROSOFT
    1.2.840.113556.1.4.1413 - Permissive modify - Control - MICROSOFT
    1.2.840.113556.1.4.319 - LDAP Simple Paged Results - Control - RFC2696
    1.2.840.113556.1.4.805 - Tree delete - Control - MICROSOFT
    1.3.6.1.1.12 - Assertion - Control - RFC4528
    1.3.6.1.1.13.1 - LDAP Pre-read - Control - RFC4527
    1.3.6.1.1.13.2 - LDAP Post-read - Control - RFC4527
    1.3.6.1.1.22 - LDAP Don't Use Copy - Control - RFC6171
    1.3.6.1.4.1.21008.108.63.1
    1.3.6.1.4.1.42.2.27.8.5.1 - Password policy - Control - IETF DRAFT behera-ldap-password-policy
    1.3.6.1.4.1.4203.1.10.1 - Subentries - Control - RFC3672
    1.3.6.1.4.1.4203.1.9.1.1 - LDAP content synchronization - Control - RFC4533
    1.3.6.1.4.1.4203.666.11.3
    1.3.6.1.4.1.4203.666.11.6.3
    1.3.6.1.4.1.4203.666.5.12
    1.3.6.1.4.1.4203.666.5.14
    1.3.6.1.4.1.4203.666.5.2
    2.16.840.1.113730.3.4.18 - Proxy Authorization Control - Control - RFC6171
    2.16.840.1.113730.3.4.2 - ManageDsaIT - Control - RFC3296
  Supported extensions: 
    1.3.6.1.1.8 - Cancel Operation - Extension - RFC3909
    1.3.6.1.4.1.1466.101.119.1 - Dynamic Refresh - Extension - RFC2589
    1.3.6.1.4.1.1466.20037 - StartTLS - Extension - RFC4511-RFC4513
    1.3.6.1.4.1.4203.1.11.1 - Modify Password - Extension - RFC3062
    1.3.6.1.4.1.4203.1.11.3 - Who am I - Extension - RFC4532
    1.3.6.1.4.1.4203.666.11.6.1
  Supported features: 
    1.3.6.1.1.14 - Modify-Increment - Feature - RFC4525
    1.3.6.1.4.1.4203.1.5.1 - All Op Attrs - Feature - RFC3673
    1.3.6.1.4.1.4203.1.5.2 - OC AD Lists - Feature - RFC4529
    1.3.6.1.4.1.4203.1.5.3 - True/False filters - Feature - RFC4526
    1.3.6.1.4.1.4203.1.5.4 - Language Tag Options - Feature - RFC3866
    1.3.6.1.4.1.4203.1.5.5 - language Range Options - Feature - RFC3866
  Supported SASL mechanisms: 
    DIGEST-MD5, CRAM-MD5
  Schema entry: 
    cn=Subschema
Other:
  entryDN: 

  structuralObjectClass: 
OpenLDAProotDSE
  configContext: 
cn=config
  objectClass: 
    top
    OpenLDAProotDSE
  monitorContext: 
cn=Monitor

Plain 1
 ldap://someldapserver.with.starttls:389 - cleartext - user: None - not lazy - bound - open - <local: 10.xx.xx.yy:35806 - remote: 10.xx.xx.xx:389> - tls not started - listening - SyncStrategy - internal decoder
START-TLS 2
 ldap://someldapserver.with.starttls:389 - cleartext - user: None - not lazy - bound - open - <local: 10.xx.xx.yy:35806 - remote: 10.xx.xx.xx:389> - tls started - listening - SyncStrategy - internal decoder
START-TLS again
 ldap://someldapserver.with.starttls:389 - cleartext - user: None - not lazy - unbound - open - <local: 10.xx.xx.yy:35808 - remote: 10.xx.xx.xx:389> - tls started - listening - SyncStrategy - internal decoder

result.user_groups TypeError: 'NoneType' object is not callable

Hi,

The authentication itself works fine, but the application appears to be failing down the road.

File "/foo/bar/lib/python3.6/site-packages/flask_ldap3_login/forms.py", line 45, in validate_ldap
result.user_groups
TypeError: 'NoneType' object is not callable

In order to troubleshoot this, I created the following script:

from flask_ldap3_login import LDAP3LoginManager

config = dict()

user = 'myuser'
password = 'mypassword'

config['LDAP_HOST'] = 'ldap.corp.dummy.local'
config['LDAP_BASE_DN'] = 'DC=corp,DC=dummy,DC=local'
config['LDAP_USER_DN'] = 'OU=Standard,OU=Users,OU=BR,OU=corp'
config['LDAP_GROUP_DN'] = 'OU=Corp-Groups,OU=Roles,OU=Groups,OU=BR,OU=corp'
config['LDAP_USER_RDN_ATTR'] = 'cn'
config['LDAP_USER_LOGIN_ATTR'] = 'sAMAccountName'
config['LDAP_BIND_USER_DN'] = 'CN=BindAccount,OU=Service,OU=Users,OU=BR,OU=corp,DC=corp,DC=dummy,DC=local'
config['LDAP_BIND_USER_PASSWORD'] = '<bind password>'
ldap_manager = LDAP3LoginManager()
ldap_manager.init_config(config)

response = ldap_manager.authenticate(user, password)
print(response.status, response.user_groups, len(response.user_info['memberOf']))

When I run it, it returns the following:

AuthenticationResponseStatus.success [] 40

That is, the authentication is successful, but response.user_groups is empty.
response.user_info returns loads of info from the AD, and the groups are contained in 'memberOf' within it.
How do I fix this? Is there any way to tell it where in user info to search for user groups for? Or is this something else?

Best regards,
Albert.

Authenticate flask app against multiple AD's

I'm new to LDAP. I've written a FLASK app that I'm trying to roll out at work. One of the requirements that the IT dept has stipulated is that I authenticate users via AD integration. I'm trying out flask-ldap3-login currently.

Do you have any advice on how I might authenticate against multiple AD's? We have people from different companies who may need to access the FLASK application. This wasn't an issue when working with a user table managed in the app itself.

By the way, I realise that this may not be the appropriate forum for this question but there seems to be some experts here who may be able to help!

Documentation missing in ReadTheDocs

Hello Nick,

I get a 404 code back when I try to reach the ReadTheDocs page for the flask-ldap3-login.

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

You've found something that doesn't exist.

We're sorry, we don't know what you're looking for


        \          SORRY            /
         \                         /
          \    This page does     /
           ]   not exist yet.    [    ,'|
           ]                     [   /  |
           ]___               ___[ ,'   |
           ]  ]\             /[  [ |:   |
           ]  ] \           / [  [ |:   |
           ]  ]  ]         [  [  [ |:   |
           ]  ]  ]__     __[  [  [ |:   |
           ]  ]  ] ]\ _ /[ [  [  [ |:   |
           ]  ]  ] ] (#) [ [  [  [ :===='
           ]  ]  ]_].nHn.[_[  [  [
           ]  ]  ]  HHHHH. [  [  [
           ]  ] /   `HH("N  \ [  [
           ]__]/     HHH  "  \[__[
           ]         NNN         [
           ]         N/"         [
           ]         N H         [
          /          N            \
         /           q,            \
        /                           \

Regards,
Xavier

TypeError: 'NoneType' object is not callable for result.user_groups

Hi, I have a flask project configured with multiple blueprints and we are working to integrate the project with this module. We are receiving the below error

DEBUG:root:Validating LDAPLoginForm against LDAP
DEBUG:flask_ldap3_login:Opening connection with bind user '...'
DEBUG:flask_ldap3_login:Authentication was successful for user '...'
DEBUG:flask_ldap3_login:Destroying connection at <0x10f48ff98>
INFO:werkzeug:127.0.0.1 - - [15/Mar/2019 17:12:12] "POST /login HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/ciobancaiv2/PycharmProjects/ThePortal/app/auth/views.py", line 98, in login
    if form.validate_on_submit():
  File "/usr/local/lib/python3.7/site-packages/flask_wtf/form.py", line 101, in validate_on_submit
    return self.is_submitted() and self.validate()
  File "/usr/local/lib/python3.7/site-packages/flask_ldap3_login/forms.py", line 69, in validate
    return self.validate_ldap()
  File "/usr/local/lib/python3.7/site-packages/flask_ldap3_login/forms.py", line 45, in validate_ldap
    result.user_groups
TypeError: 'NoneType' object is not callable

Below is the configuration for ldap
# Ldap
LDAP_HOST = 'ldap-host'
LDAP_BASE_DN = 'dc=com'
LDAP_USER_DN = 'ou=People'
LDAP_GROUP_DN = 'ou=Groups'
LDAP_BIND_USER_DN = 'secret'
LDAP_BIND_USER_PASSWORD = 'secret'
LDAP_USE_SSL = True
LDAP_PORT = 636
LDAP_GROUP_OBJECT_FILTER = '(objectclass=groupOfUniqueNames)'
LDAP_GROUP_SEARCH_SCOPE = 'SUBTREE'

From the logs we can see the user is authenticated but for some reason the group is empty, is there any way to ignore this ?

AttributeError when login form does not validate.

I get the following error when a user tries to log in with invalid credentials:

ERROR:flask.app:Exception on /api/auth/login [POST]
Traceback (most recent call last):
    File "/var/www/site/backend/auth/api.py", line 42, in post
        if form.validate_ldap():
    File "/var/www/site/venv/lib/python3.6/site-packages/flask_ldap3_login/forms.py", line 51, in validate_ldap
        self.username.errors.append('Invalid Username/Password.')
AttributeError: 'tuple' object has no attribute 'append'

So something might have changed in a WTForms update to make the errors object a tuple?

I'm using:

  • Python 3.6
  • flask-ldap3-login 0.9.16
  • WTForms 2.2.1

get_user_groups() iterates over connection.response instead of connection.entries

I'm trying to authenticate against Active Directory, but when the search completes, connection.response is iterated over instead of connection.entries. Unfortunately, AD (or maybe just my administrator?) appears to return some cruft in connection.response which causes the logic into an exception, and fails to authenticate anyone. My connection.response looks like this:

{'type': 'searchResEntry', 'raw_attributes': {}, 'dn': ..., 'attributes': {}}
{'type': 'searchResEntry', 'raw_attributes': {}, 'dn': ..., 'attributes': {}}
{'type': 'searchResEntry', 'raw_attributes': {}, 'dn': ..., 'attributes': {}}
{'uri': ["b'ldap://ForestDnsZones...'"], 'type': 'searchResRef'}
{'uri': ["b'ldap://DomainDnsZones...'"], 'type': 'searchResRef'}

Obviously, the last two items fail during the iteration because they have no attributes key, and even if they did, no dn key. Connection.entries just has the groups.

At the moment, I'm working around this by not fetching groups, but that's a problem long-term.

It looks like something close to PR #5 is needed here. Or Is there some other way I should specify my search? Can you add a check to see if there is an attributes key before referencing it? Please advise.

get_object() throws a KeyError exception when user not found

This issue only happens whenever I want to user get_user_info_for_username() and search applies to Base DN only (i.e. User DN is None). The way our AD is structured is there are following elements at its root

  • DC=domain,DC=com
    all user and group OUs/CNs are here
    • OU=Global Users
    • OU=Privileged Users
    • etc
  • CN=Configuration,DC=domain,DC=com
  • CN=Schema,CN=Configuration,DC=domain,DC=com
  • DC=ForestDnsZones,DC=domain,DC=com
  • DC=DomainDnsZones,DC=domain,DC=com

Unfortunately, if I use get_user_info_for_username(username) it throws the following error:

  File "./app/forms.py", line 159, in __call__
    portalUser = ldap3.get_user_info_for_username(field.data)
  File "/home/admin/venv/byod-management/lib/python3.7/site-packages/flask_ldap3_login/__init__.py", line 639, in get_user_info_for_username
    _connection=_connection,
  File "/home/admin/venv/byod-management/lib/python3.7/site-packages/flask_ldap3_login/__init__.py", line 702, in get_object
    data = connection.response[0]['attributes']
KeyError: 'attributes'

I had to modify source code of get_object() as per below to get some debug data:

        log.error(dn)
        log.error(filter)
        log.error(attributes)

        data = None
        if len(connection.response) > 0:
            log.error(connection.response)
            data = connection.response[0]['attributes']

It returned the following

ERROR:flask_ldap3_login:DC=domain,DC=com
ERROR:flask_ldap3_login:(&(sAMAccountName=asdasd)(objectclass=person))
ERROR:flask_ldap3_login:*
ERROR:flask_ldap3_login:[{'uri': ['ldap://DomainDnsZones.domain.com/DC=DomainDnsZones,DC=domain,DC=com'], 'type': 'searchResRef'}, {'uri': ['ldap://ForestDnsZones.domain.com/DC=ForestDnsZones,DC=domain,DC=com'], 'type': 'searchResRef'}, {'uri': ['ldap://domain.com/CN=Configuration,DC=domain,DC=com'], 'type': 'searchResRef'}]

So, even though user does not exist under DC=domain,DC=com, LDAP plugin searches through parallel structures and returns a list as seen above. Because get_object() only checks for len(connection.response) > 0, this results into condition as if user was found. Last line in the code then raises KeyError exception because first item (in fact all those in the response) has no 'attributes' key in its list.

Would you be so kind to advise if I have to apply an alternative approach? At the moment I ended up capturing this exception in my code, but it doesn't seem CLEAN. This exception is due to Flask-LDAP3-Login not processing the data properly, imho.

ERROR:flask_ldap3_login:invalid class in objectClass attribute: group

Hello! I set up a simple project with authorization on flask. First of all, to test connectivity with LDAP, I try the Basic Application from a resource: https://flask-ldap3-login.readthedocs.io/en/latest/quick_start.html
My LDAP is 100% working. After requesting the Basic Application to the LDAP server, I see that the LDAP server returns "success", but flask gives the error.

Please help me where and how to see what LDAP returns to me and how to solve the problem?

Error:

 * Serving Flask app "run_auth_test" (lazy loading)
 * Environment: production
   WARNING: Do not use the development environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL + C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 201-317-530

127.0.0.1 - - [07 / Jan / 2019 19:51:30] "GET / login HTTP / 1.1" 200 -
ERROR: flask_ldap3_login: invalid class in objectClass attribute: group
127.0.0.1 - - [07 / Jan / 2019 19:51:41] "POST / login HTTP / 1.1" 200 -
INFO: werkzeug: 127.0.0.1 - - [07 / Jan / 2019 19:51:41] "POST / login HTTP / 1.1" 200 -

'ascii' codec can't encode character u'\xf6' in position 15: ordinal not in range(128)

DEBUG:flask_ldap3_login:Opening connection with bind user 'domain.local\foobar'
DEBUG:flask_ldap3_login:Successfully bound to LDAP as 'domain.local\foobar' for search_bind method
DEBUG:flask_ldap3_login:Performing an LDAP Search using filter '(&(objectclass=person)(displayName=foobar))', base 'CN=Users,DC=xxxxxx,DC=sec', and scope 'LEVEL'
'ascii' codec can't encode character u'\xf6' in position 15: ordinal not in range(128)

When non-ascii characters is returned from a search

`

    config = dict()

    config['LDAP_HOST'] = "x.x.x.x"
    config['LDAP_BASE_DN'] = "DC=xxxxxx,DC=sec"
    config['LDAP_BIND_USER_DN'] = "domain.local\foobar"
    config['LDAP_BIND_USER_PASSWORD'] = "password"
    config['LDAP_USER_LOGIN_ATTR'] = "sAMAccountName"
    config['LDAP_USER_DN'] = "CN=Users"
    config['LDAP_GROUP_DN'] = "CN=Users"

    ldap_manager = LDAP3LoginManager()
    ldap_manager.init_config(config)

    response = ldap_manager.authenticate("foobar", "password)
    print(response.status)

`

I noticed this happened to my user which has an "ö" in the Full name field.

Regards

Using LDAPLoginForm with Flask app processes > 1

Require some guidence on how to troubleshoot using LDAPLoginForm when running flask with more than one process.

Sample configuration:

# etc/config.py

PORT = os.environ.get("PORT") or 8001
PROCESSES = os.environ.get("PROCESSES") or 5
DEBUG = os.environ.get("DEBUG") or True
THREADED = os.environ.get("THREADED") or False
HOST = os.environ.get("HOST") or "0.0.0.0"

Sample flask app:

# server/app.py
...
from flask_ldap3_login import LDAP3LoginManager
from flask_login import LoginManager, login_user, logout_user, login_required, UserMixin, current_user
from flask_ldap3_login.forms import LDAPLoginForm
...
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
CORS(app)
login_manager = LoginManager(app)
ldap_manager = LDAP3LoginManager(app)
...
if __name__ == "__main__":
		app.run(
				host=config.HOST,
				port=config.PORT,
				threaded=config.THREADED,
				processes=config.PROCESSES,
				debug=config.DEBUG
		)

If I use PROCESSES = 1; I can successfully login and navigate flask app.
If this is > 1 I see that the authentication is successful however I am redirected back to the login page to re-authenticate:

13-03-2019 22:35:40.054 115146:140433430583104 DEBUG              forms 32  : Validating LDAPLoginForm against LDAP
13-03-2019 22:35:40.056 115146:140433430583104 DEBUG           __init__ 782 : Opening connection with bind user 'adreader@noop'
13-03-2019 22:35:41.070 115146:140433430583104 DEBUG           __init__ 438 : Successfully bound to LDAP as 'adreader@noop' for search_bind method
13-03-2019 22:35:41.070 115146:140433430583104 DEBUG           __init__ 460 : Performing an LDAP Search using filter '(&(objectclass=person)(mail=jay@noop))', base 'OU=Users,DC=noop', and scope 'LEVEL'
13-03-2019 22:35:41.082 115146:140433430583104 DEBUG           __init__ 782 : Opening connection with bind user 'CN=jay,OU=Users,DC=noop'
13-03-2019 22:35:41.082 115146:140433430583104 DEBUG           __init__ 496 : Directly binding a connection to a server with user:'CN=jay,OU=Users,DC=noop'
13-03-2019 22:35:41.645 115146:140433430583104 DEBUG           __init__ 500 : Authentication was successful for user 'jay@noop'
13-03-2019 22:35:41.645 115146:140433430583104 DEBUG           __init__ 566 : Searching for groups for specific user with filter '(&(objectclass=group)(uniqueMember=CN=jay,OU=Users,DC=noop))' , base 'OU=Users,DC=noop' and scope 'LEVEL'
13-03-2019 22:35:41.651 115146:140433430583104 DEBUG           __init__ 808 : Destroying connection at <0x7fb8edbf9860>
13-03-2019 22:35:41.652 115146:140433430583104 DEBUG           __init__ 808 : Destroying connection at <0x7fb8edc5cf28>

Drop support for old versions of Flask

As @nickw444 mentioned in #66 (comment), we can reduce the complexity by requiring a moderately new version of Flask. The first thing mentioned (teardown_appcontext) was added in Flask 0.9, but we may want to depend on something even newer if it gives additional benefits.

LDAPForm never gets validated

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

problem filling LDAP Configuration Variables

Hello,

I succeed logging in Active Directory through ldap3. However, I think your lib would be very convenient through Flask.

But auth fails...
I think my misunderstanding of LDAP makes me failing to fill the configuration variables.

My user (successfully authenticated through ldap3 lib) is of the form:
"CN=USER1234,OU=Users,OU=Accounts,OU=FR,OU=MyOrg,DC=dc1,DC=dc2,DC=dc3,DC=dc4"

What would be the values of those variables:
LDAP_BASE_DN, LDAP_USER_DN, LDAP_GROUP_DN, LDAP_USER_RDN_ATTR, LDAP_USER_LOGIN_ATTR.

Thanks if you can provide some help!

Drop support for Python 3.4

Python 3.4 lost upstream support from the Python developers in March 2019. We should drop it from our CI matrix and PyPI metadata.

import users from LDAP

I currently have this extension working for login to my app.

When someone authenticates, they are added to my app's database using their LDAP GUID as an id.

How could I pre-populate the database with all my LDAP accounts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.