Git Product home page Git Product logo

flask-ldapconn's People

Contributors

a-detiste avatar alexei38 avatar berlincount avatar bm371613 avatar cherusk avatar dependabot[bot] avatar hamano avatar natureshadow avatar rbw avatar rroemhild avatar rschwarzkopf 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

flask-ldapconn's Issues

Intention on forking the project

I would like to use the code in this project as a starting point for an LDAP3 ORM that does not depend necessarily on flask, that is splitting the current project into two projects ldap3_orm and ldap3_orm_flask.
I am also planning to implement new features, e.g. inheritance for the model.
Since those changes could not easily merged back into this project I do not plan on using githubs fork button, but just push the current state to a new repository and work from there.
Please let me know what do you think about those plans!

access the initialized LDAPConn from blueprints

I wasn't able to find anything about this in the docs.

after application initialization I need access to the LDAPConn object. I can't simply import it because these are blueprints, which means that they have to be imported by the application configuration and thus can't import the application configuration without circular import problems.

The documentation considers only simple setups.

So here I am forced to use current_app to access the application. ldap = LDAPConn(current_app) doesn't work, however. It yields:
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late. To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.

I can't init and import, and I can't init in the authentication module itself. I CAN hack the app to store the object, but before I do this I wanted to know if there is an undocumented way to get at LDAPConn through the app (using current_app)?

Active Directory : query the user

Hi,

i'm getting following error when i try to query ActiveDirectory ldap. Code is working with openldap without any problem.

auth_user = LdapUser.query.filter('name:'+username).first()

return self.view_functions[rule.endpoint](**req.view_args)

File "/webapps/kpimanager/app/views.py", line 40, in login
if not User.try_login(form.username.data, form.password.data):
File "/webapps/kpimanager/app/models.py", line 42, in try_login
auth_user = LdapUser.query.filter('name:'+username).first()
File "/platform/python-2.7/lib/python2.7/site-packages/flask_ldapconn/query.py", line 70, in first
for entry in iter(self):
File "/platform/python-2.7/lib/python2.7/site-packages/flask_ldapconn/query.py", line 23, in iter
ldapentry = new_cls(dn=entry.entry_get_dn(),
AttributeError: 'NoneType' object has no attribute 'entry_get_dn'

LDAP server SSL cert not verified in all cases / tests missing

When using

LDAP_REQUIRE_CERT = ssl.CERT_REQUIRED
LDAP_USE_SSL = True
LDAP_USE_TLS = False
LDAP_PORT = 8636

not even the hostname check is done; let alone a full certificate chain check. Also, the SSL method is not configurable (e.g. switchable to PROTOCOL_TLSv1_2), neither is e.g. the cipher string.

No tests are present for any of this :(

get more than 50 results in a query

Hello,

A basic question; how can increase (or modify) the number of maximum results that i can get in a query?

For example, i have a basic model named group, with basic attributes cn, description and member.

I know that i have in my ldap 130 entries of that model; but if I do:

group.query.filter('cn: *').all()

for get all entries

Instead of get my list with the 130 entries, I only got a list with the first 50 results.

So... How I can change this? or. How I can get more results than these first 50?

So, thanks for the answers!

Model change detection in unreliable

entry.py detects changes to an ldap entry item only if the change triggers <item>.__setattr__. This is not the case with mutable objects like lists, they can be updates without __setattr__ being triggered. Best example is calling .append on a list item, this will not result in an ldap change. This behaviour should be documented in the README.

_app_ctx_stack will be removed in Flask 2.3 (current Flask version is 2.2)

Thanks for this nice and useful repo!

I've found a bunch of new deprecation warnings while running tests on our software, I guess this happened after a recent release of Flask (2.2):

tests/server/blueprints/login/test_views.py::test_ldap_login
/Users/chiararasi/miniconda3/envs/py38/lib/python3.8/site-packages/flask_ldapconn/init.py:114: DeprecationWarning: '_app_ctx_stack' is deprecated and will be removed in Flask 2.3. Use 'g' to store data, or 'app_ctx' to access the current context.
ctx = _app_ctx_stack.top

ldap3==1.0.1 doesn't exists in pypi

Could not find a version that satisfies the requirement ldap3==1.0.1 (from versions: 0.9.8.2.post1, 0.9.8.3.post1, 0.9.8.4, 0.9.8.5.post2, 0.9.8.6, 0.9.8.7, 0.9.8.8, 0.9.9, 0.9.9.1, 0.9.9.2, 0.9.9.3, 1.0.2)
No matching distribution found for ldap3==1.0.1

FORCE_ATTRIBUTE_VALUES_AS_LIST doesn't work

For example, i define a model named Group. I want to use groupOfNames, so i also define an attribute named member. In ldap schema this attribute has non-single value, so i want to work with them in python as with list. And when i create Group instance using flask-ldapconn i provide fake dn ( like uid=nobody,... ) via members.append() and call save() method. Works! But later, when i want to append new user, python says that member is str. Why?

FR: Allow inheritance in model

It would be cool to allow inheritance in the model, e.g. define a Person class and a User class derived from that, adding objectClasses and attributes in the latter.

Source tarball improvements

I am maintaining Flask-LDAPConn in Debian and have the following remarks:

  • Please include the changelog in the source tarball.
  • Please sign the source tarball published on PyPI

Writing to binary valued attributes does not work

I'm trying to write binary data (python type bytes) to a jpegPhoto attribute and get errors:

class User(UserMixin, ldap.Entry):
    ...
    jpegPhoto = ldap.Attribute('jpegPhoto')

jpeg = ... # binary data, bytes type
user.jpegPhoto = jpeg
user.save()

This results in "AttributeError: 'int' object has no attribute 'encode'" in Attribute.get_changes_tuple() because it thinks it's a multi-valued attribute of integers.

jpeg = ... # binary data, bytes type
user.jpegPhoto = [jpeg]
user.save()

A slight improvement, now the data is at least accepted as a single value, error is "AttributeError: 'bytes' object has no attribute 'encode'".

class BytesLDAPHackAdapter(bytes):
    def encode(self, enc):
        return self

jpeg = ... # binary data, bytes type
user.jpegPhoto = [BytesLDAPHackAdapter(jpeg)]

This work-around does the trick by providing a no-op encode member function. But it would be much better if LDAPConn would deal properly with bytes typed data. The problem is that bytes is iterable and not str as far as I can see.

Thank you for a nice library otherwise :-)

Fix for username = response[0]['dn'] KeyError

Trying to test extension, not working out of the box as expected, got error when entering intentionally wrong credentials

flask_ldapconn\__init__.py", line 162, in authenticate
username = response[0]['dn']
KeyError: 'dn' 

Slight code changing required. In line 162 of __init__.py
except (LDAPInvalidDnError, LDAPInvalidFilterError, IndexError):
to empty
except:
gave correct error handling! Hope this will help to someone.

List attribute access does not work (as before/as expected)

The fix/change in #24 and #25 mostly breaks working with list attributes in any sensible/easy or obviously correct way. As hinted to in the comment for b59c495 a field is either a list or it is not a list, but there's no way to indicate that in the model, and #24 makes accessing it much harder.

Steps to reproduce:

  1. Create the following model
class Test(ldap.Entry):
	object_classes = ['groupOfNames']
	entry_rdn = ['cn', 'base_dn']

	name = ldap.Attribute('cn')
	members = ldap.Attribute('member', default=[])
  1. Create two objects of this type in LDAP: object1 should have 1 member attribute value (foo), object2 should have 2 member attribute values (bar and baz).
  2. print ", ".join(object1.members)
  3. print ", ".join(object2.members)

Expected results (flask-ldapconn<0.7.0)

  • At step 3: foo
  • At step 4: bar, baz

Actual results (flask-ldapconn>=0.7.0)

  • At step 3: f, o, o
  • At step 4: bar, baz

Explanation

For basically all objects with multivalued attributes the accessing code does not want to care whether currently there's only one item in the list or multiple items. Example: I want to display the list with comma-separated values (", ".join(…)). With the new behaviour I would have to add a case distinction (along the lines of object1.members if isinstance(object1.members, str) else ", ".join(object1.members)).

Beginning with #24 all attribute access in LDAPEntry is delegated to the LDAPAttribute value property which conditionally returns a single value or a list of values. It's now impossible to access the LDAPAttribute values list to work around the behaviour of the value getter.

The two only workarounds I see:

  • Access the LDAPEntry._attributes internal property directly. (", ".join(object1._attributes["members"].values))
  • Go through get_attributes_dict(): ", ".join(object1.get_attributes_dict()["members"])

The most preferred solution would be some way to declare an LDAPAttribute to be a list and circumvent all "now it's a list, now it's a string, you can never know" magic.

ldap3 version 0.9.7.10 is not available

Hello Rafael,

The requirement for this library ldap3 version 0.9.7.10 is not available, please update the library so we can use it with ldap3 0.9.8.3. Thank you

Change Users Password

Allow to change the user Password by admin or user with extend.standard.modify_password().

Attribute access does not work as expected

The documentation says that an attribute is accessed by just, well, accessing it, but the code really returns the raw LDAPAttribute object instead of its value. It seems like a minor mistake in the code, but I wonder why noone noticed it…

[question] single values as string

I'm able to obtain a list of Entry objects and convert these to dictionaries for JSON serialization using get_attributes_dict().
The result is a list of objects containing the expected properties - however, values are contained in lists; Is there an easy way to get "single value" properties as string instead?

BTW - I noticed LDAPAttribute is missing some features available in AttrDef, such as post_query. Any plans on implementing those?

Anyway - thank you for a great extension.

Have a good day

Can set LDAP_SERVER

Hi
I can seem to set the LDAP_SERVER Variable
I get this error
ldap3.core.exceptions.LDAPSocketOpenError: ('unable to open socket', [(LDAPSocketOpenError('socket connection error while opening: [Errno 111] Connection refused',), ('::1', 389, 0, 0)), (LDAPSocketOpenError('socket connection error while opening: [Errno 111] Connection refused',), ('127.0.0.1', 389))])
I have set this in bot the app.py and config.py
LDAP_SERVER = 'mmcenvdc01.metmom.mmih.biz'
I also tried
app.config['LDAP_SERVER'] = 'mmcenvdc01.metmom.mmih.biz'

use of "personal" connections

My use case is basically that a user logs into (using authenticate()) the app and changes his personal data (e.g. mail). The server is configured that you can query a user without binding using a password, so I do not need to store the admin password in a plain text file and a user binding with his own password may only ever change attributes he is entitled to.
But to change a users data, I would need his connection (as in authenticate()) instead of the general connection of the app (as configured in the plain text config). Given that, I think I would need to replace the original connection somehow and maybe even use the LDAPEntry object for flask-login (that also does not work, at least in the obvious way). Or am I missing something?

Is what I describe here possible to achieve with flask-ldapconn? If so, how?

can't serialice an LDAP entry model

Using python 3.7.0,
On the last version of flask_ldapconn (0.10.0)
when you try to serialize as json an object created from a ldap Model, throws this exception:
TypeError: Object of type LDAPAttribute is not JSON serializable

In flask_ldapconn 0.7.0 this didn't happen and works perfectli. what changed on these versions?

this is the model:

class User(LDAPEntry):

base_dn = settings.config[config_name].LDAP_BASE_DN
object_classes = ['posixAccount']

name = Attribute('cn')
email = Attribute('mail')
userid = Attribute('uid')
surname = Attribute('sn')
givenname = Attribute('givenName')
manager = Attribute('manager')
groups = Attribute('memberOf')
phone = Attribute('mobile')
organization = Attribute('o')
organizationUnit = Attribute('ou')

def to_json(self):
    return jsonify(
        dn=self._dn,
        username=self.userid,
        firstName=self.givenname,
        lastName=self.surname,
        email=self.email,
        name=self.name,
        phone=self.phone,
        manager=self.manager,
        ldapGroups=self.groups,
        company=self.organization,
        unit=self.organizationUnit,


    )

In 0.7.0 you can call toJson and works perfectly!
but with 0.10.0 it completely fails.
how to fix that?

For the configuration, I used the default values.

Thanks!

Parametrizing usage collection for Connection()

Hi!

In my project, I needed to fetch metrics about LDAP connection, like amount of queries, etc. ldap3 has a usage class that allows it, but the flask-ldapconn by default doesn't allow changing this. I 'solved' this by hacking the LDAPConn object, but it'd be nice to have it in the upstream package by default.

I made a commit in my fork here - matejpipiska@fd05b04

But I am not sure how to write a test for this.

LDAPConn.connection.usage gives output like this:

Connection Usage:
  Time: [elapsed:          0:03:02.554842]
    Initial start time:    2018-08-13T11:28:32.031308
    Open socket time:      2018-08-13T11:28:32.031308
    Last transmitted time: 2018-08-13T11:31:34.244952
    Last received time:    2018-08-13T11:31:34.275247
    Close socket time:
  Server:
    Servers from pool:     0
    Sockets open:          1
    Sockets closed:        0
    Sockets wrapped:       0
  Bytes:                   17738951
    Transmitted:           2690634
    Received:              15048317
  Messages:                12730
    Transmitted:           4244
    Received:              8486
  Operations:              4244
    Abandon:               0
    Bind:                  2
    Add:                   0
    Compare:               0
    Delete:                0
    Extended:              0
    Modify:                0
    ModifyDn:              0
    Search:                4242
    Unbind:                0
  Referrals:
    Received:              0
    Followed:              0
    Connections:           0
  Restartable tries:       0
    Failed restarts:       0
    Successful restarts:   0

Going to a specific metric, like:
LDAPConn.connection.usage.search_operations gives 4242

Can someone help me with a test for this?

Thanks :)

