Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

ProbstDJakob
Copy link
Contributor

@ProbstDJakob ProbstDJakob commented Sep 13, 2020

Why ldap3

ldap3 does not need any C libraries neither must it be compiled and therefore is simpler to deploy.
ldap3:

A more pythonic LDAP

What has been done and what has not:

  • Replace python-ldap methods/functions/... with the corresponding ldap3 ones.
  • Adjust tests to work with the new changes.
  • Type hints have been added to see what does what and make it simpler for me to apply the changes.

TODOs:

  • Documentation has not been changed. This will done after the PR has been approved.

Breaking changes:

  • This PR currently drops support for CONNECTION_OPTIONS and GLOBAL_OPTIONS and depends on ldap3.ASYNC connections (it does not support sync connections). The options may be replaced by something from ldap3 wich does nearly the same. Support for sync connections or other types could be implemented if desired.
  • Deprecated features have been dropped.
  • Class variables have been replaced with instance variables (corresponding __init__'s have been updated).
  • Remove all ldap properties and get_ldap methods.
  • Rename some protected variables and methods.
  • Remove LDAPSearch._process_results and _DeepStringCoder.
  • If an ldap attribute is a single attribute, the response will not be stored as list, but directly as value (see the documentation for more information)
  • If ldap3 recognizes the data type it automatically converts it to a corresponding python object (see the documentation for more information)

See also the commit messages for more informations.

Disclaimer:

This has not been tested in production only all tox envs have been run successfully.

@ProbstDJakob
Copy link
Contributor Author

Currently this PR does not support Python 3.6 since from __future__ import annotations is not available until Python 3.7, but this can be fixed if Python 3.6 is desired.

@timabbott
Copy link

It seems like preserving Python 3.6 support is worth doing, since it won't be EOL for quite some time. Certainly downstream projects like Zulip that support all non-EOL Python projects wouldn't be able to use it if Python 3.6 support is removed.

@ProbstDJakob
Copy link
Contributor Author

Sorry for the late response, but now Python 3.6 support ist back with some additional improvements.

@Natureshadow
Copy link
Contributor

Hi!

What is the current status here? Do the maintainers intend to merge it and move to ldap3?

I am currently trying to generalise the Django Debug Toolbar panel from django-windowsauth, and having django-auth-ldap use ldap3 would ease things a lot.

@francoisfreitag
Copy link
Member

Switching to ldap3 sounds good to me. I believe the type hinting should move to a separate PR to keep things focused. Type hinting benefits the project regardless of the change to ldap3.
Likewise, if changes were made that are improvements on their own (dropping deprecated features, renaming internal methods, etc), please move them to a separate PR so that this PR is only focused on changing from python-ldap to ldap3.

I’ll dive deeper into this PR during the work week. I have an environment to test the changes on, that will certainly come handy.

@ProbstDJakob
Copy link
Contributor Author

Splitting up the PR into ldap3 andy type hinting would of course be possible, but either the ldap3 branch has to sit ontop of the type hinting branch or ldap3 would loose type hinting and therefore would lead to an merge confilct when merging both.

Since this is defenetely a breaking change, wouldn't it make sense to keep dropping the deprecaded features together? Furthermore (it's been a long time since i wrote the code, so I could remember wrongly) I think some changes had to be done to get ldap3 working.

And thanks for testing the code. This would definitely help to verify the PR.

@Natureshadow
Copy link
Contributor

I just migrated our staging system with a rather complex setup (including a mass import utility sitting on top of django-ldap-auth) to this PR and it works. One thing to add to the list of breaking changes is that with python-ldap, the attrs dictionaries were guaranteed to have lists as values, even for single-value attributes, and in ldap3 only multi-value attributes are packed in lists.

Another nice thing is that ldap3 returns reasonable objects if it detects the attribute correctly, i.e. datetime for LDAP datetime attributes.

Apart from that, simply dropping in the code from this PR worked.

@francoisfreitag
Copy link
Member

either the ldap3 branch has to sit ontop of the type hinting branch or ldap3 would loose type hinting and therefore would lead to an merge confilct when merging both.

The ldap3 sitting on top of the type hinting branch is fine. Can prefix the commit title with [DO NOT REVIEW] or marking to similar effect to indicate the change is part of another PR.

Since this is defenetely a breaking change, wouldn't it make sense to keep dropping the deprecaded features together?

Removal of deprecated feature is going to happen, regardless of other breaking changes. Making all breaking changes in the same release avoids successively releasing versions with breaking changes, but may break more installations. Not a clear win IMO. I’ll get back to you once I am more familiar with the suggested changes.
Generally, smaller and focused PRs help reviewing and is a good way to present changes, that’s why I suggested to split any work that stands on its own from this PR.

@francoisfreitag
Copy link
Member

I migrated our staging system with a rather complex setup (including a mass import utility sitting on top of django-ldap-auth) to this PR and it works.

Awesome, that’s very promising!

@Natureshadow
Copy link
Contributor

For reference, here's the diff in our consuming application:

https://edugit.org/AlekSIS/official/AlekSIS-App-LDAP/-/merge_requests/45/diffs

