Code Monkey home page Code Monkey logo

flask-simpleldap's Introduction

Flask-SimpleLDAP

Flask-SimpleLDAP provides LDAP authentication for Flask and is compatible with and tested on Python 3.8+.

Quickstart

First, install Flask-SimpleLDAP:

pip install flask-simpleldap

Flask-SimpleLDAP depends, and will install for you, a recent version of Flask (2.2.5 or later) and python-ldap. Please consult the python-ldap installation instructions if you get an error during installation.

Next, add an LDAP instance to your code and at least the three required configuration options. The complete sample from examples/basic_auth/app.py looks like this:

from flask import Flask, g
from flask_simpleldap import LDAP

app = Flask(__name__)
# app.config["LDAP_HOST"] = "ldap.example.org"  # defaults to localhost
app.config["LDAP_BASE_DN"] = "OU=users,dc=example,dc=org"
app.config["LDAP_USERNAME"] = "CN=user,OU=Users,DC=example,DC=org"
app.config["LDAP_PASSWORD"] = "password"

ldap = LDAP(app)

@app.route("/")
@ldap.basic_auth_required
def index():
    return f"Welcome, {g.ldap_username}!"

if __name__ == "__main__":
    app.run()

When the user visits the protected URL, the browser will prompt for the login and password via the built-in HTTP authentication window. Note that with the default value of LDAP_USER_OBJECT_FILTER the login is expected to match the userPrincipalName attribute of the LDAP user, e.g. [email protected].

Once you get the basic example working, check out the more complex ones:

OpenLDAP

Add the LDAP instance to your code and depending on your OpenLDAP configuration, add the following at least LDAP_USER_OBJECT_FILTER and LDAP_USER_OBJECT_FILTER.

from flask import Flask, g
from flask_simpleldap import LDAP

app = Flask(__name__)

# Base
app.config["LDAP_REALM_NAME"] = "OpenLDAP Authentication"
app.config["LDAP_HOST"] = "openldap.example.org"
app.config["LDAP_BASE_DN"] = "dc=users,dc=openldap,dc=org"
app.config["LDAP_USERNAME"] = "cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org"
app.config["LDAP_PASSWORD"] = "password"

# OpenLDAP
app.config["LDAP_OBJECTS_DN"] = "dn"
app.config["LDAP_OPENLDAP"] = True
app.config["LDAP_USER_OBJECT_FILTER"] = "(&(objectclass=inetOrgPerson)(uid=%s))"

# Groups
app.config["LDAP_GROUP_MEMBERS_FIELD"] = "uniquemember"
app.config["LDAP_GROUP_OBJECT_FILTER"] = "(&(objectclass=groupOfUniqueNames)(cn=%s))"
app.config["LDAP_GROUP_MEMBER_FILTER"] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))"
app.config["LDAP_GROUP_MEMBER_FILTER_FIELD"] = "cn"

ldap = LDAP(app)

@app.route("/")
@ldap.basic_auth_required
def index():
    return f"Welcome, {g.ldap_username}!"

if __name__ == "__main__":
    app.run()

Configuration

Setting Description
LDAP_HOST The host name or IP address of your LDAP server. Default: "localhost".
LDAP_PORT The port number of your LDAP server. Default: 389.
LDAP_SCHEMA The LDAP schema to use between "ldap", "ldapi" and "ldaps". Default: "ldap".
LDAP_SOCKET_PATH If LDAP_SCHEMA is set to "ldapi", the path to the Unix socket path. Default: "/".
LDAP_USERNAME Required: The username used to bind.
LDAP_PASSWORD Required: The password used to bind.
LDAP_TIMEOUT How long (seconds) a connection can take to be opened before timing out. Default: 10.
LDAP_LOGIN_VIEW Views decorated with .login_required() or.group_required() will redirect unauthenticated requests to this view. Default: "login".
LDAP_REALM_NAME Views decorated with .basic_auth_required() will use this as the "realm" part of HTTP Basic Authentication when responding to unauthenticated requests.
LDAP_OPENLDAP Set to True if your server is running OpenLDAP. Default: False.
LDAP_USE_SSL Set to True if your server uses SSL. Default: False.
LDAP_USE_TLS Set to True if your server uses TLS. Default: False.
LDAP_REQUIRE_CERT Set to True if your server requires a certificate. Default: False.
LDAP_CERT_PATH Path to the certificate if LDAP_REQUIRE_CERT is True.
LDAP_CUSTOM_OPTIONS dict of ldap options you want to set in this format: {option: value}. Default: None.
LDAP_BASE_DN Required: The distinguished name to use as the search base.
LDAP_OBJECTS_DN The field to use as the objects' distinguished name. Default: "distinguishedName".
LDAP_USER_FIELDS list of fields to return when searching for a user's object details. Default: [] (all).
LDAP_USER_GROUPS_FIELD The field to return when searching for a user's groups. Default: "memberOf".
LDAP_USER_OBJECT_FILTER The filter to use when searching for a user object. Default: "(&(objectclass=Person)(userPrincipalName=%s))"
LDAP_USERS_OBJECT_FILTER The filter to use when searching for users objects. Default: "objectclass=Person"
LDAP_GROUP_FIELDS list of fields to return when searching for a group's object details. Default: [] (all).
LDAP_GROUP_MEMBER_FILTER The group member filter to use when using OpenLDAP. Default: "*".
LDAP_GROUP_MEMBER_FILTER_FIELD The group member filter field to use when using OpenLDAP. Default: "*".
LDAP_GROUP_MEMBERS_FIELD The field to return when searching for a group's members. Default: "member".
LDAP_GROUP_OBJECT_FILTER The filter to use when searching for a group object. Default: "(&(objectclass=Group)(userPrincipalName=%s))".
LDAP_GROUPS_OBJECT_FILTER The filter to use when searching for groups objects. Default: "objectclass=Group".

