Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion ldapom/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def __init__(self, uri, base, bind_dn, bind_password,
cacertfile=None, require_cert=LDAP_OPT_X_TLS_NEVER,
timelimit=30, max_retry_reconnect=5,
schema_base="cn=subschema", enable_attribute_type_mapping=True,
retrieve_operational_attributes=False):
retrieve_operational_attributes=False, read_only=False):
"""
:param uri: URI of the server to connect to.
:param base: Base DN for LDAP operations.
Expand All @@ -104,6 +104,8 @@ def __init__(self, uri, base, bind_dn, bind_password,
:param enable_attribute_type_mapping: Whether to enable the mapping of LDAP attribute types
to corresponding Python types. Requires the schema to be fetched when connecting. If
disabled, all attributes will be treated as a multi-value string attribute.
:param read_only: Do not try to modify entries, do not return empty sets on missing
attributes.
"""
self._base = base
self._uri = uri
Expand All @@ -115,6 +117,7 @@ def __init__(self, uri, base, bind_dn, bind_password,
self._timelimit = timelimit
self._schema_base = schema_base
self._enable_attribute_type_mapping = enable_attribute_type_mapping
self._read_only = read_only

self._connect()

Expand Down Expand Up @@ -337,6 +340,8 @@ def delete(self, entry, recursive=False):
:param recursive: If subentries should be deleted recursively.
:type recursive: bool
"""
if self._read_only:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably better suited as a decorator, e.g. @check_for_ro.

raise error.LDAPomReadOnlyError
if recursive:
entries_to_delete = self._connection._search(
base=entry.dn,
Expand All @@ -356,6 +361,9 @@ def rename(self, entry, new_dn):
:param new_dn: The DN that the entry should have after the rename.
:type new_dn: str
"""
if self._read_only:
raise error.LDAPomReadOnlyError

new_rdn, new_parent_dn = new_dn.split(",", 1)
if new_parent_dn == entry.parent_dn:
new_parent_dn = None
Expand Down Expand Up @@ -389,6 +397,8 @@ def save(self, entry):
:param entry: The entry to save.
:type entry: ldapom.LDAPEntry
"""
if self._read_only:
raise error.LDAPomReadOnlyError
entry_exists = entry.exists()
# Refuse to save if attributes have not been fetched or set explicitly.
if entry._attributes is None:
Expand Down Expand Up @@ -482,6 +492,8 @@ def set_password(self, entry, password):
:param password: The password to set.
:type password: str
"""
if self._read_only:
raise error.LDAPomReadOnlyError
password_p = ffi.new("char[]", compat._encode_utf8(password))
password_berval = libldap.ber_bvstr(password_p)
entry_dn_p = ffi.new("char[]", compat._encode_utf8(entry.dn))
Expand All @@ -493,3 +505,6 @@ def set_password(self, entry, password):
password_berval, password_berval,
ffi.NULL, ffi.NULL)
handle_ldap_error(err)

def is_read_only(self):
return self._read_only
2 changes: 1 addition & 1 deletion ldapom/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __getattr__(self, name):
else:
return attribute.values
else:
if attribute_type.multi_value:
if attribute_type.multi_value and not self._connection.is_read_only():
setattr(self, name, set())
return self.get_attribute(name).values
else:
Expand Down
3 changes: 3 additions & 0 deletions ldapom/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ class LDAPAttributeNameNotFoundError(LDAPomError):

class LDAPCouldNotFetchAttributeTypes(LDAPomError):
pass

class LDAPomReadOnlyError(LDAPomError):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As only the base error uses LDAPom, I would skip the om in the class name here.

pass