Esempio n. 1
0
def test_verify_token_encrypted_no_key():
    idt = IdToken(
        sub="553df2bcf909104751cfd8b2",
        aud=["5542958437706128204e0000", "554295ce3770612820620000"],
        auth_time=1441364872,
        azp="554295ce3770612820620000",
    )
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(
        os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"),
        "some",
        ["enc", "sig"],
    )
    kj.add_kb("", kb)
    kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb)

    packer = JWT(
        kj,
        lifetime=3600,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        encrypt=True,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    # Do not pass they keyjar with keys
    with pytest.raises(VerificationError):
        verify_id_token(
            msg,
            keyjar=KeyJar(),
            iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
            client_id="554295ce3770612820620000",
        )
Esempio n. 2
0
    def _create_op(self, issuer, endpoint_baseurl, jwks_uri):
        """
        Create the necessary Provider instance.
        :type issuer: str
        :type endpoint_baseurl: str
        :type jwks_uri: str
        :param issuer: issuer URL for the OP
        :param endpoint_baseurl: baseurl to build endpoint URL from
        :param jwks_uri: URL to where the JWKS will be published
        """
        kj = KeyJar()
        signing_key = KeyBundle(source="file://{}".format(self.conf["signing_key_path"]),
                                fileformat="der", keyusage=["sig"])
        kj.add_kb("", signing_key)
        capabilities = {
            "response_types_supported": ["id_token"],
            "id_token_signing_alg_values_supported": [self.sign_alg],
            "response_modes_supported": ["fragment", "query"],
            "subject_types_supported": ["public", "pairwise"],
            "grant_types_supported": ["implicit"],
            "claim_types_supported": ["normal"],
            "claims_parameter_supported": True,
            "request_parameter_supported": False,
            "request_uri_parameter_supported": False,
        }

        if "client_db_path" in self.conf:
            cdb = shelve_wrapper.open(self.conf["client_db_path"])
        else:
            cdb = {}  # client db in memory only

        self.provider = Provider(issuer, None, cdb, None, None, None, None, None, keyjar=kj,
                                 capabilities=capabilities, jwks_uri=jwks_uri)
        self.provider.baseurl = endpoint_baseurl
        self.provider.endp = [RegistrationEndpoint, AuthorizationEndpoint]
Esempio n. 3
0
def test_verify_token_encrypted():
    idt = IdToken(
        sub="553df2bcf909104751cfd8b2",
        aud=["5542958437706128204e0000", "554295ce3770612820620000"],
        auth_time=1441364872,
        azp="554295ce3770612820620000",
    )
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(
        os.path.join(os.path.dirname(__file__), "data", "keys", "cert.key"),
        "some",
        ["enc", "sig"],
    )
    kj.add_kb("", kb)
    kj.add_kb("https://sso.qa.7pass.ctf.prosiebensat1.com", kb)

    packer = JWT(
        kj,
        lifetime=3600,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        encrypt=True,
    )
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    vidt = verify_id_token(
        msg,
        keyjar=kj,
        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
        client_id="554295ce3770612820620000",
    )
    assert vidt
    assert vidt.jwe_header == {"enc": "A128CBC-HS256", "alg": "RSA1_5", "cty": "JWT"}
Esempio n. 4
0
def init_keyjar():
    # Keys that are kept by the AS
    kb = KeyBundle()
    kb.do_keys(JWKS["keys"])
    keyjar = KeyJar()
    keyjar.add_kb('', kb)
    return keyjar
Esempio n. 5
0
def init_keyjar():
    # Keys that are kept by the AS
    kb = KeyBundle()
    kb.do_keys(JWKS["keys"])
    keyjar = KeyJar()
    keyjar.add_kb('', kb)
    return keyjar
Esempio n. 6
0
def export_keys(keys):
    kbl = []
    keyjar = KeyJar()
    for typ, info in keys.items():
        kb = KeyBundle(source="file://%s" % info["key"], fileformat="der",
                       keytype=typ)
        keyjar.add_kb("", kb)
        kbl.append(kb)

    try:
        new_name = "static/jwks.json"
        dump_jwks(kbl, new_name)
    except KeyError:
        pass

    return keyjar
Esempio n. 7
0
    def _create_op(self, issuer, endpoint_baseurl, jwks_uri):
        """
        Create the necessary Provider instance.
        :type issuer: str
        :type endpoint_baseurl: str
        :type jwks_uri: str
        :param issuer: issuer URL for the OP
        :param endpoint_baseurl: baseurl to build endpoint URL from
        :param jwks_uri: URL to where the JWKS will be published
        """
        kj = KeyJar()
        signing_key = KeyBundle(source="file://{}".format(
            self.conf["signing_key_path"]),
                                fileformat="der",
                                keyusage=["sig"])
        kj.add_kb("", signing_key)
        capabilities = {
            "response_types_supported": ["id_token"],
            "id_token_signing_alg_values_supported": [self.sign_alg],
            "response_modes_supported": ["fragment", "query"],
            "subject_types_supported": ["public", "pairwise"],
            "grant_types_supported": ["implicit"],
            "claim_types_supported": ["normal"],
            "claims_parameter_supported": True,
            "request_parameter_supported": False,
            "request_uri_parameter_supported": False,
        }

        if "client_db_path" in self.conf:
            cdb = shelve_wrapper.open(self.conf["client_db_path"])
        else:
            cdb = {}  # client db in memory only

        self.provider = Provider(issuer,
                                 None,
                                 cdb,
                                 None,
                                 None,
                                 None,
                                 None,
                                 None,
                                 keyjar=kj,
                                 capabilities=capabilities,
                                 jwks_uri=jwks_uri)
        self.provider.baseurl = endpoint_baseurl
        self.provider.endp = [RegistrationEndpoint, AuthorizationEndpoint]
Esempio n. 8
0
def export_keys(keys):
    kbl = []
    keyjar = KeyJar()
    for typ, info in keys.items():
        kb = KeyBundle(source="file://%s" % info["key"],
                       fileformat="der",
                       keytype=typ)
        keyjar.add_kb("", kb)
        kbl.append(kb)

    try:
        new_name = "static/jwks.json"
        dump_jwks(kbl, new_name)
    except KeyError:
        pass

    return keyjar
Esempio n. 9
0
def test_verify_token_encrypted_no_key():
    idt = IdToken(sub='553df2bcf909104751cfd8b2', aud=['5542958437706128204e0000', '554295ce3770612820620000'],
                  auth_time=1441364872, azp='554295ce3770612820620000')
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(os.path.join(os.path.dirname(__file__), 'data', 'keys', 'cert.key'), 'some', ['enc', 'sig'])
    kj.add_kb('', kb)
    kj.add_kb('https://sso.qa.7pass.ctf.prosiebensat1.com', kb)

    packer = JWT(kj, lifetime=3600, iss='https://sso.qa.7pass.ctf.prosiebensat1.com', encrypt=True)
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    # Do not pass they keyjar with keys
    with pytest.raises(VerificationError):
        verify_id_token(msg, keyjar=KeyJar(),
                        iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
                        client_id="554295ce3770612820620000")
Esempio n. 10
0
def test_verify_token_encrypted():
    idt = IdToken(sub='553df2bcf909104751cfd8b2', aud=['5542958437706128204e0000', '554295ce3770612820620000'],
                  auth_time=1441364872, azp='554295ce3770612820620000')
    kj = KeyJar()
    kb = KeyBundle()
    kb.do_local_der(os.path.join(os.path.dirname(__file__), 'data', 'keys', 'cert.key'), 'some', ['enc', 'sig'])
    kj.add_kb('', kb)
    kj.add_kb('https://sso.qa.7pass.ctf.prosiebensat1.com', kb)

    packer = JWT(kj, lifetime=3600, iss='https://sso.qa.7pass.ctf.prosiebensat1.com', encrypt=True)
    _jws = packer.pack(**idt.to_dict())
    msg = AuthorizationResponse(id_token=_jws)
    vidt = verify_id_token(msg, keyjar=kj,
                           iss="https://sso.qa.7pass.ctf.prosiebensat1.com",
                           client_id="554295ce3770612820620000")
    assert vidt
    assert vidt.jwe_header == {'enc': 'A128CBC-HS256', 'alg': 'RSA1_5', 'cty': 'JWT'}
Esempio n. 11
0
signed_reg_req = _jws.sign_compact(keys)

rr['signed_metadata'] = signed_reg_req

print(70 * "-")
print('Client registration request')
print(70 * "-")
print_lines(
    json.dumps(rr.to_dict(), sort_keys=True, indent=2, separators=(',', ': ')))

#### ======================================================================
##   On the OP
#### ======================================================================

op_keyjar = KeyJar()
op_keyjar.add_kb('https://fo.example.com/', KeyBundle(fo_jwks['keys']))

# -----------------------------------------------------------------------------
# Unpack software_statements
# -----------------------------------------------------------------------------

msgs = []

# Only one software statement
sost = rr['software_statements'][0]

_sost = unpack_software_statement(sost, '', op_keyjar)
fo_id = _sost['iss']

# ------------------------------
# get the long lived RP key (A)
Esempio n. 12
0
class OIDCFederationEntity(object):
    def __init__(self, name, root_key, software_statements, federation_keys, signed_jwks_uri):
        # type: (str, Key, Sequence[str], Sequence[Key], str) -> None
        """
        :param name: URI identifying the entity
        :param root_key: root signing key for this entity
        :param software_statements: all software statements isssued by federations for this entity
        :param federation_keys: public keys from all federations this entity is part of
        :param signed_jwks_uri: URL endpoint where the signed JWKS is published
        """

        verify_signing_key(root_key)
        self.root_key = root_key

        self.name = name

        self.software_statements = [self._verify(ss, federation_keys) for ss in software_statements]
        self.federation_keys = federation_keys
        self.signed_jwks_uri = signed_jwks_uri

        self.intermediate_key = None
        self.jwks = None

        self.rotate_intermediate_key()
        self.rotate_jwks()

    @property
    def signed_intermediate_key(self):
        # type: () -> str
        """
        :return: JWS containing the intermediate key
        """
        return self._sign(self.intermediate_key.serialize(private=False), self.root_key)

    @property
    def signed_jwks(self):
        # type: () -> str
        """
        :return: JWS containing the JWKS
        """
        return self._sign(self.jwks.export_jwks(), self.intermediate_key)

    @property
    def software_statements_jws(self):
        # type: () -> List[str]
        """
        :return: all the entity's software statements as JWS
        """
        return [ss.jwt.pack() for ss in self.software_statements]

    def rotate_intermediate_key(self):
        # type: () -> None
        """Replace the current intermediate key with a fresh one."""
        self.intermediate_key = RSAKey(key=RSA.generate(1024), use="sig", alg="RS256", kid=self._create_kid())

    def rotate_jwks(self):
        # type: () -> None
        """Replace the current JWKS with a fresh one."""
        self.jwks = KeyJar()
        kb = KeyBundle(keyusage=["enc", "sig"])
        kb.append(RSAKey(key=RSA.generate(1024), kid=self._create_kid()))
        self.jwks.add_kb("", kb)

    def _create_kid(self):
        # type () -> str
        """
        Create a scope (by the entity's name) key id.
        :return: a new key id
        """
        return "{}/{}".format(self.name, uuid.uuid4())

    def _sign(self, data, key):
        # type: (Mapping[str, Union[str, Sequence[str]]], Key) -> str
        """
        Create a JWS containing the data, signed with key.

        :param data: data to sign
        :param key: key to use for signature
        :return: JWS containing the data
        """
        return JWS(json.dumps(data), alg=key.alg).sign_compact(keys=[key])

    def _verify(self, jws, keys):
        # type: (str, Sequence[Key]) -> Dict[str, Union[str, Lists[str]]]
        """
        Verify signature of JWS.

        :param jws: JWS to verify signature of
        :param keys: possible keys to verify the signature with
        :return: payload of the JWS
        """
        unpacked = JWS()
        unpacked.verify_compact(jws, keys=keys)
        return unpacked

    def _verify_signature_chain(self, software_statements, signing_key):
        # type: (Sequence[str], str) -> Tuple[str, Key]
        """
        Verify the signature chain: signature of software statement (containing root key) and
        signature of a signing key (in the form of a JWS).

        :param software_statements: all software statements from the provider
        :param signing_key: the entity's intermediate signing key
        :return:
        """
        software_statement = self._verify_software_statements(software_statements)

        root_key = keyrep(software_statement.msg["root_key"])
        signing_key = self._verify_signing_key(signing_key, root_key)
        return software_statement, signing_key

    def _verify_signing_key(self, signing_key, verification_key):
        # type: (str, Key) -> Key
        """
        Verify the signature of an intermediate signing key.

        :param signing_key: JWS containing the providers intermediate key
        :param verification_key: key to verify the signature with
        :raise OIDCFederationError: if the signature could not be verified
        :return: key contained in the JWS
        """
        try:
            signing_key = self._verify(signing_key, keys=[verification_key]).msg
        except JWKESTException as e:
            raise OIDCFederationError("The entity's signing key could not be verified.")

        return keyrep(signing_key)

    def _verify_software_statements(self, software_statements):
        # type: (Sequence[str]) -> Dict[str, Union[str, List[str]]]
        """
        Find and verify the signature of the first software statement issued by a common federation.

        :param software_statements: all software statements the entity presented in the
         metadata
        :raise OIDCFederationError: if no software statement has been issued by a common federation
        :return: payload of the first software statement issued by a common federation
        """
        for jws in software_statements:
            try:
                return self._verify(jws, self.federation_keys)
            except JWKESTException as e:
                pass

        raise OIDCFederationError("No software statement issued by known federation.")

    def _find_software_statement_for_federation(self, federation_kid):
        # type: (str) -> Optional[JWS]
        """
        Find a software statement signed by the specified key id.
        :param federation_kid: key id to search for
        :return: the first occurrence of a software statement signed by the specified key id
        """
        for ss in self.software_statements:
            if ss.jwt.headers["kid"] == federation_kid:
                return ss

        return None
    }
)

