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]
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 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' }
def test_get_configuration_information(): 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')) _jws = collector.get_configuration_information(target) entity_statement = verify_self_signed_signature(_jws) assert entity_statement['iss'] == target assert entity_statement['sub'] == target assert 'metadata' in entity_statement
def test_get_entity_statement(): 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')) _jws = collector.get_entity_statement( api_endpoint='https://foodle.uninett.no/fed_api', issuer=entity_id, subject=target) msg = verify_self_signed_signature(_jws) assert msg['iss'] == entity_id assert msg['sub'] == target
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)
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)
def test_get_configuration_information(self): entity_id = 'https://foodle.uninett.no' _jws = self.fedent.get_configuration_information(entity_id) msg = verify_self_signed_signature(_jws) assert msg['iss'] == entity_id
logger = configure_logging(config=LOGGING).getChild(__name__) trusted_roots = json.loads(open(args.trusted_roots_file).read()) # Creates an entity that can do the collecting of information federation_entity = FederationEntity( 'issuer', trusted_roots=trusted_roots, entity_type=args.entity_type, opponent_entity_type=args.opponent_entity_type) if args.insecure: federation_entity.collector.insecure = args.insecure jws = federation_entity.get_configuration_information(args.url) metadata = verify_self_signed_signature(jws) _tree = federation_entity.collect_statement_chains(metadata['iss'], metadata) chains = branch2lists(_tree) for c in chains: c.append(jws) statements = [ eval_chain(c, federation_entity.keyjar, args.opponent_entity_type) for c in chains ] for statement in statements: print(20 * "=", statement.fo, 20 * "=") for node in statement.verified_chain: