def verify(self, **kwargs): """ Verifies that an instance of this class adhers to the given restrictions. """ super(MetadataStatement, self).verify(**kwargs) if "signing_keys" in self: if 'signing_keys_uri' in self: raise VerificationError( 'You can only have one of "signing_keys" and ' '"signing_keys_uri" in a metadata statement') else: # signing_keys MUST be a JWKS kj = KeyJar() try: kj.import_jwks(self['signing_keys'], '') except Exception: raise VerificationError('"signing_keys" not a proper JWKS') if "metadata_statements" in self and "metadata_statement_uris" in self: s = set(self['metadata_statements'].keys()) t = set(self['metadata_statement_uris'].keys()) if s.intersection(t): raise VerificationError( 'You should not have the same key in "metadata_statements" ' 'and in "metadata_statement_uris"') return True
def loads(self, jstr): _info = json.loads(jstr) for iss, jwks in _info.items(): kj = KeyJar() kj.import_jwks(jwks, issuer=iss) self.bundle[iss] = kj return self
def __setitem__(self, key, value): """ :param key: issuer ID :param value: Supposed to be KeyJar or a JWKS (JSON document) """ if not isinstance(value, KeyJar): kj = KeyJar() kj.import_jwks(value, issuer=key) value = kj else: _val = value.copy() _iss = list(_val.keys()) if _iss == ['']: _val.issuer_keys[key] = _val.issuer_keys[''] del _val.issuer_keys[''] elif len(_iss) == 1: if _iss[0] != key: _val.issuer_keys[key] = _val.issuer_keys[_iss[0]] del _val.issuer_keys[_iss[0]] else: raise ValueError('KeyJar contains to many issuers') value = _val self.bundle[key] = value
def __setitem__(self, key, value): """ :param key: issuer ID :type: String :param value: Cryptographic keys that should be connected to to an issuer ID. :type value: KeyJar or a JWKS (JSON document) """ if not isinstance(value, KeyJar): kj = KeyJar() kj.import_jwks(value, issuer=key) value = kj else: _val = value.copy() _iss = list(_val.keys()) if _iss == ['']: _val.issuer_keys[key] = _val.issuer_keys[''] del _val.issuer_keys[''] elif len(_iss) == 1: if _iss[0] != key: _val.issuer_keys[key] = _val.issuer_keys[_iss[0]] del _val.issuer_keys[_iss[0]] else: raise ValueError('KeyJar contains to many issuers') value = _val self.bundle[key] = value
def test_get_signing_key_use_undefined(): kj = KeyJar() kj.import_jwks(JWK1, "") keys = kj.get_signing_key(kid="rsa1") assert len(keys) == 1 keys = kj.get_signing_key(key_type="rsa") assert len(keys) == 1 keys = kj.get_signing_key(key_type="rsa", kid="rsa1") assert len(keys) == 1
def test_get_signing_key_use_undefined(): kj = KeyJar() kj.import_jwks(JWK1, '') keys = kj.get_signing_key(kid='rsa1') assert len(keys) == 1 keys = kj.get_signing_key(key_type='rsa') assert len(keys) == 1 keys = kj.get_signing_key(key_type='rsa', kid='rsa1') assert len(keys) == 1
class KeyBundle(keyio.KeyBundle): def __init__(self, keys=None, source="", cache_time=300, verify_ssl=True, fileformat="jwk", keytype="RSA", keyusage=None, verify_keys=None): super(KeyBundle, self).__init__(keys=keys, source=source, cache_time=cache_time, verify_ssl=verify_ssl, fileformat=fileformat, keytype=keytype, keyusage=keyusage) if verify_keys is not None: if isinstance(verify_keys, KeyJar): self.verify_keys = verify_keys else: self.verify_keys = KeyJar() self.verify_keys.import_jwks(verify_keys, '') def _parse_remote_response(self, response): """ Parse simple JWKS or signed JWKS from the HTTP response. :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri' endpoint :return: response parsed as JSON """ # Check if the content type is the right one. try: if response.headers["Content-Type"] == 'application/json': logger.debug("Loaded JWKS: %s from %s" % (response.text, self.source)) try: return json.loads(response.text) except ValueError: return None elif response.headers["Content-Type"] == 'application/jose': logger.debug("Signed JWKS: %s from %s" % (response.text, self.source)) _jws = factory(response.text) _resp = _jws.verify_compact( response.text, keys=self.verify_keys.get_signing_key()) return _resp else: logger.error('Wrong content type: {}'.format( response.headers['Content-Type'])) return None except KeyError: pass
def test_create_verify(): jb = JWKSBundle('iss', SignKeyJar) for iss, op in OPERATOR.items(): jb[op.iss] = op.keyjar _jws = jb.create_signed_bundle() _jwks = SignKeyJar.export_jwks() kj = KeyJar() kj.import_jwks(_jwks, 'iss') bundle = verify_signed_bundle(_jws, kj) assert bundle
def loads(self, jstr): """ Upload a bundle from a string :param jstr: :return: """ _info = json.loads(jstr) for iss, jwks in _info.items(): kj = KeyJar() kj.import_jwks(jwks, issuer=iss) self.bundle[iss] = kj return self
def read_jwks_file(jwks_file): """ Reads a file containing a JWKS and populates a oic.utils.keyio.KeyJar from it. :param jwks_file: file name of the JWKS file :return: A oic.utils.keyio.KeyJar instance """ _jwks = open(jwks_file, 'r').read() _kj = KeyJar() _kj.import_jwks(json.loads(_jwks), '') return _kj
def keyjar_from_metadata_statements(iss, msl): """ Builds a keyJar instance based on the information in the 'signing_keys' claims in a list of metadata statements. :param iss: Owner of the signing keys :param msl: List of :py:class:`MetadataStatement` instances. :return: A oic.utils.keyio.KeyJar instance """ keyjar = KeyJar() for ms in msl: keyjar.import_jwks(ms['signing_keys'], iss) return keyjar
def get_signing_keys(iss, keydef, key_file): if os.path.isfile(key_file): kj = KeyJar() kj.import_jwks(json.loads(open(key_file, 'r').read()), iss) else: kj = build_keyjar(keydef)[1] # make it know under both names fp = open(key_file, 'w') fp.write(json.dumps(kj.export_jwks())) fp.close() kj.issuer_keys[iss] = kj.issuer_keys[''] return kj
def get_fo_keyjar_from_dir(self): try: fetched_jwks, _mtime = self.get_files_from_dir(self.fo_jwks_dir, self.jwks_mtime) except Exception as err: logger.error(err) else: _kj = KeyJar() for iss, jwks in fetched_jwks.items(): _kj.import_jwks(json.loads(jwks), unquote_plus(iss)) self.fo_keyjar = _kj self.jwks_mtime = _mtime
def own_sign_keys(sigkey_name, issuer, sig_def_keys): try: jwks = json.loads(open(sigkey_name, 'r').read()) sign_kj = KeyJar() sign_kj.import_jwks(jwks, issuer) except FileNotFoundError: jwks, sign_kj, _ = build_keyjar(sig_def_keys) sign_kj.issuer_keys[issuer] = sign_kj.issuer_keys[''] fp = open(sigkey_name, 'w') fp.write(json.dumps(sign_kj.export_jwks(private=True, issuer=issuer))) fp.close() return sign_kj
def test_create_verify(): sign_keyjar = build_keyjar(KEYDEFS)[1] jb = make_jwks_bundle('https://example.com', ['fo0', 'fo1', 'fo2', 'fo3'], sign_keyjar, KEYDEFS) _jws = jb.create_signed_bundle() _jwks = sign_keyjar.export_jwks() kj = KeyJar() kj.import_jwks(_jwks, 'https://example.com') bundle = verify_signed_bundle(_jws, kj) assert bundle
def jwks_to_keyjar(jwks): """ :param jwks: String representation of a JWKS :return: A KeyJar instance """ try: _jwks = json.loads(jwks) except json.JSONDecodeError: raise ValueError('No proper JWKS') kj = KeyJar() kj.import_jwks(_jwks, issuer='') return kj
def loads(self, jstr): """ Upload a bundle from an unsigned JSON document :param jstr: A bundle as a dictionary or a JSON document """ if isinstance(jstr, dict): _info = jstr else: _info = json.loads(jstr) for iss, jwks in _info.items(): kj = KeyJar() kj.import_jwks(jwks, issuer=iss) self.bundle[iss] = kj return self
def jwks_to_keyjar(jwks, iss=''): """ Convert a JWKS to a KeyJar instance. :param jwks: String representation of a JWKS :return: A :py:class:`oic.utils.keyio.KeyJar` instance """ if not isinstance(jwks, dict): try: jwks = json.loads(jwks) except json.JSONDecodeError: raise ValueError('No proper JSON') kj = KeyJar() kj.import_jwks(jwks, issuer=iss) return kj
def get_jwks(path, private_path): if os.path.isfile(private_path): _jwks = open(path, 'r').read() _kj = KeyJar() _kj.import_jwks(json.loads(_jwks), '') else: _kj = build_keyjar(config.ENT_KEYS)[1] jwks = _kj.export_jwks(private=True) fp = open(private_path, 'w') fp.write(json.dumps(jwks)) fp.close() jwks = _kj.export_jwks() # public part fp = open(path, 'w') fp.write(json.dumps(jwks)) fp.close() return _kj
def index(self, iss, jwks, ms, **kwargs): _kj = KeyJar() _kj.import_jwks(json.loads(jwks), iss) op = Operator() try: _pi = op.unpack_metadata_statement(jwt_ms=ms, keyjar=_kj, cls=MetadataStatement) response = json.dumps(_pi.result.to_dict(), sort_keys=True, indent=2, separators=(',', ': ')) cherrypy.response.headers['Content-Type'] = 'text/plain' return as_bytes(response) except (RegistrationError, ParameterError, MissingSigningKey) as err: raise cherrypy.HTTPError( 400, as_bytes('Invalid Metadata statement: {}'.format(err)))
def get_signed_keys(self, uri, signing_keys): """ :param uri: Where the signed JWKS can be found :param signing_keys: Dictionary representation of a JWKS :return: list of KeyBundle instances or None """ r = self.server.http_request(uri, allow_redirects=True) if r.status_code == 200: _skj = KeyJar() _skj.import_jwks(signing_keys, '') _jws = factory(r.text) _jwks = _jws.verify_compact(r.text, Keys=_skj.get_signing_key()) _kj = KeyJar() _kj.import_jwks(json.loads(_jwks), '') return _kj.issuer_keys[''] else: return None
def bundle2keyjar(): url = 'https://localhost:8080/bundle' r = requests.get(url, verify=False) assert r.status_code == 200 _bundle = r.text url = 'https://localhost:8080/bundle/sigkey' r = requests.get(url, verify=False) assert r.status_code == 200 _sigkey_jwks = json.loads(as_unicode(r.text)) kj = KeyJar() kj.import_jwks(_sigkey_jwks, '') _ver_bundle = JWS().verify_compact(_bundle, kj.get_verify_key()) jwks_dir = _ver_bundle['bundle'] for iss, jwks in jwks_dir.items(): kj.import_jwks(jwks, iss) return kj
def get_signing_keys(eid, keydef, key_file): """ If the *key_file* file exists then read the keys from there, otherwise create the keys and store them a file with the name *key_file*. :param eid: The ID of the entity that the keys belongs to :param keydef: What keys to create :param key_file: A file name :return: A KeyJar instance """ if os.path.isfile(key_file): kj = KeyJar() kj.import_jwks(json.loads(open(key_file, 'r').read()), eid) else: kj = build_keyjar(keydef)[1] # make it know under both names fp = open(key_file, 'w') fp.write(json.dumps(kj.export_jwks())) fp.close() kj.issuer_keys[eid] = kj.issuer_keys[''] return kj
def create_client(self): """Create the OpenIDConnect client from the data stored in the contest object, and store some information in this handler object. """ oic_info = json.loads(self.contest.openidconnect_info) self.redirect_uri = ( self.request.protocol + "://" + self.request.host + self.request.path) self.op_info = oic_info["op_info"] self.client_info = oic_info["client_info"] self.client_info["redirect_uris"] = [self.redirect_uri] self.jwks = oic_info["jwks"] keyjar = KeyJar() keyjar.import_jwks(self.jwks, self.op_info["issuer"]) self.client = Client( client_authn_method=CLIENT_AUTHN_METHOD, keyjar=keyjar) self.client.provider_info = \ ProviderConfigurationResponse(**self.op_info) self.client.store_registration_info( RegistrationResponse(**self.client_info))
def verify(self, **kwargs): if "signing_keys" in self: if 'signing_keys_uri' in self: raise VerificationError( 'You can only have one of "signing_keys" and ' '"signing_keys_uri" in a metadata statement') else: # signing_keys MUST be a JWKS kj = KeyJar() try: kj.import_jwks(self['signing_keys'], '') except Exception: raise VerificationError('"signing_keys" not a proper JWKS') elif not 'signing_keys_uri' in self: raise VerificationError( ' You must have one of "signing_keys" or ' '"signing_keys_uri" in a metadata statement') if "metadata_statements" in self and "metadata_statement_uris" in self: raise VerificationError( 'You can only have one of "metadata_statements" and ' '"metadata_statement_uris" in a metadata statement') return True
def test_import_jwks(): kj = KeyJar() kj.import_jwks(JWK1, '') assert len(kj.get_issuer_keys('')) == 2
def test_load_spomky_keys(): kj = KeyJar() kj.import_jwks(JWKS_SPO, '') assert len(kj.get_issuer_keys('')) == 4
def test_load_unknown_keytype(): kj = KeyJar() kj.import_jwks(JWK_UK, '') assert len(kj.get_issuer_keys('')) == 1
def fo_member(*args): _kj = KeyJar() for fo in args: _kj.import_jwks(fo.jwks, fo.iss) return Operator(fo_keyjar=_kj)
def keyjar_from_metadata_statements(iss, msl): keyjar = KeyJar() for ms in msl: keyjar.import_jwks(ms['signing_keys'], iss) return keyjar
from fedoidc.signing_service import Signer from oic.utils.keyio import KeyJar parser = argparse.ArgumentParser() parser.add_argument('-i', dest='issuer', help="issuer id of the OP") parser.add_argument('-c', dest='context', help="OIDC operation") parser.add_argument('-t', dest='target') parser.add_argument(dest="filename") args = parser.parse_args() oa = args.issuer qpoa = quote_plus(oa) _kj = KeyJar() _jwks = json.loads(open(os.path.join('fo_jwks', qpoa)).read()) _kj.import_jwks(_jwks, oa) sign_serv = InternalSigningService(iss=oa, signing_keys=_kj) signer = Signer(sign_serv, ms_dir=os.path.join('ms', qpoa)) _req = open(args.filename, 'r').read() _msg = MetadataStatement() _msg.from_json(_req) _res = signer.create_signed_metadata_statement(_msg, context=args.context) for iss, sms in _res.items(): _qp = quote_plus(iss) _dn = os.path.join(args.target, qpoa, args.context) if not os.path.isdir(_dn): os.makedirs(_dn) _fn = os.path.join(_dn, _qp) _fp = open(_fn, 'w')
def fo_keyjar(*args): _kj = KeyJar() for fo in args: _kj.import_jwks(fo.jwks, fo.iss) return _kj
def test_load_null_jwks(): kj = KeyJar() with pytest.raises(JWKSError): kj.import_jwks({'keys': [None, None]}, '')
# parser.add_argument(dest="config") args = parser.parse_args() _flows = Flow(args.flowsdir, profile_handler=None) tests = _flows.keys() # Get the necessary information about the JWKS bundle info = {} for path in ['bundle', 'bundle/signer', 'bundle/sigkey']: _url = "{}/{}".format(tool_url, path) resp = requests.request('GET', _url, verify=False) info[path] = resp.text # Create a KeyJar instance that contains the key that the bundle was signed with kj = KeyJar() kj.import_jwks(json.loads(info['bundle/sigkey']), info['bundle/signer']) # Create a JWKSBundle instance and load it with the keys in the bundle # I got from the tool jb = JWKSBundle('') jb.upload_signed_bundle(info['bundle'], kj) # This is for the federation entity to use when signing something # like the keys at jwks_uri. _kj = build_keyjar(KEY_DEFS)[1] SIGNERS = [ 'https://swamid.sunet.se', 'https://edugain.com', 'https://www.feide.no' ] # A dictionary of web based signers sig = {}
def test_load_jwks_wrong_argtype(): kj = KeyJar() with pytest.raises(JWKSError): kj.import_jwks(JWKS_ERR_1, '')