diff options
author | Petr Spacek <pspacek@redhat.com> | 2015-12-15 15:22:45 +0100 |
---|---|---|
committer | Martin Basti <mbasti@redhat.com> | 2016-01-07 14:13:23 +0100 |
commit | ddf7397a4beb8095a24981998461aecc0e1ec40d (patch) | |
tree | edbbc64f29207813f28ed959ef7a063f9f2d4fa0 /ipapython/dnssec | |
parent | 6bdc18d0c538c658ae6022b127bf5776436f68e7 (diff) | |
download | freeipa-ddf7397a4beb8095a24981998461aecc0e1ec40d.tar.gz freeipa-ddf7397a4beb8095a24981998461aecc0e1ec40d.tar.xz freeipa-ddf7397a4beb8095a24981998461aecc0e1ec40d.zip |
DNSSEC: remove keys purged by OpenDNSSEC from master HSM from LDAP
Key purging has to be only only after key metadata purging so
ipa-dnskeysyncd on replices does not fail while dereferencing
non-existing keys.
https://fedorahosted.org/freeipa/ticket/5334
Reviewed-By: Martin Basti <mbasti@redhat.com>
Diffstat (limited to 'ipapython/dnssec')
-rw-r--r-- | ipapython/dnssec/ldapkeydb.py | 72 |
1 files changed, 61 insertions, 11 deletions
diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py index 3f9fbcfa7..b0b259f0e 100644 --- a/ipapython/dnssec/ldapkeydb.py +++ b/ipapython/dnssec/ldapkeydb.py @@ -104,40 +104,56 @@ def get_default_attrs(object_classes): result.update(defaults[cls]) return result + class Key(collections.MutableMapping): """abstraction to hide LDAP entry weirdnesses: - non-normalized attribute names - boolean attributes returned as strings + - planned entry deletion prevents subsequent use of the instance """ def __init__(self, entry, ldap, ldapkeydb): self.entry = entry + self._delentry = None # indicates that object was deleted self.ldap = ldap self.ldapkeydb = ldapkeydb self.log = ldap.log.getChild(__name__) + def __assert_not_deleted(self): + assert self.entry and not self._delentry, ( + "attempt to use to-be-deleted entry %s detected" + % self._delentry.dn) + def __getitem__(self, key): + self.__assert_not_deleted() val = self.entry.single_value[key] if key.lower() in bool_attr_names: val = ldap_bool(val) return val def __setitem__(self, key, value): + self.__assert_not_deleted() self.entry[key] = value def __delitem__(self, key): + self.__assert_not_deleted() del self.entry[key] def __iter__(self): """generates list of ipa names of all PKCS#11 attributes present in the object""" + self.__assert_not_deleted() for ipa_name in list(self.entry.keys()): lowercase = ipa_name.lower() if lowercase in attrs_name2id: yield lowercase def __len__(self): + self.__assert_not_deleted() return len(self.entry) def __repr__(self): + if self._delentry: + return 'deleted entry: %s' % repr(self._delentry) + sanitized = dict(self.entry) for attr in ['ipaPrivateKey', 'ipaPublicKey', 'ipk11publickeyinfo']: if attr in sanitized: @@ -152,6 +168,49 @@ class Key(collections.MutableMapping): if self.get(attr, empty) == default_attrs[attr]: del self[attr] + def _update_key(self): + """remove default values from LDAP entry and write back changes""" + if self._delentry: + self._delete_key() + return + + self._cleanup_key() + + try: + self.ldap.update_entry(self.entry) + except ipalib.errors.EmptyModlist: + pass + + def _delete_key(self): + """remove key metadata entry from LDAP + + After calling this, the python object is no longer valid and all + subsequent method calls on it will fail. + """ + assert not self.entry, ( + "Key._delete_key() called before Key.schedule_deletion()") + assert self._delentry, "Key._delete_key() called more than once" + self.log.debug('deleting key id 0x%s DN %s from LDAP', + hexlify(self._delentry.single_value['ipk11id']), + self._delentry.dn) + self.ldap.delete_entry(self._delentry) + self._delentry = None + self.ldap = None + self.ldapkeydb = None + + def schedule_deletion(self): + """schedule key deletion from LDAP + + Calling schedule_deletion() will make this object incompatible with + normal Key. After that the object must not be read or modified. + Key metadata will be actually deleted when LdapKeyDB.flush() is called. + """ + assert not self._delentry, ( + "Key.schedule_deletion() called more than once") + self._delentry = self.entry + self.entry = None + + class ReplicaKey(Key): # TODO: object class assert def __init__(self, entry, ldap, ldapkeydb): @@ -238,21 +297,12 @@ class LdapKeyDB(AbstractHSM): self._update_keys() return keys - def _update_key(self, key): - """remove default values from LDAP entry and write back changes""" - key._cleanup_key() - - try: - self.ldap.update_entry(key.entry) - except ipalib.errors.EmptyModlist: - pass - def _update_keys(self): for cache in [self.cache_masterkeys, self.cache_replica_pubkeys_wrap, - self.cache_zone_keypairs]: + self.cache_zone_keypairs]: if cache: for key in cache.values(): - self._update_key(key) + key._update_key() def flush(self): """write back content of caches to LDAP""" |