Esempio n. 1
0
def test_exceeds_maximum_length():
    path = 'a' * 2028

    with pytest.raises(ArgumentError) as exception:
        SpiffeId.parse('spiffe://example.org/{}'.format(path))

    assert str(exception.value) == 'SPIFFE ID: maximum length is 2048 bytes.'
Esempio n. 2
0
def test_fetch_x509_svids_success(mocker):
    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,
                ),
                workload_pb2.X509SVID(
                    spiffe_id='spiffe://example.org/service2',
                    x509_svid=CHAIN2,
                    x509_svid_key=KEY2,
                ),
            ])
        ]))

    svids = WORKLOAD_API_CLIENT.fetch_x509_svids()

    assert len(svids) == 2

    svid1 = svids[0]
    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 = 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)
Esempio n. 3
0
def test_fetch_x509_context_success(mocker):
    federated_bundles = dict()
    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('example.org'))
    assert bundle
    assert len(bundle.x509_authorities()) == 1

    federated_bundle = bundle_set.get_x509_bundle_for_trust_domain(
        TrustDomain('domain.test')
    )
    assert federated_bundle
    assert len(federated_bundle.x509_authorities()) == 1
Esempio n. 4
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
Esempio n. 5
0
def test_parse_chain_and_ec_key():
    chain_bytes = read_bytes('2-chain.pem')
    key_bytes = read_bytes('2-key.pem')

    x509_svid = X509Svid.parse(chain_bytes, key_bytes)

    expected_spiffe_id = SpiffeId.parse('spiffe://example.org/service')
    assert x509_svid.spiffe_id() == SpiffeId.parse(
        'spiffe://example.org/service')
    assert len(x509_svid.cert_chain()) == 2
    assert isinstance(x509_svid.leaf(), Certificate)
    assert isinstance(x509_svid.cert_chain()[1], Certificate)
    assert isinstance(x509_svid.private_key(), ec.EllipticCurvePrivateKey)
    assert _extract_spiffe_id(x509_svid.leaf()) == expected_spiffe_id
Esempio n. 6
0
    def parse_insecure(cls, token: str, expected_audience: List) -> 'JwtSvid':
        """Parses and validates a JWT-SVID token and returns an instance of a JwtSvid with a SPIFFE ID parsed from the 'sub', audience from 'aud',
        and expiry from 'exp' claim. The JWT-SVID signature is not verified.

        Args:
            token: A token as a string that is parsed and validated.
            audience: Audience as a list of strings used to validate the 'aud' claim.

        Returns:
            An instance of JwtSvid with a SPIFFE ID parsed from the 'sub', audience from 'aud', and expiry
            from 'exp' claim.

        Raises:
            ValueError: When the token is blank or cannot be parsed, or in case header is not specified or in case expected_audience is empty or
                if the SPIFFE ID in the 'sub' claim doesn't comply with the SPIFFE standard.
            InvalidAlgorithmError: In case specified 'alg' is not supported as specified by the SPIFFE standard.
            InvalidTypeError: If 'typ' is present in header but is not set to 'JWT' or 'JOSE'.
            InvalidClaimError: If a required claim ('exp', 'aud', 'sub') is not present in payload or expected_audience is not a subset of audience_claim.
            TokenExpiredError: If token is expired.
            InvalidTokenError: If token is malformed and fails to decode.
        """
        if not token:
            raise ValueError(INVALID_INPUT_ERROR.format('token cannot be empty'))
        try:
            token_header = jwt.get_unverified_header(token)
            validator = JwtSvidValidator()
            validator.validate_header(token_header)
            claims = jwt.decode(token, options={'verify_signature': False})
            validator.validate_claims(claims, expected_audience)
            spiffe_ID = SpiffeId.parse(claims['sub'])
            return JwtSvid(spiffe_ID, claims['aud'], claims['exp'], claims, token)
        except PyJWTError as err:
            raise InvalidTokenError(str(err))
Esempio n. 7
0
def test_x509_source_get_default_x509_svid(mocker):
    mock_client_return_multiple_svids(mocker)

    x509_source = DefaultX509Source(WORKLOAD_API_CLIENT)

    x509_svid = x509_source.get_x509_svid()
    assert x509_svid.spiffe_id() == SpiffeId.parse(
        'spiffe://example.org/service')
