Exemplo n.º 1
0
def test_collect_configuration():
    collector = Collector(trust_anchors=ANCHOR,
                          http_cli=requests.request,
                          insecure=True)

    with responses.RequestsMock() as rsps:
        rsps.add(rsps.GET,
                 "https://foodle.uninett.no/.well-known/openid-federation",
                 status=404)
        # Get the self-signed entity statement from a leaf
        with pytest.raises(MissingPage):
            collector.get_configuration_information(
                "https://foodle.uninett.no")
Exemplo n.º 2
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")
def test_collect():
    jwks = open(
        os.path.join(BASE_PATH, 'base_data', 'feide.no', 'feide.no',
                     'jwks.json')).read()

    ANCHOR = {'https://feide.no': json.loads(jwks)}

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

    chain = []
    _collector = Collector(trust_anchors=ANCHOR)
    subject = "foodle.uninett.no"
    with responses.RequestsMock() as rsps:
        _msg = open(
            os.path.join(BASE_PATH, 'base_data', subject, subject,
                         'jws')).read()
        rsps.add(rsps.GET,
                 "https://foodle.uninett.no/.well-known/openid-federation",
                 body=_msg)
        # Get the self-signed entity statement from a leaf
        _self_signed = _collector.get_configuration_information(
            "https://foodle.uninett.no")

    chain.append(_self_signed)
    _statement = verify_self_signed_signature(_self_signed)
    assert _statement
    authority = ""

    while authority not in _collector.trusted_anchors:
        authority = _statement['authority_hints'][0]
        netloc = authority[8:]
        with responses.RequestsMock() as rsps:
            _msg = open(
                os.path.join(BASE_PATH, 'base_data', netloc, netloc,
                             "jws")).read()
            _url = "https://{}/.well-known/openid-federation".format(netloc)
            rsps.add(rsps.GET, _url, body=_msg)
            # Get the self-signed entity statement from a leaf
            _self_signed = _collector.get_configuration_information(authority)

        _statement = verify_self_signed_signature(_self_signed)
        assert _statement

        _api_endpoint = _statement['metadata']['federation_entity'][
            'federation_api_endpoint']

        with responses.RequestsMock() as rsps:
            _msg = open(
                os.path.join(BASE_PATH, 'base_data', netloc, subject,
                             "jws")).read()
            _url = construct_entity_statement_query(
                _api_endpoint, authority, "https://{}".format(subject))
            rsps.add(rsps.GET, _url, body=_msg)
            # Get the self-signed entity statement from a leaf
            _signed_statement = _collector.get_entity_statement(
                _api_endpoint, authority, "https://{}".format(subject))
            chain.append(_signed_statement)
            _jwt = factory(_signed_statement)
            _statement = _jwt.jwt.payload()
            subject = _statement['iss'][8:]

    # Now I have the chain should be 3 items in it
    assert len(chain) == 3

    # verify the trust chain
    chain.reverse()
    verified_chain = verify_trust_chain(chain, KEYJAR)
    # The result is the verified statements
    assert len(verified_chain) == 3
    # Check that the constraints are met
    assert meets_restrictions(verified_chain)
Exemplo n.º 4
0
class FederationEntity(OidcContext):
    def __init__(self,
                 entity_id,
                 trusted_roots,
                 authority_hints=None,
                 default_lifetime=86400,
                 httpd=None,
                 priority=None,
                 entity_type='',
                 opponent_entity_type='',
                 registration_type='',
                 cwd='',
                 httpc_params=None,
                 config=None):
        OidcContext.__init__(self, config, entity_id=entity_id)
        self.collector = Collector(trust_anchors=trusted_roots,
                                   http_cli=httpd,
                                   cwd=cwd,
                                   httpc_params=httpc_params,
                                   db_conf=self.db_conf)
        self.entity_id = entity_id
        self.entity_type = entity_type
        self.opponent_entity_type = opponent_entity_type

        for iss, jwks in trusted_roots.items():
            self.keyjar.import_jwks(jwks, iss)

        self.authority_hints = authority_hints
        self.default_lifetime = default_lifetime
        self.tr_priority = priority or sorted(set(trusted_roots.keys()))
        self.registration_type = registration_type

    def collect_statement_chains(self, entity_id, statement):
        return self.collector.collect_superiors(entity_id, statement)

    def eval_chains(self, chains, entity_type='', apply_policies=True):
        """

        :param chains: A list of lists of signed JWT
        :param entity_type: The leafs entity type
        :param apply_policies: Apply metadata policies from the list on the the metadata of the
            leaf entity
        :return: List of Statement instances
        """
        if not entity_type:
            entity_type = self.opponent_entity_type

        return [
            eval_chain(c, self.keyjar, entity_type, apply_policies)
            for c in chains
        ]

    def create_entity_statement(self,
                                iss,
                                sub,
                                key_jar=None,
                                metadata=None,
                                metadata_policy=None,
                                authority_hints=None,
                                lifetime=0,
                                **kwargs):
        if not key_jar:
            key_jar = self.keyjar
        if not authority_hints:
            authority_hints = self.authority_hints
        if not lifetime:
            lifetime = self.default_lifetime

        return create_entity_statement(iss,
                                       sub,
                                       key_jar=key_jar,
                                       metadata=metadata,
                                       metadata_policy=metadata_policy,
                                       authority_hints=authority_hints,
                                       lifetime=lifetime,
                                       **kwargs)

    def get_configuration_information(self, subject_id):
        return self.collector.get_configuration_information(subject_id)

    def pick_metadata(self, statements):
        """
        Pick one statement out of the list of possible statements

        :param statements: A list of :py:class:`fedservice.entity_statement.statement.Statement
            instances
        :return: A :py:class:`fedservice.entity_statement.statement.Statement instance
        """
        if len(statements) == 1:
            # right now just pick the first:
            return statements[0]
        else:
            for fid in self.tr_priority:
                for statement in statements:
                    if statement.fo == fid:
                        return statement

        # Can only arrive here if the federations I got back and trust are not
        # in the priority list. So, just pick one

        return statements[0]

    def get_payload(self, self_signed_statement):
        _jws = as_unicode(self_signed_statement)
        _jwt = factory(_jws)
        return _jwt.jwt.payload()

    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]
