Esempio n. 1
0
    def _func(self, conv):
        _response = conv.last_response
        _content = conv.last_content
        res = {}
        if _response.status_code == 400:
            err = ErrorResponse().deserialize(_content, "json")
            err.verify()
            res["content"] = err.to_json()
            conv.protocol_response.append((err, _content))
            pass
        elif _response.status_code in [301, 302, 303]:
            pass
        elif _response.status_code in SUCCESSFUL:
            err = ErrorResponse().deserialize(_content, "json")
            err.verify()
            res["content"] = err.to_json()
            conv.protocol_response.append((err, _content))
        else:
            self._message = "Expected a 400 error message"
            self._status = CRITICAL

        return res
Esempio n. 2
0
    def _func(self, conv):
        _response = conv.last_response
        _content = conv.last_content
        res = {}
        if _response.status_code == 400:
            err = ErrorResponse().deserialize(_content, "json")
            try:
                err.verify()
            except MissingRequiredAttribute:
                try:
                    self._status = self._kwargs["status"]
                except KeyError:
                    self._status = ERROR
                self._message = "Expected an error message"
            else:
                res["content"] = err.to_json()
        elif _response.status_code in [301, 302, 303]:
            pass
        elif _response.status_code < 300:
            err = ErrorResponse().deserialize(_content, "json")
            try:
                err.verify()
            except MissingRequiredAttribute:
                try:
                    self._status = self._kwargs["status"]
                except KeyError:
                    self._status = ERROR
                self._message = "Expected an error message"
            else:
                res["content"] = err.to_json()
            conv.protocol_response.append((err, _content))
        else:
            self._message = "Expected an error message"
            try:
                self._status = self._kwargs["status"]
            except KeyError:
                self._status = CRITICAL

        return res
Esempio n. 3
0
    def do_patch(self, path, info):
        """
        UPDATE: PATCH /{collection}/{id}

        """

        _name = self.resource_name(path)
        try:
            f = open(_name, "r")
        except IOError:
            return ErrorResponse(error="not_allowed")

        head, tail = os.path.split(_name)

        try:
            _ji = json.loads(info)
        except ValueError:
            return ErrorResponse(error="not_json")

        try:
            assert _ji["_id"] == tail
        except KeyError:
            pass
        except AssertionError:
            return ErrorResponse(error="not_allowed")

        _stored = json.loads(f.read())
        _stored.update(_ji)
        f.close()
        try:
            f = open(_name, "w")
        except IOError:
            return ErrorResponse(error="not_allowed")
        f.write(json.dumps(_stored))
        f.close()
        return Response(json.dumps({"_id": tail}),
                        headers=[("Location",
                                  "%s/%s" % (self.baseurl, self.url(_name)))])
Esempio n. 4
0
    def test_omit(self):
        err = ErrorResponse(
            error="invalid_request",
            error_description="Something was missing",
            error_uri="http://example.com/error_message.html",
        )

        ue_str = err.to_urlencoded()
        del err["error_uri"]
        ueo_str = err.to_urlencoded()

        assert ue_str != ueo_str
        assert "error_message" not in ueo_str
        assert "error_message" in ue_str
Esempio n. 5
0
    def test_end_session_endpoint_with_cookie_dual_login_wrong_client(self):
        self._code_auth()
        self._code_auth2()
        # The cookie states that a user has a session at a client and this
        # statement is false.
        cookie = self._create_cookie("username", "a1b2c3")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