Esempio n. 8
0
def _extract_spiffe_id(cert: Certificate) -> SpiffeId:
    ext = cert.extensions.get_extension_for_oid(
        x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
    sans = ext.value.get_values_for_type(x509.UniformResourceIdentifier)
    if len(sans) == 0:
        raise InvalidLeafCertificateError(
            'Certificate does not contain a SPIFFE ID in the URI SAN')
    return SpiffeId.parse(sans[0])
Esempio n. 9
0
def test_x509_source_get_x509_svid_with_picker(mocker):
    mock_client_return_multiple_svids(mocker)

    x509_source = DefaultX509Source(WORKLOAD_API_CLIENT,
                                    picker=lambda svids: svids[1])

    x509_svid = x509_source.get_x509_svid()
    assert x509_svid.spiffe_id() == SpiffeId.parse(
        'spiffe://example.org/service2')
Esempio n. 10
0
    def parse_and_validate(
        cls, token: str, jwt_bundle: JwtBundle, audience: List[str]
    ) -> 'JwtSvid':
        """Parses and validates a JWT-SVID token and returns an instance of JwtSvid.

        The JWT-SVID signature is verified using the JWT bundle source.

        Args:
            token: A token as a string that is parsed and validated.
            jwt_bundle: An instance of JwtBundle that provides the JWT authorities to verify the signature.
            audience: A list of strings used to validate the 'aud' claim.

        Returns:
            An instance of JwtSvid with a SPIFFE ID parsed from the 'sub', audience from 'aud', and expiry
            from 'exp' claim.

        Raises:
            JwtSvidError:   When the token expired or the expiration claim is missing,
                            when the algorithm is not supported, when the header 'kid' is missing,
                            when the signature cannot be verified, or
                            when the 'aud' claim has an audience that is not in the audience list provided as parameter.
            ValueError:     When the token is blank or cannot be parsed.
            BundleNotFoundError:    If the bundle for the trust domain of the spiffe id from the 'sub'
                                    cannot be found the jwt_bundle_source.
            AuthorityNotFoundError: If the authority cannot be found in the bundle using the value from the 'kid' header.
            InvalidTokenError: In case token is malformed and fails to decode.
        """
        if not token:
            raise ValueError(INVALID_INPUT_ERROR.format('token cannot be empty'))

        if not jwt_bundle:
            raise ValueError(INVALID_INPUT_ERROR.format('jwt_bundle cannot be empty'))
        try:
            token_header = jwt.get_unverified_header(token)
            validator = JwtSvidValidator()
            validator.validate_header(token_header)
            signing_key = jwt_bundle.find_jwt_authority(token_header['kid'])
            claims = jwt.decode(
                token,
                algorithms=token_header['alg'],
                key=signing_key,
                audience=audience,
                options={
                    'verify_signature': True,
                    'verify_aud': True,
                    'verify_exp': True,
                },
            )
            # TODO:validate required claims
            spiffe_ID = SpiffeId.parse(claims['sub'])
            return JwtSvid(spiffe_ID, claims['aud'], claims['exp'], claims, token)
        except PyJWTError as err:
            raise InvalidTokenError(str(err))
Esempio n. 11
0
def test_parse_leaf_only_and_rsa_key():
    chain_bytes = read_bytes('3-good-leaf-only.pem')
    key_bytes = read_bytes('3-key-pkcs8-rsa.pem')

    x509_svid = X509Svid.parse(chain_bytes, key_bytes)

    expected_spiffe_id = SpiffeId.parse('spiffe://example.org/workload-1')
    assert x509_svid.spiffe_id() == expected_spiffe_id
    assert len(x509_svid.cert_chain()) == 1
    assert isinstance(x509_svid.leaf(), Certificate)
    assert isinstance(x509_svid.private_key(), rsa.RSAPrivateKey)
    assert _extract_spiffe_id(x509_svid.leaf()) == expected_spiffe_id
Esempio n. 12
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
Esempio n. 13
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)

        # Don't test '/' since it is the delimiter between path segments
        if c == '/':
            continue

        path = '/path' + c

        if c in PATH_CHARS:
            spiffe_id = SpiffeId.parse('spiffe://trustdomain' + path)
            assert str(spiffe_id) == 'spiffe://trustdomain' + path
        else:
            with pytest.raises(SpiffeIdError) as exception:
                SpiffeId.parse('spiffe://trustdomain' + path)
            assert (
                str(exception.value) ==
                'Path segment characters are limited to letters, numbers, dots, dashes, and underscores.'
            )

        td = 'spiffe://trustdomain' + c
        if c in TD_CHARS:
            spiffe_id = SpiffeId.parse(td)
            assert str(spiffe_id) == td
        else:
            with pytest.raises(SpiffeIdError) as exception:
                SpiffeId.parse(td)
            assert (
                str(exception.value) ==
                'Trust domain characters are limited to lowercase letters, numbers, dots, dashes, and underscores.'
            )
Esempio n. 14
0
def test_load_from_der_files():
    chain_path = _TEST_CERTS_PATH.format('1-chain.der')
    key_path = _TEST_CERTS_PATH.format('1-key.der')

    x509_svid = X509Svid.load(chain_path, key_path, serialization.Encoding.DER)

    expected_spiffe_id = SpiffeId.parse('spiffe://example.org/service')
    assert x509_svid.spiffe_id() == expected_spiffe_id
    assert len(x509_svid.cert_chain()) == 2
    assert isinstance(x509_svid.leaf(), Certificate)
    assert isinstance(x509_svid.cert_chain()[1], Certificate)
    assert isinstance(x509_svid.private_key(), ec.EllipticCurvePrivateKey)
    assert _extract_spiffe_id(x509_svid.leaf()) == expected_spiffe_id
def test_fetch_jwt_svid_aud(mocker):
    spiffe_id = 'spiffe://test.com/my_service'
    jwt_svid = create_jwt(spiffe_id=spiffe_id)

    WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTSVID = mocker.Mock(
        return_value=workload_pb2.JWTSVIDResponse(
            svids=[workload_pb2.JWTSVID(svid=jwt_svid, )]))

    svid = WORKLOAD_API_CLIENT.fetch_jwt_svid(audiences=DEFAULT_AUDIENCE)
    utc_time = timegm(datetime.datetime.utcnow().utctimetuple())
    assert svid.spiffe_id == SpiffeId.parse(spiffe_id)
    assert svid.token == jwt_svid
    assert svid.claims['aud'] == DEFAULT_AUDIENCE
    assert int(svid.expiry) > utc_time
Esempio n. 16
0
def test_validate_jwt_svid(mocker):
    audience = 'spire'
    spiffe_id = 'spiffe://test.com/my_service'
    jwt_svid = create_jwt(audience=[audience], spiffe_id=spiffe_id)

    WORKLOAD_API_CLIENT._spiffe_workload_api_stub.ValidateJWTSVID = mocker.Mock(
        return_value=workload_pb2.ValidateJWTSVIDResponse(spiffe_id=spiffe_id,
                                                          ))

    svid = WORKLOAD_API_CLIENT.validate_jwt_svid(token=jwt_svid,
                                                 audience=audience)

    assert svid.spiffe_id == SpiffeId.parse(spiffe_id)
    assert svid.token == jwt_svid
    assert svid.claims['aud'] == [audience]
    assert svid.audience == [audience]
Esempio n. 17
0
def test_save_chain_and_rsa_key_as_der(tmpdir):
    chain_bytes = read_bytes('3-good-leaf-only.pem')
    key_bytes = read_bytes('3-key-pkcs8-rsa.pem')

    # create the X509Svid to be saved
    x509_svid = X509Svid.parse(chain_bytes, key_bytes)

    # temp files to store the certs and private_key
    chain_der_file = tmpdir.join('chain.der')
    key_der_file = tmpdir.join('key.der')

    x509_svid.save(chain_der_file, key_der_file, serialization.Encoding.DER)

    # now load the saved svid, and check that everything was stored correctly
    saved_svid = X509Svid.load(chain_der_file, key_der_file,
                               serialization.Encoding.DER)
    expected_spiffe_id = SpiffeId.parse('spiffe://example.org/workload-1')
    assert saved_svid.spiffe_id() == expected_spiffe_id
    assert len(saved_svid.cert_chain()) == 1
    assert isinstance(saved_svid.leaf(), Certificate)
    assert isinstance(saved_svid.private_key(), rsa.RSAPrivateKey)
    assert _extract_spiffe_id(saved_svid.leaf()) == expected_spiffe_id
