Imported Upstream version 4.0.5

This commit is contained in:
Mario Fetka
2021-07-25 07:50:50 +02:00
parent 8ff3be4216
commit 3bfaa6e020
2049 changed files with 317193 additions and 1632423 deletions

View File

@@ -1,116 +0,0 @@
# Copyright (C) 2015 IPA Project Contributors, see COPYING for license
from __future__ import print_function
# pylint: disable=relative-import
from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC
# pylint: enable=relative-import
from jwcrypto.common import json_decode
from jwcrypto.jwk import JWK
from ipaserver.secrets.kem import IPAKEMKeys
from ipaserver.secrets.store import iSecStore
from ipaplatform.paths import paths
from base64 import b64encode
import ldapurl
import gssapi
import os
import urllib3
import requests
class CustodiaClient(object):
def _client_keys(self):
return self.ikk.server_keys
def _server_keys(self, server, realm):
principal = 'host/%s@%s' % (server, realm)
sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG)))
ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC)))
return (sk, ek)
def _ldap_uri(self, realm):
dashrealm = '-'.join(realm.split('.'))
socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,)
return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath)
def _keystore(self, realm, ldap_uri, auth_type):
config = dict()
if ldap_uri is None:
config['ldap_uri'] = self._ldap_uri(realm)
else:
config['ldap_uri'] = ldap_uri
if auth_type is not None:
config['auth_type'] = auth_type
return iSecStore(config)
def __init__(
self, client_service, keyfile, keytab, server, realm,
ldap_uri=None, auth_type=None):
self.client_service = client_service
self.keytab = keytab
# Init creds immediately to make sure they are valid. Creds
# can also be re-inited by _auth_header to avoid expiry.
#
self.creds = self.init_creds()
self.service_name = gssapi.Name('HTTP@%s' % (server,),
gssapi.NameType.hostbased_service)
self.server = server
self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri})
self.kemcli = KEMClient(self._server_keys(server, realm),
self._client_keys())
self.keystore = self._keystore(realm, ldap_uri, auth_type)
# FIXME: Remove warnings about missing subjAltName for the
# requests module
urllib3.disable_warnings()
def init_creds(self):
name = gssapi.Name(self.client_service,
gssapi.NameType.hostbased_service)
store = {'client_keytab': self.keytab,
'ccache': 'MEMORY:Custodia_%s' % b64encode(
os.urandom(8)).decode('ascii')}
return gssapi.Credentials(name=name, store=store, usage='initiate')
def _auth_header(self):
if not self.creds or self.creds.lifetime < 300:
self.creds = self.init_creds()
ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds)
authtok = ctx.step()
return {'Authorization': 'Negotiate %s' % b64encode(
authtok).decode('ascii')}
def fetch_key(self, keyname, store=True):
# Prepare URL
url = 'https://%s/ipa/keys/%s' % (self.server, keyname)
# Prepare signed/encrypted request
encalg = ('RSA-OAEP', 'A256CBC-HS512')
request = self.kemcli.make_request(keyname, encalg=encalg)
# Prepare Authentication header
headers = self._auth_header()
# Perform request
r = requests.get(url, headers=headers,
verify=paths.IPA_CA_CRT,
params={'type': 'kem', 'value': request})
r.raise_for_status()
reply = r.json()
if 'type' not in reply or reply['type'] != 'kem':
raise RuntimeError('Invlid JSON response type')
value = self.kemcli.parse_reply(keyname, reply['value'])
if store:
self.keystore.set('keys/%s' % keyname, value)
else:
return value

View File

@@ -1,45 +0,0 @@
# Copyright (C) 2015 IPA Project Contributors, see COPYING for license
from __future__ import print_function
import ldap
import ldap.sasl
import ldap.filter
class iSecLdap(object):
def __init__(self, uri, auth_type=None):
self.uri = uri
if auth_type is not None:
self.auth_type = auth_type
else:
if uri.startswith('ldapi'):
self.auth_type = 'EXTERNAL'
else:
self.auth_type = 'GSSAPI'
self._basedn = None
@property
def basedn(self):
if self._basedn is None:
conn = self.connect()
r = conn.search_s('', ldap.SCOPE_BASE)
self._basedn = r[0][1]['defaultnamingcontext'][0].decode('utf-8')
return self._basedn
def connect(self):
conn = ldap.initialize(self.uri)
if self.auth_type == 'EXTERNAL':
auth_tokens = ldap.sasl.external(None)
elif self.auth_type == 'GSSAPI':
auth_tokens = ldap.sasl.sasl({}, 'GSSAPI')
else:
raise ValueError(
'Invalid authentication type: %s' % self.auth_type)
conn.sasl_interactive_bind_s('', auth_tokens)
return conn
def build_filter(self, formatstr, args):
escaped_args = dict()
for key, value in args.items():
escaped_args[key] = ldap.filter.escape_filter_chars(value)
return formatstr.format(**escaped_args)

