def test_access_and_id_token_by_reference(self, httpserver):
        res = self.rph.begin(issuer_id='github')
        _session = self.rph.get_session_information(res['state'])
        client = self.rph.issuer2rp[_session['iss']]
        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = client.client_id
        idval = {'nonce': _nonce, 'sub': 'EndUserSubject', 'iss': _iss,
                 'aud': _aud}

        idts = IdToken(**idval)
        _signed_jwt = idts.to_jwt(
            key=client.service_context.keyjar.get_signing_key('oct'),
            algorithm="HS256", lifetime=300)

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

        at = AccessTokenResponse(**_info)
        httpserver.serve_content(at.to_json())
        client.service['accesstoken'].endpoint = httpserver.url

        _response = AuthorizationResponse(code='access_code',
                                          state=res['state'])
        auth_response = self.rph.finalize_auth(client, _session['iss'],
                                               _response.to_dict())
        resp = self.rph.get_access_and_id_token(state=res['state'])
        assert resp['access_token'] == 'accessTok'
        assert isinstance(resp['id_token'], IdToken)
Example #2
0
    def test_get_access_token(self):
        res = self.rph.begin(issuer_id='github')
        _session = self.rph.get_session_information(res['state'])
        client = self.rph.issuer2rp[_session['iss']]

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

        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = client.client_id
        idval = {
            'nonce': _nonce,
            'sub': 'EndUserSubject',
            'iss': _iss,
            'aud': _aud
        }

        idts = IdToken(**idval)
        _signed_jwt = idts.to_jwt(
            key=GITHUB_KEY.get_signing_key(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.service['accesstoken'].endpoint = _url

            auth_response = AuthorizationResponse(code='access_code',
                                                  state=res['state'])
            resp = self.rph.finalize_auth(client, _session['iss'],
                                          auth_response.to_dict())

            resp = self.rph.get_access_token(res['state'], client)
            assert set(resp.keys()) == {
                'access_token', 'expires_in', 'id_token', 'token_type',
                '__verified_id_token', '__expires_at'
            }

            atresp = client.service['accesstoken'].get_item(
                AccessTokenResponse, 'token_response', res['state'])
            assert set(atresp.keys()) == {
                'access_token', 'expires_in', 'id_token', 'token_type',
                '__verified_id_token', '__expires_at'
            }
Example #3
0
def create_authn_response(endpoint, request, sid):
    """

    :param endpoint:
    :param request:
    :param sid:
    :return:
    """
    # create the response
    aresp = AuthorizationResponse()
    if request.get("state"):
        aresp["state"] = request["state"]

    if "response_type" in request and request["response_type"] == ["none"]:
        fragment_enc = False
    else:
        _context = endpoint.endpoint_context
        _sinfo = _context.sdb[sid]

        if request.get("scope"):
            aresp["scope"] = request["scope"]

        rtype = set(request["response_type"][:])
        handled_response_type = []

        fragment_enc = True
        if len(rtype) == 1 and "code" in rtype:
            fragment_enc = False

        if "code" in request["response_type"]:
            _code = aresp["code"] = _context.sdb[sid]["code"]
            handled_response_type.append("code")
        else:
            _context.sdb.update(sid, code=None)
            _code = None

        if "token" in rtype:
            _dic = _context.sdb.upgrade_to_token(issue_refresh=False, key=sid)

            logger.debug("_dic: %s" % sanitize(_dic))
            for key, val in _dic.items():
                if key in aresp.parameters() and val is not None:
                    aresp[key] = val

            handled_response_type.append("token")

        _access_token = aresp.get("access_token", None)

        not_handled = rtype.difference(handled_response_type)
        if not_handled:
            resp = AuthorizationErrorResponse(
                error="invalid_request",
                error_description="unsupported_response_type")
            return {"response_args": resp, "fragment_enc": fragment_enc}

    return {"response_args": aresp, "fragment_enc": fragment_enc}
    def rphandler_setup(self, httpserver):
        self.rph = RPHandler(base_url=BASE_URL,
                             client_configs=CLIENT_CONFIG,
                             keyjar=CLI_KEY)
        res = self.rph.begin(issuer_id='github')
        _session = self.rph.get_session_information(res['state'])
        client = self.rph.issuer2rp[_session['iss']]
        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = client.client_id
        idval = {
            'nonce': _nonce,
            'sub': 'EndUserSubject',
            'iss': _iss,
            'aud': _aud
        }

        _github_id = iss_id('github')
        client.service_context.keyjar.import_jwks(
            GITHUB_KEY.export_jwks(issuer=_github_id), _github_id)

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

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

        at = AccessTokenResponse(**_info)
        httpserver.serve_content(at.to_json(),
                                 headers={'Content-Type': 'application/json'})
        client.service['accesstoken'].endpoint = httpserver.url

        _response = AuthorizationResponse(code='access_code',
                                          state=res['state'])
        auth_response = self.rph.finalize_auth(client, _session['iss'],
                                               _response.to_dict())

        token_resp = self.rph.get_access_and_id_token(auth_response,
                                                      client=client)

        httpserver.serve_content('{"sub":"EndUserSubject"}',
                                 headers={'Content-Type': 'application/json'})
        client.service['userinfo'].endpoint = httpserver.url

        self.rph.get_user_info(res['state'], client,
                               token_resp['access_token'])
        self.state = res['state']
    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)
Example #6
0
    def test_finalize_auth(self):
        res = self.rph.begin(issuer_id='linkedin')
        _session = self.rph.get_session_information(res['state'])
        client = self.rph.issuer2rp[_session['iss']]

        auth_response = AuthorizationResponse(code='access_code',
                                              state=res['state'])
        resp = self.rph.finalize_auth(client, _session['iss'],
                                      auth_response.to_dict())
        assert set(resp.keys()) == {'state', 'code'}
        aresp = client.service['authorization'].get_item(
            AuthorizationResponse, 'auth_response', res['state'])
        assert set(aresp.keys()) == {'state', 'code'}
Example #7
0
    def test_finalize(self):
        auth_query = self.rph.begin(issuer_id='github')
        #  The authorization query is sent and after successful authentication
        client = self.rph.get_client_from_session_key(
            state=auth_query['state'])
        # register a response
        p = urlparse(
            CLIENT_CONFIG['github']['provider_info']['authorization_endpoint'])
        self.mock_op.register_get_response(p.path, 'Redirect', 302)

        _ = client.http(auth_query['url'])

        #  the user is redirected back to the RP with a positive response
        auth_response = AuthorizationResponse(code='access_code',
                                              state=auth_query['state'])

        # need session information and the client instance
        _session = self.rph.get_session_information(auth_response['state'])
        client = self.rph.get_client_from_session_key(
            state=auth_response['state'])

        # Faking
        resp = construct_access_token_response(
            _session['auth_request']['nonce'],
            issuer=self.issuer,
            client_id=CLIENT_CONFIG['github']['client_id'],
            key_jar=GITHUB_KEY)

        p = urlparse(
            CLIENT_CONFIG['github']['provider_info']['token_endpoint'])
        self.mock_op.register_post_response(
            p.path, resp.to_json(), 200, {'content-type': "application/json"})

        _info = OpenIDSchema(sub='EndUserSubject',
                             given_name='Diana',
                             family_name='Krall',
                             occupation='Jazz pianist')
        p = urlparse(
            CLIENT_CONFIG['github']['provider_info']['userinfo_endpoint'])
        self.mock_op.register_get_response(
            p.path, _info.to_json(), 200, {'content-type': "application/json"})

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

        # do the rest (= get access token and user info)
        # assume code flow
        resp = self.rph.finalize(_session['iss'], auth_response.to_dict())

        assert set(resp.keys()) == {'userinfo', 'state', 'token', 'id_token'}
    def test_get_access_token(self, httpserver):
        res = self.rph.begin(issuer_id='github')
        _session = self.rph.get_session_information(res['state'])
        client = self.rph.issuer2rp[_session['iss']]
        _nonce = _session['auth_request']['nonce']
        _iss = _session['iss']
        _aud = client.client_id
        idval = {
            'nonce': _nonce,
            'sub': 'EndUserSubject',
            'iss': _iss,
            'aud': _aud
        }

        idts = IdToken(**idval)
        _signed_jwt = idts.to_jwt(
            key=client.service_context.keyjar.get_signing_key('oct'),
            algorithm="HS256",
            lifetime=300)

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

        at = AccessTokenResponse(**_info)
        httpserver.serve_content(at.to_json(),
                                 headers={'Content-Type': 'application/json'})
        client.service['accesstoken'].endpoint = httpserver.url

        auth_response = AuthorizationResponse(code='access_code',
                                              state=res['state'])
        resp = self.rph.finalize_auth(client, _session['iss'],
                                      auth_response.to_dict())

        resp = self.rph.get_access_token(res['state'], client)
        assert set(resp.keys()) == {
            'access_token', 'expires_in', 'id_token', 'token_type',
            '__verified_id_token', '__expires_at'
        }

        atresp = client.service['accesstoken'].get_item(
            AccessTokenResponse, 'token_response', res['state'])
        assert set(atresp.keys()) == {
            'access_token', 'expires_in', 'id_token', 'token_type',
            '__verified_id_token', '__expires_at'
        }
    def test_response_mode(self, response_mode):
        request = AuthorizationRequest(
            client_id="client_1",
            response_type=["code"],
            redirect_uri="https://example.com/cb",
            state="state",
            scope="openid",
            response_mode=response_mode,
        )

        response_args = AuthorizationResponse(scope="openid", code="abcdefghijklmnop")

        if response_mode == "fragment":
            info = self.endpoint.response_mode(
                request, response_args, request["redirect_uri"], fragment_enc=True
            )
        else:
            info = self.endpoint.response_mode(request, response_args, request["redirect_uri"])

        if response_mode == "form_post":
            assert set(info.keys()) == {
                "response_msg",
                "content_type",
                "response_placement",
            }
        elif response_mode == "fragment":
            assert set(info.keys()) == {"response_args", "return_uri", "fragment_enc"}
        elif response_mode == "query":
            assert set(info.keys()) == {"response_args", "return_uri"}
Example #10
0
 def test_response_mode_form_post(self):
     request = {"response_mode": "form_post"}
     info = {
         "response_args": AuthorizationResponse(foo="bar"),
         "return_uri": "https://example.com/cb",
     }
     info = self.endpoint.response_mode(request, **info)
     assert set(info.keys()) == {"response_args", "return_uri", "response_msg"}
     assert info["response_msg"] == FORM_POST
    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'}
Example #12
0
 def test_response_mode_form_post(self):
     request = {"response_mode": "form_post"}
     info = {
         "response_args": AuthorizationResponse(foo="bar"),
         "return_uri": "https://example.com/cb",
     }
     info = self.endpoint.response_mode(request, **info)
     assert set(info.keys()) == {
         "response_args", "return_uri", "response_msg", "content_type",
         "response_placement"
     }
     assert info["response_msg"] == FORM_POST.format(
         action="https://example.com/cb",
         inputs='<input type="hidden" name="foo" value="bar"/>',
     )
    def test_finalize(self):
        auth_query = self.rph.begin(issuer_id='github')
        #  The authorization query is sent and after successful authentication
        client = self.rph.get_client_from_session_key(
            state=auth_query['state'])
        _ = client.http(auth_query['url'])

        #  the user is redirected back to the RP with a positive response
        auth_response = AuthorizationResponse(code='access_code',
                                              state=auth_query['state'])

        # need session information and the client instance
        _session = self.rph.get_session_information(auth_response['state'])
        client = self.rph.get_client_from_session_key(
            state=auth_response['state'])

        # Faking
        self.rph.httplib.keyjar = client.service_context.keyjar

        # do the rest (= get access token and user info)
        # assume code flow
        resp = self.rph.finalize(_session['iss'], auth_response.to_dict())

        assert set(resp.keys()) == {'userinfo', 'state', 'token'}
Example #14
0
def create_authn_response(endpoint, request, sid):
    """

    :param endpoint:
    :param request:
    :param sid:
    :return:
    """
    # create the response
    aresp = AuthorizationResponse()
    if request.get("state"):
        aresp["state"] = request["state"]

    if "response_type" in request and request["response_type"] == ["none"]:
        fragment_enc = False
    else:
        _context = endpoint.endpoint_context
        _sinfo = _context.sdb[sid]

        if request.get("scope"):
            aresp["scope"] = request["scope"]

        rtype = set(request["response_type"][:])
        handled_response_type = []

        fragment_enc = True
        if len(rtype) == 1 and "code" in rtype:
            fragment_enc = False

        if "code" in request["response_type"]:
            _code = aresp["code"] = _context.sdb[sid]["code"]
            handled_response_type.append("code")
        else:
            _context.sdb.update(sid, code=None)
            _code = None

        if "token" in rtype:
            _dic = _context.sdb.upgrade_to_token(issue_refresh=False, key=sid)

            logger.debug("_dic: %s" % sanitize(_dic))
            for key, val in _dic.items():
                if key in aresp.parameters() and val is not None:
                    aresp[key] = val

            handled_response_type.append("token")

        _access_token = aresp.get("access_token", None)

        if "id_token" in request["response_type"]:
            kwargs = {}
            if {"code", "id_token", "token"}.issubset(rtype):
                kwargs = {"code": _code, "access_token": _access_token}
            elif {"code", "id_token"}.issubset(rtype):
                kwargs = {"code": _code}
            elif {"id_token", "token"}.issubset(rtype):
                kwargs = {"access_token": _access_token}

            if request["response_type"] == ["id_token"]:
                kwargs["user_claims"] = True

            try:
                id_token = _context.idtoken.make(request, _sinfo, **kwargs)
            except (JWEException, NoSuitableSigningKeys) as err:
                logger.warning(str(err))
                resp = AuthorizationErrorResponse(
                    error="invalid_request",
                    error_description="Could not sign/encrypt id_token",
                )
                return {"response_args": resp, "fragment_enc": fragment_enc}

            aresp["id_token"] = id_token
            _sinfo["id_token"] = id_token
            handled_response_type.append("id_token")

        not_handled = rtype.difference(handled_response_type)
        if not_handled:
            resp = AuthorizationErrorResponse(
                error="invalid_request",
                error_description="unsupported_response_type")
            return {"response_args": resp, "fragment_enc": fragment_enc}

    return {"response_args": aresp, "fragment_enc": fragment_enc}
    'nonce': NONCE
})

