Opened 7 years ago

Closed 5 years ago

# LDAP bind using login creds

Reported by: Owned by: shawn.ohail@… branson normal DirectoryAuthPlugin normal 0.12

### Description

Nice plugin, thanks for writing it.

I was wondering if it's possible to bind to the ldap server using the login username/password and using that as the test for successful authentication. One other question then pops up, if we bind this way will we still be able to get the person's real name and email address to populate the session_attribute table?

### comment:1 Changed 7 years ago by John Hampton

Priority: normal → low new → assigned

So, I think I understand your question. I'll go with a long explanation and you can tell me that I misunderstood everything later.

The plugin does bind to the AD server using the creds supplied by the user logging into Trac. In fact, this is the only way that I know of to actually check whether or not they typed in the correct password.

That being said, I think you're interested in getting rid of the need to specify the bind_dn and bind_passwd options in the trac.ini

Obviously, it would require a code change to remove the need for bind_dn and bind_passwd. However, that's not to say it can't be done.

The bigger problem is in mapping usernames to DNs. To bind to AD, one needs a DN in the form of:

cn=Test M. User,ou=Users,dc=domain,dc=com


Rarely, however, do the login name (sAMAccountName attribute) and the cn portion match. A method for mapping sAMAccountName to DN would be needed. However, it may not be possible. For instance, in my organization, sAMAccountNames are first initial, middle initial, lastname. The cn, however, is the full name with the middle initial. There is no way to map from sAMAccountName to DN. Because of this, we bind as a known user, bind_dn, and then look for the sAMAccountName.

If we allow anonymous queries to AD (not the default as far as I am aware), then we could do the search for sAMAccountName without using bind_dn

If you have other suggestions, or perhaps even a patch, I'd be happy to consider them. I don't have an environment where I can play around with anonymous binds, so, without a patch, I'm not sure how quickly this will be implemented.

### comment:2 follow-up:  3 Changed 7 years ago by Shawn O'Hail

I think I follow what you're saying. To perform auth:

1. You bind using bind_dn and do a search for the login name to get the DN.

I'm not a python guy, but i am a perl guy. There is a class, Authen::Simple::ActiveDirectory, which does auth via AD, but does not require the same bind_dn account info that this plugin requires. Looking at the perl code they bind using the string 'username@domain' and login password. The host it binds to is the domain name itself.

So, in this way, can your plugin attempt to bind as the users's principal and avoid a separate bind account? If so, then I wonder if you're still able to look up attributes such as real name and password.

I'll try to have a look at your code and see if I can make this change. Not a python or LDAP guy but I would love to get this working for Trac!

### comment:3 in reply to:  2 ; follow-up:  5 Changed 7 years ago by John Hampton

Priority: low → normal

I think I follow what you're saying. To perform auth:

1. You bind using bind_dn and do a search for the login name to get the DN.

Exactly

Apparently, that also works. This is what I get for misunderstanding the documentation. I realize now that there is a slight difference between binding and authenticating. When binding using the full dn, it forces authentication using that object. However, once can also simply authenticate using the username@domain, and, if I read it correctly, domain\username should work also.

So, in this way, can your plugin attempt to bind as the users's principal and avoid a separate bind account? If so, then I wonder if you're still able to look up attributes such as real name and password.

In order to get full name, and email address we will still have to do a search and bind, but we should be able to do that with the authentication of the user.

I'll try to have a look at your code and see if I can make this change. Not a python or LDAP guy but I would love to get this working for Trac!

So, if you still feel inclined, you're more than welcome to try to make a patch. I will also try to find some time to adjust the code to make this possible. Thanks for helping me learn something.

### comment:4 Changed 7 years ago by Shawn O'Hail

Off the bat, for performance sake, I replaced _get_user_dn() with:

    def _get_user_dn(self, user):
return '%s@%s' % ( user, self.ads );


I messed around with this for quite a while, and best I can tell, unless you mangle the existing functionality or store login passwords for retrieval later, there's no clean way around having the extra account. Not a big deal though, I can work with it as is. The only thing I would change is upon login, update the session_attributes table with the current email/full name values from LDAP in case a) the user wasn't in LDAP the last time /admin/accounts/users was hit or b) this info changed.

Between this plugin, FlexibleAssignToPlugin, and this patch, I have everything I need.

### comment:5 in reply to:  3 Changed 6 years ago by olaf.meeuwissen@…

Apparently, that also works. This is what I get for misunderstanding the documentation. I realize now that there is a slight difference between binding and authenticating. When binding using the full dn, it forces authentication using that object. However, once can also simply authenticate using the username@domain, and, if I read it correctly, domain\username should work also.

I've been experimenting a bit on what is needed to bind. These are the conclusions regarding the strings I tried for bind_dn:

• using my distinguishedName fails to bind
• using my mail attribute fails to bind
• using my sAMAccountName attribute fails to bind
• using my userPrincipalName binding succeeds. The value of this attribute is formatted as an email address but different from mail.
• using the /o and /cn of the legacyExchangeDN in a domain\username binding succeeds. The /cn is identical to my sAMAccountName.
• same when using the information from msExchADCGlobalNames
• in all cases, case is irrelevant

I should add that we have had a domain name change. My mail attribute uses the new domain name, but the userPrincipalName still uses the old domain name. This value also uses my sAMAccountName as the username part.

Hope this helps.

### comment:6 Changed 5 years ago by branson

Owner: changed from John Hampton to branson assigned → new

So some points here:

• AD does not allow anonymous bind unless the registry is hacked. SO not sure that allowing search via anonymous is valid.
• if we tried to use the user/pass of the current user, we'd have to cache that password somewhere locally using reversable encryption. This is a Bad Idea(tm) from a security POV.
• you can use {user}@{realm} in some cases.. and we could flag to support that as the username if you wanted. Might even be able to extend to validate against multiple realms that way. Would take some coding, and I dont' have a multi-realm AD config to test with ;-)
• it's fairly trivial to setup a non-priv'd user for AD ( cn=search,cn=users,dc=ad,dc=com ) to perform searches .. but no logins.

### comment:7 Changed 5 years ago by branson

Resolution: → fixed new → closed

So .. I have fixed several things on this that you might find useful:

• Renamed the plugin to DirectoryAuthPlugin
• Now can do anonymous and SSL based bind.
• Name and email are now populating to the session table.. and you can select the vars that are used

I am gonna close this as I think it's fixed now. If you find trouble .. please open a new ticket.

### Modify Ticket

Change Properties