print('Registration Request published by RP')
print(70 * "-")
print_lines(json.dumps(rere.to_dict(), sort_keys=True, indent=2,
                       separators=(',', ': ')))

# ### ======================================================================
# #   On the OP
# ### ======================================================================

print('The OP chooses which federation it will work under - SWAMID of course')

op_keyjar = KeyJar()
op_keyjar.add_kb(swamid_issuer, KeyBundle(swamid_jwks['keys']))

# -----------------------------------------------------------------------------
# Unpacking the russian doll (= the software_statement)
# -----------------------------------------------------------------------------

msgs = []

# Only one software statement
_rp_jwt = factory(rp_swamid_sost)
_rp_sost = json.loads(_rp_jwt.jwt.part[1].decode('utf8'))

# Only one Software Statement within the signed
sost = _rp_sost['software_statements'][0]

_sost_dev = unpack_software_statement(sost, '', op_keyjar)
Esempio n. 14
0
print('Registration Request published by RP')
print(70 * "-")
print_lines(
    json.dumps(rere.to_dict(),
               sort_keys=True,
               indent=2,
               separators=(',', ': ')))

# ### ======================================================================
# #   On the OP
# ### ======================================================================

print('The OP chooses which federation it will work under - SWAMID of course')

op_keyjar = KeyJar()
op_keyjar.add_kb(swamid_issuer, KeyBundle(swamid_jwks['keys']))

