Пример #1
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"}
Пример #2
0
def test_keyjar_pairkeys():
    ks = KeyJar()
    ks[""] = KeyBundle([{
        "kty": "oct",
        "key": "a1b2c3d4",
        "use": "sig"
    }, {
        "kty": "oct",
        "key": "a1b2c3d4",
        "use": "ver"
    }])
    ks["http://www.example.org"] = KeyBundle([{
        "kty": "oct",
        "key": "e5f6g7h8",
        "use": "sig"
    }, {
        "kty": "oct",
        "key": "e5f6g7h8",
        "use": "ver"
    }])
    ks["http://www.example.org"].append(
        keybundle_from_local_file(RSAKEY, "rsa", ["ver", "sig"]))

    collection = ks.verify_keys("http://www.example.org")
    assert len(collection) == 3
    assert len([k for k in collection if k.kty == "oct"]) == 2
    assert len([k for k in collection if k.kty == "RSA"]) == 1
Пример #3
0
def test_dump_private_jwks():
    keys = [
        {
            "type": "RSA",
            "use": ["enc", "sig"]
        },
        {
            "type": "EC",
            "crv": "P-256",
            "use": ["sig"]
        },
    ]

    jwks, keyjar, kidd = build_keyjar(keys)

    kbl = keyjar.issuer_keys['']
    dump_jwks(kbl, 'foo.jwks', private=True)
    kb_public = KeyBundle(source='file://./foo.jwks')
    # All RSA keys
    for k in kb_public.keys():
        if k.kty == 'RSA':
            assert k.d
            assert k.p
            assert k.q
        else:  # MUST be 'EC'
            assert k.d
Пример #4
0
    def test_parse_jwt_request(self):
        ar = AuthorizationRequest(
            response_type=["code"],
            client_id="foobar",
            redirect_uri="http://foobar.example.com/oaclient",
            state="cold",
        )

        self.srv.keyjar["foobar"] = KeyBundle(
            [
                {"kty": "oct", "key": "A1B2C3D4".encode("utf-8"), "use": "ver"},
                {"kty": "oct", "key": "A1B2C3D4".encode("utf-8"), "use": "sig"},
            ]
        )
        self.srv.keyjar[""] = KeyBundle(
            [
                {"kty": "oct", "key": "A1B2C3D4".encode("utf-8"), "use": "ver"},
                {"kty": "oct", "key": "A1B2C3D4".encode("utf-8"), "use": "sig"},
            ]
        )

        keys = self.srv.keyjar.get_signing_key(owner="foobar")
        _jwt = ar.to_jwt(key=keys, algorithm="HS256")

        req = self.srv.parse_jwt_request(txt=_jwt)

        assert isinstance(req, AuthorizationRequest)
        assert req["response_type"] == ["code"]
        assert req["client_id"] == "foobar"
        assert req["redirect_uri"] == "http://foobar.example.com/oaclient"
        assert req["state"] == "cold"
Пример #5
0
def test_dump_public_jwks():
    keys = [
        {
            "type": "RSA",
            "use": ["enc", "sig"]
        },
        {
            "type": "EC",
            "crv": "P-256",
            "use": ["sig"]
        },
    ]

    jwks, keyjar, kidd = build_keyjar(keys)

    kbl = keyjar.issuer_keys[""]
    dump_jwks(kbl, "foo.jwks")
    kb_public = KeyBundle(source="file://./foo.jwks")
    # All RSA keys
    for k in kb_public.keys():
        if k.kty == "RSA":
            assert not k.d
            assert not k.p
            assert not k.q
        else:  # MUST be 'EC'
            assert not k.d
Пример #6
0
    def export(self, client, cconf, role):
        # has to be there
        self.trace.info("EXPORT")

        if client.keyjar is None:
            client.keyjar = KeyJar()

        kbl = []
        for typ, info in cconf["keys"].items():
            kb = KeyBundle(source="file://%s" % info["key"],
                           fileformat="der", keytype=typ)
            for k in kb.keys():
                k.serialize()
            client.keyjar.add_kb("", kb)
            kbl.append(kb)

        try:
            new_name = "static/%s_jwks.json" % role
            dump_jwks(kbl, new_name)
            client.jwks_uri = "%s%s" % (cconf["_base_url"], new_name)
        except KeyError:
            pass

        if not self.args.external_server and not self.keysrv_running:
            self._pop = start_key_server(cconf["_base_url"])

            self.environ["keyprovider"] = self._pop
            self.trace.info("Started key provider")
            time.sleep(1)
            self.keysrv_running = True
Пример #7
0
    def export(self, client, cconf, role):
        # has to be there
        self.trace.info("EXPORT")

        if client.keyjar is None:
            client.keyjar = KeyJar()

        kbl = []
        for typ, info in cconf["keys"].items():
            kb = KeyBundle(source="file://%s" % info["key"],
                           fileformat="der",
                           keytype=typ)
            for k in kb.keys():
                k.serialize()
            client.keyjar.add_kb("", kb)
            kbl.append(kb)

        try:
            new_name = "static/%s_jwks.json" % role
            dump_jwks(kbl, new_name)
            client.jwks_uri = "%s%s" % (cconf["_base_url"], new_name)
        except KeyError:
            pass

        if not self.args.external_server and not self.keysrv_running:
            self._pop = start_key_server(cconf["_base_url"])

            self.environ["keyprovider"] = self._pop
            self.trace.info("Started key provider")
            time.sleep(1)
            self.keysrv_running = True
Пример #8
0
    def export(self):
        # has to be there
        self.trace.info("EXPORT")

        if self.client.keyjar is None:
            self.client.keyjar = KeyJar()

        kbl = []
        kid_template = "a%d"
        kid = 0
        for typ, info in self.cconf["keys"].items():
            kb = KeyBundle(source="file://%s" % info["key"], fileformat="der", keytype=typ)

            for k in kb.keys():
                k.serialize()
                k.kid = kid_template % kid
                kid += 1
                self.client.kid[k.use][k.kty] = k.kid
            self.client.keyjar.add_kb("", kb)

            kbl.append(kb)

        try:
            new_name = "static/jwks.json"
            dump_jwks(kbl, new_name)
            self.client.jwks_uri = "%s%s" % (self.cconf["_base_url"], new_name)
        except KeyError:
            pass

        if self.args.internal_server:
            self._pop = start_key_server(self.cconf["_base_url"], self.args.script_path or None)
            self.environ["keyprovider"] = self._pop
            self.trace.info("Started key provider")
            time.sleep(1)
