Django整合OpenLDAP認證

運維咖啡吧發表於2019-04-04

本文詳細介紹了django-auth-ldap的使用方法,引數含義,並提供了示例程式碼

版本說明

  • Django==2.2
  • django-auth-ldap==1.7.0

整合過程

Django整合LDAP認證有現成的django-auth-ldap模組可以使用,本文也主要以這個模組的使用為主,先安裝模組

pip install django-auth-ldap
複製程式碼

然後在setting.py全域性配置檔案中新增如下內容就可以正常使用了:

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType

# Baseline configuration.
AUTH_LDAP_SERVER_URI = 'ldap://ldap.ops-coffee.cn'

AUTH_LDAP_BIND_DN = 'uid=authz,ou=Public,dc=ops-coffee,dc=cn'
AUTH_LDAP_BIND_PASSWORD = 'CzfdX629K7'

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    'ou=People,dc=ops-coffee,dc=cn',
    ldap.SCOPE_SUBTREE,
    '(uid=%(user)s)',
)
# Or:
# AUTH_LDAP_USER_DN_TEMPLATE = 'uid=%(user)s,ou=People,dc=ops-coffee,dc=cn'

AUTH_LDAP_USER_ATTR_MAP = {
    'first_name': 'cn',
    'last_name': 'sn',
    'email': 'mail',
}

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)
複製程式碼

這裡詳細解釋下上邊配置的含義:

AUTH_LDAP_SERVER_URI: LDAP伺服器的地址

AUTH_LDAP_BIND_DN: 一個完整的使用者DN,用來登入LDAP伺服器驗證使用者輸入的賬號密碼資訊是否正確

AUTH_LDAP_BIND_PASSWORD: BIND_DN使用者的密碼,這裡我們簡單說明下LDAP的認證邏輯以便更好的理解為啥需要這兩個配置

Django使用AUTH_LDAP_BIND_DNAUTH_LDAP_BIND_PASSWORD作為使用者名稱和密碼登陸LDAP伺服器,根據AUTH_LDAP_USER_SEARCH指定的查詢規則來查詢使用者輸入的屬性(即username)的值有沒有,如果查詢的條數為0或者大於1,則返回錯誤,如果查詢的條數等於1,則使用查詢到的這個條目的DN和使用者輸入的密碼進行匹配驗證,成功則返回成功允許登入,失敗則不允許登入

AUTH_LDAP_USER_SEARCH: 可通過LDAP登入的使用者的範圍,如上配置會去ou=People,dc=ops-coffee,dc=cn下搜尋使用者是否存在

其中(uid=%(user)s)'指明瞭作為Django的username所對應的LDAP的屬性,這裡為LDAP使用者的uid屬性作為Django的username

以上配置是在一個OU下查詢使用者,當需要在多個OU下搜尋使用者時用如下配置:

from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion

AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(
    LDAPSearch(
        'ou=Public,dc=ops-coffee,dc=cn',
        ldap.SCOPE_SUBTREE,
        '(uid=%(user)s)'
    ),
    LDAPSearch(
        'ou=PeoPle,dc=ops-coffee,dc=cn',
        ldap.SCOPE_SUBTREE,
        '(uid=%(user)s)'
    ),
)
複製程式碼

AUTH_LDAP_USER_ATTR_MAP: LDAP中的使用者屬性跟Django後臺使用者屬性的對應關係,當使用者第一次登入且驗證成功後會將LDAP中對應的使用者屬性寫入到Django的User表中

AUTHENTICATION_BACKENDS: 配置Django的後端認證列表

當Django呼叫auth.authenticate方法進行驗證時,Django將嘗試AUTHENTICATION_BACKENDS元組中指定的所有認證後端。如果第一個認證方法失敗了,Django將會繼續嘗試下一個,直到所有認證方式都嘗試完成

Django預設的認證後端是django.contrib.auth.backends.ModelBackend,如上配置我們新增了ldap的認證到AUTHENTICATION_BACKENDS中,那麼Django在登入的時候就會先去LDAP伺服器驗證使用者,驗證失敗後再去查詢本地資料庫的User表進行驗證,如果只希望Django驗證LDAP不驗證本地資料庫的話去掉AUTHENTICATION_BACKENDS中的ModelBackend配置即可

其他幾個django-auth-ldap的全域性配置引數解釋如下:

AUTH_LDAP_ALWAYS_UPDATE_USER: 是否同步LDAP的修改,預設為True,即當LDAP中使用者的屬性修改後使用者通過LDAP系統認證時自動同步更新到Django的User表中,如果設定為False則不自動更新

AUTH_LDAP_CACHE_TIMEOUT: 設定LDAP認證快取的時間

登入驗證

上邊的配置沒有問題後就可以通過LDAP系統賬號進行登入操作了,預設登陸邏輯及前端登入程式碼均無需修改,可以參考github的相關程式碼,地址:

github.com/ops-coffee/…

高階配置

所謂高階配置這裡主要是說明下django-auth-ldap中組相關的配置,這需要對LDAP的組有一定的概念,為了方便理解,接下來我們以實際的例子來說明

假如我們有三個組overmind、kerrigan、admin,配置如下:

# ldapsearch -LLL -x -D "uid=authz,ou=Public,dc=ops-coffee,dc=cn" -w "CzfdX629K7" -b cn=overmind,ou=Group,dc=ops-coffee,dc=cn 
dn: cn=overmind,ou=Group,dc=ops-coffee,dc=cn
cn: overmind
member: uid=sre,ou=People,dc=ops-coffee,dc=cn
objectClass: groupOfNames
objectClass: top
複製程式碼
# ldapsearch -LLL -x -D "uid=authz,ou=Public,dc=ops-coffee,dc=cn" -w "CzfdX629K7" -b cn=kerrigan,ou=Group,dc=ops-coffee,dc=cn 
dn: cn=kerrigan,ou=Group,dc=ops-coffee,dc=cn
cn: kerrigan
objectClass: groupOfNames
objectClass: top
member: uid=u1,ou=Public,dc=ops-coffee,dc=cn
member: uid=u2,ou=People,dc=ops-coffee,dc=cn
複製程式碼
# ldapsearch -LLL -x -D "uid=authz,ou=Public,dc=ops-coffee,dc=cn" -w "CzfdX629K7" -b cn=admin,ou=Group,dc=ops-coffee,dc=cn 
dn: cn=admin,ou=Group,dc=ops-coffee,dc=cn
cn: admin
member: uid=u3,ou=Admin,dc=ops-coffee,dc=cn
objectClass: groupOfNames
objectClass: top
複製程式碼

我們需要實現Django整合LDAP認證,且不允許隸屬於kerrigan分組的使用者登入系統,如果使用者隸屬於admin分組,則需要在登入Django時給設定為管理員,接下來的配置將會解釋如何實現該需求

django-auth-ldap中與group有關的配置:

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    'ou=Group,dc=ops-coffee,dc=cn',
    ldap.SCOPE_SUBTREE,
    '(objectClass=groupOfNames)',
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr='cn')

# Simple group restrictions
# AUTH_LDAP_REQUIRE_GROUP = 'cn=overmind,ou=Group,dc=ops-coffee,dc=cn'
AUTH_LDAP_DENY_GROUP = 'cn=kerrigan,ou=Group,dc=ops-coffee,dc=cn'

AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    'is_superuser': 'cn=admin,ou=Group,dc=ops-coffee,dc=cn',
}
複製程式碼

以上配置的詳細解釋如下:

AUTH_LDAP_GROUP_SEARCH: 搜尋某個ou下的資訊,與AUTH_LDAP_USER_SEARCH引數類似,這裡的ou一般指group,例如ou=Group,dc=ops-coffee,dc=cn的組目錄

AUTH_LDAP_GROUP_TYPE: 返回的組的型別,組DN的第一個屬性值,例如組DNcn=overmind,ou=Group,dc=ops-coffee,dc=cn,那麼這裡為cn

AUTH_LDAP_REQUIRE_GROUP: 設定允許哪些組成員登入,如果我們只允許overmind組的成員可以登入系統的話這裡可以設定

AUTH_LDAP_REQUIRE_GROUP = 'cn=overmind,ou=Group,dc=ops-coffee,dc=cn'
複製程式碼

AUTH_LDAP_DENY_GROUP: 設定拒絕哪些組成員登入,如果我們不允許kerrigan組的成員可以登入系統的話這裡可以設定

AUTH_LDAP_DENY_GROUP = 'cn=kerrigan,ou=Group,dc=ops-coffee,dc=cn'
複製程式碼

當我們同時設定了使用者既屬於overmind組又屬於kerrigan組,也就是這個使用者即設定了允許登入,又設定了拒絕登入,那麼以拒絕登入為準,使用者無法登入

AUTH_LDAP_USER_FLAGS_BY_GROUP: 根據LDAP的group設定Django使用者的額外屬性,例如我們想要設定LDAP中admin組具有Django中超級管理員的許可權,除了在Django中手動設定外,還可以直接在setting中配置AUTH_LDAP_USER_FLAGS_BY_GROUP

AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    'is_superuser': 'cn=admin,ou=Group,dc=ops-coffee,dc=cn',
}
複製程式碼

當admin組使用者登入的時候就會自動給使用者的is_superuser屬性設定為True

至此我們對django-auth-ldap有了一個全面的瞭解,在實際專案整合中可以做到遊刃有餘,如有問題可以參考我github的程式碼

踩坑記錄

windowns 10下安裝python-ldapdjango-auth-ldap報錯:

c:\users\ops-coffee\appdata\local\temp\pip-install-sec1o036\python-ldap\modules\constants.h(7): fatal error C1083: Cannot open include file: 'lber.h': No such file or directory
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\cl.exe' failed with exit status 2
複製程式碼

這個報錯需要手動安裝下whl檔案,具體方法為:

先在這個網站www.lfd.uci.edu/~gohlke/pyt…下載對應版本的python-ldap的whl檔案

然後使用pip命令安裝whl,注意檔案路徑要正確

D:\demo\openldap>python -m pip install python_ldap-3.2.0-cp36-cp36m-win_amd64.whl
Processing d:\demo\openldap\python_ldap-3.2.0-cp36-cp36m-win_amd64.whl
Requirement already satisfied: pyasn1>=0.3.7 in c:\python36\lib\site-packages (from python-ldap==3.2.0) (0.4.2)
Requirement already satisfied: pyasn1-modules>=0.1.5 in c:\python36\lib\site-packages (from python-ldap==3.2.0) (0.2.4)
Installing collected packages: python-ldap
Successfully installed python-ldap-3.2.0
複製程式碼

Django整合OpenLDAP認證

相關文章推薦閱讀:

相關文章