Пример #1
0
    def _parse_remote_response(self, response):
        """
        Parse simple JWKS or signed JWKS from the HTTP response.

        :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri'
            endpoint
        :return: response parsed as JSON or None
        """
        # Check if the content type is the right one.
        try:
            if response.headers["Content-Type"] == 'application/json':
                logger.debug("Loaded JWKS: %s from %s" %
                             (response.text, self.source))
                try:
                    return json.loads(response.text)
                except ValueError:
                    return None
            elif response.headers["Content-Type"] == 'application/jwt':
                logger.debug("Signed JWKS: %s from %s" %
                             (response.text, self.source))
                _jws = factory(response.text)
                _resp = _jws.verify_compact(
                    response.text, keys=self.verify_keys.get_signing_key())
                return _resp
            else:
                logger.error('Wrong content type: {}'.format(
                    response.headers['Content-Type']))
                raise ValueError('Content-type mismatch')
        except KeyError:
            pass
Пример #2
0
def get_sub(token):
    _jwt = factory(token)

    if _jwt:
        return json.loads(as_unicode(_jwt.jwt.part[1]))['sub']
    else:
        return ''
Пример #3
0
    def test_sign_encrypt_id_token(self):
        client_info = RegistrationResponse(
            id_token_signed_response_alg="RS512", client_id="client_1")
        session_info = {
            "authn_req": AREQN,
            "sub": "sub",
            "authn_event": {
                "authn_info": "loa2",
                "authn_time": time.time()
            },
        }

        self.endpoint_context.jwx_def["signing_alg"] = {"id_token": "RS384"}
        self.endpoint_context.cdb["client_1"] = client_info.to_dict()

        _token = self.endpoint_context.idtoken.sign_encrypt(session_info,
                                                            "client_1",
                                                            sign=True)
        assert _token

        _jws = jws.factory(_token)

        assert _jws.jwt.headers["alg"] == "RS512"

        client_keyjar = KeyJar()
        _jwks = self.endpoint_context.keyjar.export_jwks()
        client_keyjar.import_jwks(_jwks, self.endpoint_context.issuer)

        _jwt = JWT(key_jar=client_keyjar, iss="client_1")
        res = _jwt.unpack(_token)
        assert isinstance(res, dict)
        assert res["aud"] == ["client_1"]
Пример #4
0
def test_get_self_signed_entity_statement():
    sses = entity_statement_with_x5c()

    collector = Collector(trust_anchors=ANCHOR,
                          http_cli=requests.request,
                          insecure=True)
    collector.ssc_dir = "."

    with responses.RequestsMock() as rsps:
        rsps.add(rsps.GET,
                 "https://foodle.uninett.no/.well-known/openid-federation",
                 body=sses)
        # Get the self-signed entity statement from a leaf
        self_signed_statement = collector.get_configuration_information(
            "https://foodle.uninett.no")

    _jwt = factory(self_signed_statement)
    assert _jwt

    # this should work. Not interested in the value, just that it can be done.
    msg = _jwt.jwt.payload()
    x5c_to_pems(msg["x5c"])

    # Same here
    collector.store_ssc_cert(msg, "https://foodle.uninett.no")
Пример #5
0
    def test_id_token_payload_with_access_token(self):
        session_id = self._create_session(AREQ)
        grant = self.session_manager[session_id]
        code = self._mint_code(grant, session_id)
        access_token = self._mint_access_token(grant, session_id, code)

        id_token = self._mint_id_token(grant,
                                       session_id,
                                       token_ref=code,
                                       access_token=access_token.value)

        _jws = factory(id_token.value)
        assert _jws.jwt.headers["alg"] == "RS256"
        payload = _jws.jwt.payload()

        assert set(payload.keys()) == {
            "sub",
            "auth_time",
            "aud",
            "exp",
            "iss",
            "iat",
            "nonce",
            "at_hash",
        }
Пример #6
0
 def test_get_trust_mark_self_signed(self):
     # Verify the self signed trust marks
     for _jws in self.entity.server_get('context').signed_trust_marks:
         _jwt = factory(_jws)
         _payload = _jwt.jwt.payload()
         _tm = TrustMark(**_payload)
         assert _tm.verify()
Пример #7
0
def test_create_self_signed():
    metadata = {
        "application_type": "web",
        "claims": ["sub", "name", "email", "picture"],
        "id_token_signing_alg_values_supported": ["RS256", "RS512"],
        "redirect_uris": ["https://foodle.uninett.no/callback"],
        "response_types": ["code"]
    }

    iss = "https://example.com"
    sub = iss

    key_jar = build_keyjar(KEYSPEC, issuer_id=iss)
    authority = ["https://ntnu.no"]

    _jwt = create_entity_statement(iss,
                                   sub,
                                   key_jar,
                                   metadata=metadata,
                                   authority_hints=authority)

    assert _jwt

    _verifier = factory(_jwt)
    keys = key_jar.get_jwt_verify_keys(_verifier.jwt)
    res = _verifier.verify_compact(keys=keys)

    assert res
    assert res['iss'] == iss
    assert res['sub'] == sub
    assert set(res.keys()) == {
        'metadata', 'iss', 'exp', 'sub', 'iat', 'authority_hints', 'jwks'
    }
Пример #8
0
    def test_process_request(self):
        session_id = self._create_session(AUTH_REQ)
        grant = self.session_manager[session_id]
        code = self._mint_code(grant, AUTH_REQ["client_id"])

        _token_request = TOKEN_REQ.to_dict()
        _context = self.endpoint_context
        _token_request["code"] = code.value
        _req = self.token_endpoint.parse_request(_token_request, http_info={
            "headers": {"dpop": DPOP_HEADER},
            "url": 'https://server.example.com/token',
            "method": "POST"
        })

        assert "dpop_jkt" in _req

        _resp = self.token_endpoint.process_request(request=_req)
        assert _resp["response_args"]["token_type"] == "DPoP"

        access_token = _resp["response_args"]["access_token"]
        jws = factory(access_token)
        _payload = jws.jwt.payload()
        assert "cnf" in _payload
        assert _payload["cnf"]["jkt"] == _req["dpop_jkt"]

        # Make sure DPoP also is in the session access token instance.
        _session_info = self.session_manager.get_session_info_by_token(access_token)
        _token = self.session_manager.find_token(_session_info["session_id"], access_token)
        assert _token.token_type == "DPoP"
Пример #9
0
def verify_self_signed_jwks(sjwt):
    """
    Verify the signature of a signed JWT containing a JWKS.
    The JWT is signed by one of the keys in the JWKS. 
    In the JWT the JWKS is stored using this format ::
    
        'jwks': {
            'keys': [ ]
        }

    :param sjwt: Signed Jason Web Token
    :return: Dictionary containing 'jwks' (the JWKS) and 'iss' (the issuer of 
        the JWT)
    """

    _jws = factory(sjwt)
    _json = _jws.jwt.part[1]
    _body = json.loads(as_unicode(_json))
    iss = _body['iss']
    _jwks = _body['jwks']

    _kj = jwks_to_keyjar(_jwks, iss)

    try:
        _kid = _jws.jwt.headers['kid']
    except KeyError:
        _keys = _kj.get_signing_key(owner=iss)
    else:
        _keys = _kj.get_signing_key(owner=iss, kid=_kid)

    _ver = _jws.verify_compact(sjwt, _keys)
    return {'jwks': _ver['jwks'], 'iss': iss}
def main(jwt, keys, quiet):
    _jw = jwe.factory(jwt)
    if _jw:
        if not quiet:
            print("Encrypted JSON Web Token")
            print('Headers: {}'.format(_jw.jwt.headers))
        if keys:
            res = _jw.decrypt(keys=keys)
            json_object = json.loads(res)
            json_str = json.dumps(json_object, indent=2)
            print(highlight(json_str, JsonLexer(), TerminalFormatter()))
        else:
            print("No keys can't decrypt")
            sys.exit(1)
    else:
        _jw = jws.factory(jwt)
        if _jw:
            if quiet:
                json_object = json.loads(_jw.jwt.part[1].decode("utf-8"))
                json_str = json.dumps(json_object, indent=2)
                print(highlight(json_str, JsonLexer(), TerminalFormatter()))
            else:
                print("Signed JSON Web Token")
                print('Headers: {}'.format(_jw.jwt.headers))
                if keys:
                    res = _jw.verify_compact(keys=keys)
                    print('Verified message: {}'.format(res))
                else:
                    json_object = json.loads(_jw.jwt.part[1].decode("utf-8"))
                    json_str = json.dumps(json_object, indent=2)
                    print('Unverified message: {}'.format(
                        highlight(json_str, JsonLexer(), TerminalFormatter())))
Пример #11
0
def test_collect_superiors():
    # entity_id = 'https://feide.no'
    entity_id = 'https://foodle.uninett.no'
    target = 'https://foodle.uninett.no'
    collector = DummyCollector(trusted_roots=ANCHOR,
                               httpd=Publisher(
                                   os.path.join(BASE_PATH, 'base_data')),
                               root_dir=os.path.join(BASE_PATH, 'base_data'))
    entity_statement = collector.get_entity_statement(
        api_endpoint='https://foodle.uninett.no/fed_api',
        issuer=entity_id,
        subject=entity_id)
    _config = verify_self_signed_signature(entity_statement)
    assert _config

    tree = collector.collect_superiors(_config['iss'], entity_statement)
    node = {entity_id: (entity_statement, tree)}
    chains = branch2lists(node)

    assert len(chains) == 1  # only one chain
    assert len(chains[0]) == 4  # And that chain contains 4 statements
    _jws00 = factory(chains[0][0])
    payload = _jws00.jwt.payload()
    # The Federation Entity Statement will be first in line
    assert payload["iss"] == 'https://feide.no'
Пример #12
0
def test_sign_encrypt_id_token():
    client_info = RegistrationResponse(id_token_signed_response_alg='RS512',
                                       client_id='client_1')
    session_info = {
        'authn_req': AREQN,
        'sub': 'sub',
        'authn_event': {
            "authn_info": 'loa2',
            "authn_time": time.time()
        }
    }

    ENDPOINT_CONTEXT.jwx_def["signing_alg"] = {'id_token': 'RS384'}
    ENDPOINT_CONTEXT.cdb['client_1'] = client_info.to_dict()

    _token = sign_encrypt_id_token(ENDPOINT_CONTEXT,
                                   session_info,
                                   'client_1',
                                   sign=True)
    assert _token

    _jws = jws.factory(_token)

    assert _jws.jwt.headers['alg'] == 'RS512'

    client_keyjar = KeyJar()
    _jwks = KEYJAR.export_jwks()
    client_keyjar.import_jwks(_jwks, ENDPOINT_CONTEXT.issuer)

    _jwt = JWT(key_jar=client_keyjar, iss='client_1')
    res = _jwt.unpack(_token)
    assert isinstance(res, dict)
    assert res['aud'] == ['client_1']
Пример #13
0
    def test_id_token_payload_many_0(self):
        session_id = self._create_session(AREQ)
        grant = self.session_manager[session_id]
        grant.claims = {"id_token": {"given_name": None}}
        code = self._mint_code(grant, session_id)
        access_token = self._mint_access_token(grant, session_id, code)

        id_token = self._mint_id_token(
            grant,
            session_id,
            token_ref=code,
            code=code.value,
            access_token=access_token.value,
        )

        _jwt = factory(id_token.value)
        payload = _jwt.jwt.payload()
        assert set(payload.keys()) == {
            "nonce",
            "c_hash",
            "at_hash",
            "sub",
            "auth_time",
            "given_name",
            "aud",
            "exp",
            "iat",
            "iss",
        }
Пример #14
0
    def parse_federation_response(self, response, **kwargs):
        """
        Takes a provider info response and parses it.
        If according to the info the OP has more then one federation
        in common with the client then the decision has to be handled higher up.
        For each Metadata statement that appears in the response, and was
        possible to parse, one
        :py:class:`fedservice.entity_statement.statement.Statement`
        instance is stored in the response by federation operator ID under the
        key 'fos'.

        :param response: A self-signed JWT containing an entity statement
        :returns: A list of lists of Statement instances. The innermost lists represents
        trust chains
        """

        _jwt = factory(response)
        entity_statement = _jwt.jwt.payload()
        entity_id = entity_statement['iss']

        _fe = self.service_context.federation_entity

        statement = verify_self_signed_signature(response)
        _tree = _fe.collect_statement_chains(entity_id, statement)
        _node = {entity_id: (response, _tree)}
        _chains = branch2lists(_node)
        for c in _chains:
            c.append(response)
        return [eval_chain(c, _fe.keyjar, 'openid_provider') for c in _chains]
Пример #15
0
 def test_no_kid_multiple_keys_no_kid_issuer(self):
     a_kids = [k.kid for k in self.alice_keyjar.get_verify_key(owner="Alice", key_type="RSA")]
     no_kid_issuer = {"Alice": a_kids}
     _jwt = factory(self.sjwt_a)
     _jwt.jwt.headers["kid"] = ""
     keys = self.bob_keyjar.get_jwt_verify_keys(_jwt.jwt, no_kid_issuer=no_kid_issuer)
     assert len(keys) == 3
 def test_no_kid_multiple_keys_no_kid_issuer_lim(self):
     no_kid_issuer = {'Alice': []}
     _jwt = factory(self.sjwt_a)
     _jwt.jwt.headers['kid'] = ''
     keys = self.bob_keyjar.get_jwt_verify_keys(_jwt.jwt,
                                                no_kid_issuer=no_kid_issuer)
     assert len(keys) == 3
Пример #17
0
    def test_get_trust_mark_3rd_party(self):
        # Create the Signed JWT representing the Trust Mark

        _jws = self.tmi.create_trust_mark(self.id, "https://example.com")
        _jwt = factory(_jws)
        _payload = _jwt.jwt.payload()
        _tm = TrustMark(**_payload)
        assert _tm.verify()
Пример #18
0
def test_extra_headers_1():
    pkey = import_private_rsa_key_from_file(full_path("./size2048.key"))
    payload = "Please take a moment to register today"
    keys = [RSAKey(priv_key=pkey)]
    _jws = JWS(payload, alg="RS256")
    sjwt = _jws.sign_compact(keys, foo="bar")
    _jwt = factory(sjwt)
    assert set(_jwt.jwt.headers.keys()) == {"alg", "foo"}
Пример #19
0
def main(fedent, entity_id, entity_type):
    _jws = fedent.get_configuration_information(entity_id)
    _jwt = factory(_jws)
    msg = _jwt.jwt.payload()
    tree = fedent.collect_statement_chains(entity_id, msg)
    chains = branch2lists((_jws, tree))
    statements = [eval_chain(c, fedent.keyjar, entity_type) for c in chains]
    return statements
Пример #20
0
def test_dj_usage():
    pkey = import_private_rsa_key_from_file(full_path("./size2048.key"))
    payload = "Please take a moment to register today"
    keys = [RSAKey(priv_key=pkey)]
    _jws = JWS(payload, alg="RS256")
    sjwt = _jws.sign_compact(keys)
    _jwt = factory(sjwt)
    assert _jwt.jwt.headers["alg"] == "RS256"
Пример #21
0
    def test_parse_registration_response(self):
        # construct the entity statement the OP should return
        es_api = FSEntityStatementAPI(os.path.join(BASE_PATH, 'base_data'), iss="op.ntnu.no")
        jws = es_api.create_entity_statement("op.ntnu.no")

        # parse the response and collect the trust chains
        res = self.service['discovery'].parse_response(jws)

        self.service['discovery'].update_service_context(res)

        _sc = self.service['registration'].service_context
        self.service['registration'].endpoint = _sc.get('provider_info')[
            'federation_registration_endpoint']

        # construct the client registration request
        req_args = {'entity_id': self.federation_entity.entity_id}
        jws = self.service['registration'].construct(request_args=req_args)
        assert jws

        # construct the information needed to send the request
        _info = self.service['registration'].get_request_parameters(
            request_body_type="jose", method="POST")

        # create the request
        _req_jwt = factory(_info['body'])
        payload = _req_jwt.jwt.payload()

        # The OP as federation entity
        _fe = _sc.federation_entity
        del _fe.keyjar["https://op.ntnu.no"]
        # make sure I have the private keys
        _fe.keyjar.import_jwks(
            es_api.keyjar.export_jwks(True, "https://op.ntnu.no"),
            "https://op.ntnu.no"
        )
        tree = _fe.collect_statement_chains(payload['iss'], _info['body'])
        _node = {payload['iss']: (_info['body'], tree)}
        chains = branch2lists(_node)
        statements = [eval_chain(c, _fe.keyjar, 'openid_relying_party') for c in chains]

        metadata_policy = {
            "client_id": {"value": "aaaaaaaaa"},
            "client_secret": {"value": "bbbbbbbbbb"}
        }

        # This is the registration response from the OP
        _jwt = _fe.create_entity_statement(
            'https://op.ntnu.no', 'https://foodle.uninett.no',
            metadata_policy={_fe.entity_type: metadata_policy},
            metadata={"federation_entity": {"trust_anchor_id": statements[0].fo}},
            authority_hints=['https://feide.no'])

        claims = self.service['registration'].parse_response(_jwt, request_body=_info['body'])

        assert set(claims.keys()) == {
            'id_token_signed_response_alg', 'application_type', 'client_secret',
            'client_id', 'response_types', 'token_endpoint_auth_method',
            'grant_types', "contacts", 'federation_type'}
Пример #22
0
def fetch_entity(fetch_endpoint, iss, sub, iss_entity_statement):
    _response = requests.request("GET", fetch_endpoint, verify=False,
                                 params={'iss': iss, 'sub': sub})
    _jws = factory(_response.text)
    _key_jar = KeyJar()
    _key_jar.import_jwks(iss_entity_statement['jwks'], iss)
    _keys = _key_jar.get_jwt_verify_keys(_jws.jwt)
    _res = _jws.verify_compact(keys=_keys)
    return _res
Пример #23
0
def test_extra_headers_3():
    pkey = import_private_rsa_key_from_file(full_path("./size2048.key"))
    payload = "Please take a moment to register today"
    keys = [RSAKey(priv_key=pkey)]
    _jws = JWS(payload, alg='RS256')
    _jws.set_header_claim('foo', 'bar')
    sjwt = _jws.sign_compact(keys, abc=123)
    _jwt = factory(sjwt)
    assert set(_jwt.jwt.headers.keys()) == {'alg', 'foo', 'abc'}
Пример #24
0
def test_signed_jwks():
    _bundle = build_key_bundle(key_conf=KEYSPEC)
    _keys = [k.serialize() for k in _bundle.keys()]

    federation_key_bundle = KeyBundle(keys=_keys, federation_keys=KEY_JAR)
    _jws = federation_key_bundle.signed_jwks(issuer=ISSUER)

    _jwt = factory(_jws)
    assert set(_jwt.jwt.payload().keys()) == {"keys", "iat", "iss"}
Пример #25
0
def test_factory_verify_alg():
    pkey = import_private_rsa_key_from_file(full_path("./size2048.key"))
    payload = "Please take a moment to register today"
    keys = [RSAKey(priv_key=pkey)]
    _signer = JWS(payload, alg="RS256")
    _signer.set_header_claim("foo", "bar")
    _jws = _signer.sign_compact(keys, abc=123)
    _verifier = factory(_jws)
    assert _verifier.jwt.verify_headers(alg="RS512") is False
Пример #26
0
 def test_no_kid_multiple_keys(self):
     """This is extremely strict"""
     _jwt = factory(self.sjwt_a)
     # remove kid reference
     _jwt.jwt.headers["kid"] = ""
     keys = self.bob_keyjar.get_jwt_verify_keys(_jwt.jwt)
     assert len(keys) == 0
     keys = self.bob_keyjar.get_jwt_verify_keys(_jwt.jwt, allow_missing_kid=True)
     assert len(keys) == 3
Пример #27
0
def trusted_anchor(es, key_jar):
    _jwt = factory(es)
    payload = _jwt.jwt.payload()
    if payload['iss'] not in key_jar:
        logger.warning(
            "Trust chain ending in a trust anchor I do not know: '%s'",
            payload['iss'])
        return False

    return True
Пример #28
0
def unfurl(jwt):
    """
    Return the body of a signed JWT, without verifying the signature.
    
    :param jwt: A signed JWT 
    :return: The body of the JWT as a 'UTF-8' string
    """

    _rp_jwt = factory(jwt)
    return json.loads(_rp_jwt.jwt.part[1].decode('utf8'))
Пример #29
0
 def test_well_known(self):
     _ctx = self.entity.context
     _statement = _ctx.make_configuration_statement()
     _jws = factory(_statement)
     _payload = _jws.jwt.payload()
     assert _payload["iss"] == _ctx.entity_id
     assert set(_payload.keys()) == {
         'sub', 'metadata', 'authority_hints', 'jwks', 'iss', 'iat', 'exp'
     }
     assert _payload["sub"] == _ctx.entity_id
Пример #30
0
    def parse_federation_registration_response(self, resp, **kwargs):
        """
        Receives a dynamic client registration response,

        :param resp: An entity statement instance
        :return: A set of metadata claims
        """
        _sc = self.service_context
        _fe = _sc.federation_entity

        # Can not collect trust chain. Have to verify the signed JWT with keys I have

        kj = self.service_context.federation_entity.keyjar
        _jwt = factory(resp)
        entity_statement = _jwt.verify_compact(resp,
                                               keys=kj.get_jwt_verify_keys(
                                                   _jwt.jwt))

        _trust_anchor_id = self.get_trust_anchor_id(entity_statement)

        chosen = None
        for op_statement in _fe.op_statements:
            if op_statement.fo == _trust_anchor_id:
                chosen = op_statement
                break

        if not chosen:
            raise ValueError('No matching federation operator')

        # based on the Federation ID, conclude which OP config to use
        op_claims = chosen.metadata
        # _sc.trust_path = (chosen.fo, _fe.op_paths[statement.fo][0])
        _sc.provider_info = self.response_cls(**op_claims)

        # To create RPs metadata collect the trust chains
        tree = {}
        for ah in _fe.authority_hints:
            tree[ah] = _fe.collector.collect_intermediate(_fe.entity_id, ah)

        _node = {_fe.entity_id: (resp, tree)}
        chains = branch2lists(_node)

        # Get the policies
        policy_chains_tup = [
            eval_policy_chain(c, _fe.keyjar, _fe.entity_type) for c in chains
        ]
        _policy = combine_policy(
            policy_chains_tup[0][1],
            entity_statement['metadata_policy'][_fe.entity_type])
        logger.debug("Combined policy: {}".format(_policy))
        _uev = unverified_entity_statement(kwargs["request_body"])
        logger.debug("Registration request: {}".format(_uev))
        _query = _uev["metadata"][_fe.entity_type]
        _sc.registration_response = apply_policy(_query, _policy)
        return _sc.registration_response