Пример #9
0
def test_key_export():
    kj = KeyJar()
    url = key_export(
        "http://example.com/keys/",
        "outbound",
        "secret",
        keyjar=kj,
        sig={
            "alg": "rsa",
            "format": ["x509", "jwk"]
        },
    )

    assert url == "http://example.com/keys/outbound/jwks"

    # Now a jwks should reside in './keys/outbound/jwks'

    kb = KeyBundle(source="file://./keys/outbound/jwks")

    # One key
    assert len(kb) == 1
    # more specifically one RSA key
    assert len(kb.get("RSA")) == 1
    k = kb.get("RSA")[0]
    # For signing
    assert k.use == "sig"
Пример #10
0
    def test_keyjar_group_keys(self):
        ks = KeyJar()
        ks[""] = KeyBundle([{
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "a1b2c3d4",
            "use": "ver"
        }])
        ks["http://www.example.org"] = KeyBundle([{
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "sig"
        }, {
            "kty": "oct",
            "key": "e5f6g7h8",
            "use": "ver"
        }])
        ks["http://www.example.org"].append(
            keybundle_from_local_file(RSAKEY, "rsa", ["ver", "sig"]))

        verified_keys = ks.verify_keys("http://www.example.org")
        assert len(verified_keys) == 6
        assert len([k for k in verified_keys if k.kty == "oct"]) == 4
        assert len([k for k in verified_keys if k.kty == "RSA"]) == 2
Пример #11
0
    def __call__(self):
        keyjar = self.conv.entity.keyjar
        self.conv.entity.original_keyjar = keyjar.copy()

        # invalidate the old key
        old_kid = self.op_args["old_kid"]
        old_key = keyjar.get_key_by_kid(old_kid)
        old_key.inactive_since = time.time()

        # setup new key
        key_spec = self.op_args["new_key"]
        typ = key_spec["type"].upper()
        if typ == "RSA":
            kb = KeyBundle(keytype=typ, keyusage=key_spec["use"])
            kb.append(RSAKey(use=key_spec["use"]).load_key(
                RSA.generate(key_spec["bits"])))
        elif typ == "EC":
            kb = ec_init(key_spec)
        else:
            raise Exception('Wrong key type')

        # add new key to keyjar with
        list(kb.keys())[0].kid = self.op_args["new_kid"]
        keyjar.add_kb("", kb)

        # make jwks and update file
        keys = []
        for kb in keyjar[""]:
            keys.extend(
                [k.to_dict() for k in list(kb.keys()) if not k.inactive_since])
        jwks = dict(keys=keys)
        with open(self.op_args["jwks_path"], "w") as f:
            f.write(json.dumps(jwks))
Пример #12
0
    def __call__(self):
        # find the name of the file to which the JWKS should be written
        try:
            _uri = self.conv.entity.registration_response["jwks_uri"]
        except KeyError:
            raise RequirementsNotMet("No dynamic key handling")

        r = urlparse(_uri)
        # find the old key for this key usage and mark that as inactive
        for kb in self.conv.entity.keyjar.issuer_keys[""]:
            for key in list(kb.keys()):
                if key.use in self.new_key["use"]:
                    key.inactive = True

        kid = 0
        # only one key
        _nk = self.new_key
        _typ = _nk["type"].upper()

        if _typ == "RSA":
            kb = KeyBundle(source="file://%s" % _nk["key"],
                           fileformat="der", keytype=_typ,
                           keyusage=_nk["use"])
        else:
            kb = {}

        for k in list(kb.keys()):
            k.serialize()
            k.kid = self.kid_template % kid
            kid += 1
            self.conv.entity.kid[k.use][k.kty] = k.kid
        self.conv.entity.keyjar.add_kb("", kb)

        dump_jwks(self.conv.entity.keyjar[""], r.path[1:])
Пример #13
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",
        )
Пример #14
0
    def _func(self, conv):

        response = get_protocol_response(conv, ASConfigurationResponse)
        if not response:
            response = get_protocol_response(conv, ServerMetadata)

        response = response[-1]  # Should only be one but ...
        res = {}

        try:
            _jwks_uri = response['jwks_uri']
        except KeyError:
            try:
                kb = KeyBundle(response['jwks'])
            except KeyBundle:
                self._message = "Neither jwks_uri or jwks defined"
                self._status = ERROR
            except UnknownKeyType as err:
                self._message = '{}'.format(err)
                self._status = ERROR
        else:
            kb = KeyBundle(source=_jwks_uri, verify_ssl=False)
            try:
                kb.update()
            except UpdateFailed as err:
                self._message = '{}'.format(err)
                self._status = ERROR

        return res
Пример #15
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
Пример #16
0
    def __call__(self, conv, **kwargs):
        # find the name of the file to which the JWKS should be written
        try:
            _uri = conv.client.registration_response["jwks_uri"]
        except KeyError:
            raise RequirementsNotMet("No dynamic key handling")

        r = urlparse(_uri)
        # find the old key for this key usage and mark that as inactive
        for kb in conv.client.keyjar.issuer_keys[""]:
            for key in kb.keys():
                if key.use in self.new_key["use"]:
                    key.inactive = True

        kid = 0
        # only one key
        _nk = self.new_key
        _typ = _nk["type"].upper()

        if _typ == "RSA":
            kb = KeyBundle(source="file://%s" % _nk["key"],
                           fileformat="der",
                           keytype=_typ,
                           keyusage=_nk["use"])
        else:
            kb = {}

        for k in kb.keys():
            k.serialize()
            k.kid = self.kid_template % kid
            kid += 1
            conv.client.kid[k.use][k.kty] = k.kid
        conv.client.keyjar.add_kb("", kb)

        dump_jwks(conv.client.keyjar[""], r.path[1:])
