def _create_td_jwt_bundle_dict( jwt_bundle_response: workload_pb2.JWTBundlesResponse, ) -> Dict[TrustDomain, JwtBundle]: jwt_bundles = {} for td, jwk_set in jwt_bundle_response.bundles.items(): jwt_bundles[TrustDomain.parse(td)] = JwtBundle.parse( TrustDomain.parse(td), jwk_set) return jwt_bundles
def test_fetch_x509_context_success(mocker): federated_bundles = {'domain.test': FEDERATED_BUNDLE} WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchX509SVID = mocker.Mock( return_value=iter([ workload_pb2.X509SVIDResponse( svids=[ workload_pb2.X509SVID( spiffe_id='spiffe://example.org/service', x509_svid=CHAIN1, x509_svid_key=KEY1, bundle=BUNDLE, ), workload_pb2.X509SVID( spiffe_id='spiffe://example.org/service2', x509_svid=CHAIN2, x509_svid_key=KEY2, bundle=BUNDLE, ), ], federated_bundles=federated_bundles, ) ])) x509_context = WORKLOAD_API_CLIENT.fetch_x509_context() svids = x509_context.x509_svids() bundle_set = x509_context.x509_bundle_set() assert len(svids) == 2 svid1 = x509_context.default_svid() assert svid1.spiffe_id() == SpiffeId.parse('spiffe://example.org/service') assert len(svid1.cert_chain()) == 2 assert isinstance(svid1.leaf(), Certificate) assert isinstance(svid1.private_key(), ec.EllipticCurvePrivateKey) svid2 = x509_context.x509_svids()[1] assert svid2.spiffe_id() == SpiffeId.parse('spiffe://example.org/service2') assert len(svid2.cert_chain()) == 1 assert isinstance(svid2.leaf(), Certificate) assert isinstance(svid2.private_key(), ec.EllipticCurvePrivateKey) bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert bundle assert len(bundle.x509_authorities()) == 1 federated_bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('domain.test')) assert federated_bundle assert len(federated_bundle.x509_authorities()) == 1
def test_x509_source_get_bundle_for_trust_domain(mocker): mock_client_return_multiple_svids(mocker) x509_source = DefaultX509Source(WORKLOAD_API_CLIENT) bundle = x509_source.get_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert bundle.trust_domain() == TrustDomain.parse('example.org') assert len(bundle.x509_authorities()) == 1 bundle = x509_source.get_bundle_for_trust_domain( TrustDomain.parse('domain.test')) assert bundle.trust_domain() == TrustDomain.parse('domain.test') assert len(bundle.x509_authorities()) == 1
def test_parse_with_all_chars(): # Go all the way through 255, which ensures we reject UTF-8 appropriately for i in range(0, 255): c = chr(i) td = "trustdomain" + c if c in TD_CHARS: trust_domain = TrustDomain.parse(td) assert trust_domain.name() == td else: with pytest.raises(ArgumentError) as exception: TrustDomain.parse(td) assert ( str(exception.value) == 'Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores.' )
def test_create_new_x509_bundle_set(): bundle_bytes = read_bytes(_TEST_CERTS_PATH.format('cert.der')) bundle_1 = X509Bundle.parse_raw(trust_domain_1, bundle_bytes) bundle_2 = X509Bundle.parse_raw(trust_domain_2, bundle_bytes) bundles = {trust_domain_1: bundle_1, trust_domain_2: bundle_2} x509_bundle_set = X509BundleSet(bundles) assert len(x509_bundle_set._bundles) == 2 # check that the bundle map was copied assert x509_bundle_set._bundles is not bundles found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_1) assert found_bundle == bundle_1 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_2) assert found_bundle == bundle_2 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('other.test')) assert found_bundle is None
def _create_bundle_set(self, resp_bundles: Mapping[str, bytes]) -> X509BundleSet: x509_bundles = [ self._create_x509_bundle(TrustDomain.parse(td), resp_bundles[td]) for td in resp_bundles ] return X509BundleSet.of(x509_bundles)
def get_jwt_bundle(mocker): mock_client_get_jwt_svid(mocker) mock_client_fetch_jwt_bundles(mocker) jwt_source = DefaultJwtSource(WORKLOAD_API_CLIENT) jwt_bundle = jwt_source.get_jwt_bundle(TrustDomain.parse('example.org')) assert jwt_bundle assert len(jwt_bundle.jwt_authorities()) == 1
def test_fetch_x509_bundles_success(mocker): bundles = {'example.org': BUNDLE, 'domain.test': FEDERATED_BUNDLE} WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchX509Bundles = mocker.Mock( return_value=iter( [workload_pb2.X509BundlesResponse(bundles=bundles, )])) bundle_set = WORKLOAD_API_CLIENT.fetch_x509_bundles() bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert bundle assert len(bundle.x509_authorities()) == 1 federated_bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('domain.test')) assert federated_bundle assert len(federated_bundle.x509_authorities()) == 1
def test_watch_jwt_bundle_success(mocker): jwt_bundles = { 'example.org': JWKS_1_EC_KEY, 'domain.prod': JWKS_2_EC_1_RSA_KEYS } jwt_bundles_2 = {'domain.dev': JWKS_1_EC_KEY} WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTBundles = mocker.Mock( return_value=delayed_responses([ workload_pb2.JWTBundlesResponse(bundles=jwt_bundles), workload_pb2.JWTBundlesResponse(bundles=jwt_bundles_2), ])) event = threading.Event() response_holder = ResponseHolder() WORKLOAD_API_CLIENT.watch_jwt_bundles( on_success=lambda r: handle_success(r, response_holder, event), on_error=lambda e: handle_error(e, response_holder, event), ) event.wait(3) # add timeout to prevent test from hanging assert not response_holder.error jwt_bundle_set = response_holder.success assert jwt_bundle_set jwt_bundle_1 = jwt_bundle_set.get(TrustDomain.parse('example.org')) assert jwt_bundle_1 assert len(jwt_bundle_1.jwt_authorities()) == 1 jwt_bundle_2 = jwt_bundle_set.get(TrustDomain.parse('domain.prod')) assert jwt_bundle_2 assert len(jwt_bundle_2.jwt_authorities()) == 3 # Wait to receive the second response from delayed_responses() time.sleep(1) assert not response_holder.error jwt_bundle_set = response_holder.success jwt_bundle = jwt_bundle_set.get(TrustDomain.parse('domain.dev')) assert jwt_bundle assert len(jwt_bundle.jwt_authorities()) == 1
def test_watch_x509_context_success(mocker): federated_bundles = {'domain.test': FEDERATED_BUNDLE} WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchX509SVID = mocker.Mock( return_value=iter([ workload_pb2.X509SVIDResponse( svids=[ workload_pb2.X509SVID( spiffe_id='spiffe://example.org/service', x509_svid=CHAIN1, x509_svid_key=KEY1, bundle=BUNDLE, ), workload_pb2.X509SVID( spiffe_id='spiffe://example.org/service2', x509_svid=CHAIN2, x509_svid_key=KEY2, bundle=BUNDLE, ), ], federated_bundles=federated_bundles, ) ])) done = threading.Event() response_holder = ResponseHolder() WORKLOAD_API_CLIENT.watch_x509_context( lambda r: handle_success(r, response_holder, done), lambda e: handle_error(e, response_holder, done), retry_connect=True, ) done.wait(5) # add timeout to prevent test from hanging assert not response_holder.error x509_context = response_holder.success svid1 = x509_context.default_svid() assert svid1.spiffe_id() == SpiffeId.parse('spiffe://example.org/service') assert len(svid1.cert_chain()) == 2 assert isinstance(svid1.leaf(), Certificate) assert isinstance(svid1.private_key(), ec.EllipticCurvePrivateKey) svid2 = x509_context.x509_svids()[1] assert svid2.spiffe_id() == SpiffeId.parse('spiffe://example.org/service2') assert len(svid2.cert_chain()) == 1 assert isinstance(svid2.leaf(), Certificate) assert isinstance(svid2.private_key(), ec.EllipticCurvePrivateKey) bundle_set = x509_context.x509_bundle_set() bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert bundle assert len(bundle.x509_authorities()) == 1
def test_fetch_jwt_bundles(mocker): bundles = { 'example.org': JWKS_1_EC_KEY, 'domain.test': JWKS_2_EC_1_RSA_KEYS } WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTBundles = mocker.Mock( return_value=iter([ workload_pb2.JWTBundlesResponse(bundles=bundles, ), ])) jwt_bundle_set = WORKLOAD_API_CLIENT.fetch_jwt_bundles() jwt_bundle = jwt_bundle_set.get(TrustDomain.parse('example.org')) assert jwt_bundle assert len(jwt_bundle.jwt_authorities()) == 1 federated_jwt_bundle = jwt_bundle_set.get(TrustDomain.parse('domain.test')) assert federated_jwt_bundle assert len(federated_jwt_bundle.jwt_authorities()) == 3
def test_x509_source_is_closed_get_bundle(mocker): mock_client_return_multiple_svids(mocker) x509_source = DefaultX509Source(WORKLOAD_API_CLIENT) x509_source.close() with (pytest.raises(X509SourceError)) as exception: x509_source.get_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert (str(exception.value) == 'X.509 Source error: Cannot get X.509 Bundle: source is closed.')
def test_watch_jwt_bundle_retry_on_grpc_error(mocker): grpc_error = FakeCall() jwt_bundles = { 'example.org': JWKS_1_EC_KEY, 'domain.prod': JWKS_2_EC_1_RSA_KEYS } WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTBundles = mocker.Mock( side_effect=[ grpc_error, delayed_responses( [workload_pb2.JWTBundlesResponse(bundles=jwt_bundles)]), ]) expected_error = FetchJwtBundleError(grpc_error.details()) event = threading.Event() response_holder = ResponseHolder() WORKLOAD_API_CLIENT.watch_jwt_bundles( on_success=lambda r: handle_success(r, response_holder, event), on_error=lambda e: assert_error(e, expected_error), ) event.wait(3) # add timeout to prevent test from hanging # Wait to receive the response from delayed_responses() time.sleep(1) jwt_bundle_set = response_holder.success assert jwt_bundle_set jwt_bundle_1 = jwt_bundle_set.get(TrustDomain.parse('example.org')) assert jwt_bundle_1 assert len(jwt_bundle_1.jwt_authorities()) == 1 jwt_bundle_2 = jwt_bundle_set.get(TrustDomain.parse('domain.prod')) assert jwt_bundle_2 assert len(jwt_bundle_2.jwt_authorities()) == 3
def test_get_jwt_bundle_exception(mocker): jwt_bundles = { 'example.org': JWKS_1_EC_KEY, 'domain.prod': JWKS_2_EC_1_RSA_KEYS } WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTBundles = mocker.Mock( return_value=[ workload_pb2.JWTBundlesResponse(bundles=jwt_bundles), ], side_effect=Exception('Mocked Error'), ) jwt_source = DefaultJwtSource(WORKLOAD_API_CLIENT) with pytest.raises(JwtSourceError) as exception: _ = jwt_source.get_jwt_bundle(TrustDomain.parse('example.org')) assert (str(exception.value) == 'JWT Source error: Cannot get JWT Bundle: source is closed.')
def test_watch_x509_context_raise_retryable_grpc_error_and_then_ok_response( mocker): mock_error_iter = mocker.MagicMock() mock_error_iter.__iter__.side_effect = ( yield_grpc_error_and_then_correct_x509_svid_response()) WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchX509SVID = mocker.Mock( return_value=mock_error_iter) expected_error = FetchX509SvidError('StatusCode.DEADLINE_EXCEEDED') done = threading.Event() response_holder = ResponseHolder() WORKLOAD_API_CLIENT.watch_x509_context( lambda r: handle_success(r, response_holder, done), lambda e: assert_error(e, expected_error), True, ) done.wait(5) # add timeout to prevent test from hanging x509_context = response_holder.success svid1 = x509_context.default_svid() assert svid1.spiffe_id() == SpiffeId.parse('spiffe://example.org/service') assert len(svid1.cert_chain()) == 2 assert isinstance(svid1.leaf(), Certificate) assert isinstance(svid1.private_key(), ec.EllipticCurvePrivateKey) svid2 = x509_context.x509_svids()[1] assert svid2.spiffe_id() == SpiffeId.parse('spiffe://example.org/service2') assert len(svid2.cert_chain()) == 1 assert isinstance(svid2.leaf(), Certificate) assert isinstance(svid2.private_key(), ec.EllipticCurvePrivateKey) bundle_set = x509_context.x509_bundle_set() bundle = bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('example.org')) assert bundle assert len(bundle.x509_authorities()) == 1
def test_of_with_all_chars(): # Go all the way through 255, which ensures we reject UTF-8 appropriately for i in range(0, 255): c = chr(i) # Don't test '/' since it is the delimiter between path segments if c == '/': continue path1 = '/Path1' + c path2 = '/Path2' + c trust_domain = TrustDomain.parse('trustdomain') if c in PATH_CHARS: spiffe_id = SpiffeId.of(trust_domain, [path1, path2]) assert str(spiffe_id) == 'spiffe://trustdomain' + path1 + path2 else: with pytest.raises(SpiffeIdError) as exception: SpiffeId.of('spiffe://trustdomain', [path1, path2]) assert ( str(exception.value) == 'Path segment characters are limited to letters, numbers, dots, dashes, and underscores.' )
def test_create_x509_bundle_set_from_list_of_bundles(): bundle_bytes = read_bytes(_TEST_CERTS_PATH.format('certs.der')) bundle_1 = X509Bundle.parse_raw(trust_domain_1, bundle_bytes) bundle_2 = X509Bundle.parse_raw(trust_domain_2, bundle_bytes) bundles = [bundle_1, bundle_2] x509_bundle_set = X509BundleSet.of(bundles) assert len(x509_bundle_set._bundles) == 2 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_1) assert found_bundle == bundle_1 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_2) assert found_bundle == bundle_2 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( TrustDomain.parse('other.test')) assert found_bundle is None
from pyspiffe.bundle.x509_bundle.x509_bundle import X509Bundle from pyspiffe.bundle.x509_bundle.x509_bundle_set import X509BundleSet from pyspiffe.spiffe_id.spiffe_id import TrustDomain _TEST_CERTS_PATH = 'test/bundle/x509bundle/certs/{}' trust_domain_1 = TrustDomain.parse('domain.test') trust_domain_2 = TrustDomain.parse('example.org') def test_create_new_x509_bundle_set(): bundle_bytes = read_bytes(_TEST_CERTS_PATH.format('cert.der')) bundle_1 = X509Bundle.parse_raw(trust_domain_1, bundle_bytes) bundle_2 = X509Bundle.parse_raw(trust_domain_2, bundle_bytes) bundles = {trust_domain_1: bundle_1, trust_domain_2: bundle_2} x509_bundle_set = X509BundleSet(bundles) assert len(x509_bundle_set._bundles) == 2 # check that the bundle map was copied assert x509_bundle_set._bundles is not bundles found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_1) assert found_bundle == bundle_1 found_bundle = x509_bundle_set.get_x509_bundle_for_trust_domain( trust_domain_2) assert found_bundle == bundle_2
def test_is_not_member_of(): spiffe_id = SpiffeId.parse('spiffe://domain.test/path/element') trust_domain = TrustDomain.parse('other.test') assert not spiffe_id.is_member_of(trust_domain)
def test_not_equal_spiffe_ids(): trust_domain = TrustDomain.parse('trustdomain') spiffeid_1 = SpiffeId.from_segments(trust_domain, '/path1') spiffeid_2 = SpiffeId.from_segments(trust_domain, '/path2') assert spiffeid_1 != spiffeid_2
def test_equal_spiffe_id_with_multiple_paths(): trust_domain = TrustDomain.parse('trustdomain') spiffeid_1 = SpiffeId.from_segments(trust_domain, ['/PATH1', '/PATH2']) spiffeid_2 = SpiffeId.from_segments(trust_domain, ['/PATH1', '/PATH2']) assert spiffeid_1 == spiffeid_2
'5', '6', '7', '8', '9', '.', '-', '_', } @pytest.mark.parametrize( 'trust_domain,path_segments,expected_spiffe_id', [ ( TrustDomain.parse('example.org'), ['path', 'element'], 'spiffe://example.org/path/element', ), ( TrustDomain.parse('example.org'), ['path', 'element'], 'spiffe://example.org/path/element', ), ( TrustDomain.parse('domain.test'), ['pAth1', 'pATH2'], 'spiffe://domain.test/pAth1/pATH2', ), ( TrustDomain.parse('domain.test'),
def test_not_equal_when_different_objects(): trust_domain = TrustDomain.parse('domain.test') td_list = list([trust_domain]) assert trust_domain != td_list
def test_to_string(): trust_domain = TrustDomain.parse('domain.test') assert str(trust_domain) == 'domain.test'
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.x509 import Certificate from pyspiffe.bundle.x509_bundle.exceptions import ( X509BundleError, ParseX509BundleError, LoadX509BundleError, SaveX509BundleError, ) from pyspiffe.bundle.x509_bundle.x509_bundle import X509Bundle from pyspiffe.spiffe_id.spiffe_id import TrustDomain from pyspiffe.exceptions import ArgumentError _TEST_CERTS_PATH = 'test/bundle/x509bundle/certs/{}' trust_domain = TrustDomain.parse('domain.test') def test_parse_raw_bundle_single_authority(): bundle_bytes = read_bytes('cert.der') x509_bundle = X509Bundle.parse_raw(trust_domain, bundle_bytes) assert x509_bundle.trust_domain() == trust_domain assert len(x509_bundle.x509_authorities()) == 1 authority = x509_bundle.x509_authorities().pop() assert isinstance(authority, Certificate) assert 'CN=PEMUTILTEST1' == authority.subject.rfc4514_string()
def test_invalid_trust_domain(test_input, expected): with pytest.raises(ArgumentError) as exception: TrustDomain.parse(test_input) assert str(exception.value) == expected
def test_compare_multiple_equal_trust_domains(): trust_domain1 = TrustDomain.parse('domain.test') trust_domain2 = TrustDomain.parse('domain.test') assert trust_domain1 == trust_domain2
def test_compare_different_trust_domains(): trust_domain1 = TrustDomain.parse('domain.test') trust_domain2 = TrustDomain.parse('other.test') assert not trust_domain1 == trust_domain2
def test_equal_spiffe_id(): trust_domain = TrustDomain.parse('trustdomain') spiffeid_1 = SpiffeId.of(trust_domain, '/path1') spiffeid_2 = SpiffeId.of(trust_domain, '/path1') assert spiffeid_1 == spiffeid_2
def test_as_str_id(): trust_domain = TrustDomain.parse('example.org') assert trust_domain.as_str_id() == 'spiffe://example.org'