Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import ldap
- import logging
- import random
- import sys
- import traceback
- import os
- import hashlib
- from base64 import urlsafe_b64encode as encode
- from base64 import urlsafe_b64decode as decode
- LOG_FILENAME = '/tmp/ldap_backend.log'
- log = logging
- logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
- #log = logging.getLogger('atrium.auth.backends')
- from django.conf import settings
- from django.contrib.auth.models import User
- from django.db import transaction
- class LDAPBackendError(Exception):
- pass
- #need to map all of our user attributes to a LDAP attr for commit to work
- #CHANGE THIS FOR INETORG, JWUSER
- _DEFAULTS = {
- 'bindname': None,
- 'binddn': None,
- 'bindpw': None,
- 'group': None,
- 'groupdn': None,
- 'groupsu': None,
- 'groupstaff': None,
- 'groupactive': None,
- 'replicas': True,
- 'email': 'mail',
- 'first_name': 'cn',
- 'last_name': 'sn',
- 'username' : 'uid',
- 'sqlfallback' : True,
- 'objectClass' : ['jwUser' ,'inetOrgPerson', 'organizationalPerson', 'person', 'top'] ,
- 'timeout': 3,
- 'disable_update': False,
- 'all_attr' : ('username', 'first_name', 'last_name', 'email' ),
- }
- _REQUIRED = ('url', 'userdn')
- _TO_ITERABLE = ('url', 'group', 'groupsu', 'groupstaff', 'groupactive')
- class LDAPBackend():
- def changePasswd(self, username, newpassword):
- log.debug('LDAPBackend.changePasswd(%s,%s)' % (username, newpassword) )
- self._modifyPasswd(username, None, newpassword)
- #we just make sure that our password is set to the unusable value
- #user.password = '!'
- def authenticate(self, username=None, password=None):
- log.debug('LDAPBackend.authenticate(%s,%s)' % (username, password))
- if username is None or password is None:
- log.debug('Username or password is None, automatically returning None')
- return None
- blocks = self._buildBlocks()
- for block in blocks:
- log.debug('Processing block, settings: %s' % str(block))
- for opt in ('NETWORK_TIMEOUT', 'TIMELIMIT', 'TIMEOUT'):
- ldap.set_option(getattr(ldap, 'OPT_%s' % opt), block['timeout'])
- for uri in block['url']:
- conn = self._buildConn(uri)
- if not conn:
- log.error('Could not initialize connection to %s' % uri)
- continue
- #we need to pull our Primary uid here
- uid = self._getPrimaryUid(username, block)
- if uid is None:
- log.debug('Uid %s not found in %s' % (username, uri))
- break
- try:
- try:
- conn.simple_bind_s('uid=%s,%s' % (uid, block['userdn']), password)
- except ldap.INVALID_CREDENTIALS:
- log.debug('%s returned invalid credentials for %s' % (uri,uid))
- if block['replicas'] is True:
- return None
- break
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library: %s' % str(e))
- break
- if block['group'] is None:
- log.info('%s authenticated successfully against %s' % (uid, uri))
- return self._return_user(uid, conn, block)
- # If your directory is setup such that this user couldn't search (for whatever reason)
- # switch to an account that can so we can check the group
- if block['bindname'] is not None:
- log.debug('Rebinding to check group membership')
- conn.unbind()
- del conn
- conn = self._buildConn(uri)
- try:
- conn.simple_bind_s('cn=%s,%s' % (block['bindname'], block['binddn']), block['bindpw'])
- except ldap.LDAPError, e:
- log.error('Error during rebind: %s' % str(e))
- break
- for group in block['group']:
- log.debug('Checking if %s is a member of %s' % (uid, group))
- try:
- result = conn.search_s('cn=%s,%s' % (group, block['groupdn']), ldap.SCOPE_SUBTREE, '(objectclass=*)', ['memberUid'])
- except ldap.NO_SUCH_OBJECT:
- log.error('Could not find user object cn=%s,%s' % (group, block['groupdn']) )
- continue
- print result
- # If there's more than one result, it gets ignored (there shouldn't be more than one
- # group with the same name anyway)
- if not result:
- log.debug('No group found with name %s' % group)
- continue
- if 'memberUid' not in result[0][1]:
- log.debug('No memberUid in group %s' % group)
- continue
- else:
- log.debug('memberUid in group %s found!' % group)
- result = result[0][1]['memberUid']
- #print result[0]
- #print username
- u = 'uid=' + uid + ',' + block['userdn']
- if u in result:
- log.info('%s belongs to group %s' % (uid, group))
- log.info('%s authenticated successfully against %s' % (uid, uri))
- return self._return_user(uid, conn, block)
- else:
- log.info('%s user is not a member of %s' % (u, group))
- #return self._return_user(idmap, conn, block)
- if block['replicas'] is True:
- break
- finally:
- del conn
- if block['sqlfallback'] == True:
- log.debug('Going to SQL fall back for %s' % username)
- try:
- user = User.objects.get(username=username)
- #we set our data back to our raw password, then we import the user to LDAP, then we check the authentication
- if user.check_password(password):
- #Since our SQL user validated correctly, we now fall back to the LDAP user, and pull their details into the system.
- user = LDAP_User.objects.get(username=username)
- user.password = password
- #this pulls our data to LDAP ....
- user.save()
- #user = self._return_user(username, conn, block)
- user.password = '!'
- #And this pushes back to SQL some changes such as CN and SN and the password unusable hash
- user.save()
- #we want to save the SQL found user to our authentication service
- return user
- except User.DoesNotExist:
- #then our attempt was in vain anyway, and we just wait for the rest of our module to take it course
- log.debug('User %s does not exist in SQL, continuing' % username)
- log.info('User %s could not be authenticated against LDAP' % uid)
- return None
- def checkPasswd(self, uid, password):
- log.debug('LDAPBackend.checkPassword(%s,%s)' % (uid,password) )
- blocks = self._buildBlocks()
- for block in blocks:
- for uri in block['url']:
- #we only compare the current changes, rather than changes between servers (this will put their state into sync incidentaly)
- conn = self._buildConn(uri)
- if uid == None:
- continue
- puid = self._getPrimaryUid(uid, block)
- try:
- conn.simple_bind_s('uid=%s,%s' % (puid, block['userdn']), password)
- conn.unbind()
- except ldap.INVALID_CREDENTIALS:
- log.info('%s user could not bind, password is incorrect' % puid)
- continue
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library: %s' % str(e))
- continue
- return True
- #since one server has validated the authentication, we allow the user to proceed.
- return False
- def commitUser(self, user):
- log.debug('LDAPBackend.commitUser(%s)' % user)
- #log.debug('Refernece from %s to modify user')
- blocks = self._buildBlocks()
- update = False
- for block in blocks:
- for uri in block['url']:
- #we only compare the current changes, rather than changes between servers (this will put their state into sync incidentaly)
- conn = self._buildConn(uri)
- try:
- conn.simple_bind_s('cn=%s,%s' % (block['bindname'], block['binddn']), block['bindpw'])
- except ldap.INVALID_CREDENTIALS:
- log.error('%s Admin user could not bind. something is wrong...' % uri)
- continue
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library: %s' % str(e))
- continue
- #ldap_data = self._getUserByName(user.username, user, conn, block)
- #IDmap here to our "old" username, if not, it will find the current. if not, it will find that no user exists.
- uid = self._getPrimaryUid(user.username, block)
- #if uid is None:
- #if our uid fails to return data, it may be due to a username change.
- # oldname = User.objects.get(id=user.id).username
- # uid = self._getPrimaryUid(str(oldname), block)
- if uid == None:
- result = self._createUser(conn, block, user, uri)
- log.debug('User create returned %s' % result)
- else:
- result = self._modifyUser(conn, block, user, uid, uri)
- log.debug('User modify returned %s' % result)
- conn.unbind()
- log.debug('Unbound from cn=%s,%s' % (block['bindname'], block['binddn']) )
- del conn
- if result:
- update = True
- #this means our update has occured on at least one server, so we can continue
- if update == False:
- log.error('%s was unable to be (completely) saved!' % uid)
- #raise LDAPUserCreateError('%s was unabled to be saved/modified to the LDAP system. please view the logs' % uid)
- def get_user(self, user_id):
- log.debug('LDAPBackend.get_user(%s)' % user_id )
- try:
- return LDAP_User.objects.get(pk=user_id)
- except User.DoesNotExist:
- return None
- ################
- #private methods
- ################
- def _buildBlocks(self):
- log.debug('LDAPBackend._buildBlocks()')
- if isinstance(settings.LDAP_AUTH_SETTINGS[0], dict):
- log.debug('Using complex settings')
- blocks = settings.LDAP_AUTH_SETTINGS
- else:
- log.debug('Using simple settings')
- blocks = (self._parse_simple_config(),)
- # First get our configuration into a standard format
- for block in blocks:
- for r in _REQUIRED:
- if r not in block:
- raise LDAPBackendError('Missing required configuration option: %s' % r)
- for d in _DEFAULTS:
- if d not in block:
- block[d] = _DEFAULTS[d]
- for i in _TO_ITERABLE:
- if isinstance(block[i], str):
- block[i] = (block[i],)
- #Dont make our access random, we want to access servers in the order in the config
- block['url'] = list(block['url'])
- return blocks
- def _buildConn(self, uri):
- log.debug('LDAPBackend._buildConn(%s)' % uri)
- log.debug('Attempting to authenticate to %s' % uri)
- conn = ldap.initialize(uri)
- TLS = False
- for i in range(1, 3):
- try:
- conn.start_tls_s()
- TLS = True
- log.debug('TLS Established')
- break
- except ldap.LDAPError, e:
- log.error("Could not start TLS %s" % i)
- time.sleep(1)
- if TLS == False:
- log.error('TLS could not be initiated to %s!' % uri)
- #mail the admin
- #raise an error here
- raise LDAPBackendError('TLS Could not be initiated to the authentication server!')
- return None
- return conn
- def _changeUsername(self, user, uid, conn, block):
- log.debug('LDAPBackend.changeUsername(%s)' % uid )
- #since this uid we have is the primary from our former operation
- uid2 = self._getUid(uid, block)
- if uid2 != uid:
- #then our name has already been changed, we want to replace the second version with the new
- stack = [ (ldap.MOD_DELETE, block['username'], uid2), ( ldap.MOD_ADD, block['username'], user.username ) ]
- else:
- #our name hasnt been modified, we want to add the second attribute
- stack = [ ( ldap.MOD_ADD, block['username'], user.username ) ]
- try:
- conn.modify_s('uid=%s,%s' % (uid, block['userdn']) , stack)
- except ldap.LDAPError, e:
- log.error('Error modifying %s username to %s - %s' % (uid, user.username, str(e)) )
- def _createUser(self, conn, block, user, uri):
- log.debug('LDAPBackend._createUser(%s,%s,%s,%s)' % (conn,block,user,uri))
- log.debug('Choosing to create user %s' % user.username)
- exist = True
- #CHANGE THIS FOR INETORG
- try:
- conn.search_s('uid=%s,%s' % (user.username, block['userdn']), ldap.SCOPE_ONELEVEL, '(objectclass=*)', ['uid'])
- except ldap.NO_SUCH_OBJECT, e:
- log.debug('User %s does not exist, time to insert them' % user.username)
- exist = False
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library: %s' % str(e))
- return False
- if exist:
- log.debug('User %s already exists, migrating to %s' % (user.username, uri) )
- #if they exist, we should be adding the group membership
- try:
- r = self._migrateUser(conn, block, user, uri)
- except:
- log.debug(sys.exc_info()[0])
- return r
- #with this, since user creates are handled by the UserManage module, we can be pretty safe we are adding a new user, not overiding one.
- #we need to iterate over all our user values.
- stack = []
- #for oc in block['objectClass']:
- stack.append( ('objectClass', block['objectClass'] ) )
- #Create our idmap here
- if user.password is not None:
- password = user.password
- else:
- password = LDAP_User.objects.make_random_password(20)
- hashpassword = self._makeSecret(password)
- stack.append( ('userPassword' , hashpassword) )
- for attr in block['all_attr']:
- #we need a way to skip some attributes like username and password etc.
- if attr != 'password' or attr != 'username':
- log.debug('%s attr , %s' % (attr, str(getattr(user,attr)) ) )
- if str(getattr(user,attr)) is None or str(getattr(user,attr)) is '' :
- stack.append( (block[attr] , 'Anonymous' ), )
- else:
- stack.append( (block[attr] , str(getattr(user, attr)) ), )
- #now we push out our user, and hope nothing bad happens .....
- try:
- log.debug(stack)
- conn.add_s('uid=%s,%s' % (user.username, block['userdn']) , stack)
- log.debug('Succesfully created user %s' % user.username)
- #we should also be catching when a unique constrait is violated.
- except ldap.LDAPError, e:
- log.error('Error attempting to create user %s to %s' % (user.username, uri))
- return False
- #now we want to call our actually user password change method so the new user can *actually* bind and atuhenticate
- #we also want to make our userpassword ! to force validation against the LDAP
- if password is not None:
- self.changePasswd(user, password)
- else:
- user.set_unusable_password()
- #we also need to add groups from the user_is active etc
- r = self._modifyUserGroup(conn, user, user.username, block)
- if r == False:
- #shit has gone down, fix it in our create
- conn.delete_s('uid=%s,%s' % (user.username, block['userdn']) )
- return True
- def _getUserByUid(self, uid, user, conn, block):
- log.debug('LDAPBackend._getUserByName(%s)' % uid)
- #CHANGE HERE FOR INETORG
- try:
- r = conn.search_s('uid=%s,%s' % (uid, block['userdn']), ldap.SCOPE_SUBTREE,
- '(objectclass=*)', [block['email'], block['first_name'], block['last_name']])
- except ldap.NO_SUCH_OBJECT, e:
- log.warning('Could not get user information for %s, LDAP user does not exist returning possibly stale user object' % uid)
- return user
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library, returning our user: %s' % str(e))
- return user
- #log.debug('Got back results %s' % r)
- results = r[0][1]
- ldap_data = {}
- if block['email'] is not None:
- ldap_data['email'] = results[block['email']][0] if block['email'] in results else ''
- if block['first_name'] is not None:
- ldap_data['first_name'] = results[block['first_name']][0] if block['first_name'] in results else ''
- if block['last_name'] is not None:
- ldap_data['last_name'] = results[block['last_name']][0] if block['last_name'] in results else ''
- if block['username'] is not None:
- ldap_data['username'] = self._getUid(user.username, block)
- #pull back our username value here. It should exist in our useralso.
- #If we have a secondary username, we should retrieve it here, and apply it to the user.
- for g, attr in (('groupsu', 'is_superuser'), ('groupstaff', 'is_staff'), ('groupactive', 'is_active')):
- if block[g] is not None:
- ldap_data[attr] = False
- for group in block[g]:
- #these groups MUST exist, but if not we want to log this error.
- try:
- result = conn.search_s('cn=%s,%s' % (group, block['groupdn']), ldap.SCOPE_SUBTREE,
- '(objectclass=*)', ['memberuid'])
- except ldap.NO_SUCH_OBJECT:
- log.error('Group object %s does not exist %s!' % (group, str(e)) )
- continue
- if not result or 'memberUid' not in result[0][1]:
- continue
- log.debug(result)
- result = result[0][1]['memberUid']
- if 'uid=%s,%s' % (uid, block['userdn']) in result:
- ldap_data[attr] = True
- #break
- log.debug(ldap_data)
- return ldap_data
- def _getPrimaryUid(self, username, block):
- log.debug('LDAPBackend.getPrimaryUid(%s)' % username )
- for uri in block['url']:
- conn = self._buildConn(uri)
- try:
- conn.simple_bind_s('cn=%s,%s' % (block['bindname'], block['binddn']), block['bindpw'])
- except ldap.INVALID_CREDENTIALS:
- log.error('Admin user could not bind. something is wrong...')
- continue
- except ldap.LDAPError, e:
- log.error('Got error from the LDAP library: %s' % str(e))
- continue
- r = conn.search_s(block['userdn'], ldap.SCOPE_SUBTREE, 'uid=%s' % username, ['uid'])
- conn.unbind()
- del conn
- log.debug(r)
- if r != []:
- return r[0][1]['uid'][0]
- return None
- def _getUid(self,username, block):
- log.debug('LDAPBackend.getUid(%s)' % username)
- for uri in block['url']:
- conn = self._buildConn(uri)
- try:
- conn.simple_bind_s('cn=%s,%s' % (block['bindname'], block['binddn']), block['bindpw'])
- except ldap.INVALID_CREDENTIALS:
- log.error('Admin user could not bind. something is wrong...')
- continue
- except ldap.LDAPError, e:
- log.error('Got error from the LDAP library: %s' % str(e))
- continue
- r = conn.search_s(block['userdn'], ldap.SCOPE_SUBTREE, 'uid=%s' % username, ['uid'])
- conn.unbind()
- del conn
- log.debug(r)
- if r != []:
- try:
- return r[0][1]['uid'][1]
- except:
- return r[0][1]['uid'][0]
- return None
- def _makeSecret(self, password):
- log.debug('LDAPBackend._makeSecret(%s)' % password)
- salt = os.urandom(4)
- h = hashlib.sha1(password)
- h.update(salt)
- return "{SSHA}" + encode(h.digest() + salt)
- def _migrateUser(self, conn, block, user, uri):
- log.debug('LDAPBackend._migrateUser(%s,%s,%s,%s)' % (conn,block,user,uri))
- #we know our user already exists, so we need to check they have a JW user attribute
- uid = self._getPrimaryUid(user.username, block)
- log.debug('Checking if %s has JW attrs' % uid)
- try:
- result = conn.search_s('uid=%s,%s' % (str(uid), block['userdn']), ldap.SCOPE_SUBTREE, '(objectclass=*)')
- except ldap.NO_SUCH_OBJECT:
- log.error('Could not find user object, this isnt correct, uid=%s,%s' % (uid, block['userdn']) )
- return False
- stack = []
- if result:
- if 'jwUser' not in result[0][1]['objectClass']:
- #we should make it so that we delete the other object classes, then add them back with the jwUser, providded that they are compatible.
- log.error('Cannot add %s, this would create an object class violation!' % uid)
- return False
- #technically this section should never be called, but it will be useful to 'resync' a broken user profile that lacks the attributes it needs.
- for oclass in block['objectClass']:
- if oclass not in result[0][1]['objectClass']:
- stack.append( (ldap.MOD_ADD, 'objectClass', str(oclass) ) )
- log.debug('User %s does not have %s objectClass, adding' % (str(uid) , oclass))
- #check that we have all of our needed attributes. if not push them to the stack to be added
- for attr in block['all_attr']:
- if block[attr] not in result[0][1]:
- stack.append( (ldap.MOD_ADD, block[attr] , str(getattr(user, attr)) ) )
- Result = self._modifyUserGroup(conn, user, uid, block)
- if Result:
- #since we don't depend on the user migrate working, we wait till we knows groups have worked, then we commit our user.
- try:
- conn.modify_s('uid=%s,%s' % (uid, block['userdn']), stack)
- log.debug('%s migrated succesfully' % uid)
- except ldap.LDAPError, e:
- log.error('%s at %s migrate command failed. %s %s' % (uid, uri, stack, str(e) ) )
- return False
- return Result
- def _modifyPasswd(self, username, oldpassword, newpassword):
- log.debug('LDAPBackend._modifyPassword(%s,%s,%s)' % (username, oldpassword, newpassword))
- blocks = self._buildBlocks()
- for block in blocks:
- for uri in block['url']:
- conn = self._buildConn(uri)
- try:
- uid = self._getPrimaryUid(username, block)
- if uid != None:
- conn.simple_bind_s('cn=%s,%s' % (block['bindname'], block['binddn']), block['bindpw'])
- conn.passwd_s('uid=%s,%s' % (uid, block['userdn']), oldpassword, newpassword)
- conn.unbind()
- del conn
- else:
- continue
- except ldap.INVALID_CREDENTIALS:
- log.error('%s returned invalid admin credentials on attempt to change passwd by %s' % (uri, uid))
- break
- except ldap.LDAPError, e:
- log.error('Got error from LDAP library: %s' % str(e))
- break
- r = self.checkPasswd(uid, newpassword)
- if r is True:
- log.debug('New password for %s authenticated succesfully' % uid)
- else:
- log.error('%s error binding as changed %s password - holy shitting dick nipples something is bad!' % (uri, uid))
- def _modifyUser(self, conn, block, user, uid, uri):
- log.debug('LDAPBackend._modifyUser(%s,%s,%s,%s,%s)' % (conn,block,user,uid,uri))
- log.debug('Choosing to modify user %s' % uid)
- user_stack = []
- ldap_data = self._getUserByUid(uid, user, conn, block)
- #if we dont find our user, we get the original object back and no update will occur.
- #if we do, add our uri to the stack of servers to modify / add
- #we need to work out if it is a group change or a attr change, and act accordingly
- for attr in ldap_data:
- if attr != 'password' or attr != 'username': #this allows us to skip values that should be immutable
- if getattr(user, attr) != ldap_data[attr]:
- #push our changed attr to a stack, ready to be modified
- if not (ldap.MOD_ADD, block[attr], getattr(user, attr)) in user_stack or not (ldap.MOD_REPLACE, block[attr], getattr(user, attr)) in user_stack:
- #work out if its a replace or add operation (we can have many emails etc but likely not)
- if ldap_data[attr] == None:
- op = ldap.MOD_ADD
- else:
- op = ldap.MOD_REPLACE
- if str(getattr(user,attr)) is '' or str(getattr(user,attr)) is None:
- user_stack.append( (op, block[attr], 'Anonymous') )
- else:
- user_stack.append( (op , block[attr], str(getattr(user, attr)) ) )
- #once we know the changes, we save them to the ldap in a single hit.
- if user_stack != []:
- try:
- conn.modify_s('uid=%s,%s' % (uid, block['userdn']), user_stack)
- log.debug('%s modified succesfully' % uid)
- except ldap.LDAPError, e:
- log.error('%s at %s modify command failed. %s %s' % (uid, uri, user_stack, str(e) ) )
- return False
- #does this really need to worry about the return of the group mod op?
- r = self._modifyUserGroup(conn, user, uid, block)
- if ldap_data['username'] != user.username:
- #likely our username has changed, and we should update this.
- self._changeUsername(user, uid, conn, block)
- return r
- #we should consider checking that it worked .....
- def _modifyUserGroup(self, conn, user, uid, block):
- log.debug('LDAPBackend._modifyUserGroup(%s,%s,%s,%s)' % (conn,user,uid,block))
- #check that our membership exists
- try:
- member_stack = [ (ldap.MOD_ADD, 'memberUid', 'uid=%s,%s' % (str(uid), block['userdn']) ) ]
- conn.modify_s('cn=%s,%s' % (block['group'][0], block['groupdn']), member_stack)
- except ldap.TYPE_OR_VALUE_EXISTS:
- log.error('%s already exists in %s' % (uid, block['group']) )
- except ldap.LDAPError, e:
- #we hit an error, so we revent our change to the user, this one is the bad error to hit.
- log.error('Error adding %s to %s %s' % (uid, block['group'], str(e) ) )
- return False
- for g, attr in (('groupsu', 'is_superuser'), ('groupstaff', 'is_staff'), ('groupactive', 'is_active')):
- if block[g] is not None:
- for group in block[g]:
- #now we check that our user, and add them to the group
- try:
- if getattr(user, attr) == True:
- mod_attrs = [ (ldap.MOD_ADD, 'memberUid', 'uid=%s,%s' % (str(uid), block['userdn']) ) ]
- else:
- mod_attrs = [ (ldap.MOD_DELETE, 'memberUid', 'uid=%s,%s' % (str(uid), block['userdn']) ) ]
- conn.modify_s('cn=%s,%s' % (group, block['groupdn']), mod_attrs)
- log.debug('Successfully modified %s with user %s' % (group, uid) )
- except ldap.NO_SUCH_ATTRIBUTE:
- continue
- except ldap.TYPE_OR_VALUE_EXISTS:
- continue
- except ldap.LDAPError, e:
- log.error('Error adding %s to %s %s' % (uid, group, str(e) ) )
- #we hit an error, but, in the schema of things a group error isnt to big of a deal and is easy to correct, and also extremely unlikely to occur.
- #in the majority of cases, this will only result in a user having no ablitiy to login, or permissions not granted, both of which are not bad situations
- return True
- def _parse_simple_config(self):
- log.debug('LDAPBackend._parse_simple_config()')
- if len(settings.LDAP_AUTH_SETTINGS) < 2:
- raise LDAPBackendError('In a minimal configuration, you must at least specify url and user DN')
- ret = {'url': settings.LDAP_AUTH_SETTINGS[0], 'userdn': settings.LDAP_AUTH_SETTINGS[1]}
- if len(settings.LDAP_AUTH_SETTINGS) < 3:
- return ret
- if len(settings.LDAP_AUTH_SETTINGS) < 4:
- raise LDAPBackendError('If you specify a required group, you must specify the group DN as well')
- ret['group'] = settings.LDAP_AUTH_SETTINGS[2]
- ret['groupdn'] = settings.LDAP_AUTH_SETTINGS[3]
- return ret
- def _return_user(self, uid, conn, block):
- log.debug('LDAPBackend._return_user(%s,%s,%s)' % (uid,conn,block))
- try:
- user = LDAP_User.objects.get(username=uid)
- except User.DoesNotExist:
- log.info('User %s did not exist in Django database, creating' % uid)
- user = LDAP_User(username=uid, password='')
- user.set_unusable_password()
- #user.save()
- ldap_data = self._getUserByUid(uid, user, conn, block)
- log.debug(ldap_data)
- log.info('Updating Django database for user %s' % uid)
- log.debug('Setting attributes: %s' % str(ldap_data))
- for attr in ldap_data:
- setattr(user, attr, ldap_data[attr])
- #conviniently, this will pull our other servers into sync with the data our user has here.
- user.save()
- return user
- #we define our custom error handlers.
- class Error(Exception):
- pass
- class LDAPUserCreateError(Error):
- def __init__(self, expr, msg):
- self.msg = msg
- class LDAP_User(User):
- class Meta:
- proxy = True
- def save(self,*args,**kwargs):
- log.debug('LDAP_User.save()' )
- try:
- sid = transaction.savepoint()
- #save to ldap here
- ldapbackend = LDAPBackend()
- # we dont want to catch this raised exception, we want to use it to hook our roll back.
- ldapbackend.commitUser(self)
- del ldapbackend
- super(User,self).save(*args,**kwargs)
- transaction.savepoint_commit(sid)
- except:
- log.debug('Error saving user: %s' % sys.exc_info()[0] )
- transaction.savepoint_rollback(sid)
- def set_password(self, rawpassword):
- log.debug('LDAP_User.set_password(%s)' % rawpassword)
- ldapbackend = LDAPBackend()
- ldapbackend.changePasswd(self, rawpassword)
- #we should be checking if our user exists before saving, and set the unusable password anyway
- #since the user model already exists, it must have come out of the lday system, so we dont need to check.
- #we dont need to do a self.save() because it is not in the original models method, its also saved to ldap internal to the methods.
- def check_password(self, rawpassword):
- log.debug('LDAP_User.check_password(%s)' % rawpassword)
- #return a boolean of true or false if we can bind.
- ldapbackend = LDAPBackend()
- return ldapbackend.checkPasswd(self.username, rawpassword)
- #do a bind operation
Add Comment
Please, Sign In to add comment