Пример #17
0
    def construct_jwks(_client, key_conf):
        """
        Construct the jwks
        """
        if _client.keyjar is None:
            _client.keyjar = KeyJar()

        kbl = []
        kid_template = "a%d"
        kid = 0
        for typ, info in key_conf.items():
            kb = KeyBundle(source="file://%s" % info["key"], fileformat="der",
                           keytype=typ)

            for k in kb.keys():
                k.serialize()
                k.kid = kid_template % kid
                kid += 1
                _client.kid[k.use][k.kty] = k.kid
            _client.keyjar.add_kb("", kb)

            kbl.append(kb)

        jwks = {"keys": []}
        for kb in kbl:
            # ignore simple keys
            jwks["keys"].extend([k.to_dict()
                                 for k in kb.keys() if k.kty != 'oct'])

        return jwks
Пример #18
0
 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)
Пример #19
0
    def test_remove_key(self):
        ks = KeyJar()
        ks[""] = KeyBundle([{"kty": "oct", "key": "a1b2c3d4", "use": "sig"},
                            {"kty": "oct", "key": "a1b2c3d4", "use": "ver"}])
        ks["http://www.example.org"] = [
            KeyBundle([
                {"kty": "oct", "key": "e5f6g7h8", "use": "sig"},
                {"kty": "oct", "key": "e5f6g7h8", "use": "ver"}]),
            keybundle_from_local_file(RSAKEY, "rsa", ["enc", "dec"])
        ]
        ks["http://www.example.com"] = keybundle_from_local_file(RSA0, "rsa",
                                                                 ["enc", "dec"])

        coll = ks["http://www.example.org"]
        # coll is list of KeyBundles
        assert len(coll) == 2
        keys = ks.get_encrypt_key(key_type="RSA",
                                  owner="http://www.example.org")
        assert len(keys) == 1
        _key = keys[0]
        ks.remove_key("http://www.example.org", "RSA", _key)

        coll = ks["http://www.example.org"]
        assert len(coll) == 1  # Only one remaining key
        keys = ks.get_encrypt_key(key_type="rsa",
                                  owner="http://www.example.org")
        assert len(keys) == 0

        keys = ks.verify_keys("http://www.example.com")
        assert len(keys) == 1
        assert len([k for k in keys if k.kty == "oct"]) == 1

        keys = ks.decrypt_keys("http://www.example.org")
        assert keys == []
Пример #20
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
Пример #21
0
def _create_symmetric_key(issuer, key):
    provider_keys = KeyJar()
    key = SYMKey(use='sig', k=key)
    kb = KeyBundle(keytype='oct')
    kb.append(key)
    provider_keys[issuer] = [kb]

    return provider_keys
Пример #22
0
    def store_key(self, key):
        kb = KeyBundle()
        kb.do_keys([key])

        # Store key with thumbprint as key
        key_thumbprint = b64e(kb.keys()[0].thumbprint("SHA-256")).decode("utf8")
        self.thumbprint2key[key_thumbprint] = key
        return key_thumbprint
Пример #23
0
    def __call__(self):
        kb = KeyBundle(source=self.conv.entity.provider_info["jwks_uri"])
        kb.verify_ssl = False
        kb.update()

        try:
            self.conv.keybundle.append(kb)
        except AttributeError:
            self.conv.keybundle = [kb]
Пример #24
0
    def __call__(self):
        kb = KeyBundle(source=self.conv.entity.provider_info["jwks_uri"])
        kb.verify_ssl = False
        kb.update()

        try:
            self.conv.keybundle.append(kb)
        except AttributeError:
            self.conv.keybundle = [kb]
Пример #25
0
    def store_key(self, key):
        kb = KeyBundle()
        kb.do_keys([key])

        # Store key with thumbprint as key
        key_thumbprint = b64e(kb.keys()[0].thumbprint('SHA-256')).decode(
            'utf8')
        self.thumbprint2key[key_thumbprint] = key
        return key_thumbprint
Пример #26
0
    def __call__(self, conv, **kwargs):
        pi = conv.client.provider_info
        kb = KeyBundle(source=pi["jwks_uri"])
        kb.verify_ssl = False
        kb.update()

        try:
            conv.keybundle.append(kb)
        except AttributeError:
            conv.keybundle = [kb]
Пример #27
0
    def __call__(self, conv, **kwargs):
        pi = conv.client.provider_info
        kb = KeyBundle(source=pi["jwks_uri"])
        kb.verify_ssl = False
        kb.update()

        try:
            conv.keybundle.append(kb)
        except AttributeError:
            conv.keybundle = [kb]
Пример #28
0
def test_chain_1():
    kc = KeyBundle([{"kty": "oct", "key": "supersecret", "use": "sig"}])
    assert len(kc.get("oct")) == 1
    assert len(kc.get("rsa")) == 0
    assert kc.remote is False
    assert kc.source is None

    kc.update()  # Nothing should happen
    assert len(kc.get("oct")) == 1
    assert len(kc.get("rsa")) == 0
    assert kc.remote is False
    assert kc.source is None
Пример #29
0
    def create_provider(self):
        kb = KeyBundle(JWKS["keys"])
        kj = KeyJar()
        kj.issuer_keys[''] = [kb]

        _sdb = SessionDB("https://example.com/",
                         db={},
                         code_factory=DefaultToken('supersecret',
                                                   'verybadpassword',
                                                   typ='A',
                                                   lifetime=600),
                         token_factory=JWTToken('T',
                                                keyjar=kj,
                                                lt_pattern={
                                                    'code': 3600,
                                                    'token': 900
                                                },
                                                iss='https://example.com/as',
                                                sign_alg='RS256'),
                         refresh_token_factory=JWTToken(
                             'R',
                             keyjar=kj,
                             lt_pattern={'': 24 * 3600},
                             iss='https://example.com/as'))
        #  name, sdb, cdb, authn_broker, authz, client_authn,
        self.provider = Provider("as",
                                 _sdb,
                                 CDB,
                                 AUTHN_BROKER,
                                 AUTHZ,
                                 verify_client,
                                 baseurl='https://example.com/as')
Пример #30
0
def test_enc_hmac():
    payload = {
        'nonce': 'CYeHPyA6Kmr_jy5HDHXykznu2BpDLm8ngbIJvhBoupI,',
        'sub': 'diana',
        'iss': 'https://xenosmilus2.umdc.umu.se:8091/',
        'acr': '2',
        'exp': 1401176001,
        'iat': 1401096801,
        'aud': ['ApB7TBoKV1tV']
    }

    _jwe = JWE(json.dumps(payload), alg="A128KW", enc="A128CBC-HS256")

    kb = KeyBundle(JWK1["keys"])
    kj = KeyJar()
    kj.issuer_keys["abcdefgh"] = [kb]
    keys = kj.get_encrypt_key(owner="abcdefgh")

    _enctxt = _jwe.encrypt(keys, context="public")
    assert _enctxt

    # and now for decryption

    msg, state = _jwe.decrypt(_enctxt, keys)

    assert json.loads(msg) == payload
Пример #31
0
def test_pkce_token():
    kb = KeyBundle(JWKS["keys"])
    kj = KeyJar()
    kj.issuer_keys[""] = [kb]
    constructor = JWTToken(
        "A",
        keyjar=kj,
        lt_pattern={"": 900},
        iss="https://example.com/as",
        sign_alg="RS256",
        encrypt=True,
    )

    sid = rndstr(32)
    session_info = {
        "sub": "subject_id",
        "client_id": "https://example.com/rp",
        "response_type": ["code"],
        "authzreq": "{}",
    }

    _cli = Client(config={"code_challenge": {"method": "S512", "length": 96}})
    args, cv = _cli.add_code_challenge()

    access_grant = constructor(
        sid,
        sinfo=session_info,
        kid="sign1",
        code_challenge=args["code_challenge"],
        code_challenge_method=args["code_challenge_method"],
    )

    _info = constructor.get_info(access_grant)
    assert _info["code_challenge_method"] == args["code_challenge_method"]
    assert _info["code_challenge"] == args["code_challenge"]
Пример #32
0
    def create_sdb(self):
        kb = KeyBundle(JWKS["keys"])
        kj = KeyJar()
        kj.issuer_keys[""] = [kb]

        self.sdb = SessionDB(
            "https://example.com/",
            db=DictSessionBackend(),
            code_factory=DefaultToken("supersecret",
                                      "verybadpassword",
                                      typ="A",
                                      lifetime=600),
            token_factory=JWTToken(
                "T",
                keyjar=kj,
                lt_pattern={
                    "code": 3600,
                    "token": 900
                },
                iss="https://example.com/as",
                sign_alg="RS256",
            ),
            refresh_token_factory=JWTToken(
                "R",
                keyjar=kj,
                lt_pattern={"": 24 * 3600},
                iss="https://example.com/as",
                token_storage={},
            ),
        )
Пример #33
0
def test_pkce_token():
    kb = KeyBundle(JWKS["keys"])
    kj = KeyJar()
    kj.issuer_keys[''] = [kb]
    constructor = JWTToken('A',
                           keyjar=kj,
                           lt_pattern={'': 900},
                           iss='https://example.com/as',
                           sign_alg='RS256',
                           encrypt=True)

    sid = rndstr(32)
    session_info = {
        'sub': 'subject_id',
        'client_id': 'https://example.com/rp',
        'response_type': ['code'],
        'authzreq': '{}'
    }

    _cli = Client(config={'code_challenge': {'method': 'S512', 'length': 96}})
    args, cv = _cli.add_code_challenge()

    access_grant = constructor(
        sid,
        sinfo=session_info,
        kid='sign1',
        code_challenge=args['code_challenge'],
        code_challenge_method=args['code_challenge_method'])

    _info = constructor.get_info(access_grant)
    assert _info['code_challenge_method'] == args['code_challenge_method']
    assert _info['code_challenge'] == args['code_challenge']
Пример #34
0
    def load_keys(self, request, client_id, client_secret):
        try:
            self.keyjar.load_keys(request, client_id)
            try:
                n_keys = len(self.keyjar[client_id])
                msg = "Found {} keys for client_id={}"
                logger.debug(msg.format(n_keys, client_id))
            except KeyError:
                pass
        except Exception as err:
            msg = "Failed to load client keys: {}"
            logger.error(msg.format(sanitize(request.to_dict())))
            logger.error("%s", err)
            err = ClientRegistrationError(
                error="invalid_configuration_parameter",
                error_description="%s" % err)
            return Response(err.to_json(),
                            content="application/json",
                            status_code="400 Bad Request")

        # Add the client_secret as a symmetric key to the keyjar
        _kc = KeyBundle([{
            "kty": "oct",
            "key": client_secret,
            "use": "ver"
        }, {
            "kty": "oct",
            "key": client_secret,
            "use": "sig"
        }])
        try:
            self.keyjar[client_id].append(_kc)
        except KeyError:
            self.keyjar[client_id] = [_kc]
Пример #35
0
    def load_keys(self, request, client_id, client_secret):
        try:
            self.keyjar.load_keys(request, client_id)
            try:
                logger.debug("keys for %s: [%s]" % (client_id, ",".join(
                    ["%s" % x for x in self.keyjar[client_id]])))
            except KeyError:
                pass
        except Exception as err:
            logger.error("Failed to load client keys: %s" % request.to_dict())
            logger.error("%s", err)
            err = ClientRegistrationError(
                error="invalid_configuration_parameter",
                error_description="%s" % err)
            return Response(err.to_json(),
                            content="application/json",
                            status="400 Bad Request")

        # Add the client_secret as a symmetric key to the keyjar
        _kc = KeyBundle([{
            "kty": "oct",
            "key": client_secret,
            "use": "ver"
        }, {
            "kty": "oct",
            "key": client_secret,
            "use": "sig"
        }])
        try:
            self.keyjar[client_id].append(_kc)
        except KeyError:
            self.keyjar[client_id] = [_kc]
