From a11c3165a28a5cb803c3d00bd201819cbca5f89a Mon Sep 17 00:00:00 2001 From: Jeremy Cline Date: Fri, 29 Sep 2017 16:09:47 -0400 Subject: [PATCH] Allow the CA and CRL to be file paths This also changes how they are cached in order to better handle expired or rotated CRLs/CAs. If the CA/CRL is a file, it is read into a cache and used until a message fails validation. At that point, the cache is invalidated and the CA/CRL is reloaded. If the message still fails validation, we mark it as invalid and continue. If the CA/CRL is a URL, the file is downloaded and cached in memory just like the file approach. It would be nice if the process halted when a fatal error was encountered (like the CRL being expired), but unfortunately there's no way to communicate that to moksha. Once we drop moksha we can do that with a set of fedmsg exceptions, but for now logging at the error level is the only thing we can do. fixes #481 fixes #365 Signed-off-by: Jeremy Cline --- fedmsg/crypto/utils.py | 114 +++++----- fedmsg/crypto/x509.py | 59 +++-- fedmsg/crypto/x509_ng.py | 42 ++-- fedmsg/tests/consumers/test_consumers.py | 8 +- fedmsg/tests/crypto/test_utils.py | 67 +++--- fedmsg/tests/crypto/test_x509.py | 120 +++++++--- ...ils.LoadCertificateTests.test_remote_cert} | 0 ...ryptoTests.test_loading_requests_exception | 1 + ...ryptoTests.test_loading_requests_exception | 1 + ...9BaseTests.test_loading_requests_exception | 206 ++++++++++++++++++ ...raphyTests.test_loading_requests_exception | 1 + ...ryptoTests.test_loading_requests_exception | 1 + 12 files changed, 458 insertions(+), 162 deletions(-) rename fedmsg/tests/fixtures/vcr/{fedmsg.tests.crypto.test_utils.LoadRemoteCertTests.test_remote_cert => fedmsg.tests.crypto.test_utils.LoadCertificateTests.test_remote_cert} (100%) create mode 120000 fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.CryptoWithM2CryptoTests.test_loading_requests_exception create mode 120000 fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.M2CryptoWithCryptoTests.test_loading_requests_exception create mode 100644 fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception create mode 120000 fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509CryptographyTests.test_loading_requests_exception create mode 120000 fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509M2CryptoTests.test_loading_requests_exception diff --git a/fedmsg/crypto/utils.py b/fedmsg/crypto/utils.py index aa5a6d13..b1d08a58 100644 --- a/fedmsg/crypto/utils.py +++ b/fedmsg/crypto/utils.py @@ -1,9 +1,10 @@ import logging -import os import requests -import time +# A simple dictionary to cache certificates in +_cached_certificates = dict() + _log = logging.getLogger(__name__) @@ -98,56 +99,71 @@ def validate_policy(topic, signer, routing_policy, nitpicky=False): return True -def _load_remote_cert(location, cache, cache_expiry, tries=3, **config): - """Get a fresh copy from fp.o/fedmsg/crl.pem if ours is getting stale. - - Return the local filename. - - .. note:: This is not a public API and is subject to change. +def load_certificates(ca_location, crl_location=None, invalidate_cache=False): + """ + Load the CA certificate and CRL, caching it for future use. Args: - location (str): The URL where the certificate is hosted. - cache (str): The absolute path where the certificate should be stored. - cache_expiry (int): How long the cache should be considered fresh, in seconds. - tries (int): The number of times to attempt to retry downloading the certificate. + ca_location (str): The location of the Certificate Authority certificate. This should + be the absolute path to a PEM-encoded file. It can also be an HTTPS url, but this + is deprecated and will be removed in a future release. + ca_location (str): The location of the Certificate Revocation List. This should + be the absolute path to a PEM-encoded file. It can also be an HTTPS url, but + this is deprecated and will be removed in a future release. + invalidate_cache (bool): Whether or not to invalidate the certificate cache. + + Returns: + tuple: A tuple of the (CA certificate, CRL) as unicode strings. + Raises: + requests.exception.RequestException: Any exception requests could raise. + IOError: If the location provided could not be opened and read. """ - alternative_cache = os.path.expanduser("~/.local" + cache) + if crl_location is None: + crl_location = '' try: - modtime = os.stat(cache).st_mtime - except OSError: - # File does not exist yet. - try: - # Try alternative location. - modtime = os.stat(alternative_cache).st_mtime - # It worked! Use the alternative location - cache = alternative_cache - except OSError: - # Neither file exists - modtime = 0 - - if ( - (not modtime and not cache_expiry) or - (cache_expiry and time.time() - modtime > cache_expiry) - ): - try: - with requests.Session() as session: - session.mount('http://', requests.adapters.HTTPAdapter(max_retries=tries)) - session.mount('https://', requests.adapters.HTTPAdapter(max_retries=tries)) - response = session.get(location, timeout=30) - with open(cache, 'w') as f: - f.write(response.text) - except IOError: - # If we couldn't write to the specified cache location, try a - # similar place but inside our home directory instead. - cache = alternative_cache - usr_dir = '/'.join(cache.split('/')[:-1]) - - if not os.path.isdir(usr_dir): - os.makedirs(usr_dir) - - with open(cache, 'w') as f: - f.write(response.text) - - return cache + if invalidate_cache: + del _cached_certificates[ca_location + crl_location] + else: + return _cached_certificates[ca_location + crl_location] + except KeyError: + pass + + ca, crl = None, None + if ca_location: + ca = _load_certificate(ca_location) + if crl_location: + crl = _load_certificate(crl_location) + + _cached_certificates[ca_location + crl_location] = ca, crl + return ca, crl + + +def _load_certificate(location): + """ + Load a certificate from the given location. + + Args: + location (str): The location to load. This can either be an HTTPS URL or an absolute file + path. This is intended to be used with PEM-encoded certificates and therefore assumes + ASCII encoding. + + Returns: + str: + + Raises: + requests.exception.RequestException: Any exception requests could raise. + IOError: If the location provided could not be opened and read. + """ + if location.startswith('https://'): + _log.info('Downloading x509 certificate from %s', location) + with requests.Session() as session: + session.mount('https://', requests.adapters.HTTPAdapter(max_retries=3)) + response = session.get(location, timeout=30) + response.raise_for_status() + return response.text + else: + _log.info('Loading local x509 certificate from %s', location) + with open(location, 'rb') as fd: + return fd.read().decode('ascii') diff --git a/fedmsg/crypto/x509.py b/fedmsg/crypto/x509.py index ae29c127..70f07d16 100644 --- a/fedmsg/crypto/x509.py +++ b/fedmsg/crypto/x509.py @@ -20,8 +20,11 @@ """ ``fedmsg.crypto.x509`` - X.509 backend for :mod:`fedmsg.crypto`. """ import logging +import os +import tempfile import warnings +from requests.exceptions import RequestException import six try: # Else we need M2Crypto and m2ext @@ -31,7 +34,7 @@ except ImportError: _m2crypto = False -from .utils import _load_remote_cert, validate_policy +from . import utils from .x509_ng import _cryptography, sign as _crypto_sign, validate as _crypto_validate import fedmsg.crypto # noqa: E402 import fedmsg.encoding # noqa: E402 @@ -136,28 +139,38 @@ def fail(reason): # validate_certificate will one day be a part of M2Crypto.SSL.Context # https://bugzilla.osafoundation.org/show_bug.cgi?id=11690 - default_ca_cert_loc = 'https://fedoraproject.org/fedmsg/ca.crt' - cafile = _load_remote_cert( - config.get('ca_cert_location', default_ca_cert_loc), - config.get('ca_cert_cache', '/etc/pki/fedmsg/ca.crt'), - config.get('ca_cert_cache_expiry', 0), - **config) - - ctx = m2ext.SSL.Context() - ctx.load_verify_locations(cafile=cafile) - if not ctx.validate_certificate(cert): - return fail("X509 certificate is not valid.") - - # Load and check against the CRL - crl = None - if 'crl_location' in config and 'crl_cache' in config: - crl = _load_remote_cert( - config.get('crl_location', 'https://fedoraproject.org/fedmsg/crl.pem'), - config.get('crl_cache', '/var/cache/fedmsg/crl.pem'), - config.get('crl_cache_expiry', 1800), - **config) + ca_location = config.get('ca_cert_location', 'https://fedoraproject.org/fedmsg/ca.crt') + crl_location = config.get('crl_location', 'https://fedoraproject.org/fedmsg/crl.pem') + fd, cafile = tempfile.mkstemp() + try: + ca_certificate, crl = utils.load_certificates(ca_location, crl_location) + os.write(fd, ca_certificate.encode('ascii')) + os.close(fd) + ctx = m2ext.SSL.Context() + ctx.load_verify_locations(cafile=cafile) + if not ctx.validate_certificate(cert): + ca_certificate, crl = utils.load_certificates( + ca_location, crl_location, invalidate_cache=True) + with open(cafile, 'w') as fd: + fd.write(ca_certificate) + ctx = m2ext.SSL.Context() + ctx.load_verify_locations(cafile=cafile) + if not ctx.validate_certificate(cert): + return fail("X509 certificate is not valid.") + except (IOError, RequestException) as e: + _log.error(str(e)) + return False + finally: + os.remove(cafile) + if crl: - crl = M2Crypto.X509.load_crl(crl) + fd, crlfile = tempfile.mkstemp(text=True) + os.write(fd, crl.encode('ascii')) + os.close(fd) + try: + crl = M2Crypto.X509.load_crl(crlfile) + finally: + os.remove(crlfile) # FIXME -- We need to check that the CRL is signed by our own CA. # See https://bugzilla.osafoundation.org/show_bug.cgi?id=12954#c2 # if not ctx.validate_certificate(crl): @@ -206,7 +219,7 @@ def fail(reason): signer = subject.get_entries_by_nid(subject.nid['CN'])[0]\ .get_data().as_text() - return validate_policy( + return utils.validate_policy( message.get('topic'), signer, routing_policy, config.get('routing_nitpicky', False)) diff --git a/fedmsg/crypto/x509_ng.py b/fedmsg/crypto/x509_ng.py index fb7a9760..bba7306a 100644 --- a/fedmsg/crypto/x509_ng.py +++ b/fedmsg/crypto/x509_ng.py @@ -39,6 +39,7 @@ _cryptography = True except ImportError: # pragma: no cover _cryptography = False +from requests.exceptions import RequestException import six from . import utils @@ -164,35 +165,22 @@ def validate(message, ssldir=None, **config): certificate = base64.b64decode(message['certificate']) message = fedmsg.crypto.strip_credentials(message) - crl_file = None - if 'crl_location' in config and 'crl_cache' in config: - crl_file = utils._load_remote_cert( - config.get('crl_location', 'https://fedoraproject.org/fedmsg/crl.pem'), - config.get('crl_cache', '/var/cache/fedmsg/crl.pem'), - config.get('crl_cache_expiry', 1800), - **config - ) - - ca_file = utils._load_remote_cert( - config.get('ca_cert_location', 'https://fedoraproject.org/fedmsg/ca.crt'), - config.get('ca_cert_cache', '/etc/pki/fedmsg/ca.crt'), - config.get('ca_cert_cache_expiry', 0), - **config - ) - - with open(ca_file, 'rb') as fd: - ca_certificate = fd.read() - - crl = None - if crl_file: - with open(crl_file, 'rb') as fd: - crl = fd.read() - + # Unfortunately we can't change this defaulting to Fedora behavior until + # fedmsg-2.0 + ca_location = config.get('ca_cert_location', 'https://fedoraproject.org/fedmsg/ca.crt') + crl_location = config.get('crl_location', 'https://fedoraproject.org/fedmsg/crl.pem') try: + ca_certificate, crl = utils.load_certificates(ca_location, crl_location) _validate_signing_cert(ca_certificate, certificate, crl) - except X509StoreContextError as e: - _log.error(str(e)) - return False + except (IOError, RequestException, X509StoreContextError) as e: + # Maybe the CA/CRL is expired or just rotated, so invalidate the cache and try again + try: + ca_certificate, crl = utils.load_certificates( + ca_location, crl_location, invalidate_cache=True) + _validate_signing_cert(ca_certificate, certificate, crl) + except (IOError, RequestException, X509StoreContextError) as e: + _log.error(str(e)) + return False # Validate the signature of the message itself try: diff --git a/fedmsg/tests/consumers/test_consumers.py b/fedmsg/tests/consumers/test_consumers.py index e529150c..4a831904 100644 --- a/fedmsg/tests/consumers/test_consumers.py +++ b/fedmsg/tests/consumers/test_consumers.py @@ -76,12 +76,8 @@ def setUp(self): 'dummy': True, 'ssldir': SSLDIR, 'certname': 'shell-app01.phx2.fedoraproject.org', - 'ca_cert_cache': os.path.join(SSLDIR, 'ca.crt'), - 'ca_cert_cache_expiry': 1497618475, # Stop fedmsg overwriting my CA, See Issue 420 - - 'crl_location': "http://threebean.org/fedmsg-tests/crl.pem", - 'crl_cache': os.path.join(SSLDIR, 'crl.pem'), - 'crl_cache_expiry': 1497618475, + 'ca_cert_location': os.path.join(SSLDIR, 'ca.crt'), + 'crl_location': os.path.join(SSLDIR, 'crl.pem'), 'crypto_validate_backends': ['x509'], } self.hub = mock.Mock(config=self.config) diff --git a/fedmsg/tests/crypto/test_utils.py b/fedmsg/tests/crypto/test_utils.py index 0bd136f3..736f2f52 100644 --- a/fedmsg/tests/crypto/test_utils.py +++ b/fedmsg/tests/crypto/test_utils.py @@ -1,7 +1,6 @@ import os import shutil import tempfile -import time import unittest import mock @@ -105,43 +104,51 @@ def test_topic_missing_not_nitpicky(self): self.assertTrue(result) -class LoadRemoteCertTests(base.FedmsgTestCase): +class LoadCertificateTests(base.FedmsgTestCase): """Tests for :func:`utils._load_remote_cert`.""" def setUp(self): - super(LoadRemoteCertTests, self).setUp() + super(LoadCertificateTests, self).setUp() self.cache_dir = tempfile.mkdtemp() self.cache_file = os.path.join(self.cache_dir, 'ca.crt') self.addCleanup(shutil.rmtree, self.cache_dir, True) def test_remote_cert(self): - """Assert downloading a certificate to a cache location works.""" + """Assert requesting a remote certificate works and is cached.""" + location = 'https://fedoraproject.org/fedmsg/ca.crt' with open(os.path.join(base.SSLDIR, 'fedora_ca.crt'), 'r') as fd: expected_cert = fd.read() - utils._load_remote_cert('https://fedoraproject.org/fedmsg/ca.crt', self.cache_file, 0) - - self.assertTrue(os.path.exists(self.cache_file)) - with open(self.cache_file, 'r') as fd: - actual_cert = fd.read() - self.assertEqual(expected_cert, actual_cert) - - @mock.patch('fedmsg.crypto.utils.os.stat') - def test_valid_cache(self, mock_stat): - """Assert when the primary cache is valid it's used.""" - mock_stat.return_value.st_mtime = time.time() - cache = utils._load_remote_cert('https://example.com/ca.crt', '/my/ca.crt', 60) - - self.assertEqual('/my/ca.crt', cache) - mock_stat.assert_called_once_with('/my/ca.crt') - - @mock.patch('fedmsg.crypto.utils.os.stat') - def test_valid_alternate_cache(self, mock_stat): - """Assert when the alternate cache is valid it's used.""" - mock_stat.side_effect = [OSError, mock.Mock(st_mtime=time.time())] - cache = utils._load_remote_cert('https://example.com/ca.crt', '/my/ca.crt', 60) - - self.assertEqual(os.path.expanduser('~/.local/my/ca.crt'), cache) - self.assertEqual('/my/ca.crt', mock_stat.call_args_list[0][0][0]) - self.assertEqual( - os.path.expanduser('~/.local/my/ca.crt'), mock_stat.call_args_list[1][0][0]) + + with mock.patch.dict('fedmsg.crypto.utils._cached_certificates', clear=True): + ca, crl = utils.load_certificates(location) + + self.assertEqual((expected_cert, None), utils._cached_certificates[location]) + self.assertEqual(expected_cert, ca) + self.assertTrue(crl is None) + + @mock.patch('fedmsg.crypto.utils._load_certificate') + def test_valid_cache(self, mock_load_cert): + """Assert when the cache is present it is used.""" + location = '/crt' + + with mock.patch.dict('fedmsg.crypto.utils._cached_certificates', {'/crt': ('crt', None)}): + ca, crl = utils.load_certificates(location) + + self.assertEqual('crt', ca) + self.assertTrue(crl is None) + self.assertEqual(0, mock_load_cert.call_count) + + @mock.patch('fedmsg.crypto.utils._load_certificate') + def test_invalidate_cache(self, mock_load_cert): + """Assert when the cache is present it is used.""" + location = '/crt' + mock_load_cert.return_value = 'fresh_ca' + + with mock.patch.dict('fedmsg.crypto.utils._cached_certificates', {'/crt': ('crt', None)}): + ca, crl = utils.load_certificates(location, invalidate_cache=True) + + self.assertEqual(('fresh_ca', None), utils._cached_certificates[location]) + self.assertEqual('fresh_ca', ca) + self.assertTrue(crl is None) + mock_load_cert.called_once_with('/crt') diff --git a/fedmsg/tests/crypto/test_x509.py b/fedmsg/tests/crypto/test_x509.py index 114d2dc9..d3246040 100644 --- a/fedmsg/tests/crypto/test_x509.py +++ b/fedmsg/tests/crypto/test_x509.py @@ -25,29 +25,26 @@ import six try: - from unittest import skipIf, TestCase, expectedFailure + from unittest import skipIf, expectedFailure except ImportError: - from unittest2 import skipIf, TestCase, expectedFailure + from unittest2 import skipIf, expectedFailure from fedmsg import crypto # noqa: E402 from fedmsg.crypto.x509 import _m2crypto from fedmsg.crypto.x509_ng import _cryptography -from fedmsg.tests.base import SSLDIR # noqa: E402 +from fedmsg.tests.base import SSLDIR, FedmsgTestCase @skipIf(not (_m2crypto or _cryptography), "Neither M2Crypto nor Cryptography available") -class X509BaseTests(TestCase): +class X509BaseTests(FedmsgTestCase): def setUp(self): + super(X509BaseTests, self).setUp() self.config = { 'ssldir': SSLDIR, 'certname': 'shell-app01.phx2.fedoraproject.org', - 'ca_cert_cache': os.path.join(SSLDIR, 'ca.crt'), - 'ca_cert_cache_expiry': 1497618475, # Stop fedmsg overwriting my CA, See Issue 420 - - 'crl_location': "http://threebean.org/fedmsg-tests/crl.pem", - 'crl_cache': os.path.join(SSLDIR, 'crl.pem'), - 'crl_cache_expiry': 1497618475, + 'ca_cert_location': os.path.join(SSLDIR, 'ca.crt'), + 'crl_location': os.path.join(SSLDIR, 'crl.pem'), 'crypto_validate_backends': ['x509'], } self.sign = crypto.sign @@ -95,7 +92,76 @@ def test_unsigned(self): def test_invalid_ca(self): """Assert when the CA didn't sign the certificate, validation fails.""" - self.config['ca_cert_cache'] = os.path.join(SSLDIR, 'badca.crt') + self.config['ca_cert_location'] = os.path.join(SSLDIR, 'badca.crt') + + signed = self.sign({'my': 'message'}, **self.config) + self.assertFalse(self.validate(signed, **self.config)) + + @mock.patch('fedmsg.crypto.utils.load_certificates') + def test_refreshing_ca_cache(self, mock_load_certificates): + """Assert that when validation fails, the CA cache is refreshed.""" + with open(os.path.join(SSLDIR, 'ca.crt')) as fd: + good_ca = fd.read() + with open(os.path.join(SSLDIR, 'badca.crt')) as fd: + bad_ca = fd.read() + mock_load_certificates.side_effect = [(bad_ca, None), (good_ca, None)] + + signed = self.sign({'my': 'message'}, **self.config) + self.assertTrue(self.validate(signed, **self.config)) + + @mock.patch('fedmsg.crypto.utils.load_certificates') + def test_refreshing_ca_cache_invalid(self, mock_load_certificates): + """Assert that when the refreshed CA is still bad, the message is considered invalid.""" + with open(os.path.join(SSLDIR, 'badca.crt')) as fd: + bad_ca = fd.read() + mock_load_certificates.side_effect = [(bad_ca, None), (bad_ca, None)] + + signed = self.sign({'my': 'message'}, **self.config) + self.assertFalse(self.validate(signed, **self.config)) + + @mock.patch('fedmsg.crypto.utils.load_certificates') + def test_refreshing_crl_cache(self, mock_load_certificates): + """Assert that when validation fails, the CRL cache is refreshed.""" + with open(os.path.join(SSLDIR, 'ca.crt')) as fd: + good_ca = fd.read() + with open(os.path.join(SSLDIR, 'crl.pem')) as fd: + good_crl = fd.read() + with open(os.path.join(SSLDIR, 'expired_crl.pem')) as fd: + bad_crl = fd.read() + mock_load_certificates.side_effect = [(good_ca, bad_crl), (good_ca, good_crl)] + + signed = self.sign({'my': 'message'}, **self.config) + self.assertTrue(self.validate(signed, **self.config)) + + @mock.patch('fedmsg.crypto.utils.load_certificates') + def test_refreshing_crl_cache_invalid(self, mock_load_certificates): + """Assert that when the refreshed CRL is still bad, the message is considered invalid.""" + with open(os.path.join(SSLDIR, 'ca.crt')) as fd: + good_ca = fd.read() + with open(os.path.join(SSLDIR, 'expired_crl.pem')) as fd: + bad_crl = fd.read() + mock_load_certificates.side_effect = [(good_ca, bad_crl), (good_ca, bad_crl)] + + signed = self.sign({'my': 'message'}, **self.config) + self.assertFalse(self.validate(signed, **self.config)) + + def test_ca_ioerror(self): + """Assert that if the CA is unreadable the message fails validation.""" + self.config['ca_cert_location'] = '/if/you/make/this/path/my/test/fails.crt' + + signed = self.sign({'my': 'message'}, **self.config) + self.assertFalse(self.validate(signed, **self.config)) + + def test_crl_ioerror(self): + """Assert that if the CRL is unreadable the message fails validation.""" + self.config['crl_location'] = '/if/you/make/this/path/my/test/fails.crt' + + signed = self.sign({'my': 'message'}, **self.config) + self.assertFalse(self.validate(signed, **self.config)) + + def test_loading_requests_exception(self): + """Assert that if the CA or CRL results in a Requests error, the message is invalid.""" + self.config['crl_location'] = 'https://fedoraproject.org/fedmsg/notacrl.pem' signed = self.sign({'my': 'message'}, **self.config) self.assertFalse(self.validate(signed, **self.config)) @@ -125,9 +191,7 @@ def test_invalid_message_signature(self): def test_no_crl(self): """Assert that it's okay to not use a CRL.""" - del self.config['crl_location'] - del self.config['crl_cache'] - del self.config['crl_cache_expiry'] + self.config['crl_location'] = None signed = self.sign({'message': 'so secure'}, **self.config) self.assertTrue(self.validate(signed, **self.config)) @@ -135,11 +199,9 @@ def test_no_crl(self): def test_signed_by_expired_ca(self): """Assert certs signed by an expired CA fail validation.""" self.config['certname'] = 'signed_by_expired_ca' - self.config['ca_cert_cache'] = os.path.join(SSLDIR, 'expired_ca.crt') + self.config['ca_cert_location'] = os.path.join(SSLDIR, 'expired_ca.crt') # There's no CRL for this CA. - del self.config['crl_location'] - del self.config['crl_cache'] - del self.config['crl_cache_expiry'] + self.config['crl_location'] = None signed = self.sign({'message': 'so secure'}, **self.config) self.assertFalse(self.validate(signed, **self.config)) @@ -200,7 +262,7 @@ def setUp(self): def test_old_crl(self): """Assert when an old CRL is used, validation fails.""" signed = self.sign({'my': 'message'}, **self.config) - self.config['crl_cache'] = os.path.join(SSLDIR, 'expired_crl.pem') + self.config['crl_location'] = os.path.join(SSLDIR, 'expired_crl.pem') self.assertFalse(self.validate(signed, **self.config)) @@ -223,6 +285,10 @@ def test_bytes_logs_error(self, mock_log): class X509M2CryptoTests(X509BaseTests): """Tests that explicitly use the m2crypto-based sign/verify.""" + def setUpClass(cls): + cls.test_refreshing_crl_cache_invalid = expectedFailure( + cls.test_refreshing_crl_cache_invalid) + def setUp(self): super(X509M2CryptoTests, self).setUp() self.sign = crypto.x509._m2crypto_sign @@ -232,7 +298,7 @@ def setUp(self): def test_old_crl(self): """Assert when an old CRL is used, validation fails.""" signed = self.sign({'my': 'message'}, **self.config) - self.config['crl_cache'] = os.path.join(SSLDIR, 'expired_crl.pem') + self.config['crl_location'] = os.path.join(SSLDIR, 'expired_crl.pem') self.assertFalse(self.validate(signed, **self.config)) @@ -265,6 +331,10 @@ def setUp(self): class CryptoWithM2CryptoTests(X509BaseTests): """Tests that use cryptography for signing and validate with m2crypto.""" + def setUpClass(cls): + cls.test_refreshing_crl_cache_invalid = expectedFailure( + cls.test_refreshing_crl_cache_invalid) + def setUp(self): super(CryptoWithM2CryptoTests, self).setUp() self.sign = crypto.x509._crypto_sign @@ -272,19 +342,15 @@ def setUp(self): @skipIf(not (_cryptography and _m2crypto), 'M2Crypto and cryptography required.') -class CompatibleFormatTests(TestCase): +class CompatibleFormatTests(FedmsgTestCase): """Tests that use cryptography for signing and validate with m2crypto.""" def setUp(self): self.config = { 'ssldir': SSLDIR, 'certname': 'shell-app01.phx2.fedoraproject.org', - 'ca_cert_cache': os.path.join(SSLDIR, 'ca.crt'), - 'ca_cert_cache_expiry': 1497618475, # Stop fedmsg overwriting my CA, See Issue 420 - - 'crl_location': "http://threebean.org/fedmsg-tests/crl.pem", - 'crl_cache': os.path.join(SSLDIR, 'crl.pem'), - 'crl_cache_expiry': 1497618475, + 'ca_cert_location': os.path.join(SSLDIR, 'ca.crt'), + 'crl_location': os.path.join(SSLDIR, 'crl.pem'), 'crypto_validate_backends': ['x509'], } diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_utils.LoadRemoteCertTests.test_remote_cert b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_utils.LoadCertificateTests.test_remote_cert similarity index 100% rename from fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_utils.LoadRemoteCertTests.test_remote_cert rename to fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_utils.LoadCertificateTests.test_remote_cert diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.CryptoWithM2CryptoTests.test_loading_requests_exception b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.CryptoWithM2CryptoTests.test_loading_requests_exception new file mode 120000 index 00000000..747e7e26 --- /dev/null +++ b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.CryptoWithM2CryptoTests.test_loading_requests_exception @@ -0,0 +1 @@ +fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception \ No newline at end of file diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.M2CryptoWithCryptoTests.test_loading_requests_exception b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.M2CryptoWithCryptoTests.test_loading_requests_exception new file mode 120000 index 00000000..747e7e26 --- /dev/null +++ b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.M2CryptoWithCryptoTests.test_loading_requests_exception @@ -0,0 +1 @@ +fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception \ No newline at end of file diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception new file mode 100644 index 00000000..4d8ee469 --- /dev/null +++ b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception @@ -0,0 +1,206 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [python-requests/2.18.3] + method: GET + uri: https://fedoraproject.org/fedmsg/notacrl.pem + response: + body: + string: !!binary | + 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 + xPaD7+HjbTv936X/Bc1w/28dNQAA + headers: + Accept-Ranges: [bytes] + AppServer: [proxy08.fedoraproject.org] + AppTime: [D=4698] + Connection: [Keep-Alive] + Content-Encoding: [gzip] + Content-Language: [en] + Content-Length: ['4068'] + Content-Location: [404.html.en] + Content-Type: [text/html; charset=utf-8] + Date: ['Mon, 02 Oct 2017 13:38:10 GMT'] + ETag: ['"351d-55a8f95b45580;55a8f9d73fa00-gzip"'] + Keep-Alive: ['timeout=15, max=500'] + Last-Modified: ['Mon, 02 Oct 2017 12:33:42 GMT'] + Server: [Apache/2.4.6 (Red Hat Enterprise Linux)] + TCN: [choice] + Vary: ['negotiate,accept-language,Accept-Encoding,User-Agent'] + status: {code: 404, message: Not Found} +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [python-requests/2.18.3] + method: GET + uri: https://fedoraproject.org/fedmsg/notacrl.pem + response: + body: + string: !!binary | + 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 + xPaD7+HjbTv936X/Bc1w/28dNQAA + headers: + Accept-Ranges: [bytes] + AppServer: [proxy08.fedoraproject.org] + AppTime: [D=3157] + Connection: [Keep-Alive] + Content-Encoding: [gzip] + Content-Language: [en] + Content-Length: ['4068'] + Content-Location: [404.html.en] + Content-Type: [text/html; charset=utf-8] + Date: ['Mon, 02 Oct 2017 13:38:10 GMT'] + ETag: ['"351d-55a8f95b45580;55a8f9d73fa00-gzip"'] + Keep-Alive: ['timeout=15, max=500'] + Last-Modified: ['Mon, 02 Oct 2017 12:33:42 GMT'] + Server: [Apache/2.4.6 (Red Hat Enterprise Linux)] + TCN: [choice] + Vary: ['negotiate,accept-language,Accept-Encoding,User-Agent'] + status: {code: 404, message: Not Found} +version: 1 diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509CryptographyTests.test_loading_requests_exception b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509CryptographyTests.test_loading_requests_exception new file mode 120000 index 00000000..747e7e26 --- /dev/null +++ b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509CryptographyTests.test_loading_requests_exception @@ -0,0 +1 @@ +fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception \ No newline at end of file diff --git a/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509M2CryptoTests.test_loading_requests_exception b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509M2CryptoTests.test_loading_requests_exception new file mode 120000 index 00000000..747e7e26 --- /dev/null +++ b/fedmsg/tests/fixtures/vcr/fedmsg.tests.crypto.test_x509.X509M2CryptoTests.test_loading_requests_exception @@ -0,0 +1 @@ +fedmsg.tests.crypto.test_x509.X509BaseTests.test_loading_requests_exception \ No newline at end of file