Esempio n. 6
0
    def parse_request_response(self,
                               reqresp,
                               response,
                               body_type,
                               state="",
                               **kwargs):

        if reqresp.status_code in SUCCESSFUL:
            body_type = verify_header(reqresp, body_type)
        elif reqresp.status_code in [302, 303]:  # redirect
            return reqresp
        elif reqresp.status_code == 500:
            logger.error("(%d) %s" %
                         (reqresp.status_code, sanitize(reqresp.text)))
            raise ParseError("ERROR: Something went wrong: %s" % reqresp.text)
        elif reqresp.status_code in [400, 401]:
            # expecting an error response
            if issubclass(response, ErrorResponse):
                pass
        else:
            logger.error("(%d) %s" %
                         (reqresp.status_code, sanitize(reqresp.text)))
            raise HttpError("HTTP ERROR: %s [%s] on %s" %
                            (reqresp.text, reqresp.status_code, reqresp.url))

        if response:
            if body_type == 'txt':
                # no meaning trying to parse unstructured text
                return reqresp.text
            return self.parse_response(response, reqresp.text, body_type,
                                       state, **kwargs)

        # could be an error response
        if reqresp.status_code in [200, 400, 401]:
            if body_type == 'txt':
                body_type = 'urlencoded'
            try:
                err = ErrorResponse().deserialize(reqresp.message,
                                                  method=body_type)
                try:
                    err.verify()
                except PyoidcError:
                    pass
                else:
                    return err
            except Exception:
                pass

        return reqresp
Esempio n. 7
0
    def client_info(self, client_id):
        _cinfo = self.cdb[client_id].copy()
        if not valid_client_info(_cinfo):
            err = ErrorResponse(error="invalid_client",
                                error_description="Invalid client secret")
            return BadRequest(err.to_json(), content="application/json")

        try:
            _cinfo["redirect_uris"] = self._tuples_to_uris(
                _cinfo["redirect_uris"])
        except KeyError:
            pass

        msg = ClientInfoResponse(**_cinfo)
        return Response(msg.to_json(), content="application/json")
Esempio n. 8
0
    def _func(self, conv):
        _response = conv.last_response
        _content = conv.last_content

        res = {}
        if not _response:
            return res

        if _response.status_code >= 400:
            self._status = self.status
            self._message = self.msg
            if CONT_JSON in _response.headers["content-type"]:
                try:
                    err = ErrorResponse().deserialize(_content, "json")
                    self._message = err.to_json()
                except Exception:
                    res["content"] = _content
            else:
                res["content"] = _content
            res["url"] = conv.position
            res["http_status"] = _response.status_code
        elif _response.status_code in [300, 301, 302]:
            pass
        else:
            # might still be an error message
            try:
                err = ErrorResponse().deserialize(_content, "json")
                err.verify()
                self._message = err.to_json()
                self._status = self.status
            except Exception:
                pass

            res["url"] = conv.position

        return res
Esempio n. 9
0
    def handle_registration_info(self, response):
        if response.status_code in SUCCESSFUL:
            resp = ClientInfoResponse().deserialize(response.text, "json")
            self.store_response(resp, response.text)
            self.store_registration_info(resp)
        else:
            resp = ErrorResponse().deserialize(response.text, "json")
            try:
                resp.verify()
                self.store_response(resp, response.text)
            except Exception:
                raise PyoidcError('Registration failed: {}'.format(
                    response.text))

        return resp
Esempio n. 10
0
def exception_to_error_mesg(excep):
    if isinstance(excep, PyoidcError):
        if excep.content_type:
            if isinstance(excep.args, tuple):
                resp = BadRequest(excep.args[0], content=excep.content_type)
            else:
                resp = BadRequest(excep.args, content=excep.content_type)
        else:
            resp = BadRequest()
    else:
        err = ErrorResponse(error='service_error',
                            error_description='{}:{}'.format(
                                excep.__class__.__name__, excep.args))
        resp = BadRequest(err.to_json(), content='application/json')
    return resp
Esempio n. 11
0
    def client_info(self, client_id):
        _cinfo = self.cdb[client_id].copy()
        if not valid_client_info(_cinfo):
            err = ErrorResponse(
                error="invalid_client", error_description="Invalid client secret"
            )
            return BadRequest(err.to_json(), content="application/json")

        try:
            _cinfo["redirect_uris"] = self._tuples_to_uris(_cinfo["redirect_uris"])
        except KeyError:
            pass

        msg = self.server.message_factory.get_response_type("update_endpoint")(**_cinfo)
        return Response(msg.to_json(), content="application/json")
