我們有一個使用LDAP進行身份驗證的Pyramid應用程序。目前我們不使用pyramid_ldap
,而是基於python_ldap
的自定義代碼連接到LDAP服務器。使用LDAP時出現不穩定INSUFFICIENT_ACCESS錯誤
的代碼是一個Singleton類:該__init__
方法(更確切的實例創建過程中調用該方法)調用ldap.initialize
創建LDAPObject
和simple_bind_s
。
class Singleton(object):
'''
Implements the singleton pattern. A class deriving from ``Singleton`` can
have only one instance. The first instanciation will create an object and
other instanciations return the same object. Note that the :py:meth:`__init__`
method (if any) is still called at each instanciation (on the same object).
Therefore, :py:class:`Singleton` derived classes should define
:py:meth:`__singleton_init__`
instead of :py:meth:`__init__` because the former is only called once.
'''
@classmethod
def get_instance(cls):
try:
return getattr(cls, '_singleton_instance')
except AttributeError:
msg = "Class %s has not been initialized" % cls.__name__
raise ValueError(msg)
def __new__(cls, *args, **kwargs):
if '_singleton_instance' not in cls.__dict__:
cls._singleton_instance = super(Singleton, cls).__new__(cls)
singleton_init = getattr(cls._singleton_instance,
'__singleton_init__', None)
if singleton_init is not None:
singleton_init(*args, **kwargs)
return cls._singleton_instance
def __init__(self, *args, **kwargs):
'''
The __init__ method of :py:class:`Singleton` derived class should do nothing.
Derived classes must define :py:meth:`__singleton_init__` instead of __init__.
'''
def __singleton_init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
class UsersAndGroups(Singleton):
"""
Class used to query the LDAP directory.
"""
def __singleton_init__(self, admin_login, admin_password,
server, ldap_admin_dn, ldap_password, users_dn,
groups_dn):
self.admin_login = admin_login
self.admin_password = admin_password
self.server = server
self.ldap_admin_dn = ldap_admin_dn
self.ldap_password = ldap_password
self.users_dn = users_dn
self.groups_dn = groups_dn
# Check
if admin_login and (not admin_password):
raise ValueError('You must specify a password for the local admin')
self.has_local_admin = (admin_login) and (admin_password)
if (not self.server) and (not self.has_local_admin):
raise ValueError(
'You must specify an LDAP server or a local admin')
# Connect to LDAP server
if self.server:
self.ldap_connection = ldap.initialize(self.server)
self.ldap_connection.simple_bind_s(self.ldap_admin_dn,
self.ldap_password)
else:
self.ldap_connection = None
在服務器啓動功能(所以任何請求之前)將創建辛格爾頓和後續請求只是檢索:這裏是代碼(用戶可以通過提供本地管理員帳戶,由通過LDAP服務器)實例。我們使用admin
帳戶登錄:
def main(global_config, **settings):
# Create routes and so on
# Get configuration for LDAP connection from app.registry.settings
# Create the singleton to connect to LDAP
app.users_groups = UsersAndGroups(admin_login, admin_password, ldap_server,
ldap_admin_dn, ldap_password, users_dn,
groups_dn)
return app
這工作的時間,但有時LDAP操作失敗INSUFFICIENT_ACCESS
錯誤最多。當我們在本地開發時(例如,我們使用pserve
和reload
選項)重啓服務器時,也會在生產服務器上(通過circus
和chaussette
管理服務 - 我們通常會啓動多個進程) 。我們找到的唯一解決方案是關閉服務器並重新啓動。
我們正在尋找有關正在發生的事情以及如何解決它的線索。
登錄名和密碼是正確的,因爲它大部分時間都在工作。 AFAIU綁定中的問題應該在服務器啓動時引發異常。我想知道自動重載或多個進程是否會觸發此類問題(因爲它通常在重新啓動服務器時起作用)。
一些版本信息:
- 操作系統:Ubuntu的12.04或14.04
- 蟒蛇:2.7
- 的OpenLDAP:2.4.28
- python_ldap:2.4.25
是的。你必須在這裏顯示代碼。 –
你可能是對的。你認爲我應該加上'circus'配置嗎?這個問題也發生在沒有馬戲團的地方發展過程中。 –