...
1
16
17 package authentication
18
19 import (
20 "encoding/json"
21 "errors"
22 "fmt"
23 "io"
24 "net/http"
25
26 authenticationv1 "k8s.io/api/authentication/v1"
27 authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/runtime/serializer"
31 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
32 )
33
34 var authenticationScheme = runtime.NewScheme()
35 var authenticationCodecs = serializer.NewCodecFactory(authenticationScheme)
36
37
38
39
40
41
42 const maxRequestSize = int64(1 * 1024 * 1024)
43
44 func init() {
45 utilruntime.Must(authenticationv1.AddToScheme(authenticationScheme))
46 utilruntime.Must(authenticationv1beta1.AddToScheme(authenticationScheme))
47 }
48
49 var _ http.Handler = &Webhook{}
50
51 func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
52 ctx := r.Context()
53 if wh.WithContextFunc != nil {
54 ctx = wh.WithContextFunc(ctx, r)
55 }
56
57 if r.Body == nil || r.Body == http.NoBody {
58 err := errors.New("request body is empty")
59 wh.getLogger(nil).Error(err, "bad request")
60 wh.writeResponse(w, Errored(err))
61 return
62 }
63
64 defer r.Body.Close()
65 limitedReader := &io.LimitedReader{R: r.Body, N: maxRequestSize}
66 body, err := io.ReadAll(limitedReader)
67 if err != nil {
68 wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
69 wh.writeResponse(w, Errored(err))
70 return
71 }
72 if limitedReader.N <= 0 {
73 err := fmt.Errorf("request entity is too large; limit is %d bytes", maxRequestSize)
74 wh.getLogger(nil).Error(err, "unable to read the body from the incoming request; limit reached")
75 wh.writeResponse(w, Errored(err))
76 return
77 }
78
79
80 if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
81 err := fmt.Errorf("contentType=%s, expected application/json", contentType)
82 wh.getLogger(nil).Error(err, "unable to process a request with unknown content type")
83 wh.writeResponse(w, Errored(err))
84 return
85 }
86
87
88
89
90
91
92
93
94 req := Request{}
95 ar := unversionedTokenReview{}
96
97 ar.TokenReview = &req.TokenReview
98 ar.SetGroupVersionKind(authenticationv1.SchemeGroupVersion.WithKind("TokenReview"))
99 _, actualTokRevGVK, err := authenticationCodecs.UniversalDeserializer().Decode(body, nil, &ar)
100 if err != nil {
101 wh.getLogger(nil).Error(err, "unable to decode the request")
102 wh.writeResponse(w, Errored(err))
103 return
104 }
105 wh.getLogger(&req).V(5).Info("received request")
106
107 if req.Spec.Token == "" {
108 err := errors.New("token is empty")
109 wh.getLogger(&req).Error(err, "bad request")
110 wh.writeResponse(w, Errored(err))
111 return
112 }
113
114 wh.writeResponseTyped(w, wh.Handle(ctx, req), actualTokRevGVK)
115 }
116
117
118 func (wh *Webhook) writeResponse(w io.Writer, response Response) {
119 wh.writeTokenResponse(w, response.TokenReview)
120 }
121
122
123
124 func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, tokRevGVK *schema.GroupVersionKind) {
125 ar := response.TokenReview
126
127
128
129 if tokRevGVK == nil || *tokRevGVK == (schema.GroupVersionKind{}) {
130 ar.SetGroupVersionKind(authenticationv1.SchemeGroupVersion.WithKind("TokenReview"))
131 } else {
132 ar.SetGroupVersionKind(*tokRevGVK)
133 }
134 wh.writeTokenResponse(w, ar)
135 }
136
137
138 func (wh *Webhook) writeTokenResponse(w io.Writer, ar authenticationv1.TokenReview) {
139 if err := json.NewEncoder(w).Encode(ar); err != nil {
140 wh.getLogger(nil).Error(err, "unable to encode the response")
141 wh.writeResponse(w, Errored(err))
142 }
143 res := ar
144 wh.getLogger(nil).V(5).Info("wrote response", "requestID", res.UID, "authenticated", res.Status.Authenticated)
145 }
146
147
148 type unversionedTokenReview struct {
149 *authenticationv1.TokenReview
150 }
151
152 var _ runtime.Object = &unversionedTokenReview{}
153
View as plain text