Skip to content

Commit

Permalink
add missing limitedReader
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
  • Loading branch information
inteon committed Dec 3, 2023
1 parent 13c946d commit a169f8b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 2 deletions.
12 changes: 11 additions & 1 deletion pkg/webhook/admission/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ import (
var admissionScheme = runtime.NewScheme()
var admissionCodecs = serializer.NewCodecFactory(admissionScheme)

// based on https://github.com/kubernetes/kubernetes/blob/c28c2009181fcc44c5f6b47e10e62dacf53e4da0/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go
var maxRequestSize = int64(3 * 1024 * 1024)

func init() {
utilruntime.Must(v1.AddToScheme(admissionScheme))
utilruntime.Must(v1beta1.AddToScheme(admissionScheme))
Expand All @@ -55,12 +58,19 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

defer r.Body.Close()
body, err := io.ReadAll(r.Body)
limitedReader := &io.LimitedReader{R: r.Body, N: maxRequestSize}
body, err := io.ReadAll(limitedReader)
if err != nil {
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
wh.writeResponse(w, Errored(http.StatusBadRequest, err))
return
}
if limitedReader.N <= 0 {
err := fmt.Errorf("request entity is too large; limit is %d bytes", maxRequestSize)
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request; limit reached")
wh.writeResponse(w, Errored(http.StatusBadRequest, err))
return
}

// verify the content type is accurate
if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
Expand Down
14 changes: 14 additions & 0 deletions pkg/webhook/admission/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package admission
import (
"bytes"
"context"
"crypto/rand"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -84,6 +85,19 @@ var _ = Describe("Admission Webhooks", func() {
Expect(respRecorder.Body.String()).To(Equal(expected))
})

It("should error when given an infinite body", func() {
req := &http.Request{
Header: http.Header{"Content-Type": []string{"application/json"}},
Method: http.MethodPost,
Body: nopCloser{Reader: rand.Reader},
}

expected := `{"response":{"uid":"","allowed":false,"status":{"metadata":{},"message":"request entity is too large; limit is 3145728 bytes","code":400}}}
`
webhook.ServeHTTP(respRecorder, req)
Expect(respRecorder.Body.String()).To(Equal(expected))
})

It("should return the response given by the handler with version defaulted to v1", func() {
req := &http.Request{
Header: http.Header{"Content-Type": []string{"application/json"}},
Expand Down
12 changes: 11 additions & 1 deletion pkg/webhook/authentication/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ import (
var authenticationScheme = runtime.NewScheme()
var authenticationCodecs = serializer.NewCodecFactory(authenticationScheme)

// based on https://github.com/kubernetes/kubernetes/blob/c28c2009181fcc44c5f6b47e10e62dacf53e4da0/staging/src/k8s.io/pod-security-admission/cmd/webhook/server/server.go
var maxRequestSize = int64(3 * 1024 * 1024)

func init() {
utilruntime.Must(authenticationv1.AddToScheme(authenticationScheme))
utilruntime.Must(authenticationv1beta1.AddToScheme(authenticationScheme))
Expand All @@ -55,12 +58,19 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

defer r.Body.Close()
body, err := io.ReadAll(r.Body)
limitedReader := &io.LimitedReader{R: r.Body, N: maxRequestSize}
body, err := io.ReadAll(limitedReader)
if err != nil {
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
wh.writeResponse(w, Errored(err))
return
}
if limitedReader.N <= 0 {
err := fmt.Errorf("request entity is too large; limit is %d bytes", maxRequestSize)
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request; limit reached")
wh.writeResponse(w, Errored(err))
return
}

// verify the content type is accurate
if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
Expand Down
14 changes: 14 additions & 0 deletions pkg/webhook/authentication/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package authentication
import (
"bytes"
"context"
"crypto/rand"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -94,6 +95,19 @@ var _ = Describe("Authentication Webhooks", func() {
Expect(respRecorder.Body.String()).To(Equal(expected))
})

It("should error when given an infinite body", func() {
req := &http.Request{
Header: http.Header{"Content-Type": []string{"application/json"}},
Method: http.MethodPost,
Body: nopCloser{Reader: rand.Reader},
}

expected := `{"metadata":{"creationTimestamp":null},"spec":{},"status":{"user":{},"error":"request entity is too large; limit is 3145728 bytes"}}
`
webhook.ServeHTTP(respRecorder, req)
Expect(respRecorder.Body.String()).To(Equal(expected))
})

It("should return the response given by the handler with version defaulted to v1", func() {
req := &http.Request{
Header: http.Header{"Content-Type": []string{"application/json"}},
Expand Down

0 comments on commit a169f8b

Please sign in to comment.