print()
print('--- Authorization, request ----')
print('uri: {}'.format(info['url']))

op_authz_resp = {
    'state': 'Oh3w3gKlvoM2ehFqlxI3HIK5',
    'scope': 'openid',
    'code': 'Z0FBQUFBQmFkdFFjUVpFWE81SHU5N1N4N01',
    'iss': OP_BASEURL,
    'client_id': 'zls2qhN1jO6A'
}

_authz_rep = AuthorizationResponse(**op_authz_resp)
print(_authz_rep.to_urlencoded())
_resp = service['authorization'].parse_response(_authz_rep.to_urlencoded())
service['authorization'].update_service_context(_resp, key=STATE)
print()
print('--- Authorization registration, response ----')
print(_resp)

_json = service['authorization'].state_db.get(STATE)
_state = State().from_json(_json)

print('code: {}'.format(_state['auth_response']['code']))

# =================== Access token ====================

request_args = {
Example #16
0
def create_authn_response(endpoint_context, request, sid):
    # create the response
    aresp = AuthorizationResponse()
    try:
        aresp["state"] = request["state"]
    except KeyError:
        pass

    if "response_type" in request and request["response_type"] == ["none"]:
        fragment_enc = False
    else:
        _sinfo = endpoint_context.sdb[sid]

        try:
            aresp["scope"] = request["scope"]
        except KeyError:
            pass

        rtype = set(request["response_type"][:])
        handled_response_type = []
        if len(rtype) == 1 and "code" in rtype:
            fragment_enc = False
        else:
            fragment_enc = True

        if "code" in request["response_type"]:
            _code = aresp["code"] = endpoint_context.sdb[sid]["code"]
            handled_response_type.append("code")
        else:
            endpoint_context.sdb.update(sid, code=None)
            _code = None

        if "token" in rtype:
            _dic = endpoint_context.sdb.upgrade_to_token(issue_refresh=False,
                                                         key=sid)

            logger.debug("_dic: %s" % sanitize(_dic))
            for key, val in _dic.items():
                if key in aresp.parameters() and val is not None:
                    aresp[key] = val

            handled_response_type.append("token")

        try:
            _access_token = aresp["access_token"]
        except KeyError:
            _access_token = None

        if "id_token" in request["response_type"]:
            user_info = userinfo_in_id_token_claims(endpoint_context, _sinfo)
            if request["response_type"] == ["id_token"]:
                #  scopes should be returned here
                info = collect_user_info(endpoint_context, _sinfo)
                if user_info is None:
                    user_info = info
                else:
                    user_info.update(info)

            # client_info = endpoint_context.cdb[str(request["client_id"])]

            hargs = {}
            if {'code', 'id_token', 'token'}.issubset(rtype):
                hargs = {"code": _code, "access_token": _access_token}
            elif {'code', 'id_token'}.issubset(rtype):
                hargs = {"code": _code}
            elif {'id_token', 'token'}.issubset(rtype):
                hargs = {"access_token": _access_token}

            # or 'code id_token'
            try:
                id_token = sign_encrypt_id_token(endpoint_context, _sinfo,
                                                 str(request["client_id"]),
                                                 user_info=user_info,
                                                 sign=True, **hargs)
            except (JWEException, NoSuitableSigningKeys) as err:
                logger.warning(str(err))
                return AuthorizationErrorResponse(
                    error="invalid_request",
                    error_description="Could not sign/encrypt id_token")

            aresp["id_token"] = id_token
            _sinfo["id_token"] = id_token
            handled_response_type.append("id_token")

        not_handled = rtype.difference(handled_response_type)
        if not_handled:
            raise UnSupported("unsupported_response_type", list(not_handled))

    return {'response_args': aresp, 'fragment_enc': fragment_enc}
def test_conversation():
    service_context = ServiceContext(
        RP_KEYJAR, {
            "client_preferences": {
                "application_type": "web",
                "application_name": "rphandler",
                "contacts": ["*****@*****.**"],
                "response_types": ["code"],
                "scope": ["openid", "profile", "email", "address", "phone"],
                "token_endpoint_auth_method": "client_secret_basic",
            },
            "redirect_uris": ["{}/authz_cb".format(RP_BASEURL)],
            "jwks_uri": "{}/static/jwks.json".format(RP_BASEURL)
        })

    service_spec = DEFAULT_SERVICES.copy()
    service_spec['WebFinger'] = {'class': WebFinger}

    service = init_services(service_spec,
                            state_db=InMemoryStateDataBase(),
                            service_context=service_context)

    assert set(service.keys()) == {
        'accesstoken', 'authorization', 'webfinger', 'registration',
        'refresh_token', 'userinfo', 'provider_info'
    }

    service_context.service = service

    # ======================== WebFinger ========================

    info = service['webfinger'].get_request_parameters(
        request_args={'resource': '*****@*****.**'})

    assert info[
               'url'] == 'https://example.org/.well-known/webfinger?rel=http' \
                         '%3A%2F' \
                         '%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer' \
                         '&resource' \
                         '=acct%3Afoobar%40example.org'

    webfinger_response = json.dumps({
        "subject":
        "acct:[email protected]",
        "links": [{
            "rel": "http://openid.net/specs/connect/1.0/issuer",
            "href": "https://example.org/op"
        }],
        "expires":
        "2018-02-04T11:08:41Z"
    })

    response = service['webfinger'].parse_response(webfinger_response)

    assert isinstance(response, JRD)
    assert set(response.keys()) == {'subject', 'links', 'expires'}
    assert response['links'] == [
        Link(rel='http://openid.net/specs/connect/1.0/issuer',
             href='https://example.org/op')
    ]

    service['webfinger'].update_service_context(resp=response)
    assert service_context.issuer == OP_BASEURL

    # =================== Provider info discovery ====================

    info = service['provider_info'].get_request_parameters()

    assert info[
               'url'] == 'https://example.org/op/.well-known/openid' \
                         '-configuration'

    provider_info_response = json.dumps({
        "version":
        "3.0",
        "token_endpoint_auth_methods_supported": [
            "client_secret_post", "client_secret_basic", "client_secret_jwt",
            "private_key_jwt"
        ],
        "claims_parameter_supported":
        True,
        "request_parameter_supported":
        True,
        "request_uri_parameter_supported":
        True,
        "require_request_uri_registration":
        True,
        "grant_types_supported": [
            "authorization_code", "implicit",
            "urn:ietf:params:oauth:grant-type:jwt-bearer", "refresh_token"
        ],
        "response_types_supported": [
            "code", "id_token", "id_token token", "code id_token",
            "code token", "code id_token token"
        ],
        "response_modes_supported": ["query", "fragment", "form_post"],
        "subject_types_supported": ["public", "pairwise"],
        "claim_types_supported": ["normal", "aggregated", "distributed"],
        "claims_supported": [
            "birthdate", "address", "nickname", "picture", "website", "email",
            "gender", "sub", "phone_number_verified", "given_name", "profile",
            "phone_number", "updated_at", "middle_name", "name", "locale",
            "email_verified", "preferred_username", "zoneinfo", "family_name"
        ],
        "scopes_supported": [
            "openid", "profile", "email", "address", "phone", "offline_access",
            "openid"
        ],
        "userinfo_signing_alg_values_supported": [
            "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "HS256",
            "HS384", "HS512", "PS256", "PS384", "PS512", "none"
        ],
        "id_token_signing_alg_values_supported": [
            "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "HS256",
            "HS384", "HS512", "PS256", "PS384", "PS512", "none"
        ],
        "request_object_signing_alg_values_supported": [
            "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "HS256",
            "HS384", "HS512", "PS256", "PS384", "PS512", "none"
        ],
        "token_endpoint_auth_signing_alg_values_supported": [
            "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "HS256",
            "HS384", "HS512", "PS256", "PS384", "PS512"
        ],
        "userinfo_encryption_alg_values_supported": [
            "RSA1_5", "RSA-OAEP", "RSA-OAEP-256", "A128KW", "A192KW", "A256KW",
            "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"
        ],
        "id_token_encryption_alg_values_supported": [
            "RSA1_5", "RSA-OAEP", "RSA-OAEP-256", "A128KW", "A192KW", "A256KW",
            "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"
        ],
        "request_object_encryption_alg_values_supported": [
            "RSA1_5", "RSA-OAEP", "RSA-OAEP-256", "A128KW", "A192KW", "A256KW",
            "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW"
        ],
        "userinfo_encryption_enc_values_supported": [
            "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512", "A128GCM",
            "A192GCM", "A256GCM"
        ],
        "id_token_encryption_enc_values_supported": [
            "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512", "A128GCM",
            "A192GCM", "A256GCM"
        ],
        "request_object_encryption_enc_values_supported": [
            "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512", "A128GCM",
            "A192GCM", "A256GCM"
        ],
        "acr_values_supported": ["PASSWORD"],
        "issuer":
        OP_BASEURL,
        "jwks_uri":
        "{}/static/jwks_tE2iLbOAqXhe8bqh.json".format(OP_BASEURL),
        "authorization_endpoint":
        "{}/authorization".format(OP_BASEURL),
        "token_endpoint":
        "{}/token".format(OP_BASEURL),
        "userinfo_endpoint":
        "{}/userinfo".format(OP_BASEURL),
        "registration_endpoint":
        "{}/registration".format(OP_BASEURL),
        "end_session_endpoint":
        "{}/end_session".format(OP_BASEURL)
    })

    resp = service['provider_info'].parse_response(provider_info_response)

    assert isinstance(resp, ProviderConfigurationResponse)
    service['provider_info'].update_service_context(resp)

    assert service_context.provider_info['issuer'] == OP_BASEURL
    assert service_context.provider_info[
               'authorization_endpoint'] == \
           'https://example.org/op/authorization'
    assert service_context.provider_info[
        'registration_endpoint'] == 'https://example.org/op/registration'

    # =================== Client registration ====================

    info = service['registration'].get_request_parameters()

    assert info['url'] == 'https://example.org/op/registration'
    _body = json.loads(info['body'])
    assert _body == {
        "application_type": "web",
        "response_types": ["code"],
        "contacts": ["*****@*****.**"],
        "jwks_uri": "https://example.com/rp/static/jwks.json",
        "redirect_uris": ["{}/authz_cb".format(RP_BASEURL)],
        'token_endpoint_auth_method': 'client_secret_basic',
        "grant_types": ["authorization_code"]
    }
    assert info['headers'] == {'Content-Type': 'application/json'}

    now = int(time.time())

    op_client_registration_response = json.dumps({
        "client_id":
        "zls2qhN1jO6A",
        "client_secret":
        "c8434f28cf9375d9a7",
        "registration_access_token":
        "NdGrGR7LCuzNtixvBFnDphGXv7wRcONn",
        "registration_client_uri":
        "{}/registration?client_id=zls2qhN1jO6A".format(RP_BASEURL),
        "client_secret_expires_at":
        now + 3600,
        "client_id_issued_at":
        now,
        "application_type":
        "web",
        "response_types": ["code"],
        "contacts": ["*****@*****.**"],
        "redirect_uris": ["{}/authz_cb".format(RP_BASEURL)],
        "token_endpoint_auth_method":
        "client_secret_basic",
        "grant_types": ["authorization_code"]
    })

    response = service['registration'].parse_response(
        op_client_registration_response)

    service['registration'].update_service_context(response)
    assert service_context.client_id == 'zls2qhN1jO6A'
    assert service_context.client_secret == 'c8434f28cf9375d9a7'
    assert isinstance(service_context.registration_response,
                      RegistrationResponse)
    assert set(service_context.registration_response.keys()) == {
        'client_secret_expires_at', 'contacts', 'client_id',
        'token_endpoint_auth_method', 'redirect_uris', 'response_types',
        'client_id_issued_at', 'client_secret', 'application_type',
        'registration_client_uri', 'registration_access_token', 'grant_types'
    }

    # =================== Authorization ====================

    STATE = 'Oh3w3gKlvoM2ehFqlxI3HIK5'
    NONCE = 'UvudLKz287YByZdsY3AJoPAlEXQkJ0dK'

    info = service['authorization'].get_request_parameters(request_args={
        'state': STATE,
        'nonce': NONCE
    })

    p = urlparse(info['url'])
    _query = parse_qs(p.query)
    assert set(_query.keys()) == {
        'state', 'nonce', 'response_type', 'scope', 'client_id', 'redirect_uri'
    }
    assert _query['scope'] == ['openid']
    assert _query['nonce'] == [NONCE]
    assert _query['state'] == [STATE]

    op_authz_resp = {
        'state': STATE,
        'scope': 'openid',
        'code': 'Z0FBQUFBQmFkdFFjUVpFWE81SHU5N1N4N01',
        'iss': OP_BASEURL,
        'client_id': 'zls2qhN1jO6A'
    }

    _authz_rep = AuthorizationResponse(**op_authz_resp)

    _resp = service['authorization'].parse_response(_authz_rep.to_urlencoded())
    service['authorization'].update_service_context(_resp, key=STATE)
    _item = service['authorization'].get_item(AuthorizationResponse,
                                              'auth_response', STATE)
    assert _item['code'] == 'Z0FBQUFBQmFkdFFjUVpFWE81SHU5N1N4N01'

    # =================== Access token ====================

    request_args = {
        'state': STATE,
        'redirect_uri': service_context.redirect_uris[0]
    }

    info = service['accesstoken'].get_request_parameters(
        request_args=request_args)

    assert info['url'] == 'https://example.org/op/token'
    _qp = parse_qs(info['body'])
    assert _qp == {
        'grant_type': ['authorization_code'],
        'redirect_uri': ['https://example.com/rp/authz_cb'],
        'client_id': ['zls2qhN1jO6A'],
        'state': ['Oh3w3gKlvoM2ehFqlxI3HIK5'],
        'code': ['Z0FBQUFBQmFkdFFjUVpFWE81SHU5N1N4N01']
    }
    assert info['headers'] == {
        'Authorization': 'Basic '
        'emxzMnFoTjFqTzZBOmM4NDM0ZjI4Y2Y5Mzc1ZDlhNw==',
        'Content-Type': 'application/x-www-form-urlencoded'
    }

    # create the IdToken
    _jwt = JWT(OP_KEYJAR,
               OP_BASEURL,
               lifetime=3600,
               sign=True,
               sign_alg='RS256')
    payload = {
        'sub': '1b2fc9341a16ae4e30082965d537',
        'acr': 'PASSWORD',
        'auth_time': 1517736988,
        'nonce': NONCE
    }
    _jws = _jwt.pack(payload=payload, recv='zls2qhN1jO6A')

    _resp = {
        "state": "Oh3w3gKlvoM2ehFqlxI3HIK5",
        "scope": "openid",
        "access_token": "Z0FBQUFBQmFkdFF",
        "token_type": "Bearer",
        'expires_in': 600,
        "id_token": _jws
    }

    service_context.issuer = OP_BASEURL
    _resp = service['accesstoken'].parse_response(json.dumps(_resp),
                                                  state=STATE)

    assert isinstance(_resp, AccessTokenResponse)
    assert set(_resp['__verified_id_token'].keys()) == {
        'iss', 'nonce', 'acr', 'auth_time', 'aud', 'iat', 'exp', 'sub'
    }

    service['accesstoken'].update_service_context(_resp, key=STATE)

    _item = service['authorization'].get_item(AccessTokenResponse,
                                              'token_response', STATE)

    assert set(_item.keys()) == {
        'state', 'scope', 'access_token', 'token_type', 'id_token',
        '__verified_id_token', 'expires_in', '__expires_at'
    }

    assert _item['token_type'] == 'Bearer'
    assert _item['access_token'] == 'Z0FBQUFBQmFkdFF'

    # =================== User info ====================

    info = service['userinfo'].get_request_parameters(state=STATE)

    assert info['url'] == 'https://example.org/op/userinfo'
    assert info['headers'] == {'Authorization': 'Bearer Z0FBQUFBQmFkdFF'}

    op_resp = {"sub": "1b2fc9341a16ae4e30082965d537"}

    _resp = service['userinfo'].parse_response(json.dumps(op_resp),
                                               state=STATE)
    service['userinfo'].update_service_context(_resp, key=STATE)

    assert isinstance(_resp, OpenIDSchema)
    assert _resp.to_dict() == {'sub': '1b2fc9341a16ae4e30082965d537'}

    _item = service['authorization'].get_item(OpenIDSchema, 'user_info', STATE)
    assert _item.to_dict() == {'sub': '1b2fc9341a16ae4e30082965d537'}