Django用openLDAP作認證

前言

以前有需求要作一個django+ldap用戶管理的簡單接口,研究了好幾個模塊,最後終於能實現django用ldap作用戶認證了。也是本身的水平有限吧,作了好長時間,如今就和你們分享一下這個過程吧。最終是有兩種方法實現這個認證過程,一種是經過django-python3-ldap實現的,一種是本身寫了一個簡單的。我下面有個示例程序在github上面,這個程序是兩個方法都能用,並且我放到了一個django的app下。你們能夠下載下來看看。css

基本信息

具體以下:
python pip信息:html

bogon:ldapdemo hongzhi.wang$ pip list|egrep -i 'django|ldap'
Django                                 1.8.11
django-auth-ldap                       1.2.9
django-bootstrap-form                  3.2.1
django-celery                          3.1.16
django-crontab                         0.7.1
django-python3-ldap                    0.9.11
djangorestframework                    3.6.2
ldap3                                  1.4.0
python-ldap                            2.4.32

ldap 相關信息(在我本身的虛擬機上面搭的):node

192.168.3.3:389
dn: cn=user03,ou=People,dc=node1,dc=com secret:555
dn: cn=user02,ou=People,dc=node1,dc=com secret:555
dn: cn=user01,ou=People,dc=node1,dc=com secret:555

user02的詳細信息python

dn: cn=user02,ou=People,dc=node1,dc=com
objectClass: posixAccount
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
homeDirectory: /home/user02
loginShell: /bin/bash
uid: user02
cn: user02
uidNumber: 10002
gidNumber: 100
sn: user02
mail: user02@qq.com
userPassword:: e1NTSEF9WEZXOWMxaFZFMjVaK3JnV3Q3a1FDWW0wdWxjRVZrVk8=

示例程序地址在此:https://github.com/WisWang/ldapdemojquery

目錄結構以下:git

bogon:PycharmProjects hongzhi.wang$ tree ldapdemo/|grep -v pyc
ldapdemo/
├── db.sqlite3
├── ldapdemo
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── manage.py
├── my_ldap_auth
│   ├── __init__.py
│   ├── admin.py
│   ├── django_python3_ldap_settings.py
│   ├── ldap_tool.py
│   ├── migrations
│   │   ├── __init__.py
│   ├── models.py
│   ├── mysettings.py
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
├── static
│   ├── css
│   │   ├── bootstrap.css
│   │   ├── bootstrap.min.css
│   │   └── custom.css
│   └── js
│       ├── bootstrap.js
│       ├── bootstrap.min.js
│       └── jquery-2.2.2.js
└── templates
    ├── home.html
    ├── ldap_auth.html
    └── login_content.html

本次還用了django-python3-ldapgithub

我本身實現的python+django認證

基本思路就是經過python-ldap這個模塊本身封裝了一個類,而後實現各類用到的方法,
認證過程就是拿到用戶名密碼後,先經過這個ldapdemo/my_ldap_auth/ldap_tool.py裏的以下方法驗證用戶名存不存在,存在返回這個用戶的dn(這種方法缺點是用戶名在這個basedn下面必須惟一,不過能夠經過讓用戶輸入部門名輸入到後臺,而後再search的時候添加ou篩選就能實現用戶在不一樣部門可是用戶名相同的認證,本文就再多作敘述了。)sql

def check_user(self, username):
    self.conn.simple_bind_s(USER, PASSWORD)
    filter = '(uid=%s)' % username
    attrs = ['sn', 'uid']
    ret = self.conn.search_s(BASE_DN, ldap.SCOPE_SUBTREE, filter, attrs)
    if ret:
        return ret[0][0]
    else:
        return False

拿到用戶名後self.conn.simple_bind_s(dn,userpass)這樣去server端檢查用戶名,密碼。
而後就是這段代碼了ldapdemo/my_ldap_auth/views.pydjango

ldaptool = LdapTool()
res = ldaptool.check_pass(username,password)
#res這個放回值是我自定義的,詳見代碼吧
if res == 0:
    user = User.objects.filter(username=username)
    if not user:
        u = User.objects.create_user(username=username, password="asdf1234")
    else:
        u = user[0]
        u.set_password("asdf1234")
    u.save()
    user = authenticate(username=username, password='asdf1234')
    login(request, user)
    return HttpResponseRedirect('/')
elif res == 1:
    err_msg = "username not found"
else:
    err_msg = "password wrong"
return render(request, 'ldap_auth.html', {'err_msg': err_msg, })

基本思路就是ldap驗證經過之後,檢查django默認的User表有沒有這個用戶,沒有就建立,而後把這個用戶登陸。(這個是每次有用戶認證都會和ldapserver創建一個鏈接,以前是在django啓動的時候我就創建一個鏈接,各有優缺點吧。)bootstrap

經過django-python3-ldap實現的認證

這個基本就是按照這個django-python3-ldap在github上面那個readme來作的,可是遇到些問題,我把原來的代碼改了一處,就能用了,可是感受限制有些多,下面就來講一下吧。
在配置文件中有以下配置

# The LDAP username and password of a user for authenticating the `ldap_sync_users`
# management command. Set to None if you allow anonymous queries.
LDAP_AUTH_CONNECTION_USERNAME = "admin"
LDAP_AUTH_CONNECTION_PASSWORD = "secret"

./manage.py ldap_sync_users這樣同步用戶的時候,因爲這個配置一下配置:

# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "ou=people,dc=example,dc=com"

# User model fields mapped to the LDAP
# attributes that represent them.
LDAP_AUTH_USER_FIELDS = {
    "username": "uid",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

這個admin用戶
的dn就會變成"uid=admin,ou=people,dc=example,dc=com"不是咱們但願的"uid=admin,dc=example,dc=com"由於通常admin是有沒有ou這個屬性的(個人理解是這樣),這個同步成功不了。
我把site-packages/django_python3_ldap/ldap.py這個文件其中第120行左右的內容改爲以下:

if kwargs:
    password = kwargs.pop("password")
    if username != "cn=admin,dc=node1,dc=com":
        username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs)
# Make the connection.
print "***",username # 這樣就能夠看到他這個模塊加工後的dn了,打印出來方便本身檢查問題,若是認證不了加上這個基本不少問題都能解決,我還停留在print debug階段呢,之後要設置斷點來debug了O(∩_∩)O~

這樣就能夠經過這個admin來同步用戶信息了。

結語

本文我本身實現的認證是經過python-ldap實現的,不過ldap3是更pythonic的模塊,我研究了一下,其實徹底能夠替代python-ldap這個模塊的,不過我這個都寫完了,ldap3的使用就放在之後吧,我再研究的過程當中還在stackoverflow上面問過經過python ldap的模塊在不知道用戶密碼的狀況下經過admin給用戶重置密碼的方法呢,問題連接,最後仍是我本身仔細看了官方文檔,給解決了,這裏面有python-ldap和ldap3的官方文檔鏈接,你們能夠看看。個人blog開始有我本身的聯繫方式啥的,有問題隨時問哈。

相關文章
相關標籤/搜索