[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From 8bee187ea7f87a22594d0f67a87d9411cd678f64 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as in memory. https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 205 ++- ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +- ipalib/constants.py | 14 +++ 4 files changed, 170 insertions(+), 64 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 70756df..d677ec0 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,30 +20,38 @@ from __future__ import print_function import base64 +import collections +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.padding import PKCS7 from cryptography.hazmat.primitives.serialization import ( load_pem_public_key, load_pem_private_key) -from cryptography.x509 import load_der_x509_certificate from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) def validated_read(argname, filename, mode='r', encoding=None): @@ -550,6 +558,79 @@ def forward(self, *args, **options): return response +class _TransportCertCache(collections.MutableMapping): +def __init__(self): +self._dirname = os.path.join( +USER_CACHE_PATH, 'ipa', 'kra-transport-certs') +self._transport_certs = {} + +def _get_filename(self, domain): +basename = DNSName(domain).ToASCII() + '.pem' +return os.path.join(self._dirname, basename) + +def __getitem__(self, domain): +try: +transport_cert = self._transport_certs[domain] +except KeyError: +transport_cert = None + +filename = self._get_filename(domain) +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +if transport_cert is None: +raise KeyError(domain) + +self._transport_certs[domain] = transport_cert + +return transport_cert + +def __setitem__(self, domain, transport_cert): +filename = self._get_filename(domain) +transport_cert_der = ( +transport_cert.public_bytes(serialization.Encoding.DER)) +try: +try: +os.makedirs(self._dirname) +except EnvironmentError as e: +if e.errno != errno.EEXIST: +raise +fd, tmpfilename = tempfile.mkstemp(dir=self._dirname) +os.close(fd) +x509.write_certificate(transport_cert_der, tmpfilename) +os.rename(tmpfilename, filename) +except Exception: +logger.warning("Failed to save %s", filename, exc_info=True) + +self._transport_certs[domain] = transport_cert + +def __delitem__(self, domain): +filename = self._get_filename(domain) +try: +os.unlink(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +logger.warning("Failed to remove %s", filename, exc_info=True) + +del self._transport_certs[domain] + +def __len__(self): +return len(self._transport_certs) + +def __iter__(self): +return iter(self._transport_certs) + + +_transport_cert_cache = _TransportCertCa
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From 95fe10800b5d74e610314bfab24d5935c0010a83 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as in memory. https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 205 ++- ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +- ipalib/constants.py | 14 +++ 4 files changed, 170 insertions(+), 64 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 70756df..d677ec0 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,30 +20,38 @@ from __future__ import print_function import base64 +import collections +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.padding import PKCS7 from cryptography.hazmat.primitives.serialization import ( load_pem_public_key, load_pem_private_key) -from cryptography.x509 import load_der_x509_certificate from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) def validated_read(argname, filename, mode='r', encoding=None): @@ -550,6 +558,79 @@ def forward(self, *args, **options): return response +class _TransportCertCache(collections.MutableMapping): +def __init__(self): +self._dirname = os.path.join( +USER_CACHE_PATH, 'ipa', 'kra-transport-certs') +self._transport_certs = {} + +def _get_filename(self, domain): +basename = DNSName(domain).ToASCII() + '.pem' +return os.path.join(self._dirname, basename) + +def __getitem__(self, domain): +try: +transport_cert = self._transport_certs[domain] +except KeyError: +transport_cert = None + +filename = self._get_filename(domain) +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +if transport_cert is None: +raise KeyError(domain) + +self._transport_certs[domain] = transport_cert + +return transport_cert + +def __setitem__(self, domain, transport_cert): +filename = self._get_filename(domain) +transport_cert_der = ( +transport_cert.public_bytes(serialization.Encoding.DER)) +try: +try: +os.makedirs(self._dirname) +except EnvironmentError as e: +if e.errno != errno.EEXIST: +raise +fd, tmpfilename = tempfile.mkstemp(dir=self._dirname) +os.close(fd) +x509.write_certificate(transport_cert_der, tmpfilename) +os.rename(tmpfilename, filename) +except Exception: +logger.warning("Failed to save %s", filename, exc_info=True) + +self._transport_certs[domain] = transport_cert + +def __delitem__(self, domain): +filename = self._get_filename(domain) +try: +os.unlink(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +logger.warning("Failed to remove %s", filename, exc_info=True) + +del self._transport_certs[domain] + +def __len__(self): +return len(self._transport_certs) + +def __iter__(self): +return iter(self._transport_certs) + + +_transport_cert_cache = _TransportCertCa
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From b35f363fd98dd6959d1dd2f9240dcdf308606ff9 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as in memory. https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 221 ++- ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +- ipalib/constants.py | 14 +++ 4 files changed, 186 insertions(+), 64 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 70756df..f24ec1e 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,30 +20,40 @@ from __future__ import print_function import base64 +import collections +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.padding import PKCS7 from cryptography.hazmat.primitives.serialization import ( load_pem_public_key, load_pem_private_key) -from cryptography.x509 import load_der_x509_certificate + +import six from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) def validated_read(argname, filename, mode='r', encoding=None): @@ -550,6 +560,79 @@ def forward(self, *args, **options): return response +class _TransportCertCache(collections.MutableMapping): +def __init__(self): +self._dirname = os.path.join( +USER_CACHE_PATH, 'ipa', 'kra-transport-certs') +self._transport_certs = {} + +def _get_filename(self, domain): +basename = DNSName(domain).ToASCII() + '.pem' +return os.path.join(self._dirname, basename) + +def __getitem__(self, domain): +try: +transport_cert = self._transport_certs[domain] +except KeyError: +transport_cert = None + +filename = self._get_filename(domain) +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +if transport_cert is None: +raise KeyError(domain) + +self._transport_certs[domain] = transport_cert + +return transport_cert + +def __setitem__(self, domain, transport_cert): +filename = self._get_filename(domain) +transport_cert_der = ( +transport_cert.public_bytes(serialization.Encoding.DER)) +try: +try: +os.makedirs(self._dirname) +except EnvironmentError as e: +if e.errno != errno.EEXIST: +raise +fd, tmpfilename = tempfile.mkstemp(dir=self._dirname) +os.close(fd) +x509.write_certificate(transport_cert_der, tmpfilename) +os.rename(tmpfilename, filename) +except Exception: +logger.warning("Failed to save %s", filename, exc_info=True) + +self._transport_certs[domain] = transport_cert + +def __delitem__(self, domain): +filename = self._get_filename(domain) +try: +os.unlink(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +logger.warning("Failed to remove %s", filename, exc_info=True) + +del self._transport_certs[domain] + +def __len__(self): +return len(self._transport_certs) + +def __iter__(self): +return iter(self._transport_certs) + + +_transport_cert_cache = _T
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From a8e1704ef4055b7d8083b99367b53dbdf95c475f Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as in memory. https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 161 +++ ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +-- ipalib/constants.py | 14 +++ 4 files changed, 143 insertions(+), 47 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 9efb1f1..ebfb129 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,29 +20,41 @@ from __future__ import print_function import base64 +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import load_pem_public_key,\ load_pem_private_key import nss.nss as nss +import six from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) + +TRANSPORT_CERT_CACHE_PATH = ( +os.path.join(USER_CACHE_PATH, 'ipa', 'kra-transport-certs')) def validated_read(argname, filename, mode='r', encoding=None): @@ -568,6 +580,115 @@ def forward(self, *args, **options): return response +class _TransportCertInvalid(Exception): +def __init__(self, exc_info): +self.exc_info = exc_info + + +_transport_cert_cache = {} + + +class ModVaultData(Local): +def _do_internal(self, mechanism, session_key, transport_cert_der, + *args, **options): +nss_transport_cert = nss.Certificate(transport_cert_der) + +# wrap session key with transport certificate +# pylint: disable=no-member +public_key = nss_transport_cert.subject_public_key_info.public_key +# pylint: enable=no-member +wrapped_session_key = nss.pub_wrap_sym_key(mechanism, + public_key, + session_key) + +options['session_key'] = wrapped_session_key.data + +name = self.name + '_internal' +try: +return self.api.Command[name](*args, **options) +except errors.NotFound: +raise +except (errors.InternalError, +errors.ExecutionError, +errors.GenericError): +raise _TransportCertInvalid(sys.exc_info()) + +def internal(self, mechanism, session_key, *args, **options): +""" +Calls the internal counterpart of the command. +""" +domain = self.api.env.domain +dirname = TRANSPORT_CERT_CACHE_PATH +basename = DNSName(domain).ToASCII() + '.pem' +filename = os.path.join(dirname, basename) + +# get transport cert from cache +transport_cert_der = _transport_cert_cache.get(domain) +if transport_cert_der is None: +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +else: +transport_cert_der = transport_cert.public_bytes( +serialization.Encoding.DER) +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +# try call with the cached transport cert, uncache it if unsuccessful +if transport_cert_der is not None: +try: +return self._do_internal(mechanism, + session_key, + transport_cert_der, +
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From bc9fdf7306e1ba2cf70f812dadbf65e33b629f6d Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client Cache the KRA transport certificate on disk (in ~/.cache/ipa) as well as in-memory for the lifetime of the API object. https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 157 +++ ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +-- ipalib/constants.py | 14 4 files changed, 139 insertions(+), 47 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 9efb1f1..1de5cc2 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,29 +20,41 @@ from __future__ import print_function import base64 +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import load_pem_public_key,\ load_pem_private_key import nss.nss as nss +import six from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) + +TRANSPORT_CERT_CACHE_PATH = ( +os.path.join(USER_CACHE_PATH, 'ipa', 'kra-transport-certs')) def validated_read(argname, filename, mode='r', encoding=None): @@ -568,6 +580,111 @@ def forward(self, *args, **options): return response +class _TransportCertInvalid(Exception): +def __init__(self, exc_info): +self.exc_info = exc_info + + +_transport_cert_cache = {} + + +class ModVaultData(Local): +def _do_internal(self, mechanism, session_key, transport_cert_der, + *args, **options): +nss_transport_cert = nss.Certificate(transport_cert_der) + +# wrap session key with transport certificate +# pylint: disable=no-member +public_key = nss_transport_cert.subject_public_key_info.public_key +# pylint: enable=no-member +wrapped_session_key = nss.pub_wrap_sym_key(mechanism, + public_key, + session_key) + +options['session_key'] = wrapped_session_key.data + +name = self.name + '_internal' +try: +return self.api.Command[name](*args, **options) +except errors.NotFound: +raise +except (errors.InternalError, +errors.ExecutionError, +errors.GenericError): +raise _TransportCertInvalid(sys.exc_info()) + +def internal(self, mechanism, session_key, *args, **options): +""" +Calls the internal counterpart of the command. +""" +domain = self.api.env.domain +dirname = TRANSPORT_CERT_CACHE_PATH +basename = DNSName(domain).ToASCII() + '.pem' +filename = os.path.join(dirname, basename) + +# get transport cert from cache +transport_cert_der = _transport_cert_cache.get(domain) +if transport_cert_der is None: +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +else: +transport_cert_der = transport_cert.public_bytes( +serialization.Encoding.DER) +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +# try call with the cached transport cert, uncache it if unsuccessful +if transport_cert_der is not None: +try: +return self._do_internal(mechanism, + session_key, + transpor
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From fabb614a57d2d2eec40e846d73a0b1ba18aaf836 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 149 +++ ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +-- ipalib/constants.py | 14 4 files changed, 131 insertions(+), 47 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 9efb1f1..809f7b0 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,29 +20,41 @@ from __future__ import print_function import base64 +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import load_pem_public_key,\ load_pem_private_key import nss.nss as nss +import six from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) + +TRANSPORT_CERT_CACHE_PATH = ( +os.path.join(USER_CACHE_PATH, 'ipa', 'kra-transport-certs')) def validated_read(argname, filename, mode='r', encoding=None): @@ -568,6 +580,103 @@ def forward(self, *args, **options): return response +class _TransportCertInvalid(Exception): +def __init__(self, exc_info): +self.exc_info = exc_info + + +class ModVaultData(Local): +def _do_internal(self, mechanism, session_key, transport_cert_der, + *args, **options): +nss_transport_cert = nss.Certificate(transport_cert_der) + +# wrap session key with transport certificate +# pylint: disable=no-member +public_key = nss_transport_cert.subject_public_key_info.public_key +# pylint: enable=no-member +wrapped_session_key = nss.pub_wrap_sym_key(mechanism, + public_key, + session_key) + +options['session_key'] = wrapped_session_key.data + +name = self.name + '_internal' +try: +return self.api.Command[name](*args, **options) +except errors.NotFound: +raise +except (errors.InternalError, +errors.ExecutionError, +errors.GenericError): +raise _TransportCertInvalid(sys.exc_info()) + +def internal(self, mechanism, session_key, *args, **options): +""" +Calls the internal counterpart of the command. +""" +dirname = TRANSPORT_CERT_CACHE_PATH +basename = DNSName(self.api.env.domain).ToASCII() + '.pem' +filename = os.path.join(dirname, basename) + +# try call with the cached transport cert, if there is one +transport_cert = None +try: +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +raise +except Exception: +logger.warning("Failed to load %s: %s", filename, + exc_info=True) + +if transport_cert is not None: +transport_cert_der = ( +transport_cert.public_bytes(serialization.Encoding.DER)) + +try: +return self._do_internal(mechanism, + session_key, + transport_cert_der, + *args, **options) +except _TransportCertInvalid: +try: +os.remove(filename) +except EnvironmentError: +logger.warning("Failed to remove %s", filename, + exc_info=True) + +# retrieve transport certifica
[Freeipa-devel] [freeipa PR#476][synchronized] vault: cache the transport certificate on client
URL: https://github.com/freeipa/freeipa/pull/476 Author: HonzaCholasta Title: #476: vault: cache the transport certificate on client Action: synchronized To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/476/head:pr476 git checkout pr476 From cdac87a5123b2641a19753b1dd52b741dfcc9cc3 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Fri, 17 Feb 2017 11:25:17 +0100 Subject: [PATCH] vault: cache the transport certificate on client https://fedorahosted.org/freeipa/ticket/6652 --- ipaclient/plugins/vault.py | 141 ++- ipaclient/remote_plugins/__init__.py | 3 +- ipaclient/remote_plugins/schema.py | 12 +-- ipalib/constants.py | 14 4 files changed, 123 insertions(+), 47 deletions(-) diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py index 9efb1f1..91def33 100644 --- a/ipaclient/plugins/vault.py +++ b/ipaclient/plugins/vault.py @@ -20,29 +20,41 @@ from __future__ import print_function import base64 +import errno import getpass import io import json import os import sys +import tempfile from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.serialization import load_pem_public_key,\ load_pem_private_key import nss.nss as nss +import six from ipaclient.frontend import MethodOverride +from ipalib import x509 +from ipalib.constants import USER_CACHE_PATH from ipalib.frontend import Local, Method, Object from ipalib.util import classproperty from ipalib import api, errors from ipalib import Bytes, Flag, Str from ipalib.plugable import Registry from ipalib import _ +from ipapython.dnsutil import DNSName +from ipapython.ipa_log_manager import log_mgr + +logger = log_mgr.get_logger(__name__) + +TRANSPORT_CERT_CACHE_PATH = ( +os.path.join(USER_CACHE_PATH, 'ipa', 'kra-transport-certs')) def validated_read(argname, filename, mode='r', encoding=None): @@ -568,6 +580,95 @@ def forward(self, *args, **options): return response +class _TransportCertInvalid(Exception): +def __init__(self, exc_info): +self.exc_info = exc_info + + +class ModVaultData(Local): +def _do_internal(self, mechanism, session_key, transport_cert_der, + *args, **options): +nss_transport_cert = nss.Certificate(transport_cert_der) + +# wrap session key with transport certificate +# pylint: disable=no-member +public_key = nss_transport_cert.subject_public_key_info.public_key +# pylint: enable=no-member +wrapped_session_key = nss.pub_wrap_sym_key(mechanism, + public_key, + session_key) + +options['session_key'] = wrapped_session_key.data + +name = self.name + '_internal' +try: +return self.api.Command[name](*args, **options) +except errors.NotFound: +raise +except (errors.InternalError, +errors.ExecutionError, +errors.GenericError): +raise _TransportCertInvalid(sys.exc_info()) + +def internal(self, mechanism, session_key, *args, **options): +""" +Calls the internal counterpart of the command. +""" +dirname = TRANSPORT_CERT_CACHE_PATH +basename = DNSName(self.api.env.domain).ToASCII() + '.pem' +filename = os.path.join(dirname, basename) + +# try call with the cached transport cert, if there is one +try: +transport_cert = x509.load_certificate_from_file(filename) +except EnvironmentError as e: +if e.errno != errno.ENOENT: +logger.warning("Failed to load %s: %s", filename, e) +else: +transport_cert_der = ( +transport_cert.public_bytes(serialization.Encoding.DER)) + +try: +return self._do_internal(mechanism, + session_key, + transport_cert_der, + *args, **options) +except _TransportCertInvalid: +try: +os.remove(filename) +except EnvironmentError as e: +logger.warning("Failed to remove %s: %s", filename, e) + +# retrieve transport certificate +config = self.api.Command.vaultconfig_show()['result'] +transport_cert_der = config['transport_cert'] + +# call with the retrieved transport cert, cache it if successful +transport_c