Python+LDAP+SSL

ellerseer picture ellerseer · Oct 10, 2011 · Viewed 25.6k times · Source

Good day.

In advance to apologize for my English, my national forums and resources did not help.

There was a need in the script that changes (or creates) a user password in AD.

After studying the issue, it became clear that

  1. Password to assign or change can only establish an encrypted connection to the server
  2. Send the password is only necessary in the encoding utf-16-le

In general there is no problem with the second, but first have a problem with

$ python ldap-test-starttls.py 
Traceback (most recent call last):
  File "ldap-test-starttls.py", line 9, in <module>
    l.simple_bind_s( "cn=admin,ou=users,dc=test,dc=ru", "password" )
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 206, in simple_bind_s
    msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 200, in simple_bind
    return    self._ldap_call(self._l.simple_bind,who,cred,EncodeControlTuples(serverctrls),EncodeControlTuples(clientctrls))
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 96, in _ldap_call
    result = func(*args,**kwargs)
 ldap.SERVER_DOWN: {'info': 'A TLS packet with unexpected length was received.', 'desc': "Can't contact LDAP server"}

Script code

import ldap
host = 'ldaps://ldap:636'
l = ldap.initialize(host)
l.set_option( ldap.OPT_X_TLS_DEMAND, True )
l.set_option( ldap.OPT_DEBUG_LEVEL, 255 )
username = 'someUser'
new_pass = 'ne$wP4assw0rd3!'
new_password = ('"%s"' % new_pass).encode("utf-16-le")
l.simple_bind_s( "cn=admin,ou=users,dc=test,dc=ru", "password" )
mod_attrs = [(ldap.MOD_REPLACE, 'unicodePwd', new_password)],[( ldap.MOD_REPLACE, 'unicodePwd', new_password)]
l.modify_s('CN=%s,dc=users,dc=test,dc=ru' % username, mod_attrs)
l.unbind_s()
print "Successfully changed password."

Chances are someone has already solved a similar problem. Yes, the script is running on Centos and use py32win not possible.

Thanks in advance.

Answer

ellerseer picture ellerseer · Oct 18, 2011

After looking into it more I was able to come up with a solution:

ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
l = ldap.initialize("ldaps://ldap:636")
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
l.set_option( ldap.OPT_X_TLS_DEMAND, True )
l.set_option( ldap.OPT_DEBUG_LEVEL, 255 )
l.simple_bind_s("[email protected]","password")