flask-simpleldap's People

Contributors

adarnimrod avatar admiralobvious avatar alexferl avatar cl3t4p avatar danwertheimer avatar dependabot[bot] avatar fredthomsen avatar iiseymour avatar jm66 avatar krmarien avatar milakdev avatar optivertimall avatar robbason avatar sylwit avatar theneedyguy avatar wuzhihui1123 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  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  avatar

flask-simpleldap's Issues

Failover support

If I have multiple redundant IPA-servers, and want my app to be able to use them all for authentication. Is failover to other LDAP-hosts supported, or does this need to be implemented by the client?

Not compatible with uppercase distinguished names.

The code doesn't currently work with uppercase distinguished names. eg. CN= instead of cn=
Possible fix is:
Replace [re.findall('cn=(.*?),', group)[0] for group in groups]
With [re.findall('cn=(.*?),', group,re.IGNORECASE)[0] for group in groups]

get_user_groups with OpenLDAP returns no groups

get_user_groups with an OpenLDAP server returns no groups. I've been able to workaround with this change (line 220 of flask_simpleldap/init.py):

`def get_user_groups(self, user):
"""Returns a list with the user's groups or ``None`` if
unsuccessful.

    :param str user: User we want groups for.
    """

    conn = self.bind
    try:
        if current_app.config['LDAP_OPENLDAP']:
            print ldap_filter.filter_format(
                    current_app.config['LDAP_GROUP_MEMBER_FILTER'],(user,))
            fields = \
                [str(current_app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'])]
            records = conn.search_s(
                current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE,
                ldap_filter.filter_format(
                    current_app.config['LDAP_GROUP_MEMBER_FILTER'],
                    __#(self.get_object_details(user, dn_only=True),)),
                    (user,)), # commented previous and added this line__
                fields)`

self.get_object_details(user, dn_only=True) produces the user's DN, but I can't figure out how to format a
search filter that works on a DN. I get the impression that it isn't possible.

AttributeError in bind_user with invalid username

When passing an invalid username I'm getting an exception rather than None:

Traceback (most recent call last):
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/$USER/dev/myproject/myproject.py", line 98, in login
    test = ldap.bind_user(user, passwd)
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask_simpleldap/__init__.py", line 147, in bind_user
    user_dn = self.get_object_details(user=username, dn_only=True)
  File "/Users/$USER/.local/share/virtualenvs/myproject-A47Vo0O9/lib/python3.6/site-packages/flask_simpleldap/__init__.py", line 197, in get_object_details
    for k, v in list(records[0][1].items()):
AttributeError: 'list' object has no attribute 'items'

Filtering with multiple format placeholders

I would like to do a LDAP filtering like this:

LDAP_USER_OBJECT_FILTER = '(&(objectclass=Person)(|(mail={0})(sAMAccountName={0})))'

So that a user is able to authenticate using either an email address or a username, and the LDAP-search will look for one of both matches.

But it seems that this is not possible, I get the error:

TypeError: not all arguments converted during string formatting

This might be due to the changes made following issue #4

Is there a way of achieving the desired behaviour that I'm not aware of?

flask_simpleldap.LDAPException: Invalid credentials

Hello there,

I have just installed flask and flask-simpleldap on a freshly created a Ubuntu Virtual Box.
I also installed a fresh Windows2012 Virtual Box and they can perfectly communicate (I ping the Ubuntu from Windows and I also open successfully the webapp from Internet Explorer).

I've tweaked the example script:

from flask import Flask, g, request, session, redirect, url_for
from flask_simpleldap import LDAP

app = Flask(__name__)
app.secret_key = 'dev key'
app.debug = True

#app.config['LDAP_USE_SSL'] = True
app.config['LDAP_HOST'] = 'my-dc-server'
app.config['LDAP_BASE_DN'] = 'OU=-my-ou,dc=my,dc=domain,dc=com'
app.config['LDAP_USERNAME'] = 'CN=my-domain-admin-working-user,OU=my-ou,DC=my,DC=domain,DC=com'
app.config['LDAP_PASSWORD'] = 'my-domain-admin-working-password'

ldap = LDAP(app)

@app.route('/')
@ldap.basic_auth_required
def index():
    return 'Welcome, {0}!'.format(g.ldap_username)

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0', port=8000)

I insert the right user data (double checked and tested) and all I get is:

Traceback (most recent call last):
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask_simpleldap/__init__.py", line 386, in wrapped
    if not self.bind_user(req_username, req_password):
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask_simpleldap/__init__.py", line 152, in bind_user
    user_dn = self.get_object_details(user=username, dn_only=True)
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask_simpleldap/__init__.py", line 185, in get_object_details
    conn = self.bind
  File "/home/ubuntu/ipcatalogue_env/lib/python3.5/site-packages/flask_simpleldap/__init__.py", line 129, in bind
    raise LDAPException(self.error(e.args))
flask_simpleldap.LDAPException: Invalid credentials

Is flask-simpleldap still working today with Python 3.5 and Windows 2012?

get_object_details returning None

I can't get any results from get_object_details as an if statement on line 200 always fails.
Any help would be appreciated.

Python == 3.7.3
Flask-SimpleLDAP == 1.3.0

if type(records[0][1]) == 'dict' returns False. print(type(records[0][1])) outputs <class 'dict'>

It appears as though changing the line to if isinstance(records[0][1], dict): fixes the problem.

Ldap exception:error - issue with "Bind_user" class?

I'm using the groups example app and after submitting credentials I get the LDAP exception error.

File "C:...", line 68, in login
test = ldap.bind_user(user, passwd)

I looked at the doco for this class and it states the two parameters should be strings. When I printed out the variables I was getting from the login form they were unicode. I've made them strings now, but still get the same issue.

My code is pretty much all lifted from the groups example:

application.config['LDAP_HOST'] = 'ldap://adldaps.ex.am.ple:389'
application.config['LDAP_BASE_DN'] = 'dc=ex,dc=am,dc=ple' 
application.config['LDAP_USERNAME'] = 'OU=ex,OU=am,OU=ple'
application.config['LDAP_PASSWORD'] = 'password'
application.config['LDAP_CUSTOM_OPTIONS'] = {l.OPT_REFERRALS: 0}

and the login API endpoint:

@application.route('/login', methods=['GET', 'POST'])
def login():
    if g.user:
        return redirect(url_for('index'))
    if request.method == 'POST':
        user = str(request.form['user'])
        passwd = str(request.form['passwd'])
        test = ldap.bind_user(user, passwd) #This is where the issue is 
        if test is None or passwd == '':
            return 'Invalid credentials'
        else:
            session['user_id'] = request.form['user']
            return redirect('/')
    return """<form action="" method="post">
                user: <input name="user"><br>
                password:<input type="password" name="passwd"><br>
                <input type="submit" value="Submit"></form>"""

TypeError in bind_user method

Apparently this issue is caused by fixing #25.

Environment: Python 3.6.1, pyldap 2.4.37, Windows/Linux

  File "D:\code\gohan\web\app\models.py", line 86, in verify_password
    test = ldap.bind_user(name, passwd)
  File "D:\code\gohan\venv\lib\site-packages\flask_simpleldap\__init__.py", line 154, in bind_user
    conn.simple_bind_s(user_dn, password)
  File "D:\code\gohan\venv\lib\site-packages\ldap\ldapobject.py", line 417, in simple_bind_s
    msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
  File "D:\code\gohan\venv\lib\site-packages\ldap\ldapobject.py", line 411, in simple_bind
    return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
  File "D:\code\gohan\venv\lib\site-packages\ldap\ldapobject.py", line 294, in _ldap_call
    result = func(*args,**kwargs)
TypeError: argument 1 must be str, not bytes

get_object_details returned user_dn as bytes for me, it failed because it's no longer decoded in Python 3, so this change broke my code.

I'm not sure what caused different types of return values, but it seems we can fix it by adding some type check?

ImportError: cannot import name filter

I have installed python-ldap and flask-simpldap. I get this error when trying to run my flask app

File "/Library/Python/2.7/site-packages/flask/cli.py", line 90, in locate_app
import(module)
File "/Volumes/Data/My Projects/flask/myldap.py", line 1, in
import ldap as l
File "/Volumes/Data/My Projects/flask/ldap.py", line 3, in
File "/Library/Python/2.7/site-packages/flask_simpleldap/init.py", line 5, in
from ldap import filter as ldap_filter
ImportError: cannot import name filter

I have tried "import ldap.filter" on the python cli,that doesn't work either
I am using python 2.7.10 .
Has this function been deprecated ?

openldap does not return distinguishedName field

Looks like OpenLDAP does not return distinguishedName on this call:

records = conn.search_s(current_app.config['LDAP_BASE_DN'],
                                    ldap.SCOPE_SUBTREE, query, fields)

result:

[('cn=boris,ou=users,dc=syncloud,dc=org', 
{'objectClass': ['simpleSecurityObject', 'person'], 
'description': ['LDAP administrator'], 
'userPassword': ['{SSHA}***'], 
'cn': ['boris'], 'sn': ['boris']})]

Is there any workaround or is it supported at all?

Error in bind_user method

Hi. There may be a bug in bind_user method.

The code self.get_object_details(user=username, dn_only=True) returns a string in python3, so user_dn should be a string and doesn't have decode method.

My test environment : python3.5 openldap flask-simpleldap-1.1.0 pyldap-2.4.25.1

