Exemple #1
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
Exemple #2
0
    def test_discovery(self):
        stmts = self.create_statements()

        with responses.RequestsMock() as rsps:
            _url = "https://op.ntnu.no/.well-known/openid-federation?iss=https%3A%2F%2Fop.ntnu.no"
            rsps.add("GET", _url, body=stmts['subj_sesi'], status=200)

            _url = "https://ntnu.no/.well-known/openid-federation"
            rsps.add("GET", _url, body=stmts['inter_sesi'], status=200)

            _url = "https://feide.no/.well-known/openid-federation"
            rsps.add("GET", _url, body=stmts['fedop1_sesi'], status=200)

            _url = "https://swamid.se/.well-known/openid-federation"
            rsps.add("GET", _url, body=stmts['fedop2_sesi'], status=200)

            _url = 'https://ntnu.no/api?iss=https://ntnu.no&sub=https%3A%2F%2Fop.ntnu.no'
            rsps.add("GET", _url, body=stmts['inter_on_sub'], status=200)

            _url = 'https://feide.no/api?iss=https%3A%2F%2Ffeide.no&sub=https%3A%2F%2Fntnu.no'
            rsps.add("GET", _url, body=stmts['fedop1_on_inter'], status=200)

            _url = "https://swamid.se/api?iss=https%3A%2F%2Fswamid.se&sub=https%3A%2F%2Fntnu.no"
            rsps.add("GET", _url, body=stmts['fedop2_on_inter'], status=200)

            auth_req = self.rph1.begin('ntnu')

        iss = self.rph1.hash2issuer['ntnu']
        rp = self.rph1.issuer2rp[iss]
        assert set(auth_req.keys()) == {'state', 'url'}
        p = urlparse(auth_req['url'])
        info = parse_qs(p.query)
        payload = unverified_entity_statement(info["request"][0])
        assert payload['client_id'] == rp.client_get("service_context").federation_entity.entity_id
        # assert iss in payload['aud']

        _federation_dump = rp.client_get("service_context").federation_entity.dump()

        rp2 = self.rph2.init_client(iss)
        rp2.client_get("service_context").federation_entity.load(_federation_dump)
        c = rp2.client_get("service_context").federation_entity.collector

        assert set(c.config_cache.keys()) == {'https://ntnu.no', 'https://feide.no',
                                              'https://swamid.se'}
        assert set(c.entity_statement_cache.keys()) == {
            'https://feide.no!!https://ntnu.no',
            'https://feide.no!exp!https://ntnu.no',
            'https://ntnu.no!!https://op.ntnu.no',
            'https://ntnu.no!exp!https://op.ntnu.no',
            'https://swamid.se!!https://ntnu.no',
            'https://swamid.se!exp!https://ntnu.no'}
    def test_collect_intermediate(self):
        _collector = self.endpoint.server_get(
            "endpoint_context").federation_entity.collector
        subject = 'https://op.ntnu.no'
        intermediate = 'https://ntnu.no'
        fedop1 = 'https://feide.no'
        fedop2 = 'https://swamid.se'
        # self-signed from subject
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(subject))
        subj_sesi = es_api.create_entity_statement(get_netloc(subject))
        # self-signed from intermediate
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(intermediate))
        inter_sesi = es_api.create_entity_statement(get_netloc(intermediate))
        # self-signed from fedop
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(fedop1))
        fedop_sesi_1 = es_api.create_entity_statement(get_netloc(fedop1))
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(fedop2))
        fedop_sesi_2 = es_api.create_entity_statement(get_netloc(fedop2))

        # intermediate on subject
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(intermediate))
        inter_on_sub = es_api.create_entity_statement(get_netloc(subject))
        # fedop on intermediate
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(fedop1))
        fedop_on_inter_1 = es_api.create_entity_statement(
            get_netloc(intermediate))
        es_api = FSEntityStatementAPI(ROOT_DIR, iss=get_netloc(fedop2))
        fedop_on_inter_2 = es_api.create_entity_statement(
            get_netloc(intermediate))

        sleep(1)

        with responses.RequestsMock() as rsps:
            _url = "{}/.well-known/openid-federation".format(intermediate)
            rsps.add("GET", _url, body=inter_sesi, status=200)

            _url = "{}/.well-known/openid-federation".format(fedop1)
            rsps.add("GET", _url, body=fedop_sesi_1, status=200)

            _url = "{}/.well-known/openid-federation".format(fedop2)
            rsps.add("GET", _url, body=fedop_sesi_2, status=200)

            _url = 'https://ntnu.no/api?iss=https%3A%2F%2Fntnu.no&sub=https%3A%2F%2Fop.ntnu.no'
            rsps.add("GET", _url, body=inter_on_sub, status=200)

            _url = 'https://feide.no/api?iss=https%3A%2F%2Ffeide.no&sub=https%3A%2F%2Fntnu.no'
            rsps.add("GET", _url, body=fedop_on_inter_1, status=200)

            _url = 'https://swamid.se/api?iss=https%3A%2F%2Fswamid.se&sub=https%3A%2F%2Fntnu.no'
            rsps.add("GET", _url, body=fedop_on_inter_2, status=200)

            tree = _collector.collect_intermediate(subject, 'https://ntnu.no')
            assert tree

        assert len(_collector.config_cache) == 3
        assert set(_collector.config_cache.keys()) == {
            'https://ntnu.no', 'https://feide.no', 'https://swamid.se'
        }

        # The unpacked fedop1's self signed entity statement
        _info = _collector.config_cache['https://feide.no']
        assert _info['sub'] == fedop1
        assert _info['iss'] == fedop1
        assert _info['metadata']['federation_entity'][
            'federation_api_endpoint'] == 'https://feide.no/api'

        # For each entity statement there is also the expiration time
        assert len(_collector.entity_statement_cache) == 6
        assert set(_collector.entity_statement_cache.keys()) == {
            'https://feide.no!!https://ntnu.no',
            'https://feide.no!exp!https://ntnu.no',
            'https://ntnu.no!!https://op.ntnu.no',
            'https://ntnu.no!exp!https://op.ntnu.no',
            'https://swamid.se!!https://ntnu.no',
            'https://swamid.se!exp!https://ntnu.no'
        }

        # have a look at the payload
        _info = unverified_entity_statement(
            _collector.
            entity_statement_cache['https://swamid.se!!https://ntnu.no'])
        assert _info['sub'] == intermediate
        assert _info['iss'] == fedop2
        assert _info['authority_hints'] == [fedop2]

        _collector_dump = _collector.dump()

        _c2 = Collector()
        _c2.load(_collector_dump)

        assert len(_c2.config_cache) == 3
        assert set(_c2.config_cache.keys()) == {
            'https://ntnu.no', 'https://feide.no', 'https://swamid.se'
        }

        # The unpacked fedop1's self signed entity statement
        _info = _c2.config_cache['https://feide.no']
        assert _info['sub'] == fedop1
        assert _info['iss'] == fedop1
        assert _info['metadata']['federation_entity'][
            'federation_api_endpoint'] == 'https://feide.no/api'

        # For each entity statement there is also the expiration time
        assert len(_c2.entity_statement_cache) == 6
        assert set(_c2.entity_statement_cache.keys()) == {
            'https://feide.no!!https://ntnu.no',
            'https://feide.no!exp!https://ntnu.no',
            'https://ntnu.no!!https://op.ntnu.no',
            'https://ntnu.no!exp!https://op.ntnu.no',
            'https://swamid.se!!https://ntnu.no',
            'https://swamid.se!exp!https://ntnu.no'
        }

        # have a look at the payload
        _info = unverified_entity_statement(
            _c2.entity_statement_cache['https://swamid.se!!https://ntnu.no'])
        assert _info['sub'] == intermediate
        assert _info['iss'] == fedop2
        assert _info['authority_hints'] == [fedop2]
Exemple #4
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