From 34889a466453fcec5140255aac2e61c8373a845b Mon Sep 17 00:00:00 2001 From: Philip Conrad Date: Mon, 17 Jun 2024 12:29:00 -0400 Subject: [PATCH] server/authorizer: Fix gzip payload handling. This PR fixes an issue where an OPA running authorization policies would be unable to handle gzipped request bodies. Example OPA CLI setup: opa run -s --authorization=basic Example request: echo -n '{}' | gzip | curl -H "Content-Encoding: gzip" --data-binary @- http://127.0.0.1:8181/v1/data This would result in unhelpful error messages, like: ```json { "code": "invalid_parameter", "message": "invalid character '\\x1f' looking for beginning of value" } ``` The cause was that the request body handling system in the `server/authorizer` package did not take gzipped payloads into account. The fix was to borrow the gzip request body handling function from `server/server.go`, to transparently decompress the body when needed. Fixes: #6804 Signed-off-by: Philip Conrad --- server/authorizer/authorizer.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/server/authorizer/authorizer.go b/server/authorizer/authorizer.go index 1f706c56d51..62182ce5e22 100644 --- a/server/authorizer/authorizer.go +++ b/server/authorizer/authorizer.go @@ -6,6 +6,8 @@ package authorizer import ( + "bytes" + "compress/gzip" "context" "io" "net/http" @@ -151,7 +153,6 @@ func (h *Basic) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func makeInput(r *http.Request) (*http.Request, interface{}, error) { - path, err := parsePath(r.URL.Path) if err != nil { return r, nil, err @@ -164,7 +165,11 @@ func makeInput(r *http.Request) (*http.Request, interface{}, error) { if expectBody(r.Method, path) { var err error - rawBody, err = io.ReadAll(r.Body) + plaintextBody, err := readPlainBody(r) + if err != nil { + return r, nil, err + } + rawBody, err = io.ReadAll(plaintextBody) if err != nil { return r, nil, err } @@ -277,3 +282,20 @@ func GetBodyOnContext(ctx context.Context) (interface{}, bool) { } return input.parsed, true } + +// Note(philipc): Copied over from server/server.go +func readPlainBody(r *http.Request) (io.ReadCloser, error) { + if strings.Contains(r.Header.Get("Content-Encoding"), "gzip") { + gzReader, err := gzip.NewReader(r.Body) + if err != nil { + return nil, err + } + bytesBody, err := io.ReadAll(gzReader) + if err != nil { + return nil, err + } + defer gzReader.Close() + return io.NopCloser(bytes.NewReader(bytesBody)), err + } + return r.Body, nil +}