Пример #36
0
 def test_construct(self, client):
     _key = rsa_load(os.path.join(BASE_PATH, "data/keys/rsa.key"))
     kc_rsa = KeyBundle([{
         "key": _key,
         "kty": "RSA",
         "use": "ver"
     }, {
         "key": _key,
         "kty": "RSA",
         "use": "sig"
     }])
     client.keyjar[""] = kc_rsa
     client.token_endpoint = "https://example.com/token"
     client.provider_info = {
         'issuer': 'https://example.com/',
         'token_endpoint': "https://example.com/token"
     }
     cis = AccessTokenRequest()
     pkj = PrivateKeyJWT(client)
     http_args = pkj.construct(cis,
                               algorithm="RS256",
                               authn_endpoint='token')
     assert http_args == {}
     cas = cis["client_assertion"]
     _jwt = JWT().unpack(cas)
     jso = _jwt.payload()
     assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
     assert _jwt.headers == {'alg': 'RS256'}
     assert jso['aud'] == [client.provider_info['token_endpoint']]
Пример #37
0
    def test_issuer_mismatch(self):
        ISSUER = "https://login.microsoftonline.com/b4ea3de6-839e-4ad1-ae78-c78e5c0cdc06/v2.0/"
        kb = KeyBundle(JWK2["keys"])
        kj = KeyJar()
        kj.issuer_keys[ISSUER] = [kb]
        kj.issuer_keys[""] = []

        authz_resp = AuthorizationResponse().from_urlencoded(
            "id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1u"
            "Q19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiIwMTZlZDBlNC1mYzUyLTRlYjgtOWVhYy1lODg1MmM4MjEwNTUiLCJpc3Mi"
            "OiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vYjRlYTNkZTYtODM5ZS00YWQxLWFlNzgtYzc4ZTVjMGNkYzA2L3YyLjAvI"
            "iwiaWF0IjoxNDM5OTIzNDY5LCJuYmYiOjE0Mzk5MjM0NjksImV4cCI6MTQzOTkyNzM2OSwidmVyIjoiMi4wIiwidGlkIjoiYjRlYTNkZT"
            "YtODM5ZS00YWQxLWFlNzgtYzc4ZTVjMGNkYzA2Iiwib2lkIjoiNDJjMzliNWUtYmQwNS00YTlhLTlhNWUtMTY5ZDc2N2ZlZjJmIiwicHJ"
            "lZmVycmVkX3VzZXJuYW1lIjoiaW50ZXJvcEBrYXV0aS5vbm1pY3Jvc29mdC5jb20iLCJzdWIiOiJFWGlaVldjakpsREN1LXZzOUxNb1V3"
            "ZGRNNEJZZ2ZISzBJNk40dWpXZkRFIiwibmFtZSI6ImludGVyb3AiLCJub25jZSI6IlpkSHRxQWwzR3c4QiJ9.tH4FKM4H9YCHX2XF4V64"
            "SsLaKh31c0oLpEVlFxFHw8jxL5HujUthZJDUMwngXZ2mPU_1G152ybKiRCV9DKaBh1rFSlZxTDBp0SV_YTwOkGYOt-sOzFUJyvVCjGmRh"
            "vFkOF1kiT3IYjDoRh72U8pMchj1duWSytLczdOc4LJmg24ya5jwqApuyQu7gVqoDH1kEqBAuhBj3a7ZDwxIt-bTKZklsht0RutZjv4Ckg"
            "8qJpzWnY7rIjSKFKfEpAAfk_LqWvTktvDMKTHXLxEPVZymoskE1LthtC8AYoNmtVPxgxf87yGCqYZBsuAnVChdnsItXP7tPeqUjC8Lm3J"
            "jabV-5g&id_token_expires_in=3599&state=6o3FmQ0QZl1zifsE&session_state=d2c97e8a-497c-4ce1-bb10-5058501164eb"
        )

        try:
            authz_resp.verify(keyjar=kj, skew=100000000)
        except MissingSigningKey:
            authz_resp.verify(keyjar=kj, sender=ISSUER, skew=100000000)
Пример #38
0
 def test_get_inactive_ver(self):
     ks = KeyJar()
     ks['http://example.com'] = KeyBundle(
         [{"kty": "oct", "key": "a1b2c3d4", "use": "sig"},
          {"kty": "oct", "key": "a1b2c3d4", "use": "ver"}])
     ks['http://example.com'][0]._keys[1].inactive_since = 1
     key = ks.get_verify_key(owner='http://example.com')
     assert len(key) == 2
Пример #39
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")
Пример #40
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'}
Пример #41
0
    def test_get_inactive_sig_for_ver(self):
        """get_verify_key can return inactive `sig` key."""
        ks = KeyJar()
        ks['http://example.com'] = KeyBundle(
            [{"kty": "oct", "key": "a1b2c3d4", "use": "sig"}])
        ks['http://example.com'][0]._keys[0].inactive_since = 1
        key = ks.get_verify_key(owner='http://example.com')

        assert len(key) == 1
Пример #42
0
    def create_token(self):
        kb = KeyBundle(JWKS["keys"])
        kj = KeyJar()
        kj.issuer_keys[''] = [kb]

        self.access_token = JWTToken('T',
                                     keyjar=kj,
                                     iss='https://example.com/as',
                                     sign_alg='RS256')
Пример #43
0
    def create_token(self):
        kb = KeyBundle(JWKS["keys"])
        kj = KeyJar()
        kj.issuer_keys[""] = [kb]

        self.access_token = JWTToken("T",
                                     keyjar=kj,
                                     iss="https://example.com/as",
                                     sign_alg="RS256")
Пример #44
0
def test_key_export():
    kj = KeyJar()
    url = key_export("http://example.com/keys/", "outbound", "secret",
                     keyjar=kj, sig={"alg": "rsa", "format": ["x509", "jwk"]})

    assert url == "http://example.com/keys/outbound/jwks"

    # Now a jwks should reside in './keys/outbound/jwks'

    kb = KeyBundle(source='file://./keys/outbound/jwks')

    # One key
    assert len(kb) == 1
    # more specifically one RSA key
    assert len(kb.get('RSA')) == 1
    k = kb.get('RSA')[0]
    # For signing
    assert k.use == 'sig'
Пример #45
0
    def test_get_inactive_sig(self):
        """get_signing_key cannot return inactive `sig` key."""
        ks = KeyJar()
        ks["http://example.com"] = KeyBundle(
            [{"kty": "oct", "key": "a1b2c3d4", "use": "sig"}]
        )
        ks["http://example.com"][0]._keys[0].inactive_since = 1
        key = ks.get_signing_key(owner="http://example.com")

        assert len(key) == 0
Пример #46
0
def test_dump_private_jwks():
    keys = [
        {"type": "RSA", "use": ["enc", "sig"]},
        {"type": "EC", "crv": "P-256", "use": ["sig"]},
    ]

    jwks, keyjar, kidd = build_keyjar(keys)

    kbl = keyjar.issuer_keys['']
    dump_jwks(kbl, 'foo.jwks', private=True)
    kb_public = KeyBundle(source='file://./foo.jwks')
    # All RSA keys
    for k in kb_public.keys():
        if k.kty == 'RSA':
            assert k.d
            assert k.p
            assert k.q
        else:  # MUST be 'EC'
            assert k.d
Пример #47
0
    def __init__(self, base_url, op, sp):
        self.base_url = base_url
        self.op = op
        self.sp = sp

        # Setup key for encrypting/decrypting the state (passed in the SAML RelayState).
        source = "file://symkey.json"
        self.key_bundle = KeyBundle(source=source, fileformat="jwk")

        for key in self.key_bundle.keys():
            key.deserialize()
Пример #48
0
Файл: func.py Проект: rohe/otest
def add_software_statement(oper, arg):
    argkeys = list(arg.keys())
    kwargs = {}

    tre = oper.conf.TRUSTED_REGISTRATION_ENTITY
    iss = tre['iss']
    kb = KeyBundle()
    kb.imp_jwks = json.load(open(tre['jwks']))
    kb.do_keys(kb.imp_jwks['keys'])
    oper.conv.entity.keyjar.add_kb(iss, kb)

    if arg['redirect_uris'] is None:
        kwargs['redirect_uris'] = oper.conv.entity.redirect_uris
    else:
        kwargs['redirect_uris'] = arg['redirect_uris']
    argkeys.remove('redirect_uris')

    if 'jwks_uri' in argkeys:
        if arg['jwks_uri'] is None:
            kwargs['jwks_uri'] = oper.conv.entity.jwks_uri
        else:
            kwargs['jwks_uri'] = arg['jwks_uri']
        argkeys.remove('jwks_uri')
    elif 'jwks' in argkeys:
        if arg['jwks'] is None:
            kwargs['jwks'] = {
                "keys": oper.conv.entity.keyjar.dump_issuer_keys("")}
        else:
            kwargs['jwks'] = arg['jwks']
        argkeys.remove('jwks')

    for a in argkeys:
        kwargs[a] = arg[a]

    oper.req_args['software_statement'] = make_software_statement(
        oper.conv.entity.keyjar, iss=iss, owner=iss, **kwargs)
Пример #49
0
def test_chain_3():
    kc = KeyBundle(source="file://../oc3/certs/server.crt", type="rsa",
                  src_type="x509", usage=["sig", "enc"])
    assert kc.usage == ["sig", "enc"]
    assert kc.remote == False
    assert kc.source == "../oc3/certs/server.crt"
    assert len(kc.get("hmac")) == 0
    assert len(kc.get("rsa")) == 1

    key = kc.get("rsa")[0]
    assert isinstance(key, M2Crypto.RSA.RSA)

    kc.update()
    assert kc.usage == ["sig", "enc"]
    assert kc.remote == False
    assert kc.source == "../oc3/certs/server.crt"
    assert len(kc.get("hmac")) == 0
    assert len(kc.get("rsa")) == 1

    key = kc.get("rsa")[0]
    assert isinstance(key, M2Crypto.RSA.RSA)
Пример #50
0
def test_chain_2():
    kc = KeyBundle(source="file://../oc3/certs/mycert.key", type="rsa",
                  usage=["ver", "sig"])
    assert kc.usage == ["ver", "sig"]
    assert kc.remote == False
    assert kc.source == "../oc3/certs/mycert.key"
    assert len(kc.get("hmac")) == 0
    assert len(kc.get("rsa")) == 1

    key = kc.get("rsa")[0]
    assert isinstance(key, M2Crypto.RSA.RSA)

    kc.update()
    assert kc.usage == ["ver", "sig"]
    assert kc.remote == False
    assert kc.source == "../oc3/certs/mycert.key"
    assert len(kc.get("hmac")) == 0
    assert len(kc.get("rsa")) == 1

    key = kc.get("rsa")[0]
    assert isinstance(key, M2Crypto.RSA.RSA)
Пример #51
0
def test_chain_1():
    kc = KeyBundle({"hmac": "supersecret"}, usage="sig")
    assert len(kc.get("hmac")) == 1
    assert len(kc.get("rsa")) == 0
    assert kc.usage == ["sig"]
    assert kc.remote == False
    assert kc.source is None

    kc.update() # Nothing should happen
    assert len(kc.get("hmac")) == 1
    assert len(kc.get("rsa")) == 0
    assert kc.usage == ["sig"]
    assert kc.remote == False
    assert kc.source is None
Пример #52
0
def test_parse_remote_response(caplog):
    """
    Tests parsing Content-Type header for _parse_remote_response
    """
    class FakeResponse():
        def __init__(self, header):
            self.headers = {"Content-Type": header}
            self.text = "{}"

    with caplog.at_level(logging.WARNING, logger='oic.utils.keyio'):
        kb_public = KeyBundle(source='file://./foo.jwks')

        res = FakeResponse('application/json;encoding=utf-8')
        kb_public._parse_remote_response(res)
        assert caplog.record_tuples != [
            ('oic.utils.keyio', logging.WARNING, 'Wrong Content_type')
        ]
        caplog.clear()

        res = FakeResponse('application/json')
        kb_public._parse_remote_response(res)
        assert caplog.record_tuples != [
            ('oic.utils.keyio', logging.WARNING, 'Wrong Content_type')
        ]
        caplog.clear()

        res = FakeResponse('Application/json')
        kb_public._parse_remote_response(res)
        assert caplog.record_tuples != [
            ('oic.utils.keyio', logging.WARNING, 'Wrong Content_type')
        ]
        caplog.clear()

        res = FakeResponse('text/plain')
        kb_public._parse_remote_response(res)
        assert caplog.record_tuples == [
            ('oic.utils.keyio', logging.WARNING, 'Wrong Content_type')
        ]
Пример #53
0
def test_reload():
    """
    Emulates what happens if you fetch keys from a remote site and
    you get back the same JWKS as the last time.
    """
    _jwks = JWK0

    kb = KeyBundle()
    kb.imp_jwks = _jwks
    kb.do_keys(kb.imp_jwks['keys'])

    assert len(kb) == 1

    kb.do_keys(kb.imp_jwks['keys'])

    assert len(kb) == 1
Пример #54
0
def keybundle_from_local_file(filename, typ, usage, kid):
    if typ.upper() == "RSA":
        kb = KeyBundle()
        k = RSAKey(kid=kid)
        k.load(filename)
        k.use = usage[0]
        kb.append(k)
        for use in usage[1:]:
            _k = RSAKey(kid=kid + "1")
            _k.use = use
            _k.load_key(k.key)
            kb.append(_k)
    elif typ.lower() == "jwk":
        kb = KeyBundle(source=filename, fileformat="jwk", keyusage=usage)
    else:
        raise UnknownKeyType("Unsupported key type")
    return kb
        if config.baseurl.endswith("/"):
            config.baseurl = config.baseurl[:-1]
        OAS.baseurl = "%s:%d" % (config.baseurl, args.port)

    if not OAS.baseurl.endswith("/"):
        OAS.baseurl += "/"

    # load extra keys
    try:
        extern = config.TRUSTED_REGISTRATION_ENTITIES
    except AttributeError:
        pass
    else:
        for ent in extern:
            iss = ent['iss']
            kb = KeyBundle()
            kb.imp_jwks = json.load(open(ent['jwks']))
            kb.do_keys(kb.imp_jwks['keys'])
            OAS.keyjar.add_kb(iss, kb)

    LOGGER.debug("URLS: '%s" % (URLS,))

    # Initiate the web server
    SRV = wsgiserver.CherryPyWSGIServer(('0.0.0.0', args.port), application)
    https = ""
    if config.SERVICE_URL.startswith("https"):
        https = " using HTTPS"
        # SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter(
        #     config.SERVER_CERT, config.SERVER_KEY, config.CERT_CHAIN)
        SRV.ssl_adapter = BuiltinSSLAdapter(config.SERVER_CERT,
                                            config.SERVER_KEY,
Пример #56
0
from pytest import raises

from fakeoicsrv import MyFakeOICServer


def _eq(l1, l2):
    s1 = set(l1)
    s2 = set(l2)
    return s1 == s2


CLIENT_SECRET = "abcdefghijklmnop"
CLIENT_ID = "client_1"

KC_SYM_S = KeyBundle({"kty": "oct", "key": "abcdefghijklmnop", "use": "sig"})

_key = rsa_load("../oc3/certs/mycert.key")
KC_RSA = KeyBundle({"key": _key, "kty": "RSA", "use": "sig"})

KEYJ = KeyJar()
KEYJ[""] = [KC_RSA, KC_SYM_S]
KEYJ["client_1"] = [KC_SYM_S]

IDTOKEN = IdToken(iss="http://oic.example.org/", sub="user_id",
                  aud=CLIENT_ID, exp=utc_time_sans_frac() + 86400,
                  nonce="N0nce",
                  iat=time.time())

# ----------------- CLIENT --------------------
Пример #57
0
from oic.utils.keyio import KeyBundle, key_eq

__author__ = 'rolandh'

jwk_url = ["https://connect.openid4.us/connect4us.jwk", # edmund
       "https://connect-op.heroku.com/jwk.json"]    # nov

x509_url = ["https://connect-op.heroku.com/cert.pem"]

kc0 = KeyBundle(source=jwk_url[1], src_type="jwk", type="rsa", usage=["sig", "enc"])

kc1 = KeyBundle(source=x509_url[0], src_type="x509", type="rsa", usage=["sig", "enc"])

kc0.update()

print kc0

kc1.update()

print kc1

print key_eq(kc0.get("rsa")[0], kc1.get("rsa")[0])
Пример #58
0
class InAcademiaMediator(object):
    """The main CherryPy application, with all exposed endpoints.

    This app mediates between a OpenIDConnect provider front-end, which uses SAML as the back-end for authenticating
    users.
    """

    def __init__(self, base_url, op, sp):
        self.base_url = base_url
        self.op = op
        self.sp = sp

        # Setup key for encrypting/decrypting the state (passed in the SAML RelayState).
        source = "file://symkey.json"
        self.key_bundle = KeyBundle(source=source, fileformat="jwk")

        for key in self.key_bundle.keys():
            key.deserialize()

    @cherrypy.expose
    def index(self):
        raise cherrypy.HTTPRedirect("http://www.inacademia.org")

    @cherrypy.expose
    def status(self):
        return

    @cherrypy.expose
    def authorization(self, *args, **kwargs):
        """Where the OP Authentication Request arrives.
        """
        transaction_session = self.op.verify_authn_request(cherrypy.request.query_string)
        state = self._encode_state(transaction_session)

        log_transaction_start(logger, cherrypy.request, state, transaction_session["client_id"],
                              transaction_session["scope"],
                              transaction_session["redirect_uri"])
        return self.sp.redirect_to_auth(state, transaction_session["scope"])

    @cherrypy.expose
    def disco(self, state=None, entityID=None, **kwargs):
        """Where the SAML Discovery Service response arrives.
        """
        if state is None:
            raise cherrypy.HTTPError(404, _('Page not found.'))

        transaction_session = self._decode_state(state)
        if "error" in kwargs:
            abort_with_client_error(state, transaction_session, cherrypy.request, logger,
                                    "Discovery service error: '{}'.".format(kwargs["error"]))
        elif entityID is None or entityID == "":
            abort_with_client_error(state, transaction_session, cherrypy.request, logger,
                                    "No entity id returned from discovery server.")

        return self.sp.disco(entityID, state, transaction_session)

    @cherrypy.expose
    def error(self, lang=None, error=None):
        """Where the i18n of the error page is handled.
        """
        if error is None:
            raise cherrypy.HTTPError(404, _("Page not found."))

        self._set_language(lang)

        error = json.loads(urllib.unquote_plus(error))
        raise EndUserErrorResponse(**error)

    def webfinger(self, rel=None, resource=None):
        """Where the WebFinger request arrives.

        This function is mapped explicitly using PathDiscpatcher.
        """

        try:
            assert rel == OIC_ISSUER
            assert resource is not None
        except AssertionError as e:
            raise cherrypy.HTTPError(400, "Missing or incorrect parameter in webfinger request.")

        cherrypy.response.headers["Content-Type"] = "application/jrd+json"
        return WebFinger().response(resource, self.op.OP.baseurl)

    def openid_configuration(self):
        """Where the OP configuration request arrives.

        This function is mapped explicitly using PathDispatcher.
        """

        return response_to_cherrypy(self.op.OP.providerinfo_endpoint())

    def consent_allow(self, state=None, released_claims=None):
        """Where the approved consent arrives.

        This function is mapped explicitly using PathDispatcher.
        """
        if state is None or released_claims is None:
            raise cherrypy.HTTPError(404, _("Page not found."))

        state = json.loads(urllib.unquote_plus(state))
        released_claims = json.loads(urllib.unquote_plus(released_claims))
        transaction_session = self._decode_state(state["state"])
        log_internal(logger, "consented claims: {}".format(json.dumps(released_claims)),
                     cherrypy.request, state["state"], transaction_session["client_id"])
        return self.op.id_token(released_claims, state["idp_entity_id"], state["state"],
                                transaction_session)

    def consent_deny(self, state=None, released_claims=None):
        """Where the denied consent arrives.

        This function is mapped explicitly using PathDispatcher.
        """
        if state is None:
            raise cherrypy.HTTPError(404, _("Page not found."))

        state = json.loads(urllib.unquote_plus(state))
        transaction_session = self._decode_state(state["state"])
        negative_transaction_response(state["state"], transaction_session, cherrypy.request, logger,
                                      "User did not give consent.", state["idp_entity_id"])

    def consent_index(self, lang=None, state=None, released_claims=None):
        """Where the i18n of the consent page arrives.

        This function is mapped explicitly using PathDispatcher.
        """
        if state is None or released_claims is None:
            raise cherrypy.HTTPError(404, _("Page not found."))

        self._set_language(lang)

        state = json.loads(urllib.unquote_plus(state))
        rp_client_id = self._decode_state(state["state"])["client_id"]
        released_claims = json.loads(urllib.unquote_plus(released_claims))

        client_name = self._get_client_name(rp_client_id)
        return ConsentPage.render(client_name, state["idp_entity_id"], released_claims,
                                  state["state"])

    def acs_post(self, SAMLResponse=None, RelayState=None, **kwargs):
        """Where the SAML Authentication Response arrives.

        This function is mapped explicitly using PathDiscpatcher.
        """
        return self._acs(SAMLResponse, RelayState, BINDING_HTTP_POST)

    def acs_redirect(self, SAMLResponse=None, RelayState=None):
        """Where the SAML Authentication Response arrives.
        """

        return self._acs(SAMLResponse, RelayState, BINDING_HTTP_REDIRECT)

    def _acs(self, SAMLResponse, RelayState, binding):
        """Handle the SAMLResponse from the IdP and produce the consent page.

        :return: HTML of the OP consent page.
        """
        transaction_session = self._decode_state(RelayState)
        user_id, affiliation, identity, auth_time, idp_entity_id = self.sp.acs(SAMLResponse,
                                                                               binding, RelayState,
                                                                               transaction_session)

        # if we have passed all checks, ask the user for consent before finalizing
        released_claims = self.op.get_claims_to_release(user_id, affiliation, identity, auth_time,
                                                        idp_entity_id,
                                                        self.sp.metadata, transaction_session)
        log_internal(logger, "claims to consent: {}".format(json.dumps(released_claims)),
                     cherrypy.request, RelayState, transaction_session["client_id"])

        client_name = self._get_client_name(transaction_session["client_id"])
        return ConsentPage.render(client_name, idp_entity_id, released_claims, RelayState)

    def _set_language(self, lang):
        """Set the language.
        """
        if lang is None:
            lang = "en"

        # Modify the Accept-Language header and use the CherryPy i18n tool for translation
        cherrypy.request.headers["Accept-Language"] = lang
        i18n_args = {
            "default": cherrypy.config["tools.I18nTool.default"],
            "mo_dir": cherrypy.config["tools.I18nTool.mo_dir"],
            "domain": cherrypy.config["tools.I18nTool.domain"]
        }
        cherrypy.tools.I18nTool.callable(**i18n_args)

    def _decode_state(self, state):
        """Decode the transaction data.

        If the state can not be decoded, the transaction will fail with error page for the user. We can't
        notify the client since the transaction state now is unknown.
        """
        try:
            return deconstruct_state(state, self.key_bundle.keys())
        except DecryptionFailed as e:
            abort_with_enduser_error(state, "-", cherrypy.request, logger,
                                     _(
                                             "We could not complete your validation because an error occurred while handling "
                                             "your request. Please return to the service which initiated the validation "
                                             "request and try again."),
                                     "Transaction state missing or broken in incoming response.")

    def _encode_state(self, payload):
        """Encode the transaction data.
        """
        _kids = self.key_bundle.kids()
        _kids.sort()

        return construct_state(payload, self.key_bundle.get_key_with_kid(_kids[-1]))

    def _get_client_name(self, client_id):
        """Get the display name for the client.

        :return: the clients display name, or client_id if no display name is known.
        """
        try:
            client_info = self.op.OP.cdb[client_id]
            return client_info.get("display_name", client_id)
        except KeyError as e:
            return client_id