Skip to content

Instantly share code, notes, and snippets.

@hanleybrand
Last active December 22, 2015 12:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hanleybrand/6470936 to your computer and use it in GitHub Desktop.
Save hanleybrand/6470936 to your computer and use it in GitHub Desktop.
Drop-in log-chatty replacement for mdid3: rooibos/auth/ldapauth.py that also will handle ldap configurations that require a bind user (see settings_local_fragment.py for the additional settings you need to add.
from django.contrib.auth.models import User
from django.conf import settings
import ldap
from baseauth import BaseAuthenticationBackend
import logging
class LdapAuthenticationBackend(BaseAuthenticationBackend):
def authenticate(self, username=None, password=None):
for ldap_auth in settings.LDAP_AUTH:
try:
username = username.strip()
#l = ldap.initialize(ldap_auth['uri'], trace_level=5)
l = ldap.initialize(ldap_auth['uri'])
l.protocol_version = ldap_auth['version']
for option, value in ldap_auth['options'].iteritems():
l.set_option(getattr(ldap, option), value)
### fixing this
if ldap_auth.get('bind_user'):
logging.debug('ldapauth: bind_user configured')
#bind credential for lookup
l.simple_bind(ldap_auth['bind_user'],
ldap_auth.get('bind_password'))
#search for user
result = l.search_s(ldap_auth['base'],
ldap_auth['scope'],
'%s=%s' % (ldap_auth['cn'], username),
attrlist=[ldap_auth.get('dn', 'dn')])
if (len(result) != 1):
logging.debug('ldapauth: search for %s failed, returned: %s' % (username, result))
continue
dn = result[0][1].get(ldap_auth.get('dn', 'dn'))
logging.debug('ldapauth: resulting dn from lookup of %s is %s' % (username, dn))
if type(dn) in (tuple, list):
dn = dn[0]
### end fix
elif ldap_auth.get('no_bindGetDN'):
result = l.search_s(ldap_auth['base'],
ldap_auth['scope'],
'%s=%s' % (ldap_auth['cn'], username),
attrlist=[ldap_auth.get('dn', 'dn')])
if len(result) != 1:
continue
dn = result[0][1].get(ldap_auth.get('dn', 'dn'))
#dn = result[0][0]
if type(dn) in (tuple, list):
dn = dn[0]
else:
dn = '%s=%s,%s' % (ldap_auth['cn'], username, ldap_auth['base'])
logging.debug('ldapauth: %s login with dn: %s' % (username, dn))
l.simple_bind(dn, password)
#logging.debug('result of dn, password: %s' % testing)
result = l.search_s(ldap_auth['base'],
ldap_auth['scope'],
'%s=%s' % (ldap_auth['cn'], username),
attrlist=ldap_auth['attributes'])
logging.debug('ldap bind result: \n%s' % result[0][1])
if (len(result) != 1):
continue
attributes = result[0][1]
for attr in ldap_auth['attributes']:
if attributes.has_key(attr):
if not type(attributes[attr]) in (tuple, list):
attributes[attr] = (attributes[attr],)
else:
attributes[attr] = []
try:
user = User.objects.get(username=username)
logging.debug('ldapauth: %s exists, continuing' % username)
except User.DoesNotExist:
logging.debug('ldapauth: %s does not exist, attempting to create account for %s %s' %
(username,
''.join(attributes[ldap_auth['firstname']]),
''.join(attributes[ldap_auth['lastname']])))
user = self._create_user(username,
None,
''.join(attributes[ldap_auth['firstname']]),
''.join(attributes[ldap_auth['lastname']]),
attributes[ldap_auth['email']][0],
)
if not self._post_login_check(user, attributes):
continue
logging.debug('ldapauth: success; returning %s ' % user.username)
return user
except ldap.LDAPError, error_message:
logging.debug('ldapauth: LDAP error. \n%s' % error_message)
finally:
if l:
l.unbind_s()
return None
from django.contrib.auth.models import User
from django.conf import settings
from random import Random
import string
import logging
class BaseAuthenticationBackend:
def _create_user(self, username, password=None, first_name=None, last_name=None, email=None):
password = password or ''.join(Random().sample(string.letters + string.digits, 20))
last_name = last_name or username
user = User(username=username, password=password)
user.first_name = first_name and first_name[:30] or ''
user.last_name = last_name[:30]
user.email = email
logging.debug('baseauth: Created account %s (%s %s, %s)' %
(username,
first_name,
last_name,
email,
))
user.save()
return user
def _post_login_check(self, user, info=None):
for check in settings.LOGIN_CHECKS:
module, method = check.rsplit('.', 1)
module = __import__(module, globals(), locals(), 'rooibos')
method = getattr(module, method)
if not method(user, info):
return False
return True
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
LDAP_AUTH = (
{
# standard LDAP config - you should have these correct for your instiution
'uri': 'ldap://ldap.institution.edu:11389',
'base': 'ou=folks,dc=institution,dc=edu',
'cn': 'cn',
'dn': 'dn',
'version': 3,
'scope': 1,
'options': {'OPT_X_TLS_TRY': 1,
'OPT_REFERRALS': 0,
},
'attributes': ('sn', 'mail', 'givenname', 'eduPersonPrimaryAffiliation'),
'firstname': 'givenname',
'lastname': 'sn',
'email': 'mail',
#--------------------------------#
# This section needs to be added if your ldap configuration requires a bind user
# (i.e. a special account that can connect to ldap to check username/password combos)
# uncomment this line if your LDAP implementation supports searching without
# binding first, and will then allow the user to bind themselves
'no_bindGetDN': False,
# uncomment & change bind_user and bind_password if your LDAP implementation
# requires a bind user to authenticate app users
'bind_user': 'cn=binduser,ou=roles,dc=institution,dc=edu',
'bind_password': 'somethingsupercleverforreals',
},
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment