Django:针对远程LDAP用户进行身份验证 - 简单示例?

时间:2011-02-25 12:22:20

标签: django ldap

我正在使用django_auth_ldap - 我们有一个现有的用户数据库,以及一个与我已有的用户数据库共享用户名的外部LDAP系统。

我真的可以做一个如何

的简单例子
  • 获取用户的本地名称(他们已登录到Windows LDAP系统 - 我能以某种方式从浏览器中获取用户名吗?)
  • 针对远程Windows LDAP服务器进行身份验证
  • 在Django模板中使用它(只显示名称就可以了)

任何人都可以提供(希望)几行代码,以获得如何执行此操作的简单示例吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

在你的python设置文件中添加行

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.ActiveDirectoryGroupMembershipSSLBackend',
    'django.contrib.auth.backends.ModelBackend'
)

以下是我的代码,只需将其替换为您的信息即可。将此文件另存为backend.py将文件放入名为django_auth_ldap的文件夹中。确保文件夹中包含__init.py。

import ldap;

from django.contrib.auth.models import User, Group

class ActiveDirectoryGroupMembershipSSLBackend:
    #Required parameters
    AD_DNS_NAME ='your remote ldap server location';
    AD_LDAP_PORT = 636
    AD_LDAP_URL = 'ldaps://%s' % AD_DNS_NAME;
    AD_SEARCH_DN = 'dc=bbc,dc=ad,dc=bcc,dc=net'; # this is your search dn
    AD_NT4_DOMAIN = 'bbc.ad.bbc.net'; #its your ad domain
    AD_SEARCH_FIELDS = ['mail','givenName','sn','sAMAccountName','memberOf'];
    AD_MEMBERSHIP_REQ = ['Group_Required','Alternative_Group'];
    AD_CERT_FILE = "C:/player/Python/Application/cert/mycert.cer";
AD_DEBUG = False;
AD_DEBUG_FILE ='';

def authenticate(self,username=None,password=None):
    try:
        if len(password) == 0:
            return None
        ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
        ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 2)
        l = ldap.initialize(self.AD_LDAP_URL)
        l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
        binddn = "%s@%s" % (username,self.AD_NT4_DOMAIN)
        l.simple_bind_s(binddn,password)
        l.unbind_s()
        return self.get_or_create_user(username,password)

    except ImportError:
        pass
    except ldap.INVALID_CREDENTIALS:
        pass

def get_or_create_user(self, username, password):
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:

        try:
        # debug info
            debug=0
            if len(self.AD_DEBUG_FILE) > 0:
                if self.AD_DEBUG:
                    debug = open(self.AD_DEBUG_FILE,'w')
                    print >>debug, "create user %s" % username

            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,self.AD_CERT_FILE)
            ldap.set_option(ldap.OPT_REFERRALS,0) # DO NOT TURN THIS OFF OR SEARCH WON'T WORK!      
            # initialize
            if debug:
                print >>debug, 'ldap.initialize...'
            l = ldap.initialize(self.AD_LDAP_URL)
            l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)

            # bind
            if debug:
                print >>debug, 'bind...'
            binddn = "%s@%s" % (username,self.AD_NT4_DOMAIN)
            l.bind_s(binddn,password)

            # search
            if debug:
                print >>debug, 'search...'
            result = l.search_ext_s(self.AD_SEARCH_DN,ldap.SCOPE_SUBTREE,"sAMAccountName=%s" % username,self.AD_SEARCH_FIELDS)[0][1]
            if debug:
                print >>debug, result

            # Validate that they are a member of review board group
            if result.has_key('memberOf'):
                membership = result['memberOf']
            else:
                membership = None
            if debug:
                print >>debug, "required:%s" % self.AD_MEMBERSHIP_REQ
            bValid=0
            for req_group in self.AD_MEMBERSHIP_REQ:
                if debug:
                    print >>debug, "Check for %s group..." % req_group
                for group in membership:
                    group_str="CN=%s," % req_group
                    if group.find(group_str) >= 0:
                        if debug:
                            print >>debug, "User authorized: group_str membership found!"
                        bValid=1
                        break
            if bValid == 0:
                if debug:
                    print >>debug, "User not authorized, correct group membership not found!"
                return None

            # get email
            if result.has_key('mail'):
                mail = result['mail'][0]
            else:
                mail = None
            if debug:
                print >>debug, "mail=%s" % mail
            # get surname
            if result.has_key('sn'):
                last_name = result['sn'][0]
            else:
                last_name = None
            if debug:
                print >>debug, "sn=%s" % last_name

            # get display name
            if result.has_key('givenName'):
                first_name = result['givenName'][0]
            else:
                first_name = None
            if debug:
                print >>debug, "first_name=%s" % first_name

            l.unbind_s()

            user = User(username=username,first_name=first_name,last_name=last_name,email=mail)

        except Exception, e:
            if debug:
                print >>debug, "exception caught!"
                print >>debug, e
            return None

        user.is_staff = False
        user.is_superuser = False
        user.set_password('ldap authenticated')
        user.save()

        # add user to default group
        group=Group.objects.get(pk=1)
        if debug:
            print >>debug, group
        if debug:
            print >>debug, "add %s to group %s" % (username,group)
        user.groups.add(group)
        user.save()
        if debug:
            print >>debug, "successful group add"

        if debug:
            debug.close()

    return user

def get_user(self, user_id):
    try:
        return User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

答案 1 :(得分:0)

您是否正在尝试为您的MS Windows用户提供一些单点登录解决方案?

然后,您将在http://docs.djangoproject.com/en/dev/howto/auth-remote-user/

中找到所需的所有提示

答案 2 :(得分:-1)

首先,我建议要求用户提供sAMAccountName(这是确切的Windows登录名,通常' firstName.lastName',对于用户名称中有多个单词也更好)而不是仅使用cn用户名(' firstName lastName')。

以下是我完整的LDAPUserAuthBackend代码,并将其添加到 AUTHENTICATION_BACKENDS

from django.contrib.auth.backends import RemoteUserBackend
from django.contrib.auth.models import User, Permission
from django.conf import settings
import ldap
import re

import logging

log = logging.getLogger(__name__)
INTERNAL_USER = None


class LDAPUserAuthBackend(RemoteUserBackend):

    create_unknown_user = False

    def authenticate(self, username=None, password=None, **kwargs):
        # if username or password is not given, then skip
        if not username or not password:
            return None

        try:
            # initialize connection to ActiveDirectory  the property contains ldap url like ldap://hostname:389
            connect = ldap.initialize(settings.AUTH_LDAP_SERVER_URL)

            # if user just provide account name portion 'fistName.lastName' on username
            # then use your company default domain
            if '\\' not in username:
                connect.simple_bind_s(username + '@myCompanyDomain.com', password)
                base_dn = 'cn=users,dc=myCompanyDomain,dc=com'
                search_filter = '(&(objectClass=user)(sAMAccountName=' + username + '))'
            else:
                # if user provides domain info in username like 'myCompanyDomain\firstName.lastName'
                domain,  account_name = username.split('\\')
                connect.simple_bind_s('{user_name}@{domain_name}.com'.format(user_name=account_name, domain_name=domain), password)
                base_dn = 'cn=users,dc={domain_name},dc=com,'.format(domain_name=domain)
                search_filter = '(&(objectClass=user)(sAMAccountName=' + account_name + '))'
                username = account_name
            result = connect.search_s(base_dn, ldap.SCOPE_SUBTREE, search_filter, ['memberOf'])
            log.debug(result)

            # if search result is found, result will be [(user_dn,{'memberOf':['group cn'...]}]
            if result:
                result_user_dn, result_dict = result[0]
                groups = ','.join(result_dict.get('memberOf')).lower()
                # check member is belong to the group
                if result_user_dn:
                    if settings.STAFF_USER_GROUP.lower() in groups or \
                       settings.ADMIN_USER_GROUP.lower() in groups:
                        user, created = User.objects.get_or_create(username=username)
                        first_name, last_name = re.split('\.', username)
                        user.first_name = first_name
                        user.last_name = last_name
                        user.is_active = True
                        user.is_staff = True
                        if settings.ADMIN_USER_GROUP.lower() in groups:
                            user.is_superuser = True
                        global INTERNAL_USER
                        INTERNAL_USER = user
                        return user
            log.info('fail to authorize user, username: {}'.format(username))
            return None
        except ldap.LDAPError as e:
            log.warning('authentication error, detail: {}'.format(str(e)))
            return None
        finally:
            connect.unbind_s()

    def get_user(self, user_id):
        # don't want to go back to database.
        # once auth via LDAP successful, that is the user
        # because of the user_id is for user passed auth via this backend
        global INTERNAL_USER
        return INTERNAL_USER