Jonas Byström
Jonas Byström

Reputation: 26129

Authenticate through AD/LDAP

I don't know much about AD and LDAP, but trying to implement the most trivial LDAP/AD login function in Python. Lo luck so far though I tested several different modules. The most promising one might be ldap3:

>>> import ldap3
>>> server = ldap3.Server('myserver')
>>> connection = ldap3.Connection(server)
>>> connection.bind()
True
>>> connection.search(search_base='DC=mydomain,DC=com', search_filter='(&(objectClass=person)([email protected]))', search_scope='LEVEL', attributes=ldap3.ALL_ATTRIBUTES)
True
>>> connection.response[0]
{'uri': ['ldap://ForestDnsZones.mydomain.com/DC=ForestDnsZones,DC=mydomain,DC=com??base'], 'type': 'searchResRef'}
>>> connection.result
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'searchResDone'}

Could you give me some pointers if this is on the right path or not?

The setup seems good enough for the basics, as I'm able to extract some type of metadata from it:

>>> server._get_dsa_info(connection)
>>> server._dsa_info
DSA info (from DSE):
  Supported LDAP versions: 3, 2
  Naming contexts:
    DC=mydomain,DC=com
    CN=Configuration,DC=mydomain,DC=com
    CN=Schema,CN=Configuration,DC=mydomain,DC=com
    DC=DomainDnsZones,DC=mydomain,DC=com
    DC=ForestDnsZones,DC=mydomain,DC=com

  Supported controls:
    1.2.840.113556.1.4.1338 - Verify name - Control - MICROSOFT
    1.2.840.113556.1.4.1339 - Domain scope - Control - MICROSOFT
    1.2.840.113556.1.4.1340 - Search options - Control - MICROSOFT
    ...

I've also tried flask-ldap3-login, but is starting to suspect that our AD is not configured according to standard, as I'm getting:

...
>>> response = ldap_manager.authenticate('me', 'my_pass')
LDAPNoSuchObjectResult - 32 - noSuchObject - CN=Schema,CN=Configuration,DC=mydomain,DC=com - 0000208D: NameErr: DSID-0315270B, problem 2001 (NO_OBJECT), data 0, best match of:
        'CN=Schema,CN=Configuration,DC=mydomain,DC=com'
  - searchResDone - None

Please don't hesitate to ask for additional information, and I'll try to figure it out as best I can. For instance, my own user is located in:

CN=Lastname Firstname,OU=Consultants,OU=Users,OU=SE,OU=MYDOMAIN,DC=mydomain,DC=com

Some values are:

objectClass = top;person;organizationalPerson;user
name = Lastname Firstname
userPrincipalName = [email protected]

Also, from CN=Schema,CN=Configuration,DC=mydomain,DC=com there is only one subschema, which is CN=Aggregate,CN=Schema,CN=Configuration,DC=mydomain,DC=com and it looks empty. For some reason I believe this is what flask-ldap3-login tries to use.

Upvotes: 4

Views: 5932

Answers (1)

Jonas Byström
Jonas Byström

Reputation: 26129

My problem using the ldap3.Connection was that I didn't use a login when binding. This seems to be a way forward:

import ldap3
user = '[email protected]'
password = 'mypassword'
server = ldap3.Server('myserver')
connection = ldap3.Connection(server, user=user, password=password)
connection.bind()
connection.search(search_base='DC=mycompany,DC=com', search_filter='(&(objectClass=user)(userPrincipalName='+user+'))', search_scope='SUBTREE', attributes='*')

And if you like to print some data:

attrs = connection.response[0]['attributes']
print(attrs['displayName'])
for memb in attrs['memberOf']:
    print(memb.partition('=')[2].partition(',')[0])

Upvotes: 4

Related Questions