@ProbstDJakob
Copy link
Contributor Author

I just migrated our staging system with a rather complex setup (including a mass import utility sitting on top of django-ldap-auth) to this PR and it works. One thing to add to the list of breaking changes is that with python-ldap, the attrs dictionaries were guaranteed to have lists as values, even for single-value attributes, and in ldap3 only multi-value attributes are packed in lists.

Another nice thing is that ldap3 returns reasonable objects if it detects the attribute correctly, i.e. datetime for LDAP datetime attributes.

Thanks for the hint, I adapted the PR message.

@ProbstDJakob
Copy link
Contributor Author

The ldap3 sitting on top of the type hinting branch is fine. Can prefix the commit title with [DO NOT REVIEW] or marking to similar effect to indicate the change is part of another PR.
I created a PR (#218) which includes only the type hinting commit, but this commit also includes some changes which could be breaking. I would change both PRs to remove those code parts which should not be included (e.g. dropping the deprecaded features). Just tell me which parts I should revert (if possible).

@Natureshadow
Copy link
Contributor

Natureshadow commented Jan 24, 2021

Thanks for the hint, I adapted the PR message.

Great. Please make it "an LDAP attribute", though, in the final documentation :).

@ProbstDJakob
Copy link
Contributor Author

Great. Please make it "an LDAP attribute", though, in the final documentation :).

Done

@ProbstDJakob ProbstDJakob force-pushed the master branch 2 times, most recently from 29767fd to f98d1de Compare January 27, 2021 04:18
@ProbstDJakob ProbstDJakob force-pushed the master branch 2 times, most recently from 0fe11dc to 4ab0369 Compare February 4, 2021 00:13
@Natureshadow
Copy link
Contributor

Hey @jdufresne and @francoisfreitag! An estimation whether we can expect this to be merged and released and, if we can, when, would be much appreciated.

The AlekSIS team has a long-standing and release-critical performance issue with code using django-auth-ldap, and profiling it is close to impossible with the old LDAP backend.

@francoisfreitag
Copy link
Member

Hi @Natureshadow,

I agree that the full-python implementation of the LDAP backend (ldap3) is easier to install and maintain, and probably easier for library users to interact with. My employer would also benefit from the switch to ldap3.

We’re in the process of splitting out this work into smaller increments that are easier to reason about and discuss. When the foundation is integrated, the backend change can be integrated.

The author separated the type hinting from backend switch, which is a good step towards getting type hinting integrated and keeping this PR focused on the backend switch.
Numerous unrelated “minor improvements” were suggested and need to be separated to be reviewed and discussed #231 (comment).

If you want to help integration, you can review the changes and make sure they:

  • are focused on one thing,
  • bring an improvement,
  • do not introduce regressions,
  • are documented (commit message, changelog)

Jakob Probst added 7 commits February 6, 2021 04:30
- add python 3.6+ type hints
- replace applying defaults dict in LDAPSettings with actual variables, allowing type hints, checking if variable exists (e.g. IDE), and preventing supplied defaults dict (LDAPSettings.__init__) to inject undesired variables
- add AbstractLDAPSearch as abstract base class
- fix (by removing) result of search_s not being checked if None in LDAPSearch.execute
- add conversion to string in AbstractLDAPSearch._escape_filterargs
- rename AbstractLDAPSearch._begin(...) to AbstractLDAPSearch._search(...) and AbstractLDAPSearch._results(...) to AbstractLDAPSearch._result(...)
- add AbstractLDAPSearch._abandon(...)
- LDAPSearch._search(...) saves the msgid inside the object instead of returning it
- make LDAPGroupType abstract
- MemberDNGroupType.is_member(...) now returns bool instead of Union[bool, int]
- remove kwargs from LDAPGroupQuery.__init__
- update test mocks corresponding to the AbstractLDAPSearch changes
… dynamic variable name

- renaming LDAPSettings._name(str) to LDAPSettings._prepend_prefix(str)
- replacing AUTH_LDAP_xyz in strings with LDAPSettings._prepend_prefix(xyz)
…to instance variables

- remove unused variables supports_anonymous_user, supports_object_permissions, and supports_inactive_user
- move settings_prefix to LDAPSettings
- remove default_settings
- change _settings and _ldap from class variables to instance variables
- add __setstate__ to set excluded properties to the object
- replace defaults dict with __init__ parameters
- drop support for CACHE_GROUPS
- add __setstate__ to set excluded properties to the object
- make _LDAPConfig.logger and NestedMemberDNGroupType.find_groups_with_any_member protected
- directly convert the group info into a dict in NestedMemberDNGroupType.user_groups
- check _group_type and _group_search against their corresponding type instead of None in _LDAPUserGroups._init_group_settings()
- use the settings object instead of the django settings to retrieve the global options in LDAPBackend.ldap()
- adjust type hints
- replace python-ldap methods/functions/... with the corresponding ldap3 ones
- remove deprecated features (uri call without argument and CACHE_GROUPS)
- remove CONNECTION_OPTIONS and GLOBAL_OPTIONS
- depends on async connections (`ldap3.ASYNC`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants