Ejemplo n.º 1
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'
    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
        """
        entity_statement = verify_self_signed_signature(response)
        entity_id = entity_statement['iss']

        _fe = self.client_get("service_context").federation_entity
        _tree = _fe.collect_statement_chains(entity_id, entity_statement)
        _node = {entity_id: (response, _tree)}
        logger.debug("Translate tree to chains")
        _chains = branch2lists(_node)
        logger.debug("%s chains", len(_chains))
        for c in _chains:
            c.append(response)
        return [eval_chain(c, _fe.keyjar, 'openid_provider') for c in _chains]
Ejemplo n.º 3
0
def test_eval_chains():
    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(target,
                                                      issuer=target,
                                                      subject=target)
    _config = verify_self_signed_signature(entity_statement)
    assert _config

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

    key_jar = KeyJar()
    key_jar.import_jwks_as_json(jwks, 'https://feide.no')

    statements = [
        eval_chain(c, key_jar, 'openid_relying_party') for c in chains
    ]

    assert len(statements) == 1
    statement = statements[0]
    assert statement.fo == "https://feide.no"
    assert set(statement.metadata.keys()) == {
        'response_types', 'claims', 'contacts', 'application_type',
        'redirect_uris', 'id_token_signing_alg_values_supported', 'jwks_uri'
    }
Ejemplo n.º 4
0
 def test_eval_path(self):
     leaf_entity_id = 'https://foodle.uninett.no'
     _jws = self.fedent.collector.get_entity_statement(
         '', leaf_entity_id, leaf_entity_id)
     tree = self.fedent.collect_statement_chains(leaf_entity_id, _jws)
     _node = {leaf_entity_id: (_jws, tree)}
     chains = branch2lists(_node)
     statements = [
         eval_chain(c, self.fedent.keyjar, 'openid_relying_party')
         for c in chains
     ]
     assert len(statements) == 1
     statement = statements[0]
     assert set(statement.metadata.keys()) == {
         'application_type', 'claims',
         'id_token_signing_alg_values_supported', 'redirect_uris',
         'contacts', 'response_types', 'jwks_uri'
     }
     statement = self.fedent.pick_metadata(statements)
     assert statement.fo == 'https://feide.no'
     assert set(statement.metadata.keys()) == {
         'application_type', 'claims',
         'id_token_signing_alg_values_supported', 'redirect_uris',
         'contacts', 'response_types', 'jwks_uri'
     }
Ejemplo n.º 5
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
Ejemplo n.º 6
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'}
Ejemplo n.º 7
0
 def test_collect_entity_statement(self):
     leaf_entity_id = 'https://foodle.uninett.no'
     entity_statement = self.fedent.collector.get_entity_statement('', leaf_entity_id,
                                                                   leaf_entity_id)
     tree = self.fedent.collect_statement_chains(leaf_entity_id, entity_statement)
     assert tree
     _node = {leaf_entity_id: (entity_statement, tree)}
     chains = branch2lists(_node)
     assert len(chains) == 1
     assert len(chains[0]) == 4
Ejemplo n.º 8
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
Ejemplo n.º 9
0
def test_branch2lists_1():
    tree = {
        "https://example.com/rp": ('statement1', {
            "https://example.com/intermediate1": ('statement2', {
                "https://example.com/anchor": ("statement3", {})
            })
        })
    }

    chains = branch2lists(tree)
    assert len(chains) == 1
    assert len(chains[0]) == 3
    assert chains[0] == ["statement3", "statement2", "statement1"]
Ejemplo n.º 10
0
def test_branch2lists_3():
    tree = {
        "https://example.com/rp": ('statement1', {
            "https://example.com/intermediate1": ('statement2', {
                "https://example.com/anchor1": ("statement3", {})
            }),
            "https://example.com/intermediate2": ('statement5', {
                "https://example.com/anchor2": ("statement4", {})
            })
        })
    }

    chains = branch2lists(tree)
    assert len(chains) == 2
    assert chains[0] == ["statement3", "statement2", "statement1"]
    assert chains[1] == ["statement4", "statement5", "statement1"]
Ejemplo n.º 11
0
    def collect_metadata_statements(self, self_signed_statement,
                                    metadata_type):
        """

        :param self_signed_statement: A Self signed Entity Statement
        :param metadata_type: One of the metadata types defined in the specification
        :return:
        """
        payload = self.get_payload(self_signed_statement)

        # collect trust chains
        _tree = self.collect_statement_chains(payload['iss'], payload)
        _node = {payload['iss']: (self_signed_statement, _tree)}
        _chains = branch2lists(_node)

        # verify the trust paths and apply policies
        return [eval_chain(c, self.keyjar, metadata_type) for c in _chains]
Ejemplo n.º 12
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
        """
        _context = self.client_get("service_context")
        _fe = _context.federation_entity
        _fe_ctx = _fe.context
        # Can not collect trust chain. Have to verify the signed JWT with keys I have

        kj = _fe_ctx.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)

        logger.debug("trust_anchor_id: {}".format(_trust_anchor_id))
        chosen = None
        for op_statement in _fe_ctx.op_statements:
            if op_statement.anchor == _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
        logger.debug("OP claims: {}".format(op_claims))
        # _sc.trust_path = (chosen.anchor, _fe.op_paths[statement.anchor][0])
        _context.provider_info = ProviderConfigurationResponse(**op_claims)

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

        _node = {_fe_ctx.entity_id: (resp, tree)}
        chains = branch2lists(_node)
        logger.debug("%d chains", len(chains))
        logger.debug("Evaluate policy chains")
        # Get the policies
        policy_chains_tup = [eval_policy_chain(c, _fe_ctx.keyjar, _fe_ctx.entity_type) for c in chains]
        # Weed out unusable chains
        policy_chains_tup = [pct for pct in policy_chains_tup if pct is not None]
        # Should leave me with one. The one ending in the chosen trust anchor.
        policy_chains_tup = [pct for pct in policy_chains_tup if pct[0] == _trust_anchor_id]

        if policy_chains_tup == []:
            logger.warning("No chain that ends in chosen trust anchor (%s)", _trust_anchor_id)
            raise ValueError("No trust chain that ends in chosen trust anchor (%s)",
                             _trust_anchor_id)

        _policy = combine_policy(policy_chains_tup[0][1],
                                 entity_statement['metadata_policy'][_fe_ctx.entity_type])
        logger.debug("Effective policy: {}".format(_policy))
        _req = kwargs.get("request")
        if _req is None:
            _req = kwargs.get("request_body")
        _uev = unverified_entity_statement(_req)
        logger.debug("Registration request: {}".format(_uev))
        _query = _uev["metadata"][_fe_ctx.entity_type]
        _resp = apply_policy(_query, _policy)
        _context.set("registration_response", _resp)
        return _resp