Make ldap2 class work as a client library as well.

Move the user-private group caching code out of the global config and
determine the value the first time it is needed.

Renamed global_init() back to get_schema() and make it take an optional
connection. This solves the problem of being able to do all operations
with a simple bind instead of GSSAPI.

Moved the global get_syntax() into a class method so that a schema
can be passed in.

If a schema wasn't loaded during the module import then it is loaded
when the connection is created (so we have the credntials needed for
binding).

ticket 63
This commit is contained in:
Rob Crittenden 2010-08-18 18:43:11 -04:00
parent 221351809b
commit 6049a25848
2 changed files with 49 additions and 37 deletions

View File

@ -123,7 +123,7 @@ def has_managed_entries(host_name, dm_password):
conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='cn=config')
conn.connect(bind_dn='cn=Directory Manager', bind_pw=dm_password)
(dn, attrs) = conn.get_entry('cn=Managed Entries,cn=plugins',
['*'])
['*'], time_limit=2, size_limit=3000)
return True
except errors.NotFound:
return False

View File

@ -103,7 +103,7 @@ def _handle_errors(e, **kw):
raise errors.DatabaseError(desc=desc, info=info)
def global_init(url):
def get_schema(url, conn=None):
"""
Perform global initialization when the module is loaded.
@ -114,16 +114,20 @@ def global_init(url):
in-tree "lite" server then use the current ccache. If in the context of
Apache then create a new ccache and bind using the Apache HTTP service
principal.
If a connection is provided then it the credentials bound to it are
used. The connection is not closed when the request is done.
"""
tmpdir = None
upg = False
has_conn = conn is not None
if not api.env.in_server or api.env.context not in ['lite', 'server']:
if (not api.env.in_server or api.env.context not in ['lite', 'server']
and conn is None):
# The schema is only needed on the server side
return (None, None)
return None
try:
if api.env.context == 'server':
if api.env.context == 'server' and conn is None:
try:
# Create a new credentials cache for this Apache process
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
@ -139,6 +143,7 @@ def global_init(url):
except krbV.Krb5Error, e:
raise StandardError('Unable to retrieve LDAP schema. Error initializing principal %s in %s: %s' % (principal.name, '/etc/httpd/conf/ipa.keytab', str(e)))
if conn is None:
conn = _ldap.initialize(url)
conn.sasl_interactive_bind_s('', SASL_AUTH)
@ -146,17 +151,10 @@ def global_init(url):
'cn=schema', _ldap.SCOPE_BASE,
attrlist=['attributetypes', 'objectclasses']
)[0]
try:
upg_entry = conn.search_s(
'cn=UPG Template, %s' % api.env.basedn, _ldap.SCOPE_BASE,
attrlist=['*']
)[0]
upg = True
except _ldap.NO_SUCH_OBJECT, e:
upg = False
if not has_conn:
conn.unbind_s()
except _ldap.SERVER_DOWN:
return (None, upg)
return None
except _ldap.LDAPError, e:
desc = e.args[0]['desc'].strip()
info = e.args[0].get('info', '').strip()
@ -170,28 +168,17 @@ def global_init(url):
if tmpdir:
shutil.rmtree(tmpdir)
return (_ldap.schema.SubSchema(schema_entry[1]), upg)
return _ldap.schema.SubSchema(schema_entry[1])
# cache schema and User-Private Groups when importing module
# cache schema when importing module
try:
(_schema, _upg) = global_init(api.env.ldap_uri)
_schema = get_schema(api.env.ldap_uri)
except AttributeError:
_schema = None
# The UPG setting will be cached the first time a module checks it
_upg = None
def get_syntax(attr, value):
global _schema
if not _schema:
return None
obj = _schema.get_obj(_ldap.schema.AttributeType, attr)
if obj is not None:
return obj.syntax
else:
return None
class ldap2(CrudBackend, Encoder):
"""
LDAP Backend Take 2.
@ -228,13 +215,14 @@ class ldap2(CrudBackend, Encoder):
def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None,
schema=None):
global _schema
CrudBackend.__init__(self, shared_instance=shared_instance)
Encoder.__init__(self)
self.encoder_settings.encode_dict_keys = True
self.encoder_settings.decode_dict_keys = True
self.encoder_settings.decode_dict_vals_postprocess = False
self.encoder_settings.decode_dict_vals_table = self._SYNTAX_MAPPING
self.encoder_settings.decode_dict_vals_table_keygen = get_syntax
self.encoder_settings.decode_dict_vals_table_keygen = self.get_syntax
self.encoder_settings.decode_postprocessor = lambda x: string.lower(x)
try:
self.ldap_uri = ldap_uri or api.env.ldap_uri
@ -253,6 +241,15 @@ class ldap2(CrudBackend, Encoder):
def __str__(self):
return self.ldap_uri
def get_syntax(self, attr, value):
if not self.schema:
return None
obj = self.schema.get_obj(_ldap.schema.AttributeType, attr)
if obj is not None:
return obj.syntax
else:
return None
@encode_args(2, 3, 'bind_dn', 'bind_pw')
def create_connection(self, ccache=None, bind_dn='', bind_pw='',
tls_cacertfile=None, tls_certfile=None, tls_keyfile=None,
@ -272,6 +269,7 @@ class ldap2(CrudBackend, Encoder):
Extends backend.Connectible.create_connection.
"""
global _schema
if tls_cacertfile is not None:
_ldap.set_option(_ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile)
if tls_certfile is not None:
@ -292,6 +290,9 @@ class ldap2(CrudBackend, Encoder):
conn.simple_bind_s(bind_dn, bind_pw)
except _ldap.LDAPError, e:
_handle_errors(e, **{})
if self.schema is None and _schema is None:
self.schema = get_schema(self.ldap_uri, conn)
return conn
def destroy_connection(self):
@ -534,14 +535,15 @@ class ldap2(CrudBackend, Encoder):
filter = self.make_filter(search_kw, rules=self.MATCH_ALL)
return self.find_entries(filter, attrs_list, base_dn)[0][0]
def get_entry(self, dn, attrs_list=None, normalize=True):
def get_entry(self, dn, attrs_list=None, time_limit=None,
size_limit=None, normalize=True):
"""
Get entry (dn, entry_attrs) by dn.
Keyword arguments:
attrs_list - list of attributes to return, all if None (default None)
"""
return self.find_entries(None, attrs_list, dn, self.SCOPE_BASE, normalize=normalize)[0][0]
return self.find_entries(None, attrs_list, dn, self.SCOPE_BASE, time_limit=time_limit, size_limit=size_limit, normalize=normalize)[0][0]
def get_ipa_config(self):
"""Returns the IPA configuration entry (dn, entry_attrs)."""
@ -561,6 +563,16 @@ class ldap2(CrudBackend, Encoder):
"""
global _upg
if _upg is None:
try:
upg_entry = self.conn.search_s(
'cn=UPG Template, %s' % api.env.basedn, _ldap.SCOPE_BASE,
attrlist=['*']
)[0]
_upg = True
except _ldap.NO_SUCH_OBJECT, e:
_upg = False
return _upg
@encode_args(1, 2)