Exemple #1
0
    def test_registration_request_object_sign_enc_algs(self):
        self.service_context.behaviour = {
            "application_type":
            "web",
            "redirect_uris": [
                "https://client.example.org/callback",
                "https://client.example.org/callback2"
            ],
            "token_endpoint_auth_method":
            "client_secret_basic",
            "jwks_uri":
            "https://client.example.org/my_public_keys.jwks",
            "userinfo_encrypted_response_alg":
            "RSA1_5",
            "userinfo_encrypted_response_enc":
            "A128CBC-HS256",
            "request_object_signing_alg":
            "RS384"
        }

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))
        res = srvcntx.get_enc_alg_enc('userinfo')
        # 'sign':'RS256' is an added default
        assert res == {'alg': 'RSA1_5', 'enc': 'A128CBC-HS256'}
        assert srvcntx.get_sign_alg('request_object') == 'RS384'
Exemple #2
0
    def test_registration_userinfo_sign_enc_algs(self):
        self.service_context.set(
            'behaviour', {
                "application_type":
                "web",
                "redirect_uris": [
                    "https://client.example.org/callback",
                    "https://client.example.org/callback2"
                ],
                "token_endpoint_auth_method":
                "client_secret_basic",
                "jwks_uri":
                "https://client.example.org/my_public_keys.jwks",
                "userinfo_encrypted_response_alg":
                "RSA1_5",
                "userinfo_encrypted_response_enc":
                "A128CBC-HS256"
            })

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))
        assert srvcntx.get_sign_alg('userinfo') is None
        assert srvcntx.get_enc_alg_enc('userinfo') == {
            'alg': 'RSA1_5',
            'enc': 'A128CBC-HS256'
        }
Exemple #3
0
def test_set_and_get_client_secret():
    service_context = ServiceContext()
    service_context.client_secret = 'longenoughsupersecret'

    srvcnx2 = ServiceContext().load(service_context.dump())

    assert srvcnx2.client_secret == 'longenoughsupersecret'
Exemple #4
0
 def create_client_info_instance(self):
     config = {
         'client_id': 'client_id',
         'issuer': 'issuer',
         'client_secret': 'longenoughsupersecret',
         'base_url': 'https://example.com',
         'requests_dir': 'requests'
     }
     self.service_context = ServiceContext(config=config)
Exemple #5
0
def dpop_header(service_context: ServiceContext,
                service_endpoint: str,
                http_method: str,
                headers: Optional[dict] = None,
                **kwargs) -> dict:
    """

    :param service_context:
    :param service_endpoint:
    :param http_method:
    :param headers:
    :param kwargs:
    :return:
    """

    provider_info = service_context.provider_info
    dpop_key = service_context.add_on['dpop'].get('key')

    if not dpop_key:
        algs_supported = provider_info["dpop_signing_alg_values_supported"]
        if not algs_supported:  # does not support DPoP
            return headers

        chosen_alg = ''
        for alg in service_context.add_on['dpop']["sign_algs"]:
            if alg in algs_supported:
                chosen_alg = alg
                break

        if not chosen_alg:
            return headers

        # Mint a new key
        dpop_key = key_by_alg(chosen_alg)
        service_context.add_on['dpop']['key'] = dpop_key
        service_context.add_on['dpop']['alg'] = chosen_alg

    header_dict = {
        "typ": "dpop+jwt",
        "alg": service_context.add_on['dpop']['alg'],
        "jwk": dpop_key.serialize(),
        "jti": uuid.uuid4().hex,
        "htm": http_method,
        "htu": provider_info[service_endpoint],
        "iat": utc_time_sans_frac()
    }

    _dpop = DPoPProof(**header_dict)
    _dpop.key = dpop_key
    jws = _dpop.create_header()

    if headers is None:
        headers = {"dpop": jws}
    else:
        headers["dpop"] = jws

    return headers
Exemple #6
0
def test_client_filename():
    config = {
        'client_id': 'client_id',
        'issuer': 'issuer',
        'client_secret': 'longenoughsupersecret',
        'base_url': 'https://example.com',
        'requests_dir': 'requests'
    }
    ci = ServiceContext(config=config)
    fname = ci.filename_from_webname('https://example.com/rq12345')
    assert fname == 'rq12345'
Exemple #7
0
    def test_import_keys_url(self):
        assert len(self.service_context.keyjar.get_issuer_keys('')) == 1

        # One EC key for signing
        key_def = [{"type": "EC", "crv": "P-256", "use": ["sig"]}]

        keyjar = build_keyjar(key_def)

        with responses.RequestsMock() as rsps:
            _jwks_url = 'https://foobar.com/jwks.json'
            rsps.add("GET",
                     _jwks_url,
                     body=keyjar.export_jwks_as_json(),
                     status=200,
                     adding_headers={"Content-Type": "application/json"})
            keyspec = {'url': {'https://foobar.com': _jwks_url}}
            self.service_context.import_keys(keyspec)
            self.service_context.keyjar.update()

            srvcntx = ServiceContext().load(
                self.service_context.dump(
                    exclude_attributes=["service_context"]))

            # Now there should be one belonging to https://example.com
            assert len(
                srvcntx.keyjar.get_issuer_keys('https://foobar.com')) == 1
    def __init__(self,
                 client_authn_factory: Optional[Callable] = None,
                 keyjar: Optional[KeyJar] = None,
                 config: Optional[Union[dict, Configuration]] = None,
                 services: Optional[dict] = None,
                 jwks_uri: Optional[str] = '',
                 httpc_params: Optional[dict] = None):

        if httpc_params:
            self.httpc_params = httpc_params
        else:
            self.httpc_params = {"verify": True}

        self._service_context = ServiceContext(keyjar=keyjar,
                                               config=config,
                                               jwks_uri=jwks_uri,
                                               httpc_params=self.httpc_params)

        _cam = client_authn_factory or factory

        _srvs = services or DEFAULT_SERVICES

        self._service = init_services(service_definitions=_srvs,
                                      client_get=self.client_get,
                                      client_authn_factory=_cam)
Exemple #9
0
    def test_verify_requests_uri(self):
        self.service_context.provider_info = {'issuer': 'https://example.com/'}
        url_list = self.service_context.generate_request_uris('/leading')
        sp = urlsplit(url_list[0])
        p = sp.path.split('/')
        assert p[0] == ''
        assert p[1] == 'leading'
        assert len(p) == 3

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        # different for different OPs
        srvcntx.provider_info = {'issuer': 'https://op.example.org/'}
        url_list = srvcntx.generate_request_uris('/leading')
        sp = urlsplit(url_list[0])
        np = sp.path.split('/')
        assert np[0] == ''
        assert np[1] == 'leading'
        assert len(np) == 3

        assert np[2] != p[2]
def test_request_object_encryption():
    msg = AuthorizationRequest(state='ABCDE',
                               redirect_uri='https://example.com/cb',
                               response_type='code')

    conf = {
        'redirect_uris': ['https://example.com/cli/authz_cb'],
        'client_id': 'client_1',
        'client_secret': 'abcdefghijklmnop',
    }
    service_context = ServiceContext(keyjar=KEYJAR, config=conf)
    _behav = service_context.behaviour
    _behav["request_object_encryption_alg"] = 'RSA1_5'
    _behav["request_object_encryption_enc"] = "A128CBC-HS256"
    service_context.behaviour = _behav

    _jwe = request_object_encryption(msg.to_json(),
                                     service_context,
                                     target=RECEIVER)
    assert _jwe

    _decryptor = factory(_jwe)

    assert _decryptor.jwt.verify_headers(alg='RSA1_5', enc='A128CBC-HS256')
Exemple #11
0
    def test_import_keys_file(self):
        # Should only be one and that a symmetric key (client_secret) usable
        # for signing and encryption
        assert len(self.service_context.keyjar.get_issuer_keys('')) == 1

        file_path = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'salesforce.key'))

        keyspec = {'file': {'rsa': [file_path]}}
        self.service_context.import_keys(keyspec)

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        # Now there should be 2, the second a RSA key for signing
        assert len(srvcntx.keyjar.get_issuer_keys('')) == 2
Exemple #12
0
def test_client_filename():
    config = {
        'client_id': 'client_id',
        'issuer': 'issuer',
        'client_secret': 'longenoughsupersecret',
        'base_url': 'https://example.com',
        'requests_dir': 'requests'
    }
    service_context = ServiceContext(config=config)
    srvcnx2 = ServiceContext().load(service_context.dump())
    fname = srvcnx2.filename_from_webname('https://example.com/rq12345')
    assert fname == 'rq12345'
Exemple #13
0
def test_client_info_init():
    config = {
        'client_id': 'client_id',
        'issuer': 'issuer',
        'client_secret': 'client_secret_wordplay',
        'base_url': 'https://example.com',
        'requests_dir': 'requests'
    }
    ci = ServiceContext(config=config)

    srvcnx = ServiceContext().load(ci.dump())

    for attr in config.keys():
        try:
            val = getattr(srvcnx, attr)
        except AttributeError:
            val = srvcnx.get(attr)

        assert val == config[attr]
Exemple #14
0
import json
from urllib.parse import parse_qs, unquote_plus, urlsplit

from oidcrp.entity import Entity
import pytest
from oidcmsg.exception import MissingRequiredAttribute
from oidcmsg.oidc import JRD, Link

from oidcrp.oidc import OIC_ISSUER
from oidcrp.oidc.webfinger import WebFinger
from oidcrp.service_context import ServiceContext

__author__ = 'Roland Hedberg'

SERVICE_CONTEXT = ServiceContext()

ENTITY = Entity(config={})


def test_query():
    rel = 'http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer'
    pattern = 'https://{}/.well-known/webfinger?rel={}&resource={}'
    example_oidc = {
        'example.com': ('example.com', rel, 'acct%3Aexample.com'),
        '*****@*****.**': ('example.com', rel, 'acct%3Ajoe%40example.com'),
        'example.com/joe':
        ('example.com', rel, 'https%3A%2F%2Fexample.com%2Fjoe'),
        'example.com:8080':
        ('example.com:8080', rel, 'https%3A%2F%2Fexample.com%3A8080'),
        '*****@*****.**':
        ('example.com', rel, 'acct%3AJane.Doe%40example.com'),
Exemple #15
0
def test_set_and_get_client_secret():
    service_context = ServiceContext()
    service_context.client_secret = 'longenoughsupersecret'
    assert service_context.client_secret == 'longenoughsupersecret'
Exemple #16
0
def test_set_and_get_client_id():
    ci = ServiceContext()
    ci.client_id = 'myself'
    assert ci.client_id == 'myself'
Exemple #17
0
class TestClientInfo(object):
    @pytest.fixture(autouse=True)
    def create_client_info_instance(self):
        config = {
            'client_id': 'client_id',
            'issuer': 'issuer',
            'client_secret': 'longenoughsupersecret',
            'base_url': 'https://example.com',
            'requests_dir': 'requests'
        }
        self.service_context = ServiceContext(config=config)

    def test_registration_userinfo_sign_enc_algs(self):
        self.service_context.set(
            'behaviour', {
                "application_type":
                "web",
                "redirect_uris": [
                    "https://client.example.org/callback",
                    "https://client.example.org/callback2"
                ],
                "token_endpoint_auth_method":
                "client_secret_basic",
                "jwks_uri":
                "https://client.example.org/my_public_keys.jwks",
                "userinfo_encrypted_response_alg":
                "RSA1_5",
                "userinfo_encrypted_response_enc":
                "A128CBC-HS256"
            })

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))
        assert srvcntx.get_sign_alg('userinfo') is None
        assert srvcntx.get_enc_alg_enc('userinfo') == {
            'alg': 'RSA1_5',
            'enc': 'A128CBC-HS256'
        }

    def test_registration_request_object_sign_enc_algs(self):
        self.service_context.behaviour = {
            "application_type":
            "web",
            "redirect_uris": [
                "https://client.example.org/callback",
                "https://client.example.org/callback2"
            ],
            "token_endpoint_auth_method":
            "client_secret_basic",
            "jwks_uri":
            "https://client.example.org/my_public_keys.jwks",
            "userinfo_encrypted_response_alg":
            "RSA1_5",
            "userinfo_encrypted_response_enc":
            "A128CBC-HS256",
            "request_object_signing_alg":
            "RS384"
        }

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))
        res = srvcntx.get_enc_alg_enc('userinfo')
        # 'sign':'RS256' is an added default
        assert res == {'alg': 'RSA1_5', 'enc': 'A128CBC-HS256'}
        assert srvcntx.get_sign_alg('request_object') == 'RS384'

    def test_registration_id_token_sign_enc_algs(self):
        self.service_context.behaviour = {
            "application_type":
            "web",
            "redirect_uris": [
                "https://client.example.org/callback",
                "https://client.example.org/callback2"
            ],
            "token_endpoint_auth_method":
            "client_secret_basic",
            "jwks_uri":
            "https://client.example.org/my_public_keys.jwks",
            "userinfo_encrypted_response_alg":
            "RSA1_5",
            "userinfo_encrypted_response_enc":
            "A128CBC-HS256",
            "request_object_signing_alg":
            "RS384",
            'id_token_encrypted_response_alg':
            'ECDH-ES',
            'id_token_encrypted_response_enc':
            "A128GCM",
            'id_token_signed_response_alg':
            "ES384",
        }

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        # 'sign':'RS256' is an added default
        assert srvcntx.get_enc_alg_enc('userinfo') == {
            'alg': 'RSA1_5',
            'enc': 'A128CBC-HS256'
        }
        assert srvcntx.get_sign_alg('request_object') == 'RS384'
        assert srvcntx.get_enc_alg_enc('id_token') == {
            'alg': 'ECDH-ES',
            'enc': 'A128GCM'
        }

    def test_verify_alg_support(self):
        self.service_context.provider_info = {
            "version":
            "3.0",
            "issuer":
            "https://server.example.com",
            "authorization_endpoint":
            "https://server.example.com/connect/authorize",
            "token_endpoint":
            "https://server.example.com/connect/token",
            "token_endpoint_auth_methods_supported":
            ["client_secret_basic", "private_key_jwt"],
            "token_endpoint_auth_signing_alg_values_supported":
            ["RS256", "ES256"],
            "userinfo_endpoint":
            "https://server.example.com/connect/userinfo",
            "check_session_iframe":
            "https://server.example.com/connect/check_session",
            "end_session_endpoint":
            "https://server.example.com/connect/end_session",
            "jwks_uri":
            "https://server.example.com/jwks.json",
            "registration_endpoint":
            "https://server.example.com/connect/register",
            "scopes_supported": [
                "openid", "profile", "email", "address", "phone",
                "offline_access"
            ],
            "response_types_supported":
            ["code", "code id_token", "id_token", "token id_token"],
            "acr_values_supported":
            ["urn:mace:incommon:iap:silver", "urn:mace:incommon:iap:bronze"],
            "subject_types_supported": ["public", "pairwise"],
            "userinfo_signing_alg_values_supported":
            ["RS256", "ES256", "HS256"],
            "userinfo_encryption_alg_values_supported": ["RSA1_5", "A128KW"],
            "userinfo_encryption_enc_values_supported":
            ["A128CBC+HS256", "A128GCM"],
            "id_token_signing_alg_values_supported":
            ["RS256", "ES256", "HS256"],
            "id_token_encryption_alg_values_supported": ["RSA1_5", "A128KW"],
            "id_token_encryption_enc_values_supported":
            ["A128CBC+HS256", "A128GCM"],
            "request_object_signing_alg_values_supported":
            ["none", "RS256", "ES256"],
            "display_values_supported": ["page", "popup"],
            "claim_types_supported": ["normal", "distributed"],
            "claims_supported": [
                "sub", "iss", "auth_time", "acr", "name", "given_name",
                "family_name", "nickname", "profile", "picture", "website",
                "email", "email_verified", "locale", "zoneinfo",
                "http://example.info/claims/groups"
            ],
            "claims_parameter_supported":
            True,
            "service_documentation":
            "http://server.example.com/connect/service_documentation.html",
            "ui_locales_supported":
            ["en-US", "en-GB", "en-CA", "fr-FR", "fr-CA"]
        }

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        assert verify_alg_support(srvcntx, 'RS256', 'id_token', 'signing_alg')
        assert verify_alg_support(srvcntx, 'RS512', 'id_token',
                                  'signing_alg') is False
        assert verify_alg_support(srvcntx, 'RSA1_5', 'userinfo',
                                  'encryption_alg')

        # token_endpoint_auth_signing_alg_values_supported
        assert verify_alg_support(srvcntx, 'ES256', 'token_endpoint_auth',
                                  'signing_alg')

    def test_verify_requests_uri(self):
        self.service_context.provider_info = {'issuer': 'https://example.com/'}
        url_list = self.service_context.generate_request_uris('/leading')
        sp = urlsplit(url_list[0])
        p = sp.path.split('/')
        assert p[0] == ''
        assert p[1] == 'leading'
        assert len(p) == 3

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        # different for different OPs
        srvcntx.provider_info = {'issuer': 'https://op.example.org/'}
        url_list = srvcntx.generate_request_uris('/leading')
        sp = urlsplit(url_list[0])
        np = sp.path.split('/')
        assert np[0] == ''
        assert np[1] == 'leading'
        assert len(np) == 3

        assert np[2] != p[2]

    def test_import_keys_file(self):
        # Should only be one and that a symmetric key (client_secret) usable
        # for signing and encryption
        assert len(self.service_context.keyjar.get_issuer_keys('')) == 1

        file_path = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'salesforce.key'))

        keyspec = {'file': {'rsa': [file_path]}}
        self.service_context.import_keys(keyspec)

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        # Now there should be 2, the second a RSA key for signing
        assert len(srvcntx.keyjar.get_issuer_keys('')) == 2

    def test_import_keys_file_json(self):
        # Should only be one and that a symmetric key (client_secret) usable
        # for signing and encryption
        assert len(self.service_context.keyjar.get_issuer_keys('')) == 1

        file_path = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'salesforce.key'))

        keyspec = {'file': {'rsa': [file_path]}}
        self.service_context.import_keys(keyspec)

        _sc_state = self.service_context.dump(
            exclude_attributes=["service_context"])
        _jsc_state = json.dumps(_sc_state)
        _o_state = json.loads(_jsc_state)
        srvcntx = ServiceContext().load(_o_state)

        # Now there should be 2, the second a RSA key for signing
        assert len(srvcntx.keyjar.get_issuer_keys('')) == 2

    def test_import_keys_url(self):
        assert len(self.service_context.keyjar.get_issuer_keys('')) == 1

        # One EC key for signing
        key_def = [{"type": "EC", "crv": "P-256", "use": ["sig"]}]

        keyjar = build_keyjar(key_def)

        with responses.RequestsMock() as rsps:
            _jwks_url = 'https://foobar.com/jwks.json'
            rsps.add("GET",
                     _jwks_url,
                     body=keyjar.export_jwks_as_json(),
                     status=200,
                     adding_headers={"Content-Type": "application/json"})
            keyspec = {'url': {'https://foobar.com': _jwks_url}}
            self.service_context.import_keys(keyspec)
            self.service_context.keyjar.update()

            srvcntx = ServiceContext().load(
                self.service_context.dump(
                    exclude_attributes=["service_context"]))

            # Now there should be one belonging to https://example.com
            assert len(
                srvcntx.keyjar.get_issuer_keys('https://foobar.com')) == 1
Exemple #18
0
def test_set_and_get_client_id():
    service_context = ServiceContext()
    service_context.client_id = 'myself'
    srvcnx2 = ServiceContext().load(service_context.dump())
    assert srvcnx2.client_id == 'myself'
Exemple #19
0
    def test_verify_alg_support(self):
        self.service_context.provider_info = {
            "version":
            "3.0",
            "issuer":
            "https://server.example.com",
            "authorization_endpoint":
            "https://server.example.com/connect/authorize",
            "token_endpoint":
            "https://server.example.com/connect/token",
            "token_endpoint_auth_methods_supported":
            ["client_secret_basic", "private_key_jwt"],
            "token_endpoint_auth_signing_alg_values_supported":
            ["RS256", "ES256"],
            "userinfo_endpoint":
            "https://server.example.com/connect/userinfo",
            "check_session_iframe":
            "https://server.example.com/connect/check_session",
            "end_session_endpoint":
            "https://server.example.com/connect/end_session",
            "jwks_uri":
            "https://server.example.com/jwks.json",
            "registration_endpoint":
            "https://server.example.com/connect/register",
            "scopes_supported": [
                "openid", "profile", "email", "address", "phone",
                "offline_access"
            ],
            "response_types_supported":
            ["code", "code id_token", "id_token", "token id_token"],
            "acr_values_supported":
            ["urn:mace:incommon:iap:silver", "urn:mace:incommon:iap:bronze"],
            "subject_types_supported": ["public", "pairwise"],
            "userinfo_signing_alg_values_supported":
            ["RS256", "ES256", "HS256"],
            "userinfo_encryption_alg_values_supported": ["RSA1_5", "A128KW"],
            "userinfo_encryption_enc_values_supported":
            ["A128CBC+HS256", "A128GCM"],
            "id_token_signing_alg_values_supported":
            ["RS256", "ES256", "HS256"],
            "id_token_encryption_alg_values_supported": ["RSA1_5", "A128KW"],
            "id_token_encryption_enc_values_supported":
            ["A128CBC+HS256", "A128GCM"],
            "request_object_signing_alg_values_supported":
            ["none", "RS256", "ES256"],
            "display_values_supported": ["page", "popup"],
            "claim_types_supported": ["normal", "distributed"],
            "claims_supported": [
                "sub", "iss", "auth_time", "acr", "name", "given_name",
                "family_name", "nickname", "profile", "picture", "website",
                "email", "email_verified", "locale", "zoneinfo",
                "http://example.info/claims/groups"
            ],
            "claims_parameter_supported":
            True,
            "service_documentation":
            "http://server.example.com/connect/service_documentation.html",
            "ui_locales_supported":
            ["en-US", "en-GB", "en-CA", "fr-FR", "fr-CA"]
        }

        srvcntx = ServiceContext().load(
            self.service_context.dump(exclude_attributes=["service_context"]))

        assert verify_alg_support(srvcntx, 'RS256', 'id_token', 'signing_alg')
        assert verify_alg_support(srvcntx, 'RS512', 'id_token',
                                  'signing_alg') is False
        assert verify_alg_support(srvcntx, 'RSA1_5', 'userinfo',
                                  'encryption_alg')

        # token_endpoint_auth_signing_alg_values_supported
        assert verify_alg_support(srvcntx, 'ES256', 'token_endpoint_auth',
                                  'signing_alg')