使用 LDAP 时出现不稳定 INSUFFICIENT_ACCESS 错误
Erratic INSUFFICIENT_ACCESS error when using LDAP
我们有一个使用 LDAP 进行身份验证的 Pyramid 应用程序。目前我们不使用 pyramid_ldap
,而是使用基于 python_ldap
的自定义代码来连接到 LDAP 服务器。
代码在单例中 class:__init__
方法(更准确地说是实例创建期间调用的方法)调用 ldap.initialize
来创建 LDAPObject
和 simple_bind_s
。这是代码(用户可以通过提供本地管理员帐户来绕过 LDAP 服务器):
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
Singleton 是在服务器启动函数中创建的(因此在任何请求之前),后续请求仅检索实例。我们使用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
选项)以及在生产服务器上(通过 [=23 管理服务) =] 和 chaussette
——我们通常会启动多个进程)。我们找到的唯一解决方案是关闭服务器并重新启动它。
我们正在寻找有关正在发生的事情以及如何解决它的线索。
登录名和密码是正确的,因为它大部分时间都有效。 AFAIU 绑定中的问题应该在服务器启动期间引发异常。我想知道 autoreload 或多个进程是否会触发此类问题(因为它通常在重新启动服务器时有效)。
部分版本信息:
- OS: Ubuntu 12.04 或 14.04
- python: 2.7
- OpenLDAP:2.4.28
- python_ldap: 2.4.25
我意识到错误来自代码中的其他地方。
我们有一个使用 LDAP 进行身份验证的 Pyramid 应用程序。目前我们不使用 pyramid_ldap
,而是使用基于 python_ldap
的自定义代码来连接到 LDAP 服务器。
代码在单例中 class:__init__
方法(更准确地说是实例创建期间调用的方法)调用 ldap.initialize
来创建 LDAPObject
和 simple_bind_s
。这是代码(用户可以通过提供本地管理员帐户来绕过 LDAP 服务器):
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
Singleton 是在服务器启动函数中创建的(因此在任何请求之前),后续请求仅检索实例。我们使用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
选项)以及在生产服务器上(通过 [=23 管理服务) =] 和 chaussette
——我们通常会启动多个进程)。我们找到的唯一解决方案是关闭服务器并重新启动它。
我们正在寻找有关正在发生的事情以及如何解决它的线索。
登录名和密码是正确的,因为它大部分时间都有效。 AFAIU 绑定中的问题应该在服务器启动期间引发异常。我想知道 autoreload 或多个进程是否会触发此类问题(因为它通常在重新启动服务器时有效)。
部分版本信息:
- OS: Ubuntu 12.04 或 14.04
- python: 2.7
- OpenLDAP:2.4.28
- python_ldap: 2.4.25
我意识到错误来自代码中的其他地方。