No caching works through pickle

For caching operation (for example flask-cache), is not present pickle works
I have model - app.models.Contact

In [14]: contact.__class__.name
Out[14]: <flask_ldapconn.attribute.LDAPAttribute at 0x7fe9c56cb358>

In [15]: pickle.dumps(contact)
---------------------------------------------------------------------------
PicklingError                             Traceback (most recent call last)
<ipython-input-15-348ac8e78f5a> in <module>()
----> 1 pickle.dumps(contact)

PicklingError: Can't pickle <class 'flask_ldapconn.entry.Contact'>: attribute lookup Contact on flask_ldapconn.entry failed

Using TLS 1.2 from Flask-LDAPConn example throws exception

Hi,

I have tried your example given here But it seems to raises an exception because LDAP_TLS_VERSION = ssl.PROTOCOL_TLSv1_2 is used. I'm trying to use TLS1.2 over port 389.

This was working it seems when I used the following package versions:

Flask==0.10.1
Flask-LDAPConn==0.6.12
ldap3==1.2.2

Now I have updated to the following versions and it no longer works:

Flask==0.12
Flask-LDAPConn==0.6.13
ldap3==1.3.1

Here is the code I was using which is based directly on your example.

import ssl

from flask import Flask, current_app
from flask_ldapconn import LDAPConn
from ldap3 import SUBTREE

LDAP_SERVER = '<DCName>'  # Domain Controller machine name
LDAP_BASEDN = 'DC=<mycompany>,DC=<loca>l'
LDAP_BINDDN = '<username>'  # Username
LDAP_SECRET = "<password>"  # Password

LDAP_PORT = 389
LDAP_TIMEOUT = 10
LDAP_USE_TLS = True  # default
LDAP_REQUIRE_CERT = ssl.CERT_NONE  # default: CERT_REQUIRED
LDAP_TLS_VERSION = ssl.PROTOCOL_TLSv1_2  # default: PROTOCOL_TLSv1

SECRET_KEY = "shhh... it's a secret!"

HTTP_ADDR = 'localhost'
HTTP_PORT = 8000
DEBUG = True

app = Flask(__name__)


@app.route('/')
def index():
    try:
        ldapc = current_app.ldap.connection
        search_filter = '(&(samaccounttype=805306368) (samaccountname=%s))'
        attributes = ['sn', 'givenName', 'uid', 'mail']
        ldapc.search(current_app.config["LDAP_BASEDN"], search_filter, SUBTREE,
                     attributes=attributes)
        response = ldapc.response
    except Exception as ex:
        raise


def main():
    app.config.from_pyfile(__file__)
    app.ldap = LDAPConn(app)
    app.run(app.config["HTTP_ADDR"], app.config["HTTP_PORT"], debug=True)


if __name__ == '__main__':
    main()

When you access the main page from a browser the following exception is thrown:

ldap3.core.exceptions.LDAPStartTLSError: ('wrap socket error: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:645)',)

Traceback (most recent call last):
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "D:\venv\testserver\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "D:\venv\testserver\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "D:\venv\testserver\lib\site-packages\flask\app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "D:\testserver\ldaptest.py", line 30, in index
    CMD_ADD_EXCEPTION_BREAK, CMD_SMART_STEP_INTO, InternalConsoleExec, NetCommandFactory, \
  File "D:\venv\testserver\lib\site-packages\flask_ldapconn\__init__.py", line 119, in connection
    current_app.config['LDAP_SECRET']
  File "D:\venv\testserver\lib\site-packages\flask_ldapconn\__init__.py", line 96, in connect
    read_only=current_app.config['LDAP_READ_ONLY'],
  File "D:\venv\testserver\lib\site-packages\ldap3\core\connection.py", line 293, in __init__
    self.start_tls(read_server_info=False)
  File "D:\venv\testserver\lib\site-packages\ldap3\core\connection.py", line 1040, in start_tls
    if self.server.tls.start_tls(self) and self.strategy.sync:  # for async connections _start_tls is run by the strategy
  File "D:\venv\testserver\lib\site-packages\ldap3\core\tls.py", line 237, in start_tls
    return self._start_tls(connection)
  File "D:\venv\testserver\lib\site-packages\ldap3\core\tls.py", line 252, in _start_tls
    raise start_tls_exception_factory(LDAPStartTLSError, exc)(connection.last_error)

If I use the default of LDAP_TLS_VERSION = ssl.PROTOCOL_TLSv1 then it works but wanted to use TLS1.2.

Any ideas what this exception really means or if the code I'm now using is wrong for this version of Flask-LDAPConn?

Cheers,
Del

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.