Exemplo n.º 5
0
class FederationEntity(OidcContext):
    parameter = OidcContext.parameter.copy()
    parameter.update({
        "entity_type": "",
        "opponent_entity_type": "",
        "registration_type": "",
        "default_lifetime": 0,
        "httpc_params": {},
        "trusted_roots": {},
        "collector": Collector,
        "authority_hints": [],
        "tr_priority": []
    })

    def __init__(self,
                 entity_id="",
                 trusted_roots=None,
                 authority_hints=None,
                 default_lifetime=86400,
                 httpd=None,
                 priority=None,
                 entity_type='',
                 opponent_entity_type='',
                 registration_type='',
                 cwd='',
                 httpc_params=None,
                 config=None):
        if config is None:
            config = {}

        self.entity_id = entity_id or config["entity_id"]

        OidcContext.__init__(self, config, entity_id=self.entity_id)

        self.entity_type = entity_type or config.get("entity_type")
        self.opponent_entity_type = opponent_entity_type or config.get(
            "opponent_entity_type", "")
        self.registration_type = registration_type or config.get(
            "registration_type", "")
        self.default_lifetime = default_lifetime or config.get(
            "default_lifetime", 0)
        self.httpc_params = httpc_params or config.get("httpc_params", {})
        if not trusted_roots:
            trusted_roots = json.loads(open(config["trusted_roots"]).read())

        self.collector = Collector(trust_anchors=trusted_roots,
                                   http_cli=httpd,
                                   cwd=cwd,
                                   httpc_params=self.httpc_params)

        for iss, jwks in trusted_roots.items():
            self.keyjar.import_jwks(jwks, iss)

        if authority_hints is not None:
            self.authority_hints = authority_hints
        elif "authority_hints" in config:
            self.authority_hints = json.loads(
                open(config["authority_hints"]).read())
        else:
            raise ConfigurationError("Missing authority_hints specification")

        if priority:
            self.tr_priority = priority
        elif 'priority' in config:
            self.tr_priority = config["priority"]
        else:
            self.tr_priority = sorted(set(trusted_roots.keys()))

    def collect_statement_chains(self, entity_id, statement):
        return self.collector.collect_superiors(entity_id, statement)

    def eval_chains(self, chains, entity_type='', apply_policies=True):
        """

        :param chains: A list of lists of signed JWT
        :param entity_type: The leafs entity type
        :param apply_policies: Apply metadata policies from the list on the the metadata of the
            leaf entity
        :return: List of TrustChain instances
        """
        if not entity_type:
            entity_type = self.opponent_entity_type

        return [
            eval_chain(c, self.keyjar, entity_type, apply_policies)
            for c in chains
        ]

    def create_entity_statement(self,
                                iss,
                                sub,
                                key_jar=None,
                                metadata=None,
                                metadata_policy=None,
                                authority_hints=None,
                                lifetime=0,
                                **kwargs):
        if not key_jar:
            key_jar = self.keyjar
        if not authority_hints:
            authority_hints = self.authority_hints
        if not lifetime:
            lifetime = self.default_lifetime

        return create_entity_statement(iss,
                                       sub,
                                       key_jar=key_jar,
                                       metadata=metadata,
                                       metadata_policy=metadata_policy,
                                       authority_hints=authority_hints,
                                       lifetime=lifetime,
                                       **kwargs)

    def get_configuration_information(self, subject_id):
        return self.collector.get_configuration_information(subject_id)

    def pick_trust_chain(self, trust_chains):
        """
        Pick one trust chain out of the list of possible trust chains

        :param trust_chains: A list of :py:class:`fedservice.entity_statement.statement.TrustChain
            instances
        :return: A :py:class:`fedservice.entity_statement.statement.TrustChain instance
        """
        if len(trust_chains) == 1:
            # If there is only one, then use it
            return trust_chains[0]
        elif self.tr_priority:
            # Go by priority
            for fid in self.tr_priority:
                for trust_chain in trust_chains:
                    if trust_chain.anchor == fid:
                        return trust_chain

        # Can only arrive here if the federations I got back and trust are not
        # in the priority list. So, just pick one
        return trust_chains[0]

    def get_payload(self, self_signed_statement):
        _jws = as_unicode(self_signed_statement)
        _jwt = factory(_jws)
        return _jwt.jwt.payload()

    def collect_trust_chains(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)
        logger.debug("%s chains", len(_chains))

        # verify the trust paths and apply policies
        return [eval_chain(c, self.keyjar, metadata_type) for c in _chains]