Esempio n. 12
0
    def test_end_session_endpoint_with_cookie_wrong_client(self):
        # Need cookie and ID Token to figure this out
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub", id_token["sub"])

        id_token_hint = id_token.to_jwt(algorithm="none")
        # Wrong client_id
        cookie = self._create_cookie("username", "a1b2c3")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
Esempio n. 13
0
    def test_end_session_endpoint_with_wrong_post_logout_redirect_uri(self):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        post_logout_redirect_uri = "https://www.example.com/logout"
        resp = self.provider.end_session_endpoint(
            urlencode({
                "post_logout_redirect_uri": post_logout_redirect_uri,
                "state": "abcde"
            }),
            cookie=cookie,
        )

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
Esempio n. 14
0
    def handle_registration_info(self, response):
        if response.status_code in SUCCESSFUL:
            resp = self.message_factory.get_response_type(
                "registration_endpoint"
            )().deserialize(response.text, "json")
            self.store_response(resp, response.text)
            self.store_registration_info(resp)
        else:
            resp = ErrorResponse().deserialize(response.text, "json")
            try:
                resp.verify()
                self.store_response(resp, response.text)
            except Exception:
                raise PyoidcError("Registration failed: {}".format(response.text))

        return resp
Esempio n. 15
0
    def test_end_session_endpoint_without_post_logout_redirect_uri_no_default(
            self):
        # No post_logout_redirect_uris registered
        _plru = self.provider.cdb["number5"]["post_logout_redirect_uris"]
        del self.provider.cdb["number5"]["post_logout_redirect_uris"]
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "server_error"
        # restore
        self.provider.cdb["number5"]["post_logout_redirect_uris"] = _plru
Esempio n. 16
0
    def test_end_session_endpoint_with_wrong_cookie(self):
        # Need cookie and ID Token to figure this out
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub",
                           id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        cookie = self._create_cookie("diggins", "number5")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
        assert _err["error_description"] == "Wrong user"
Esempio n. 17
0
def test_parse_access_token_response():
    client = Client()

    at = AccessTokenResponse(access_token="SlAV32hkKG",
                             token_type="Bearer",
                             refresh_token="8xLOxBtZp8",
                             expires_in=3600)

    atj = at.to_json()

    ATR = AccessTokenResponse
    atr = client.parse_response(ATR, info=atj)

    assert _eq(atr.keys(),
               ['access_token', 'token_type', 'expires_in', 'refresh_token'])

    uec = at.to_urlencoded()
    raises(ValueError, 'client.parse_response(ATR, info=uec)')

    uatr = client.parse_response(ATR, info=uec, sformat="urlencoded")
    assert _eq(uatr.keys(),
               ['access_token', 'token_type', 'expires_in', 'refresh_token'])

    huec = "%s?%s" % ("https://example.com/token", uec)

    uatr = client.parse_response(ATR, info=huec, sformat="urlencoded")
    assert _eq(uatr.keys(),
               ['access_token', 'token_type', 'expires_in', 'refresh_token'])

    err = ErrorResponse(error="invalid_request",
                        error_description="Something was missing",
                        error_uri="http://example.com/error_message.html")

    jerr = err.to_json()
    uerr = err.to_urlencoded()

    _ = client.parse_response(ATR, info=jerr)
    _ = client.parse_response(ATR, info=uerr, sformat="urlencoded")

    raises(Exception,
           'client.parse_response(ATR, info=jerr, sformat="urlencoded")')

    raises(Exception, "client.parse_response(ATR, info=uerr)")

    raises(Exception, 'client.parse_response(ATR, info=jerr, sformat="focus")')
