def test_userinfo_in_id_token(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='github')
        _session = rph_1.get_session_information(res['state'])
        client = rph_1.issuer2rp[_session['iss']]
        #_context = client.client_get("service_context")
        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = client.get_client_id()
        idval = {
            'nonce': _nonce,
            'sub': 'EndUserSubject',
            'iss': _iss,
            'aud': _aud,
            'given_name': 'Diana',
            'family_name': 'Krall',
            'occupation': 'Jazz pianist'
        }

        idts = IdToken(**idval)

        userinfo = rph_1.userinfo_in_id_token(idts)
        assert set(userinfo.keys()) == {
            'sub', 'family_name', 'given_name', 'occupation'
        }
    def test_begin(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='github')
        assert set(res.keys()) == {'url', 'state'}
        _github_id = iss_id('github')

        client = rph_1.issuer2rp[_github_id]

        assert client.client_get("service_context").get('issuer') == _github_id

        part = urlsplit(res['url'])
        assert part.scheme == 'https'
        assert part.netloc == 'github.com'
        assert part.path == '/login/oauth/authorize'
        query = parse_qs(part.query)

        assert set(query.keys()) == {
            'nonce', 'state', 'client_id', 'redirect_uri', 'response_type',
            'scope'
        }

        # nonce and state are created on the fly so can't check for those
        assert query['client_id'] == ['eeeeeeeee']
        assert query['redirect_uri'] == [
            'https://example.com/rp/authz_cb/github'
        ]
        assert query['response_type'] == ['code']
        assert query['scope'] == ['user public_repo openid']
    def test_do_client_setup(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        client = rph_1.client_setup('github')
        _github_id = iss_id('github')
        _context = client.client_get("service_context")

        assert _context.get('client_id') == 'eeeeeeeee'
        assert _context.get('client_secret') == 'aaaaaaaaaaaaaaaaaaaa'
        assert _context.get('issuer') == _github_id

        _context.keyjar.import_jwks(
            GITHUB_KEY.export_jwks(issuer_id=_github_id), _github_id)

        assert list(_context.keyjar.owners()) == ['', _github_id]
        keys = _context.keyjar.get_issuer_keys('')
        assert len(keys) == 2

        for service_type in ['authorization', 'accesstoken', 'userinfo']:
            _srv = client.client_get("service", service_type)
            _endp = client.client_get("service_context").get('provider_info')[
                _srv.endpoint_name]
            assert _srv.endpoint == _endp

        assert rph_1.hash2issuer['github'] == _context.get('issuer')
    def test_get_session_information(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='github')
        _session = rph_1.get_session_information(res['state'])
        assert rph_1.client_configs['github']['issuer'] == _session['iss']
    def test_do_provider_info(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        client_1 = rph_1.init_client('github')
        issuer = rph_1.do_provider_info(client_1)
        assert issuer == iss_id('github')

        # Make sure the service endpoints are set

        rph_2 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        client_2 = rph_2.init_client('github')

        _context_dump = client_1.client_get("service_context").dump()
        client_2.client_get("service_context").load(_context_dump)
        _service_dump = client_1.client_get("services").dump()
        client_2.client_get("services").load(
            _service_dump, init_args={"client_get": client_2.client_get})

        for service_type in ['authorization', 'accesstoken', 'userinfo']:
            _srv = client_2.client_get("service", service_type)
            _endp = client_2.client_get("service_context").provider_info[
                _srv.endpoint_name]
            assert _srv.endpoint == _endp
    def test_get_client_from_session_key(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='linkedin')
        cli1 = rph_1.get_client_from_session_key(state=res['state'])
        _session = rph_1.get_session_information(res['state'])
        cli2 = rph_1.issuer2rp[_session['iss']]
        assert cli1 == cli2
        # redo
        rph_1.do_provider_info(state=res['state'])
        # get new redirect_uris
        cli2.client_get("service_context").redirect_uris = []
        rph_1.do_client_registration(state=res['state'])
    def test_finalize_auth(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='linkedin')
        _session = rph_1.get_session_information(res['state'])
        client = rph_1.issuer2rp[_session['iss']]

        auth_response = AuthorizationResponse(code='access_code',
                                              state=res['state'])
        resp = rph_1.finalize_auth(client, _session['iss'],
                                   auth_response.to_dict())
        assert set(resp.keys()) == {'state', 'code'}
        aresp = client.client_get(
            "service",
            'authorization').client_get("service_context").state.get_item(
                AuthorizationResponse, 'auth_response', res['state'])
        assert set(aresp.keys()) == {'state', 'code'}
    def test_get_client_authn_method(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='github')
        _session = rph_1.get_session_information(res['state'])
        client = rph_1.issuer2rp[_session['iss']]
        authn_method = rph_1.get_client_authn_method(client, 'token_endpoint')
        assert authn_method == ''

        res = rph_1.begin(issuer_id='linkedin')
        _session = rph_1.get_session_information(res['state'])
        client = rph_1.issuer2rp[_session['iss']]
        authn_method = rph_1.get_client_authn_method(client, 'token_endpoint')
        assert authn_method == 'client_secret_post'
    def test_access_and_id_token_by_reference(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        res = rph_1.begin(issuer_id='github')
        _session = rph_1.get_session_information(res['state'])
        client = rph_1.issuer2rp[_session['iss']]
        _context = client.client_get("service_context")
        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = _context.client_id
        idval = {
            'nonce': _nonce,
            'sub': 'EndUserSubject',
            'iss': _iss,
            'aud': _aud
        }

        _github_id = iss_id('github')
        _context.keyjar.import_jwks(
            GITHUB_KEY.export_jwks(issuer_id=_github_id), _github_id)

        idts = IdToken(**idval)
        _signed_jwt = idts.to_jwt(key=GITHUB_KEY.get_signing_key(
            'rsa', issuer_id=_github_id),
                                  algorithm="RS256",
                                  lifetime=300)

        _info = {
            "access_token": "accessTok",
            "id_token": _signed_jwt,
            "token_type": "Bearer",
            "expires_in": 3600
        }

        at = AccessTokenResponse(**_info)
        _url = "https://github.com/token"
        with responses.RequestsMock() as rsps:
            rsps.add("POST",
                     _url,
                     body=at.to_json(),
                     adding_headers={"Content-Type": "application/json"},
                     status=200)
            client.client_get("service", 'accesstoken').endpoint = _url

            _response = AuthorizationResponse(code='access_code',
                                              state=res['state'])
            _ = rph_1.finalize_auth(client, _session['iss'],
                                    _response.to_dict())
            resp = rph_1.get_access_and_id_token(state=res['state'])
            assert resp['access_token'] == 'accessTok'
            assert isinstance(resp['id_token'], IdToken)
    def test_do_client_registration(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])

        client = rph_1.init_client('github')
        issuer = rph_1.do_provider_info(client)
        rph_1.do_client_registration(client, 'github')

        # only 2 things should have happened

        assert rph_1.hash2issuer['github'] == issuer
        assert not client.client_get("service_context").callback.get(
            'post_logout_redirect_uris')
    def test_pick_config(self):
        rph_1 = RPHandler(BASE_URL,
                          client_configs=CLIENT_CONFIG,
                          keyjar=CLI_KEY,
                          module_dirs=['oidc'])
        cnf = rph_1.pick_config('facebook')
        assert cnf['issuer'] == "https://www.facebook.com/v2.11/dialog/oauth"

        cnf = rph_1.pick_config('linkedin')
        assert cnf['issuer'] == "https://www.linkedin.com/oauth/v2/"

        cnf = rph_1.pick_config('github')
        assert cnf['issuer'] == "https://github.com/login/oauth/authorize"

        cnf = rph_1.pick_config('')
        assert 'issuer' not in cnf
示例#12
0
def init_oidc_rp_handler(app):
    _rp_conf = app.rp_config

    if _rp_conf.key_conf:
        _kj = init_key_jar(**_rp_conf.key_conf)
        _path = _rp_conf.key_conf['public_path']
        # removes ./ and / from the begin of the string
        _path = re.sub('^(.)/', '', _path)
    else:
        _kj = KeyJar()
        _path = ''
    _kj.httpc_params = _rp_conf.httpc_params

    rph = RPHandler(_rp_conf.base_url,
                    _rp_conf.clients,
                    services=_rp_conf.services,
                    hash_seed=_rp_conf.hash_seed,
                    keyjar=_kj,
                    jwks_path=_path,
                    httpc_params=_rp_conf.httpc_params)

    return rph
 def rphandler_setup(self):
     self.rph = RPHandler(BASE_URL)
class TestRPHandler(object):
    @pytest.fixture(autouse=True)
    def rphandler_setup(self):
        self.rph = RPHandler(BASE_URL)

    def test_pick_config(self):
        cnf = self.rph.pick_config('')
        assert cnf

    def test_init_client(self):
        client = self.rph.init_client('')
        assert set(client.client_get("services").keys()) == {
            'registration', 'provider_info', 'webfinger', 'authorization',
            'accesstoken', 'userinfo', 'refresh_token'
        }

        _context = client.client_get("service_context")

        assert _context.config['client_preferences'] == {
            'application_type':
            'web',
            'application_name':
            'rphandler',
            'response_types': [
                'code', 'id_token', 'id_token token', 'code id_token',
                'code id_token token', 'code token'
            ],
            'scope': ['openid'],
            'token_endpoint_auth_method':
            'client_secret_basic'
        }

        assert list(_context.keyjar.owners()) == ['', BASE_URL]
        keys = _context.keyjar.get_issuer_keys('')
        assert len(keys) == 2

        assert _context.base_url == BASE_URL

    def test_begin(self):
        ISS_ID = "https://op.example.org"
        OP_KEYS = build_keyjar(DEFAULT_KEY_DEFS)
        # The 4 steps of client_setup
        client = self.rph.init_client(ISS_ID)
        with responses.RequestsMock() as rsps:
            request_uri = '{}/.well-known/openid-configuration'.format(ISS_ID)
            _jws = ProviderConfigurationResponse(
                issuer=ISS_ID,
                authorization_endpoint='{}/authorization'.format(ISS_ID),
                jwks_uri='{}/jwks.json'.format(ISS_ID),
                response_types_supported=[
                    'code', 'id_token', 'id_token token'
                ],
                subject_types_supported=['public'],
                id_token_signing_alg_values_supported=["RS256", "ES256"],
                token_endpoint='{}/token'.format(ISS_ID),
                registration_endpoint='{}/register'.format(ISS_ID)).to_json()
            rsps.add("GET", request_uri, body=_jws, status=200)

            rsps.add("GET",
                     '{}/jwks.json'.format(ISS_ID),
                     body=OP_KEYS.export_jwks_as_json(),
                     status=200)

            issuer = self.rph.do_provider_info(client)

        _context = client.client_get("service_context")

        # Calculating request so I can build a reasonable response
        _req = client.client_get("service", 'registration').construct_request()

        with responses.RequestsMock() as rsps:
            request_uri = _context.get(
                'provider_info')["registration_endpoint"]
            _jws = RegistrationResponse(
                client_id="client uno",
                client_secret="VerySecretAndLongEnough",
                **_req.to_dict()).to_json()
            rsps.add("POST", request_uri, body=_jws, status=200)
            self.rph.do_client_registration(client, ISS_ID)

        self.rph.issuer2rp[issuer] = client

        assert set(_context.get('behaviour').keys()) == {
            'token_endpoint_auth_method', 'response_types', 'scope',
            'application_type', 'application_name'
        }
        assert _context.get('client_id') == "client uno"
        assert _context.get('client_secret') == "VerySecretAndLongEnough"
        assert _context.get('issuer') == ISS_ID

        res = self.rph.init_authorization(client)
        assert set(res.keys()) == {'url', 'state'}
        p = urlparse(res["url"])
        assert p.hostname == 'op.example.org'
        assert p.path == "/authorization"
        qs = parse_qs(p.query)
        assert qs['state'] == [res['state']]
        # PKCE stuff
        assert 'code_challenge' in qs
        assert qs["code_challenge_method"] == ["S256"]

    def test_begin_2(self):
        ISS_ID = "https://op.example.org"
        OP_KEYS = build_keyjar(DEFAULT_KEY_DEFS)
        # The 4 steps of client_setup
        client = self.rph.init_client(ISS_ID)
        with responses.RequestsMock() as rsps:
            request_uri = '{}/.well-known/openid-configuration'.format(ISS_ID)
            _jws = ProviderConfigurationResponse(
                issuer=ISS_ID,
                authorization_endpoint='{}/authorization'.format(ISS_ID),
                jwks_uri='{}/jwks.json'.format(ISS_ID),
                response_types_supported=[
                    'code', 'id_token', 'id_token token'
                ],
                subject_types_supported=['public'],
                id_token_signing_alg_values_supported=["RS256", "ES256"],
                token_endpoint='{}/token'.format(ISS_ID),
                registration_endpoint='{}/register'.format(ISS_ID)).to_json()
            rsps.add("GET", request_uri, body=_jws, status=200)

            rsps.add("GET",
                     '{}/jwks.json'.format(ISS_ID),
                     body=OP_KEYS.export_jwks_as_json(),
                     status=200)

            issuer = self.rph.do_provider_info(client)

        _context = client.client_get("service_context")
        # Calculating request so I can build a reasonable response
        # Publishing a JWKS instead of a JWKS_URI
        _context.jwks_uri = ''
        _context.jwks = _context.keyjar.export_jwks()

        _req = client.client_get("service", 'registration').construct_request()

        with responses.RequestsMock() as rsps:
            request_uri = _context.get(
                'provider_info')["registration_endpoint"]
            _jws = RegistrationResponse(
                client_id="client uno",
                client_secret="VerySecretAndLongEnough",
                **_req.to_dict()).to_json()
            rsps.add("POST", request_uri, body=_jws, status=200)
            self.rph.do_client_registration(client, ISS_ID)

        assert 'jwks' in _context.get('registration_response')