Exemplo n.º 6
0
class FederationEntity(object):
    name = "federation_entity"

    def __init__(self,
                 entity_id: str = "",
                 config: Optional[Union[dict, Configuration]] = None,
                 httpc: Optional[Any] = None,
                 cwd: Optional[str] = '',
                 httpc_params: Optional[dict] = None):

        if config is None:
            config = {}

        if httpc is None:
            httpc = request

        if httpc_params is None:
            httpc_params = config.get("httpc_params", {})

        if not entity_id:
            entity_id = config.get("entity_id")

        self.context = FederationContext(config=config,
                                         entity_id=entity_id,
                                         server_get=self.server_get)

        self.collector = Collector(trust_anchors=self.context.trusted_roots,
                                   http_cli=httpc,
                                   cwd=cwd,
                                   httpc_params=httpc_params)

        if config.get("entity_id") is None:
            config['entity_id'] = entity_id

        if 'endpoint' in config:
            self.endpoint = do_endpoints(config, self.server_get)
        else:
            self.endpoint = {}

    def collect_statement_chains(self, entity_id, statement):
        return self.collector.collect_superiors(entity_id, statement)

    def eval_chains(self, chains, entity_type='', apply_policies=True):
        """

        :param chains: A list of lists of signed JWT
        :param entity_type: The leafs entity type
        :param apply_policies: Apply metadata policies from the list on the the metadata of the
            leaf entity
        :return: List of TrustChain instances
        """
        _context = self.context
        if not entity_type:
            entity_type = _context.opponent_entity_type

        return [
            eval_chain(c, _context.keyjar, entity_type, apply_policies)
            for c in chains
        ]

    def get_configuration_information(self, subject_id):
        return self.collector.get_configuration_information(subject_id)

    def pick_trust_chain(self, trust_chains):
        """
        Pick one trust chain out of the list of possible trust chains

        :param trust_chains: A list of :py:class:`fedservice.entity_statement.statement.TrustChain
            instances
        :return: A :py:class:`fedservice.entity_statement.statement.TrustChain instance
        """
        if len(trust_chains) == 1:
            # If there is only one, then use it
            return trust_chains[0]
        elif self.context.tr_priority:
            # Go by priority
            for fid in self.context.tr_priority:
                for trust_chain in trust_chains:
                    if trust_chain.anchor == fid:
                        return trust_chain

        # Can only arrive here if the federations I got back and trust are not
        # in the priority list. So, just pick one
        return trust_chains[0]

    def get_payload(self, self_signed_statement):
        _jws = as_unicode(self_signed_statement)
        _jwt = factory(_jws)
        return _jwt.jwt.payload()

    def collect_trust_chains(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)
        logger.debug("%s chains", len(_chains))

        # verify the trust paths and apply policies
        return [
            eval_chain(c, self.context.keyjar, metadata_type) for c in _chains
        ]

    def server_get(self, what, *arg):
        _func = getattr(self, "get_{}".format(what), None)
        if _func:
            return _func(*arg)
        return None

    def get_context(self, *arg):
        return self.context

    def get_endpoint_context(self, *arg):
        return self.context

    def federation_endpoint_metadata(self):
        _config = self.context.config
        metadata = {}
        # collect endpoints
        endpoints = {}
        for key, item in self.endpoint.items():
            if key in ["fetch", "list", "status", "evaluate"]:
                endpoints[f"federation_{key}_endpoint"] = item.full_path
        for attr in message.FederationEntity.c_param.keys():
            if attr in _config:
                metadata[attr] = _config[attr]
            elif attr in endpoints:
                metadata[attr] = endpoints[attr]
        return {"federation_entity": metadata}

    def get_metadata(self):
        _config = self.context.config
        return self.federation_endpoint_metadata()

    def get_endpoints(self, *arg):
        return self.endpoint

    def get_endpoint(self, endpoint_name, *arg):
        try:
            return self.endpoint[endpoint_name]
        except KeyError:
            return None

    def get_entity(self):
        return self

    def dump(self):
        return {
            "context": self.context.dump(),
            "collector": self.collector.dump()
        }

    def load(self, dump):
        self.collector.load(dump.get("collector", {}))
        self.context.load(dump.get("context", {}))

    def get_client_id(self):
        return self.context.entity_id
Exemplo n.º 7
0
    parser = argparse.ArgumentParser()
    parser.add_argument('-k', "--insecure", action='store_true')
    parser.add_argument('-t', "--trusted_roots")
    parser.add_argument('-e', dest='entity_id')
    parser.add_argument('-c', dest='config', action='store_true')
    parser.add_argument('-s', dest='sub', action='store_true')
    parser.add_argument('-a', dest='fed_api')
    args = parser.parse_args()

    kwargs = {}
    if args.insecure:
        kwargs['insecure'] = True
    if args.trusted_roots:
        kwargs['trust_anchors'] = args.trusted_roots
    else:
        kwargs["trust_anchors"] = {}

    _collector = Collector(**kwargs)

    _info = None
    if args.config:
        _jws = _collector.get_configuration_information(args.entity_id)
        entity_statement = verify_self_signed_signature(_jws)
        json_str = json.dumps(entity_statement, indent=2)
        print(highlight(json_str, JsonLexer(), TerminalFormatter()))

    if args.sub:
        _info = _collector.get_entity_statement(args.fed_api, args.entity_id, args.sub)