View File

@@ -1,277 +0,0 @@
# Copyright (C) 2015 IPA Project Contributors, see COPYING for license
from __future__ import print_function
import errno
import os
# pylint: disable=import-error
from six.moves.configparser import ConfigParser
# pylint: enable=import-error
from ipaplatform.paths import paths
from ipapython.dn import DN
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa, ec
# pylint: disable=relative-import
from custodia.message.kem import KEMKeysStore
from custodia.message.kem import KEY_USAGE_SIG, KEY_USAGE_ENC, KEY_USAGE_MAP
# pylint: enable=relative-import
from jwcrypto.common import json_decode, json_encode
from jwcrypto.common import base64url_encode
from jwcrypto.jwk import JWK
from ipaserver.secrets.common import iSecLdap
from binascii import unhexlify
import ldap
IPA_REL_BASE_DN = 'cn=custodia,cn=ipa,cn=etc'
IPA_KEYS_QUERY = '(&(ipaKeyUsage={usage:s})(memberPrincipal={princ:s}))'
IPA_CHECK_QUERY = '(cn=enc/{host:s})'
RFC5280_USAGE_MAP = {KEY_USAGE_SIG: 'digitalSignature',
KEY_USAGE_ENC: 'dataEncipherment'}
class KEMLdap(iSecLdap):
@property
def keysbase(self):
return '%s,%s' % (IPA_REL_BASE_DN, self.basedn)
def _encode_int(self, i):
I = hex(i).rstrip("L").lstrip("0x")
return base64url_encode(unhexlify((len(I) % 2) * '0' + I))
def _parse_public_key(self, ipa_public_key):
public_key = serialization.load_der_public_key(ipa_public_key,
default_backend())
num = public_key.public_numbers()
if isinstance(num, rsa.RSAPublicNumbers):
return {'kty': 'RSA',
'e': self._encode_int(num.e),
'n': self._encode_int(num.n)}
elif isinstance(num, ec.EllipticCurvePublicNumbers):
if num.curve.name == 'secp256r1':
curve = 'P-256'
elif num.curve.name == 'secp384r1':
curve = 'P-384'
elif num.curve.name == 'secp521r1':
curve = 'P-521'
else:
raise TypeError('Unsupported Elliptic Curve')
return {'kty': 'EC',
'crv': curve,
'x': self._encode_int(num.x),
'y': self._encode_int(num.y)}
else:
raise TypeError('Unknown Public Key type')
def get_key(self, usage, principal):
conn = self.connect()
scope = ldap.SCOPE_SUBTREE
ldap_filter = self.build_filter(IPA_KEYS_QUERY,
{'usage': RFC5280_USAGE_MAP[usage],
'princ': principal})
r = conn.search_s(self.keysbase, scope, ldap_filter)
if len(r) != 1:
raise ValueError("Incorrect number of results (%d) searching for "
"public key for %s" % (len(r), principal))
ipa_public_key = r[0][1]['ipaPublicKey'][0]
jwk = self._parse_public_key(ipa_public_key)
jwk['use'] = KEY_USAGE_MAP[usage]
return json_encode(jwk)
def check_host_keys(self, host):
conn = self.connect()
scope = ldap.SCOPE_SUBTREE
ldap_filter = self.build_filter(IPA_CHECK_QUERY, {'host': host})
r = conn.search_s(self.keysbase, scope, ldap_filter)
if not r:
raise ValueError("No public keys were found for %s" % host)
return True
def _format_public_key(self, key):
if isinstance(key, str):
jwkey = json_decode(key)
if 'kty' not in jwkey:
raise ValueError('Invalid key, missing "kty" attribute')
if jwkey['kty'] == 'RSA':
pubnum = rsa.RSAPublicNumbers(jwkey['e'], jwkey['n'])
pubkey = pubnum.public_key(default_backend())
elif jwkey['kty'] == 'EC':
if jwkey['crv'] == 'P-256':
curve = ec.SECP256R1
elif jwkey['crv'] == 'P-384':
curve = ec.SECP384R1
elif jwkey['crv'] == 'P-521':
curve = ec.SECP521R1
else:
raise TypeError('Unsupported Elliptic Curve')
pubnum = ec.EllipticCurvePublicNumbers(
jwkey['x'], jwkey['y'], curve)
pubkey = pubnum.public_key(default_backend())
else:
raise ValueError('Unknown key type: %s' % jwkey['kty'])
elif isinstance(key, rsa.RSAPublicKey):
pubkey = key
elif isinstance(key, ec.EllipticCurvePublicKey):
pubkey = key
else:
raise TypeError('Unknown key type: %s' % type(key))
return pubkey.public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
def _get_dn(self, usage, principal):
servicename, host = principal.split('@')[0].split('/')
name = '%s/%s' % (KEY_USAGE_MAP[usage], host)
service_rdn = ('cn', servicename) if servicename != 'host' else DN()
return DN(('cn', name), service_rdn, self.keysbase)
def set_key(self, usage, principal, key):
"""
Write key for the host or service.
Service keys are nested one level beneath the 'cn=custodia'
container, in the 'cn=<servicename>' container; this allows
fine-grained control over key management permissions for
specific services.
The container is assumed to exist.
"""
public_key = self._format_public_key(key)
dn = self._get_dn(usage, principal)
conn = self.connect()
try:
mods = [('objectClass', [b'nsContainer',
b'ipaKeyPolicy',
b'ipaPublicKeyObject',
b'groupOfPrincipals']),
('cn', dn[0].value.encode('utf-8')),
('ipaKeyUsage', RFC5280_USAGE_MAP[usage].encode('utf-8')),
('memberPrincipal', principal.encode('utf-8')),
('ipaPublicKey', public_key)]
conn.add_s(str(dn), mods)
except ldap.ALREADY_EXISTS:
mods = [(ldap.MOD_REPLACE, 'ipaPublicKey', public_key)]
conn.modify_s(str(dn), mods)
def del_key(self, usage, principal):
"""Delete key for host or service
:returns: DN of removed key or None when key was not found
"""
dn = self._get_dn(usage, principal)
conn = self.connect()
try:
conn.delete_s(str(dn))
except ldap.NO_SUCH_OBJECT:
return None
else:
return dn
def newServerKeys(path, keyid):
skey = JWK(generate='RSA', use='sig', kid=keyid)
ekey = JWK(generate='RSA', use='enc', kid=keyid)
with open(path, 'w') as f:
os.fchmod(f.fileno(), 0o600)
os.fchown(f.fileno(), 0, 0)
f.write('[%s,%s]' % (skey.export(), ekey.export()))
return [skey.get_op_key('verify'), ekey.get_op_key('encrypt')]
class IPAKEMKeys(KEMKeysStore):
"""A KEM Keys Store.
This is a store that holds public keys of registered
clients allowed to use KEM messages. It takes the form
of an authorizer merely for the purpose of attaching
itself to a 'request' so that later on the KEM Parser
can fetch the appropariate key to verify/decrypt an
incoming request and make the payload available.
The KEM Parser will actually perform additional
authorization checks in this case.
SimplePathAuthz is extended here as we want to attach the
store only to requests on paths we are configured to
manage.
"""
def __init__(self, config=None, ipaconf=paths.IPA_DEFAULT_CONF):
super(IPAKEMKeys, self).__init__(config)
conf = ConfigParser()
conf.read(ipaconf)
self.host = conf.get('global', 'host')
self.realm = conf.get('global', 'realm')
self.ldap_uri = config.get('ldap_uri', None)
if self.ldap_uri is None:
self.ldap_uri = conf.get('global', 'ldap_uri', raw=True)
self._server_keys = None
def find_key(self, kid, usage):
if kid is None:
raise TypeError('Key ID is None, should be a SPN')
conn = KEMLdap(self.ldap_uri)
return conn.get_key(usage, kid)
def generate_server_keys(self):
self.generate_keys('host')
def generate_keys(self, servicename):
principal = '%s/%s@%s' % (servicename, self.host, self.realm)
# Neutralize the key with read if any
self._server_keys = None
# Generate private key and store it
pubkeys = newServerKeys(self.config['server_keys'], principal)
# Store public key in LDAP
ldapconn = KEMLdap(self.ldap_uri)
ldapconn.set_key(KEY_USAGE_SIG, principal, pubkeys[0])
ldapconn.set_key(KEY_USAGE_ENC, principal, pubkeys[1])
def remove_server_keys(self):
"""Remove keys from LDAP and disk
"""
self.remove_keys('host')
def remove_keys(self, servicename):
"""Remove keys from LDAP and disk
"""
principal = '%s/%s@%s' % (servicename, self.host, self.realm)
ldapconn = KEMLdap(self.ldap_uri)
ldapconn.del_key(KEY_USAGE_SIG, principal)
ldapconn.del_key(KEY_USAGE_ENC, principal)
try:
os.unlink(self.config['server_keys'])
except OSError as e:
if e.errno != errno.ENOENT:
raise
@property
def server_keys(self):
if self._server_keys is None:
with open(self.config['server_keys']) as f:
jsonkeys = f.read()
dictkeys = json_decode(jsonkeys)
self._server_keys = (JWK(**dictkeys[KEY_USAGE_SIG]),
JWK(**dictkeys[KEY_USAGE_ENC]))
return self._server_keys
# Manual testing
if __name__ == '__main__':
IKK = IPAKEMKeys({'paths': '/',
'server_keys': '/etc/ipa/custodia/server.keys'})
IKK.generate_server_keys()
print(('SIG', IKK.server_keys[0].export_public()))
print(('ENC', IKK.server_keys[1].export_public()))
print(IKK.find_key('host/%s@%s' % (IKK.host, IKK.realm),
usage=KEY_USAGE_SIG))
print(IKK.find_key('host/%s@%s' % (IKK.host, IKK.realm),
usage=KEY_USAGE_ENC))

