Ejemplo n.º 1
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]
Ejemplo n.º 2
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]
Ejemplo n.º 3
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