Pip-Install failed: Modules/common.h:9:20: fatal error: Python.h: File or directory not found.

Hello.

I tried to $ pip install flask-simpleldap but it fails. Are there any requirements missing?

[...]
  In file included from Modules/LDAPObject.c:3:0:
Modules/common.h:9:20: fatal error: Python.h: Datei oder Verzeichnis nicht gefunden
 #include "Python.h"
                    ^
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

----------------------------------------
Failed building wheel for pyldap
[...]
In file included from Modules/LDAPObject.c:3:0:
Modules/common.h:9:20: fatal error: Python.h: Datei oder Verzeichnis nicht gefunden
 #include "Python.h"
                    ^
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1


----------------------------------------
Command "/path/to/my/project/bin/python2 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-lCIS2c/pyldap/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-4t6ySw-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/schwedep/normalizer/web/include/site/python2.7/pyldap" failed with error code 1 in /tmp/pip-build-lCIS2c/pyldap/

AttributeError: '_AppCtxGlobals' object has no attribute 'user'

When I try your example with custom settings I get this error:

[2017-11-29 10:54:24,331] ERROR in app: Exception on /ldap [GET]
Traceback (most recent call last):
  File "/web/local/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/web/local/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/web/local/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/web/local/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/web/local/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/web/local/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 303, in wrapped
    if g.user is None:
  File "/web/local/lib/python2.7/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'user'

Is this error related to some wrong arguments or credentials?

@ldap.group_required not working

Hi...I'm trying to restrict a page in my app using @ldap.group_required(groups=['xxx']) but I'm unable to get it working. I have my group configuration setup like this:

# Group configuration
app.config['LDAP_GROUP_MEMBERS_FIELD'] = "uniquemember"
app.config['LDAP_GROUP_OBJECT_FILTER'] = "(&(objectclass=groupOfUniqueNames)(uniquemember=%s))"
app.config['LDAP_GROUP_MEMBER_FILTER'] = "member=%s"
app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] = "cn"

When I print the groups I belong to to the console I get this:

[b'web', b'confluence', b'google']

When I restrict a page to a group I'm not associated with but that is one of our ldap groups, nothing happens. This is the code I'm using to restrict my 'dbadmin' page:

@app.route('/group')
@ldap.group_required(groups=['dbadmin'])
def group():
    return 'For dbadmins only'

By the way, @ldap.login_required works correctly. Also, I'm using Flask 0.12 and python 3.6.0.

ImportError: cannot import name 'filter'

File "/usr/local/lib/python3.6/site-packages/flask_simpleldap/init.py", line 6, in
from ldap import filter as ldap_filter
ImportError: cannot import name 'filter'

broken authentication since 1.1.2

in your latest commit you check current python version:

user_dn = self.get_object_details(user=username, dn_only=True)

    if user_dn is None:
        return
    try:
        conn = self.initialize
        if sys.version_info[0] > 2:
            conn.simple_bind_s(user_dn, password)
        else:
            conn.simple_bind_s(user_dn.decode('utf-8'), password)
        return True
    except ldap.LDAPError:
        return

the problem is that self.get_object_details still returns bytes of strings, if you don't setup config as openldap (I'm using Win server 2012r2 provider not openldap). The dirty hack is to still decode user_dn as utf-8, no matter the version of python:
if sys.version_info[0] > 2:
conn.simple_bind_s(user_dn.decode('utf-8'), password)

If I set config to openldap = true, authentication works out of the box, but on group check another error occurs:
g.ldap_groups = ldap.get_user_groups(user=session['user_id'])
File "/usr/local/lib/python3.6/site-packages/flask_simpleldap/init.py", line 222, in get_user_groups
(self.get_object_details(user, dn_only=True),)),
File "/usr/local/lib/python3.6/site-packages/ldap/filter.py", line 59, in filter_format
return filter_template % (tuple(map(escape_filter_chars,assertion_values)))
TypeError: not all arguments converted during string formatting

Hope this helps you debug, or, if I'm made wrong assumptions, then you can correct me. Thank you for your work!

get_object_details to take query_filter and fallback to LDAP_USER_OBJECT_FILTER or LDAP_GROUP_OBJECT_FILTER

It'd be useful to provide queries to get_object_details at runtime. This provides flexibility when another query needs to be used temporarily without updating the global configuration. For example:

from app import ldap

user_dn_obj_filter = '(&(objectclass=inetOrgPerson)(entryDN=%s))'

ldap.get_object_details(user='cn=John Doe,ou=servauth-users,dc=users,dc=openldap,dc=org', query_filter=user_dn_obj_filter)

LDAP require certificate error

Hi,

I am having trouble making my app work with LDAP. When I set LDAP_REQUIRE_CERT' and LDAP_CERT_PATH' ... I get the following error when running the app:

Traceback (most recent call last):
  File "app.py", line 27, in <module>
    ldap = LDAP(app)
  File "/opt/conda/envs/flask/lib/python3.6/site-packages/flask_simpleldap/__init__.py", line 27, in __init__
    self.init_app(app)
  File "/opt/conda/envs/flask/lib/python3.6/site-packages/flask_simpleldap/__init__.py", line 73, in init_app
    current_app.config['LDAP_CERT_PATH'])
  File "/opt/conda/envs/flask/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/opt/conda/envs/flask/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
    return self.__local()
  File "/opt/conda/envs/flask/lib/python3.6/site-packages/flask/globals.py", line 51, in _find_app
    raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.

Do you know how I can solve the problem?

I am using Python 3.6 and flask-simpleldap 1.1.2

get_user_groups Returned is not an array of strings

When I update flask-simpleldap to the latest version, My app doesn't work correctly, Finally found that the function get_user_groups() returns an array of strings in the old version, the new version returns a byte array. Why is this incompatibility, I think string arrays are more reasonable.

== my env:

python: 3.5.1
flask version:  1.1.1
flask-simpleldap version : 1.4.0

== I saw that you removed these codes.

  if sys.version_info[0] > 2:
    result = [r.decode('utf-8') for r in result]

Proposing that get_user_groups always returns a list

Proposing that get_user_groups(self, user) always returns a list, or that the example is changed to recommend that you check for a None before setting g.ldap_groups.

Having g.ldap_groups be None is dangerous since the group_required() decorator will crash if it tries to iterate over g.ldap_groups.

I just tried having a valid user be without a group, and this lead to to a None, and not an empty list which would have been safe.

LDAPException: Inappropriate authentication

I'm trying to run this script

from flask import Flask, g, request, session, redirect, url_for from flask_simpleldap import LDAP app = Flask(__name__) app.secret_key = 'dev key' app.debug = True app.config['LDAP_HOST'] = 'ldap.test.fr' app.config['LDAP_REALM_NAME'] = 'LDAP Authentication' app.config['LDAP_BASE_DN'] = 'ou=personnels EN,ou=ac-test,ou=toto,o=gouv,c=fr' app.config['LDAP_USERNAME'] = 'cn=test,'ou=personnels EN,ou=ac-test,ou=toto,o=gouv,c=fr'' app.config['LDAP_PASSWORD'] = '' app.config['LDAP_OBJECTS_DN'] = 'dn' app.config['LDAP_OPENLDAP'] = True app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' ldap = LDAP(app) @app.route('/') @ldap.basic_auth_required def index(): return 'Welcome, {0}!'.format(g.ldap_username) if __name__ == '__main__': app.run()

But I get

Traceback (most recent call last): File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1997, in __call__ return self.wsgi_app(environ, start_response) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app response = self.handle_exception(e) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception reraise(exc_type, exc_value, tb) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app response = self.full_dispatch_request() File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception reraise(exc_type, exc_value, tb) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request rv = self.dispatch_request() File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 380, in wrapped if not self.bind_user(req_username, req_password): File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 147, in bind_user user_dn = self.get_object_details(user=username, dn_only=True) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 179, in get_object_details conn = self.bind File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 125, in bind raise LDAPException(self.error(e.args)) LDAPException: Inappropriate authentication

Applications

Is it possible to use Flask-SimpleLDAP not as an authentication mechanism, since I already have Flask-Login implemented, but for me to manage users/groups in Active Directory? I would like to be able to connect to the Active Directory server, poll the list of users and groups, then update which groups a user is part of. Also, it would be good if I could update the user's Active Directory password.

Working with blueprints

How do you make @ldap.login_required and @ldap.group_required available in any blueprints?

app = Flask(__name__)
ldap = LDAP(app)

from foo import foo
app.register_blueprint(foo, url_prefix='/foo')

I want to protect routes in foo.py.

User or group queries are vulnerable to LDAP injection

"LDAP injection" isn't a common term, as far as I know, but I mean something like SQL injection, but for LDAP.

In LDAP.get_object_details(), there's code that takes an untrusted string from the user and passes it directly to the LDAP server, like this:

query = current_app.config['LDAP_USER_OBJECT_FILTER'].format(user)
...
records = conn.search_s(current_app.config['LDAP_BASE_DN'],
    ldap.SCOPE_SUBTREE, query, fields)

Unfortunately, LDAP queries (like SQL queries) have certain sensitive characters including parentheses and the asterisk. Luckily, python-ldap includes the ldap.filter.filter_format() helper function that does what you want with proper escaping. You'll need to change the LDAP_USER_OBJECT_FILTER default to use %s instead of {0}, and then LDAP.get_object_details() can say:

query = ldap.filter.filter_format(
    current_app.config['LDAP_USER_OBJECT_FILTER'],
    user,
)

...and then you'll never have to worry about people putting asterisks or brackets in their usernames ever again.

LDAPException: Inappropriate authentication

I'm trying to run this script