View File

@@ -1,30 +0,0 @@
# Copyright (C) 2017 IPA Project Contributors, see COPYING for license
import argparse
import custodia.server # pylint: disable=relative-import
argparser = argparse.ArgumentParser(
prog='ipa-custodia',
description='IPA Custodia service'
)
argparser.add_argument(
'--debug',
action='store_true',
help='Debug mode'
)
argparser.add_argument(
'configfile',
nargs='?',
type=argparse.FileType('r'),
help="Path to IPA's custodia server config",
default='/etc/ipa/custodia/custodia.conf'
)
def main():
return custodia.server.main(argparser)
if __name__ == '__main__':
main()

View File

@@ -1,319 +0,0 @@
# Copyright (C) 2015 IPA Project Contributors, see COPYING for license
from __future__ import print_function
from base64 import b64encode, b64decode
from custodia.store.interface import CSStore # pylint: disable=relative-import
from jwcrypto.common import json_decode, json_encode
from ipaplatform.paths import paths
from ipapython import ipautil
from ipaserver.secrets.common import iSecLdap
import ldap
import os
import shutil
import sys
import tempfile
class UnknownKeyName(Exception):
pass
class DBMAPHandler(object):
def __init__(self, config, dbmap, nickname):
raise NotImplementedError
def export_key(self):
raise NotImplementedError
def import_key(self, value):
raise NotImplementedError
def log_error(error):
print(error, file=sys.stderr)
def PKI_TOMCAT_password_callback():
password = None
with open(paths.PKI_TOMCAT_PASSWORD_CONF) as f:
for line in f.readlines():
key, value = line.strip().split('=')
if key == 'internal':
password = value
break
return password
class NSSWrappedCertDB(DBMAPHandler):
'''
Store that extracts private keys from an NSSDB, wrapped with the
private key of the primary CA.
'''
def __init__(self, config, dbmap, nickname):
if 'path' not in dbmap:
raise ValueError(
'Configuration does not provide NSSDB path')
if 'pwcallback' not in dbmap:
raise ValueError(
'Configuration does not provide Password Calback')
if 'wrap_nick' not in dbmap:
raise ValueError(
'Configuration does not provide nickname of wrapping key')
self.nssdb_path = dbmap['path']
self.nssdb_password = dbmap['pwcallback']()
self.wrap_nick = dbmap['wrap_nick']
self.target_nick = nickname
def export_key(self):
tdir = tempfile.mkdtemp(dir=paths.TMP)
try:
nsspwfile = os.path.join(tdir, 'nsspwfile')
with open(nsspwfile, 'w+') as f:
f.write(self.nssdb_password)
wrapped_key_file = os.path.join(tdir, 'wrapped_key')
certificate_file = os.path.join(tdir, 'certificate')
ipautil.run([
paths.PKI, '-d', self.nssdb_path, '-C', nsspwfile,
'ca-authority-key-export',
'--wrap-nickname', self.wrap_nick,
'--target-nickname', self.target_nick,
'-o', wrapped_key_file])
ipautil.run([
paths.CERTUTIL, '-d', self.nssdb_path,
'-L', '-n', self.target_nick,
'-a', '-o', certificate_file])
with open(wrapped_key_file, 'rb') as f:
wrapped_key = f.read()
with open(certificate_file, 'r') as f:
certificate = f.read()
finally:
shutil.rmtree(tdir)
return json_encode({
'wrapped_key': b64encode(wrapped_key).decode('ascii'),
'certificate': certificate})
class NSSCertDB(DBMAPHandler):
def __init__(self, config, dbmap, nickname):
if 'type' not in dbmap or dbmap['type'] != 'NSSDB':
raise ValueError('Invalid type "%s",'
' expected "NSSDB"' % (dbmap['type'],))
if 'path' not in dbmap:
raise ValueError('Configuration does not provide NSSDB path')
if 'pwcallback' not in dbmap:
raise ValueError('Configuration does not provide Password Calback')
self.nssdb_path = dbmap['path']
self.nickname = nickname
self.nssdb_password = dbmap['pwcallback']()
def export_key(self):
tdir = tempfile.mkdtemp(dir=paths.TMP)
try:
nsspwfile = os.path.join(tdir, 'nsspwfile')
with open(nsspwfile, 'w') as f:
f.write(self.nssdb_password)
pk12pwfile = os.path.join(tdir, 'pk12pwfile')
password = ipautil.ipa_generate_password()
with open(pk12pwfile, 'w') as f:
f.write(password)
pk12file = os.path.join(tdir, 'pk12file')
ipautil.run([paths.PK12UTIL,
"-d", self.nssdb_path,
"-o", pk12file,
"-n", self.nickname,
"-k", nsspwfile,
"-w", pk12pwfile])
with open(pk12file, 'rb') as f:
data = f.read()
finally:
shutil.rmtree(tdir)
return json_encode({'export password': password,
'pkcs12 data': b64encode(data).decode('ascii')})
def import_key(self, value):
v = json_decode(value)
tdir = tempfile.mkdtemp(dir=paths.TMP)
try:
nsspwfile = os.path.join(tdir, 'nsspwfile')
with open(nsspwfile, 'w') as f:
f.write(self.nssdb_password)
pk12pwfile = os.path.join(tdir, 'pk12pwfile')
with open(pk12pwfile, 'w') as f:
f.write(v['export password'])
pk12file = os.path.join(tdir, 'pk12file')
with open(pk12file, 'wb') as f:
f.write(b64decode(v['pkcs12 data']))
ipautil.run([paths.PK12UTIL,
"-d", self.nssdb_path,
"-i", pk12file,
"-n", self.nickname,
"-k", nsspwfile,
"-w", pk12pwfile])
finally:
shutil.rmtree(tdir)
# Exfiltrate the DM password Hash so it can be set in replica's and this
# way let a replica be install without knowing the DM password and yet
# still keep the DM password synchronized across replicas
class DMLDAP(DBMAPHandler):
def __init__(self, config, dbmap, nickname):
if 'type' not in dbmap or dbmap['type'] != 'DMLDAP':
raise ValueError('Invalid type "%s",'
' expected "DMLDAP"' % (dbmap['type'],))
if nickname != 'DMHash':
raise UnknownKeyName("Unknown Key Named '%s'" % nickname)
self.ldap = iSecLdap(config['ldap_uri'],
config.get('auth_type', None))
def export_key(self):
conn = self.ldap.connect()
r = conn.search_s('cn=config', ldap.SCOPE_BASE,
attrlist=['nsslapd-rootpw'])
if len(r) != 1:
raise RuntimeError('DM Hash not found!')
rootpw = r[0][1]['nsslapd-rootpw'][0]
return json_encode({'dmhash': rootpw.decode('ascii')})
def import_key(self, value):
v = json_decode(value)
rootpw = v['dmhash'].encode('ascii')
conn = self.ldap.connect()
mods = [(ldap.MOD_REPLACE, 'nsslapd-rootpw', rootpw)]
conn.modify_s('cn=config', mods)
class PEMFileHandler(DBMAPHandler):
def __init__(self, config, dbmap, nickname=None):
if 'type' not in dbmap or dbmap['type'] != 'PEM':
raise ValueError('Invalid type "{t}", expected PEM'
.format(t=dbmap['type']))
self.certfile = dbmap['certfile']
self.keyfile = dbmap.get('keyfile')
def export_key(self):
_fd, tmpfile = tempfile.mkstemp(dir=paths.TMP)
password = ipautil.ipa_generate_password()
args = [
paths.OPENSSL,
"pkcs12", "-export",
"-in", self.certfile,
"-out", tmpfile,
"-password", "pass:{pwd}".format(pwd=password)
]
if self.keyfile is not None:
args.extend(["-inkey", self.keyfile])
try:
ipautil.run(args, nolog=(password, ))
with open(tmpfile, 'rb') as f:
data = f.read()
finally:
os.remove(tmpfile)
return json_encode({'export password': password,
'pkcs12 data': b64encode(data).decode('ascii')})
def import_key(self, value):
v = json_decode(value)
data = b64decode(v['pkcs12 data'])
password = v['export password']
try:
_fd, tmpdata = tempfile.mkstemp(dir=paths.TMP)
os.close(_fd)
with open(tmpdata, 'wb') as f:
f.write(data)
# get the certificate from the file
ipautil.run([paths.OPENSSL,
"pkcs12",
"-in", tmpdata,
"-clcerts", "-nokeys",
"-out", self.certfile,
"-passin", "pass:{pwd}".format(pwd=password)],
nolog=(password, ))
if self.keyfile is not None:
# get the private key from the file
ipautil.run([paths.OPENSSL,
"pkcs12",
"-in", tmpdata,
"-nocerts", "-nodes",
"-out", self.keyfile,
"-passin", "pass:{pwd}".format(pwd=password)],
nolog=(password, ))
finally:
os.remove(tmpdata)
NAME_DB_MAP = {
'ca': {
'type': 'NSSDB',
'path': paths.PKI_TOMCAT_ALIAS_DIR,
'handler': NSSCertDB,
'pwcallback': PKI_TOMCAT_password_callback,
},
'ca_wrapped': {
'handler': NSSWrappedCertDB,
'path': paths.PKI_TOMCAT_ALIAS_DIR,
'pwcallback': PKI_TOMCAT_password_callback,
'wrap_nick': 'caSigningCert cert-pki-ca',
},
'ra': {
'type': 'PEM',
'handler': PEMFileHandler,
'certfile': paths.RA_AGENT_PEM,
'keyfile': paths.RA_AGENT_KEY,
},
'dm': {
'type': 'DMLDAP',
'handler': DMLDAP,
}
}
class IPASecStore(CSStore):
def __init__(self, config=None):
self.config = config
def _get_handler(self, key):
path = key.split('/', 3)
if len(path) != 3 or path[0] != 'keys':
raise ValueError('Invalid name')
if path[1] not in NAME_DB_MAP:
raise UnknownKeyName("Unknown DB named '%s'" % path[1])
dbmap = NAME_DB_MAP[path[1]]
return dbmap['handler'](self.config, dbmap, path[2])
def get(self, key):
try:
key_handler = self._get_handler(key)
value = key_handler.export_key()
except Exception as e: # pylint: disable=broad-except
log_error('Error retrieving key "%s": %s' % (key, str(e)))
value = None
return value
def set(self, key, value, replace=False):
try:
key_handler = self._get_handler(key)
key_handler.import_key(value)
except Exception as e: # pylint: disable=broad-except
log_error('Error storing key "%s": %s' % (key, str(e)))
def list(self, keyfilter=None):
raise NotImplementedError
def cut(self, key):
raise NotImplementedError
def span(self, key):
raise NotImplementedError
# backwards compatibility with FreeIPA 4.3 and 4.4.
iSecStore = IPASecStore