Esempio n. 18
0
    def expected_error_response(self, response):
        if isinstance(response, Response):  # requests response
            # don't want bytes
            _txt = response.content.decode('utf8')
            response = ErrorResponse().from_json(_txt)

        if isinstance(response, ErrorResponse):
            self.conv.events.store(EV_PROTOCOL_RESPONSE, response,
                                   sender=self.__class__.__name__)
            if response["error"] not in self.expect_error["error"]:
                raise Break("Wrong error, got {} expected {}".format(
                    response["error"], self.expect_error["error"]))
            try:
                if self.expect_error["stop"]:
                    raise Break("Stop requested after received expected error")
            except KeyError:
                pass
        else:
            self.conv.events.store(EV_FAULT, "Expected error, didn't get it")
            raise Break("Did not receive expected error")

        return response
Esempio n. 19
0
    def test_parse_error_resp(self):
        err = ErrorResponse(
            error="invalid_request",
            error_description="Something was missing",
            error_uri="http://example.com/error_message.html",
        )
        jerr = err.to_json()
        uerr = err.to_urlencoded()

        self.client.parse_response(AccessTokenResponse, info=jerr)
        self.client.parse_response(AccessTokenResponse, info=uerr, sformat="urlencoded")

        with pytest.raises(ResponseError):
            self.client.parse_response(
                AccessTokenResponse, info=jerr, sformat="urlencoded"
            )

        with pytest.raises(DecodeError):
            self.client.parse_response(AccessTokenResponse, info=uerr)

        with pytest.raises(FormatError):
            self.client.parse_response(AccessTokenResponse, info=jerr, sformat="focus")
Esempio n. 20
0
    def _func(self, conv):
        res = {}

        try:
            _response = last_http_response(conv)
        except NoSuchEvent:
            return res

        try:
            _loc = _response.headers["location"]
            if "?" in _loc:
                query = _loc.split("?")[1]
            elif "#" in _loc:
                query = _loc.split("#")[1]
            else:  # ???
                self._message = "Expected a redirect"
                self._status = CRITICAL
                return res
            env_id = conv.events.store(EV_RESPONSE, query)
        except (KeyError, AttributeError):
            self._message = "Expected a redirect"
            self._status = CRITICAL
            return res

        if _response.status_code == 302:
            err = ErrorResponse().deserialize(query, "urlencoded")
            try:
                err.verify()
                res["content"] = err.to_json()
                conv.events.store(EV_PROTOCOL_RESPONSE, err, env_id)
            except MissingRequiredAttribute:
                self._message = "Expected an error message"
                self._status = CRITICAL
        else:
            self._message = "Expected an error message"
            self._status = CRITICAL

        return res
Esempio n. 21
0
    def _func(self, conv):
        res = {}

        try:
            _response = last_http_response(conv)
        except NoSuchEvent:
            return res

        if _response.status_code not in [200, 300, 301, 302, 400, 401]:
            self._status = self.status
            self._message = self.msg
            if CONT_JSON in _response.headers["content-type"]:
                try:
                    err = ErrorResponse().deserialize(_response.txt, "json")
                    self._message = err.to_json()
                except Exception:
                    res["content"] = _response.text
            else:
                res["content"] = _response.text
            res["url"] = _response.url
            res["http_status"] = _response.status_code

        return res
Esempio n. 22
0
    def _func(self, conv):
        res = {}
        # did I get one, should only be one
        try:
            _ = get_protocol_response(conv, ErrorResponse)[0]
        except ValueError:
            pass
        else:
            return res

        try:
            _response = last_http_response(conv)
        except NoSuchEvent:
            return {}

        if _response.status_code >= 400:
            content_type = _response.headers["content-type"]
            _content = _response.text
            if content_type is None:
                res["content"] = _content
            elif CONT_JSON in content_type:
                try:
                    self.err = ErrorResponse().deserialize(_content, "json")
                    self.err.verify()
                    res["content"] = self.err.to_json()
                except Exception:
                    res["content"] = _content
            else:
                res["content"] = _content
        elif _response.status_code in [300, 301, 302, 303]:
            pass
        else:
            # Should never get here
            self._message = 'Not an error message ??'
            self._status = WARNING

        return res