# -----------------------------------------------------------------------------
# Unpacking the russian doll (= the software_statement)
# -----------------------------------------------------------------------------

msgs = []

# Only one software statement
_rp_jwt = factory(rp_swamid_sost)
_rp_sost = json.loads(_rp_jwt.jwt.part[1].decode('utf8'))

# Only one Software Statement within the signed
sost = _rp_sost['software_statements'][0]

_sost_dev = unpack_software_statement(sost, '', op_keyjar)
Esempio n. 15
0
keys = a_keyjar.keys_by_alg_and_usage("", "RS384", "sig")
signed_reg_req = _jws.sign_compact(keys)

rr["signed_metadata"] = signed_reg_req

print(70 * "-")
print("Client registration request")
print(70 * "-")
print_lines(json.dumps(rr.to_dict(), sort_keys=True, indent=2, separators=(",", ": ")))

#### ======================================================================
##   On the OP
#### ======================================================================

op_keyjar = KeyJar()
op_keyjar.add_kb("https://fo.example.com/", KeyBundle(fo_jwks["keys"]))

# -----------------------------------------------------------------------------
# Unpack software_statements
# -----------------------------------------------------------------------------

msgs = []

# Only one software statement
sost = rr["software_statements"][0]

_sost = unpack_software_statement(sost, "", op_keyjar)
fo_id = _sost["iss"]

# ------------------------------
# get the long lived RP key (A)