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

Skip to content

Conversation

d0b3rm4n
Copy link

This is a WIP PR so not everything is polished yet, e.g. PEP8 (too long lines) fail at the moment also the documentation is not yet updated. Also the test classes could be streamlined and duplicated code avoided. But it is easier to handle things with these long lines for the moment and I wanted to make it first work and pass. Still I would like to get some feedback already.

The motivation for this PR is a issue which I ran into and is related to issue (#173) (actually might even solve it). Our ActiveDirectory does not allow anonymous binding and I want to avoid to configure a bind user. I can't just use the user template (USER_DN_TEMPLATE), since the structure is not really flat. So I have to search for users. So I want to use the BIND_AS_AUTHENTICATING_USER setting. So that the user binds himself but the real dn is still searched. But unfortunately to bind to the AD LDAP only providing the sAMAccountName is not sufficient, it needs to be sAMAccountName@AD.DOMIAN. So I came up with the BIND_DN_TEMPLATE config option which can be used for that.

I added some tests to check the current behavior (bfc5365) and changed the connection property (current state is in some 4 commits):

if not self._connection_bound:
if self.settings.BIND_AS_AUTHENTICATING_USER and self.settings.BIND_DN_TEMPLATE:
bind_dn = self.settings.BIND_DN_TEMPLATE % {"user": self._username}
logger.debug("Bind DN: %s", bind_dn)
self._bind_as(bind_dn, self.password, sticky=True)
else:
self._bind()

And updated some of the testcases that now work (work in the sense that this config options get a user)

With these changes I can now configure the following and Django can authenticate users and find their groups without bind user:

AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
AUTH_LDAP_BIND_DN_TEMPLATE = "%(user)[email protected]"


AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
    # Group one
    LDAPSearch("OU=Users,OU=GR1,OU=Identities,DC=AD,DC=DOMAIN,DC=com",
               ldap.SCOPE_ONELEVEL, "(sAMAccountName=%(user)s)"),
    # Group two
    LDAPSearch("OU=Users,OU=GR2,OU=Identities,DC=AD,DC=DOMAIN,DC=com",
               ldap.SCOPE_ONELEVEL, "(sAMAccountName=%(user)s)"),
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearchUnion(
    LDAPSearch("OU=Groups,OU=GR1,OU=Identities,DC=AD,DC=DOMAIN,DC=com",
               ldap.SCOPE_SUBTREE, "(objectClass=group)"),
    LDAPSearch("OU=Groups,OU=GR2,OU=Identities,DC=AD,DC=DOMAIN,DC=com",
               ldap.SCOPE_SUBTREE, "(objectClass=group)"),
)

AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()

I also added a coverage target to tox.ini, to verify that from my new code all is covered.

image

Maybe also #301 should be taken into account, but I didn't verify that yet.

@francoisfreitag
Copy link
Member

Thanks for the PR and rationale.

Can you give a bit more details about why you would like to avoid to configuring a bind user?
A bind user makes it easier to reason about the application permissions. Different users may have different permissions, I’m expecting the same search to have different results based on who performs the search, which initially looks like a recipe for bugs.

@d0b3rm4n
Copy link
Author

Can you give a bit more details about why you would like to avoid to configuring a bind user? A bind user makes it easier to reason about the application permissions. Different users may have different permissions, I’m expecting the same search to have different results based on who performs the search, which initially looks like a recipe for bugs.

I see your point, but IMHO any user credentials (in this case the bind user) which do not need to be saved in plain text in any config file, can not be lost are leaked by accident. And since configuring LDAP is not really easy I would not wonder if admins actually use the admin/root user as the bind user (which even might have access to read the password hash!). And in some companies it might not be "easy" to actually get a bind user from the AD admins. On the other side, I do not see a reason why an admin would want to hide from a user, to which groups he belongs (or other details of his LDAP entry e.g. email/phone number). So the user should be able to "find" his/her groups he/she belongs to (even if they are nested).

Also a bind user might be "misconfigured", but I agree that would be easier to debug.

I consider django_auth-ldap as a framework, which gives admins the power to do things in a way they want it to do. With power comes responsibility. And you never can save all admins from mistakes :)

And the option to not use a bind user is already given, this PR only add more possibilities to make use of that "feature".

So what do you think, does the PR have a chance?
If so then I can start with adding documentation and cleaning up stuff.

@francoisfreitag
Copy link
Member

This PR has a chance. I agree that the library should not block users from having their ways of doing things, unless they are obviously shooting themselves in the foot, which does not seem to be the case here.

I probably would fight pretty hard to get a “system” user that binds and executes the searches on my projects, but that’s only my perspective. Because your use case is not easy to fill with the library, changing the library is fine.

There are issues with the proposed approach:

  1. BIND_DN_TEMPLATE duplicate the logic to construct the user DN from USER_DN_TEMPLATE (without the escaping). Could both settings be merged? IMO, the authenticated search has no reason
  2. A duplicate bind is issued when BIND_AS_AUTHENTICATING_USER is True and self.settings.BIND_DN_TEMPLATE is specified (during _bind_as()). The library should avoid rebinding when unnecessary.

Ideally, the tests would reuse (and maybe extend) the existing logic to setup the LDAP rather that use a different setup.

@d0b3rm4n
Copy link
Author

This PR has a chance. I agree that the library should not block users from having their ways of doing things, unless they are obviously shooting themselves in the foot, which does not seem to be the case here.

I probably would fight pretty hard to get a “system” user that binds and executes the searches on my projects, but that’s only my perspective. Because your use case is not easy to fill with the library, changing the library is fine.

OK thx, then I will continue, but I will not have time to work on it during July. I will continue in August on it.

There are issues with the proposed approach:

  1. BIND_DN_TEMPLATE duplicate the logic to construct the user DN from USER_DN_TEMPLATE (without the escaping). Could both settings be merged? IMO, the authenticated search has no reason

Yeah I was wondering the same already earlier but back then it looked simpler to introduce the BIND_DN_TEMPLATE. I again tried it in d0b3rm4n@22cbb6d but that breaks the test_bind_as_user() test case since it now expects the USER_SEARCH. So the current way uses the USER_DN_TEMPLATE also as a flag when ever to "search" the user or not. At the moment I don't see a way to merge the functionality without breaking the current behavior. Or do you see a way?

  1. A duplicate bind is issued when BIND_AS_AUTHENTICATING_USER is True and self.settings.BIND_DN_TEMPLATE is specified (during _bind_as()). The library should avoid rebinding when unnecessary.

So yeah I need some check there, when BIND_AS_AUTHENTICATING_USER is True and already bound because we used the TEMPLATE to search already as that user. It now depends a little on issue 1 on how that could be solved, so I leave it atm open.

Ideally, the tests would reuse (and maybe extend) the existing logic to setup the LDAP rather that use a different setup.

Yeah one part uses the same LDAP, but I spent some 4-5h to try to get the already running LDAP to change the config on the fly to not allow anonymous bindings, without success. The other part is the same more or less copy/pasted. With the tests I still have some ideas how to refactor. I will also tackle that once we agreed on the use on BIND_DN_TEMPLATE and/or USER_DN_TEMPLATE usage.

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.

2 participants