from flask import Flask, g, request, session, redirect, url_for from flask_simpleldap import LDAP app = Flask(__name__) app.secret_key = 'dev key' app.debug = True app.config['LDAP_HOST'] = 'ldap.test.fr' app.config['LDAP_REALM_NAME'] = 'LDAP Authentication' app.config['LDAP_BASE_DN'] = 'ou=personnels EN,ou=ac-test,ou=toto,o=gouv,c=fr' app.config['LDAP_USERNAME'] = 'cn=test,'ou=personnels EN,ou=ac-test,ou=toto,o=gouv,c=fr'' app.config['LDAP_PASSWORD'] = '' app.config['LDAP_OBJECTS_DN'] = 'dn' app.config['LDAP_OPENLDAP'] = True app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' ldap = LDAP(app) @app.route('/') @ldap.basic_auth_required def index(): return 'Welcome, {0}!'.format(g.ldap_username) if __name__ == '__main__': app.run()

But I get

Traceback (most recent call last): File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1997, in __call__ return self.wsgi_app(environ, start_response) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app response = self.handle_exception(e) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception reraise(exc_type, exc_value, tb) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app response = self.full_dispatch_request() File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception reraise(exc_type, exc_value, tb) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request rv = self.dispatch_request() File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 380, in wrapped if not self.bind_user(req_username, req_password): File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 147, in bind_user user_dn = self.get_object_details(user=username, dn_only=True) File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 179, in get_object_details conn = self.bind File "/home/cd/Documents/dev/api/ldap-auth/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 125, in bind raise LDAPException(self.error(e.args)) LDAPException: Inappropriate authentication

Quickstart documentation is misleading

I started playing with flask-simpleldap the other day, and predictably enough I started with the source-fragment from the Quickstart documentation, but I found it somewhat misleading:

  • The docs call LDAP(app) before adding the required settings to app.config, which raises an exception.
  • The docs use the ldap.login_required decorator as a standalone wrapper, but it doesn't work that way - as far as I can tell, in order to use ldap.login_required you need to create a login page, teach it to store the authenticated username in g.user and set it up in app.config, none of which is described in the quickstart (or even in the ldap.login_required docs).

I got past those and eventually found the method I was looking for (.bind_user(), which I was expecting would be called .validate_user() since the connection that gets bound to the user is discarded after validating their password), and I really like the simplicity, but I figured I should report the problems I had with the docs.

Thanks!

get_user_groups() returns no groups with openLDAP

get_user_groups with an OpenLDAP server returns no groups. I've been able to workaround with this change (line 220 of flask_simpleldap/init.py):

`def get_user_groups(self, user):
"""Returns a list with the user's groups or ``None`` if
unsuccessful.

    :param str user: User we want groups for.
    """

    conn = self.bind
    try:
        if current_app.config['LDAP_OPENLDAP']:
            print ldap_filter.filter_format(
                    current_app.config['LDAP_GROUP_MEMBER_FILTER'],(user,))
            fields = \
                [str(current_app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'])]
            records = conn.search_s(
                current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE,
                ldap_filter.filter_format(
                    current_app.config['LDAP_GROUP_MEMBER_FILTER'],
                    **#(self.get_object_details(user, dn_only=True),)),
                    (user,)), # commented previous and added this line**
                fields)`

self.get_object_details(user, dn_only=True) produces the user's DN, but I can't figure out how to format a
search filter that works on a DN. I get the impression that it isn't possible.

Wrapper ldap.group_required not working as expected

When using the provided example for OpenLDAP, the array g.ldap_groups is an array of bytes type whereas the wrapper is checking for string values.
If I try to run the code as it is in the example (with Python 3.7), the URL with group restriction will always return a "401 Unauthorized" error.
Replacing the wrapper @ldap.group_required(groups=['web-developers']) with @ldap.group_required(groups=[b'web-developers']) is the solution that worked fine for me, but maybe there is a better workaround.

get_user_groups()

My issue is the same as #28 and #29. The fix in #29 also resolves my issue but I'd like to understand what I'm doing incorrectly to cause the struggle. From what I can tell, the authenticated user's username is being correctly passed to get_user_groups(). This function calls (self.get_object_details(user, dn_only=True) which returns the full dn for the user. get_user_groups() then uses this full dn as the %s value in LDAP_GROUP_MEMBER_FILTER = memberUid=%s which results in an LDAP query of (in my case) (memberUid=uid=bob,ou=users,dc=geekministry,dc=virt) whereas it should be (memberUid=bob).

Error during installation

Hi folks!

I'm using Python 3.6.4 (x64) with Windows 10 (x64). When I try to install by command line "pip install flask-simpleldap" appears following message error:

Building wheels for collected packages: python-ldap
Building wheel for python-ldap (setup.py) ... error
ERROR: Command errored out with exit status 1:

Group search does not work for OpenLDAP

Hi,

Yet another fix to make flask-simpleldap work with OpenLDAP. Thus, I'm not sure if adding a configuration flag to differentiate between OpenLDAP and AD would help. Please, take a look at this commit jm66@f19ca95. Does this make sense?

Thanks,
JM

user_dn as bytes instead of string

I've updated to python 3.6.2 and since then I'm encountering a error. when the function calls for bind_user the following line of code returns bytes instead of a string:
user_dn = self.get_object_details(user=username, dn_only=True)
In the code later on there is a check to see if he should decode it or not based on the python version:

if user_dn is None:
    return
try:
    conn = self.initialize
    if sys.version_info[0] > 2:
        conn.simple_bind_s(user_dn, password)
    else:
        conn.simple_bind_s(user_dn.decode('utf-8'), password)
    return True
except ldap.LDAPError:
    return

Could this be because of this change to python 3.6.2?

bpo-29755: Fixed the lgettext() family of functions in the gettext module. They now always return bytes.

Wrong code order in doc and README.md ?

I install the flask-simpleldap in my project and write a demo show in the README and doc like these:

app = Flask(__name__)
ldap = LDAP(app)

app.config['LDAP_BASE_DN'] = 'OU=users,dc=example,dc=org'
app.config['LDAP_USERNAME'] = 'CN=user,OU=Users,DC=example,DC=org'
app.config['LDAP_PASSWORD'] = 'password'

then it will raise a exception with message :
flask_simpleldap.LDAPException: LDAP_USERNAME cannot be None!

I move the line ldap = LDAP(app) after configs , my app will run as normal , so Is this order wrong?
ps. The code in basic_auth example is add configs firstly

bind_user() fails in Python3

This might be a regression between 1.1.2 and 1.2.0:

ae9eecf#diff-df961969fdc0fcec2f458e0fbb16eef9R153

Traceback:

[2017-11-28 19:13:08,163] ERROR in app: Exception on /api/v1/login [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.5/dist-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.5/dist-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "./test_api/api/v1/views.py", line 141, in login
    test = ldap.bind_user(user, passwd)
  File "/usr/local/lib/python3.5/dist-packages/flask_simpleldap/__init__.py", line 153, in bind_user
    conn.simple_bind_s(user_dn.decode('utf-8'), password)
AttributeError: 'str' object has no attribute 'decode'
[pid: 76|app: 0|req: 1/1] XXX.XXX.XXX.XXX () {40 vars in 802 bytes} [Tue Nov 28 19:13:06 2017] POST /api/v1/login =>
 generated 291 bytes in 1897 msecs (HTTP/1.1 500) 2 headers in 84 bytes (1 switches on core 0)

Changing this to conn.simple_bind_s(user_dn, password) seems to fix the problem for me.

Splitted LDAP directory tree

Hello,

I have two user groups and two organizational units (OU).
For example: User A is in the ou1 and user B is in the ou2.
All users in ou2 have a special mark in their name.
LDAP_BASE_DN for the first user is 'OU=ou1,dc=example,dc=org'
and for the second user 'OU=ou2,dc=example,dc=org'.
Is it possible to pass several LDAP_BASE_DN's?

My quick and dirty workaround is to add following code at line 181:

if 'special_mark' in request.authorization.username:
    records = conn.search_s('OU=ou2,dc=example,dc=org',
                                             ldap.SCOPE_SUBTREE, query, fields)
else:
    records = conn.search_s(current_app.config['LDAP_BASE_DN'],
                                             ldap.SCOPE_SUBTREE, query, fields)

Do you have some hint to make it better, without hard-coded changes in flask-simpleldap module?

Getting list of all groups and nested group memberships

I want to get all the groups my users are members of, not just the first-level groups. E.g. if I have a user "bob" who is a member of group "A". And group "A" is a member of group "B", then I want user "bob" to show both groups "A" and "B".

With the following settings I only get group "A" when looking up user "bob":

LDAP_BASE_DN="dc=myrealm,dc=com"
LDAP_REALM_NAME="MyFunRealm"
LDAP_OBJECTS_DN="dn"
LDAP_USER_OBJECT_FILTER="(&(objectclass=inetorgperson)(uid=%s))"
LDAP_GROUP_MEMBERS_FIELD="member"
LDAP_GROUP_OBJECT_FILTER="(&(objectclass=groupofnames)(member=%s))"
LDAP_GROUP_MEMBER_FILTER="member=%s"
LDAP_GROUP_MEMBER_FILTER_FIELD="cn"

Is it possible to get the group info I want by altering the settings or is this something that needs to be changed in the library?

simpleldap should provide a simple authentication decorator

For people just starting to integrate flask-simpleldap into their application, it would be good to have a simple decorator that people can add to their views for elementary security, or as a proof-of-concept. There's already the LDAP.login_required() and LDAP.group_required() helpers, but they both depend on the user providing a custom login page, putting its name into LDAP_LOGIN_VIEW and configuring it to put the correct keys into flask.g.

Instead, to make things as simple as possible, there should be a decorator that uses HTTP's basic authentication. All it would need is a standard suffix to turn a username into a userPrincipalName (i.e. foo -> [email protected]) and a realm description to display to the end-user, and then it could automatically generate the HTTP headers required to make the browser prompt for a username and password and to validate them against the LDAP server.

If that sounds like a good idea, I will submit a patch for your approval.

Authentication fails when using diacritics in passwords

I use flask-simpleldap with an openldap server.

It works well with these parameters:

app = Flask(__name__)
app.secret_key = 'secret key'
app.debug = True

app.config['LDAP_OPENLDAP'] = True
app.config['LDAP_OBJECTS_DN'] = 'dn'
app.config['LDAP_REALM_NAME'] = 'LDAP Authentication'
app.config['LDAP_HOST'] = 'ldap.mydomain.example'
app.config['LDAP_PORT'] = 636
app.config['LDAP_USE_SSL'] = True
app.config['LDAP_SCHEMA'] = 'ldaps'
app.config['LDAP_BASE_DN'] = 'ou=people,dc=mydomain,dc=example'
app.config['LDAP_USERNAME'] = 'cn=app,ou=services,dc=mydomain,dc=example'
app.config['LDAP_PASSWORD'] = 'REDACTED'
app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=posixAccount)(memberof=cn=appusers,ou=groups,dc=mydomain,dc=example)(uid=%s))'

@app.route('/')
@ldap.basic_auth_required
def index():
    return 'Welcome, {0}!'.format(g.ldap_username)

It works well except for a few users. I just discovered that these users have letters with accents in their password. (for exampleà, ç or é)
For these users, each try to connect ends as if they provided a bad password.

Is this a bug or some configuration I missed ?

Redirecting back to the requested page after authenticating

When requesting a page that requires authentication you are redirected to /login (when unauthenticated) and then directed to a static page i.e. /. It would be nice if once the user has logged in, that they are directed to the page they originally requested.

bind_user(user, passwd) returns TypeError

Hey,

I found issue #6, but it was closed due to the original request never being following through on. I'm getting the same thing however.

My app.config settings.

    # LDAP Auth Configuration
    app.config['LDAP_HOST'] = 'myldap.server'
    app.config['LDAP_BASE_DN'] = 'dc=unitdc,dc=orgdc,dc=typedc'
    app.config['LDAP_USERNAME'] = 'cn=managercn,dc=unitdc,dc=orgdc,dc=typedc'
    app.config['LDAP_PASSWORD'] = 'mypass'
    app.config['LDAP_USE_TLS'] = True
    app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=posixAccount)(cn=%s))'

I confirmed that the LDAP server is responding with a record and tracked it back as far as I could on my own. What I found was that the var "who" in python-ldap's simple bind function was where the dict was being sent to. That was being generated by the get_object_details in flask-simpleldap.

Now I'm not certain that this is an actual bug / issue with flask-simpleldap, in fact I'm willing to bet it's a configuration error on my end. But if you could hopefully point out what I'm missing I would appreciate it.

The traceback is below.

Thanks.

Traceback (most recent call last):
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/mkeller/PycharmProjects/dopplr/dopplr_web/__init__.py", line 148, in login
    test = ldap.bind_user(user, passwd)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 147, in bind_user
    conn.simple_bind_s(user_dn, password)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/ldap/ldapobject.py", line 232, in simple_bind_s
    msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/ldap/ldapobject.py", line 226, in simple_bind
    return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
  File "/Users/mkeller/venvs/dopplr/lib/python2.7/site-packages/ldap/ldapobject.py", line 106, in _ldap_call
    result = func(*args,**kwargs)
TypeError: must be string, not dict```

bind_user(user, passwd) returns TypeError

where both user and passwd are strings the call that gets made via simplebind / _ldap_call gets a dict instead with the whole userinfo from ldap...

eg:
bind_user('validuser', 'validpassword')

Traceback (most recent call last):
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/validuser/myapp/views.py", line 26, in login
    if ldap.bind_user(user, passwd):
  File "/Users/validuser/myapp/lib/python2.7/site-packages/flask_simpleldap/__init__.py", line 134, in bind_user
    conn.simple_bind_s(user_dn, password)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/ldap/ldapobject.py", line 214, in simple_bind_s
    msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
  File "/Users/validuser/myapp/lib/python2.7/site-packages/ldap/ldapobject.py", line 208, in simple_bind
    return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
  File "/Users/validuser/myapp/lib/python2.7/site-packages/ldap/ldapobject.py", line 106, in _ldap_call
    result = func(*args,**kwargs)
TypeError: must be string, not dict

Question regarding OPT_REFERRALS

hello,

I've been working on trying to get ldap authentication working in an API that I've written however i've been getting a number of errors like this: "LDAPException: Operations error". From the research I've done through the web, i've found that in a number of cases adding "l.set_option(ldap.OPT_REFERRALS,0)" is helpful. I've attempted to add the following via my app:

app.config['LDAP_OPT_REFERRALS'] = '0'

However this hasn't provided any joy. Is there a different way to pass ldap configuration to flask-simpleldap?

Possible security problem with basic_auth_required() decorator.

It's come to my attention that for some LDAP servers, if you try to bind your connection to a user account with a valid username and an empty password, you'll get an anonymous connection - the bind doesn't fail, you just wind up with less access than you might have expected.

Therefore, if you access a paged protected by basic_auth_required() and provide a valid username and an empty password, the wrapper will try to bind, succeed (getting an anonymous bind) and assume that the client provided the correct username for that account.

The fix would be something like changing req_password is None to req_password in [None, ""].

group_required that acts like basic_auth_required

I'm currently looking at implementing the factory pattern example as part of an API but I need something like a "group_auth_required" that uses basic auth in the request header rather then the "group_required" function that seems to need a login page.

I'm happy to build it and supply it back to the project but if you have anything in the pipeline or this already exists but I missed it, if you could let me know, that would be appreciated.

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.