Esempio n. 23
0
    def do_query(self, path, query):
        """

        """
        _name = self.resource_name(path)
        try:
            assert os.path.exists(_name)
            assert os.path.isdir(_name)
        except AssertionError:
            ErrorResponse(error="not_allowed")

        _filt = parse_qs(query)
        res = []

        for _p in os.listdir(path):
            if os.path.isfile(_p):
                try:
                    data = open(_p, "r").read()
                except IOError:
                    pass
                else:
                    _j = json.loads(data)
                    match = True
                    for key, vals in list(_filt.items()):
                        if not match:
                            break
                        for val in vals:
                            try:
                                assert val in _j[key]
                            except (AssertionError, KeyError):
                                match = False
                                break
                    if match:
                        res.append(_j)

        return Response(json.dumps(res))
Esempio n. 24
0
    def handle_response(self, r, csi):
        data = self.conv.events.last_item(EV_REQUEST)
        try:
            state = data['state']
        except KeyError:
            state = ''

        if 300 < r.status_code < 400:
            resp = self.conv.entity.parse_response(self.response,
                                                   info=r.headers['location'],
                                                   sformat="urlencoded",
                                                   state=state)
        elif r.status_code == 200:
            if "response_mode" in csi and csi["response_mode"] == "form_post":
                resp = self.response()
                forms = BeautifulSoup(r.text).findAll('form')
                for inp in forms[0].find_all("input"):
                    resp[inp.attrs["name"]] = inp.attrs["value"]
            else:
                if r.is_redirect or r.is_permanent_redirect:
                    resp = self.conv.entity.parse_response(
                        self.response,
                        info=r.headers['location'],
                        sformat="urlencoded",
                        state=state)
                else:
                    resp = self.conv.entity.parse_response(self.response,
                                                           info=r.text,
                                                           sformat="json",
                                                           state=state)

            _ent = self.conv.entity
            if isinstance(resp, AccessTokenResponse):
                if 'id_token' in resp and isinstance(resp['id_token'],
                                                     IdToken):
                    pass
                else:
                    resp.verify(keyjar=_ent.keyjar,
                                client_id=_ent.client_id,
                                iss=_ent.provider_info['issuer'])
            else:
                resp.verify(keyjar=_ent.keyjar,
                            client_id=_ent.client_id,
                            iss=_ent.provider_info['issuer'])

        elif r.status_code == 400:
            if r.headers['content-type'] == 'application/json':
                resp = ErrorResponse().from_json(r.text)
            else:
                resp = ErrorResponse(error='service_error',
                                     error_description=r.text)
        else:
            resp = r

        if not isinstance(resp, Response):  # Not a HTTP response
            try:
                try:
                    _id_token = resp["id_token"]
                except KeyError:
                    pass
                else:
                    if _id_token.jws_header:
                        self.conv.events.store('JWS header',
                                               _id_token.jws_header)
                    if _id_token.jwe_header:
                        self.conv.events.store('JWE header',
                                               _id_token.jwe_header)
                    if "kid" not in _id_token.jws_header and not \
                            _id_token.jws_header["alg"] == "HS256":
                        keys = self.conv.entity.keyjar.keys_by_alg_and_usage(
                            issuer=_id_token['iss'],
                            alg=_id_token.jws_header["alg"],
                            usage='sig')
                        if len(keys) > 1:
                            raise ParameterError(
                                "No 'kid' in id_token header!")

                    try:
                        if self.req_args['nonce'] != _id_token['nonce']:
                            raise ParameterError(
                                "invalid nonce! {} != {}".format(
                                    self.req_args['nonce'],
                                    _id_token['nonce']))
                    except KeyError:
                        pass

                    if not same_issuer(self.conv.info["issuer"],
                                       _id_token["iss"]):
                        raise IssuerMismatch(" {} != {}".format(
                            self.conv.info["issuer"], _id_token["iss"]))
                    self.conv.entity.id_token = _id_token
            except KeyError:
                pass

        return resp