Esempio n. 18
0
def test_save_chain_and_ec_key_as_pem(tmpdir):
    chain_bytes = read_bytes('2-chain.pem')
    key_bytes = read_bytes('2-key.pem')

    # create the X509Svid to be saved
    x509_svid = X509Svid.parse(chain_bytes, key_bytes)
    # temp files to store the certs and private_key

    chain_pem_file = tmpdir.join('chain.pem')
    key_pem_file = tmpdir.join('key.pem')

    x509_svid.save(chain_pem_file, key_pem_file, serialization.Encoding.PEM)

    # now load the saved svid, and check that everything was stored correctly
    saved_svid = X509Svid.load(chain_pem_file, key_pem_file,
                               serialization.Encoding.PEM)
    expected_spiffe_id = SpiffeId.parse('spiffe://example.org/service')
    assert saved_svid.spiffe_id() == expected_spiffe_id
    assert len(saved_svid.cert_chain()) == 2
    assert isinstance(saved_svid.leaf(), Certificate)
    assert isinstance(x509_svid.cert_chain()[1], Certificate)
    assert isinstance(saved_svid.private_key(), ec.EllipticCurvePrivateKey)
    assert _extract_spiffe_id(saved_svid.leaf()) == expected_spiffe_id
import pytest
from cryptography import x509
from cryptography.hazmat.primitives import serialization
from cryptography.x509 import Certificate

from pyspiffe.spiffe_id.spiffe_id import SpiffeId
from pyspiffe.utils.certificate_utils import (
    parse_pem_certificates,
    parse_der_certificates,
    load_certificates_bytes_from_file,
    write_certificate_to_file,
    serialize_certificate,
)
from pyspiffe.utils.exceptions import X509CertificateError

_EXPECTED_SPIFFE_ID = SpiffeId.parse('spiffe://example.org/service')
_TEST_CERTS_PATH = 'test/svid/x509svid/certs/{}'


def test_parse_der_certificates():
    certs_bytes = _read_bytes('1-chain.der')

    certs = parse_der_certificates(certs_bytes)

    assert len(certs) == 2
    assert isinstance(certs[0], Certificate)
    assert isinstance(certs[1], Certificate)
    assert _extract_spiffe_id(certs[0]) == _EXPECTED_SPIFFE_ID


def test_parse_pem_certificates():
Esempio n. 20
0
import pytest

from test.svid.test_utils import create_jwt, DEFAULT_AUDIENCE
from pyspiffe.spiffe_id.spiffe_id import TrustDomain
from pyspiffe.proto.spiffe import workload_pb2
from pyspiffe.spiffe_id.spiffe_id import SpiffeId
from pyspiffe.workloadapi.default_jwt_source import DefaultJwtSource
from pyspiffe.workloadapi.exceptions import JwtSourceError, FetchJwtSvidError
from test.workloadapi.test_default_workload_api_client import WORKLOAD_API_CLIENT
from pyspiffe.exceptions import ArgumentError
from test.utils.utils import (
    JWKS_1_EC_KEY,
    JWKS_2_EC_1_RSA_KEYS,
)

SPIFFE_ID = SpiffeId.parse('spiffe://example.org/my_service')


def mock_client_get_jwt_svid(mocker):
    jwt_svid = create_jwt(spiffe_id=str(SPIFFE_ID))

    WORKLOAD_API_CLIENT._spiffe_workload_api_stub.FetchJWTSVID = mocker.Mock(
        return_value=workload_pb2.JWTSVIDResponse(svids=[
            workload_pb2.JWTSVID(
                spiffe_id=str(SPIFFE_ID),
                svid=jwt_svid,
            )
        ]))


def mock_client_fetch_jwt_bundles(mocker):
Esempio n. 21
0
def test_str_when_no_path():
    spiffe_id = SpiffeId.parse('spiffe://domain.test')
    assert str(spiffe_id) == 'spiffe://domain.test'
Esempio n. 22
0
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)
Esempio n. 23
0
def test_parse_spiffe_id_from_invalid(spiffe_id_str, expected):
    with pytest.raises(ArgumentError) as exception:
        SpiffeId.parse(spiffe_id_str)

    assert str(exception.value) == expected
Esempio n. 24
0
def test_parse_spiffe_id_valid(spiffe_id_str, expected_trust_domain,
                               expected_path):
    spiffe_id = SpiffeId.parse(spiffe_id_str)
    assert spiffe_id.trust_domain() == expected_trust_domain
    assert spiffe_id.path() == expected_path
def _extract_spiffe_id(cert: Certificate) -> SpiffeId:
    ext = cert.extensions.get_extension_for_oid(
        x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
    sans = ext.value.get_values_for_type(x509.UniformResourceIdentifier)
    return SpiffeId.parse(sans[0])
Esempio n. 26
0
    def parse_and_validate(cls, token: str, jwt_bundle: JwtBundle,
                           audience: List[str]) -> 'JwtSvid':
        """Parses and validates a JWT-SVID token and returns an instance of JwtSvid.

        The JWT-SVID signature is verified using the JWT bundle source.

        Args:
            token: A token as a string that is parsed and validated.
            jwt_bundle: An instance of JwtBundle that provides the JWT authorities to verify the signature.
            audience: A list of strings used to validate the 'aud' claim.

        Returns:
            An instance of JwtSvid with a SPIFFE ID parsed from the 'sub', audience from 'aud', and expiry
            from 'exp' claim.

        Raises:
            JwtSvidError:   When the token expired or the expiration claim is missing,
                            when the algorithm is not supported, when the header 'kid' is missing,
                            when the signature cannot be verified, or
                            when the 'aud' claim has an audience that is not in the audience list provided as parameter.
            ArgumentError:     When the token is blank or cannot be parsed.
            BundleNotFoundError:    If the bundle for the trust domain of the spiffe id from the 'sub'
                                    cannot be found the jwt_bundle_source.
            AuthorityNotFoundError: If the authority cannot be found in the bundle using the value from the 'kid' header.
            InvalidTokenError: In case token is malformed and fails to decode.
        """
        if not token:
            raise ArgumentError(
                INVALID_INPUT_ERROR.format('token cannot be empty'))

        if not jwt_bundle:
            raise ArgumentError(
                INVALID_INPUT_ERROR.format('jwt_bundle cannot be empty'))
        try:
            header_params = jwt.get_unverified_header(token)
            validator = JwtSvidValidator()
            validator.validate_header(header_params)
            key_id = header_params.get('kid')
            signing_key = jwt_bundle.get_jwt_authority(key_id)
            if not signing_key:
                raise AuthorityNotFoundError(key_id)

            public_key_pem = signing_key.public_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PublicFormat.SubjectPublicKeyInfo,
            ).decode('UTF-8')

            claims = jwt.decode(
                token,
                algorithms=header_params.get('alg'),
                key=public_key_pem,
                audience=audience,
                options={
                    'verify_signature': True,
                    'verify_aud': True,
                    'verify_exp': True,
                },
            )

            spiffe_id = SpiffeId.parse(claims.get('sub', None))

            return JwtSvid(spiffe_id, claims['aud'], claims['exp'], claims,
                           token)
        except PyJWTError as err:
            raise InvalidTokenError(str(err))
        except ArgumentError as value_err:
            raise InvalidTokenError(str(value_err))
Esempio n. 27
0
def test_maximum_length():
    path = 'a' * 2027
    spiffe_id = SpiffeId.parse('spiffe://example.org/{}'.format(path))

    assert spiffe_id.trust_domain() == TrustDomain('example.org')
    assert spiffe_id.path() == '/' + path