Beispiel #1
0
    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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #6
0
 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)
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #10
0
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
Beispiel #12
0
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
Beispiel #14
0
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.')
Beispiel #15
0
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
Beispiel #16
0
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'),
Beispiel #23
0
def test_not_equal_when_different_objects():
    trust_domain = TrustDomain.parse('domain.test')
    td_list = list([trust_domain])
    assert trust_domain != td_list
Beispiel #24
0
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()

Beispiel #26
0
def test_invalid_trust_domain(test_input, expected):
    with pytest.raises(ArgumentError) as exception:
        TrustDomain.parse(test_input)

    assert str(exception.value) == expected
Beispiel #27
0
def test_compare_multiple_equal_trust_domains():
    trust_domain1 = TrustDomain.parse('domain.test')
    trust_domain2 = TrustDomain.parse('domain.test')
    assert trust_domain1 == trust_domain2
Beispiel #28
0
def test_compare_different_trust_domains():
    trust_domain1 = TrustDomain.parse('domain.test')
    trust_domain2 = TrustDomain.parse('other.test')
    assert not trust_domain1 == trust_domain2
Beispiel #29
0
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
Beispiel #30
0
def test_as_str_id():
    trust_domain = TrustDomain.parse('example.org')
    assert trust_domain.as_str_id() == 'spiffe://example.org'