Esempio n. 25
0
def error_response(error, descr=None, status="400 Bad Request"):
    logger.error("%s" % sanitize(error))
    response = ErrorResponse(error=error, error_description=descr)
    return Response(response.to_json(),
                    content="application/json",
                    status=status)
Esempio n. 26
0
def do_response(response, conv, url, trace, client, body_type, response_type,
                state, **kwargs):
    """

    :param response:
    :param conv:
    :param url:
    :param trace:
    :param client:
    :param body_type:
    :param response_type:
    :param state:
    :param kwargs:
    :return:
    """
    conv.position = url
    conv.last_response = response
    conv.last_content = response.content

    trace.reply("STATUS: %d" % response.status_code)

    _response = None
    if response.status_code >= 400:  # an error
        if response.text:
            try:
                _response = ErrorResponse().from_json(response.text)
            except (MessageException, ValueError):
                trace.reply("Non OIDC error message: %s" % response.content)
        else:
            raise MissingErrorResponse()
    elif response.status_code == 204:  # No response
        _response = Message()
    else:
        try:
            uiendp = client.provider_info["userinfo_endpoint"]
        except KeyError:
            uiendp = ""

        if uiendp == url:
            _iss = client.provider_info["issuer"]
            _ver_keys = client.keyjar.get("ver", issuer=_iss)
            _info = [(k.kid, k.kty) for k in _ver_keys]
            trace.info("Available verification keys: {}".format(_info))
            kwargs["key"] = _ver_keys
            _dec_keys = client.keyjar.get("enc", issuer="")
            _info = [(k.kid, k.kty) for k in _dec_keys]
            trace.info("Available decryption keys: {}".format(_info))
            kwargs["key"].extend(_dec_keys)
        elif "keyjar" not in kwargs:
            kwargs["keyjar"] = conv.keyjar

        if "issuer_mismatch" in client.allow:
            kwargs["sender"] = client.provider_info["issuer"]

        trace.reply("BODY: %s" % response.text)
        try:
            _response = client.parse_request_response(response, response_type,
                                                      body_type, state,
                                                      **kwargs)
        except DecryptionFailed:
            p = JWT().unpack(response)
            trace.log(
                "Failed decryption on response with JWT header {}".format(
                    p[0]))
            raise

        # Need special handling of id_token
        if "id_token" in _response:
            _dict = json.loads(response.text)
            conv.id_token = _dict["id_token"]
            # header = json.loads(b64d(str(conv.id_token.split(".")[0])))
            # trace.info("IdToken JWT header: %s" % header)
        else:
            try:
                res = JWT().unpack(response.content)
            except (BadSyntax, TypeError):
                pass
            else:
                trace.info("JWT header: {}".format(res))

    if _response is None:
        conv.protocol_response.append((_response, ""))
    else:
        conv.protocol_response.append((_response, response.content))

    return _response
 def _error(error, descr=None):
     response = ErrorResponse(error=error, error_description=descr)
     return Response(response.to_json(),
                     content="application/json",
                     status="400 Bad Request")
Esempio n. 28
0
    def test_missing_required(self):
        err = ErrorResponse()
        assert "error" not in err

        with pytest.raises(MissingRequiredAttribute):
            err.to_urlencoded()
Esempio n. 29
0
    def test_update_with_error_resp(self):
        err = ErrorResponse(error="invalid_request")
        grant = Grant()
        grant.update(err)

        assert len(grant.tokens) == 0
Esempio n. 30
0
 def _redirect_authz_error(error, redirect_uri, descr=None):
     err = ErrorResponse(error=error)
     if descr:
         err["error_description"] = descr
     location = err.request(redirect_uri)
     return Redirect(location)