Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / client-go / transport / round_trippers.go
1 /*
2 Copyright 2015 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package transport
18
19 import (
20         "fmt"
21         "net/http"
22         "strings"
23         "time"
24
25         "golang.org/x/oauth2"
26         "k8s.io/klog"
27
28         utilnet "k8s.io/apimachinery/pkg/util/net"
29 )
30
31 // HTTPWrappersForConfig wraps a round tripper with any relevant layered
32 // behavior from the config. Exposed to allow more clients that need HTTP-like
33 // behavior but then must hijack the underlying connection (like WebSocket or
34 // HTTP2 clients). Pure HTTP clients should use the RoundTripper returned from
35 // New.
36 func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) {
37         if config.WrapTransport != nil {
38                 rt = config.WrapTransport(rt)
39         }
40
41         rt = DebugWrappers(rt)
42
43         // Set authentication wrappers
44         switch {
45         case config.HasBasicAuth() && config.HasTokenAuth():
46                 return nil, fmt.Errorf("username/password or bearer token may be set, but not both")
47         case config.HasTokenAuth():
48                 var err error
49                 rt, err = NewBearerAuthWithRefreshRoundTripper(config.BearerToken, config.BearerTokenFile, rt)
50                 if err != nil {
51                         return nil, err
52                 }
53         case config.HasBasicAuth():
54                 rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt)
55         }
56         if len(config.UserAgent) > 0 {
57                 rt = NewUserAgentRoundTripper(config.UserAgent, rt)
58         }
59         if len(config.Impersonate.UserName) > 0 ||
60                 len(config.Impersonate.Groups) > 0 ||
61                 len(config.Impersonate.Extra) > 0 {
62                 rt = NewImpersonatingRoundTripper(config.Impersonate, rt)
63         }
64         return rt, nil
65 }
66
67 // DebugWrappers wraps a round tripper and logs based on the current log level.
68 func DebugWrappers(rt http.RoundTripper) http.RoundTripper {
69         switch {
70         case bool(klog.V(9)):
71                 rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders)
72         case bool(klog.V(8)):
73                 rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders)
74         case bool(klog.V(7)):
75                 rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus)
76         case bool(klog.V(6)):
77                 rt = newDebuggingRoundTripper(rt, debugURLTiming)
78         }
79
80         return rt
81 }
82
83 type requestCanceler interface {
84         CancelRequest(*http.Request)
85 }
86
87 type authProxyRoundTripper struct {
88         username string
89         groups   []string
90         extra    map[string][]string
91
92         rt http.RoundTripper
93 }
94
95 // NewAuthProxyRoundTripper provides a roundtripper which will add auth proxy fields to requests for
96 // authentication terminating proxy cases
97 // assuming you pull the user from the context:
98 // username is the user.Info.GetName() of the user
99 // groups is the user.Info.GetGroups() of the user
100 // extra is the user.Info.GetExtra() of the user
101 // extra can contain any additional information that the authenticator
102 // thought was interesting, for example authorization scopes.
103 // In order to faithfully round-trip through an impersonation flow, these keys
104 // MUST be lowercase.
105 func NewAuthProxyRoundTripper(username string, groups []string, extra map[string][]string, rt http.RoundTripper) http.RoundTripper {
106         return &authProxyRoundTripper{
107                 username: username,
108                 groups:   groups,
109                 extra:    extra,
110                 rt:       rt,
111         }
112 }
113
114 func (rt *authProxyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
115         req = utilnet.CloneRequest(req)
116         SetAuthProxyHeaders(req, rt.username, rt.groups, rt.extra)
117
118         return rt.rt.RoundTrip(req)
119 }
120
121 // SetAuthProxyHeaders stomps the auth proxy header fields.  It mutates its argument.
122 func SetAuthProxyHeaders(req *http.Request, username string, groups []string, extra map[string][]string) {
123         req.Header.Del("X-Remote-User")
124         req.Header.Del("X-Remote-Group")
125         for key := range req.Header {
126                 if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) {
127                         req.Header.Del(key)
128                 }
129         }
130
131         req.Header.Set("X-Remote-User", username)
132         for _, group := range groups {
133                 req.Header.Add("X-Remote-Group", group)
134         }
135         for key, values := range extra {
136                 for _, value := range values {
137                         req.Header.Add("X-Remote-Extra-"+headerKeyEscape(key), value)
138                 }
139         }
140 }
141
142 func (rt *authProxyRoundTripper) CancelRequest(req *http.Request) {
143         if canceler, ok := rt.rt.(requestCanceler); ok {
144                 canceler.CancelRequest(req)
145         } else {
146                 klog.Errorf("CancelRequest not implemented by %T", rt.rt)
147         }
148 }
149
150 func (rt *authProxyRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
151
152 type userAgentRoundTripper struct {
153         agent string
154         rt    http.RoundTripper
155 }
156
157 func NewUserAgentRoundTripper(agent string, rt http.RoundTripper) http.RoundTripper {
158         return &userAgentRoundTripper{agent, rt}
159 }
160
161 func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
162         if len(req.Header.Get("User-Agent")) != 0 {
163                 return rt.rt.RoundTrip(req)
164         }
165         req = utilnet.CloneRequest(req)
166         req.Header.Set("User-Agent", rt.agent)
167         return rt.rt.RoundTrip(req)
168 }
169
170 func (rt *userAgentRoundTripper) CancelRequest(req *http.Request) {
171         if canceler, ok := rt.rt.(requestCanceler); ok {
172                 canceler.CancelRequest(req)
173         } else {
174                 klog.Errorf("CancelRequest not implemented by %T", rt.rt)
175         }
176 }
177
178 func (rt *userAgentRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
179
180 type basicAuthRoundTripper struct {
181         username string
182         password string
183         rt       http.RoundTripper
184 }
185
186 // NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a
187 // request unless it has already been set.
188 func NewBasicAuthRoundTripper(username, password string, rt http.RoundTripper) http.RoundTripper {
189         return &basicAuthRoundTripper{username, password, rt}
190 }
191
192 func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
193         if len(req.Header.Get("Authorization")) != 0 {
194                 return rt.rt.RoundTrip(req)
195         }
196         req = utilnet.CloneRequest(req)
197         req.SetBasicAuth(rt.username, rt.password)
198         return rt.rt.RoundTrip(req)
199 }
200
201 func (rt *basicAuthRoundTripper) CancelRequest(req *http.Request) {
202         if canceler, ok := rt.rt.(requestCanceler); ok {
203                 canceler.CancelRequest(req)
204         } else {
205                 klog.Errorf("CancelRequest not implemented by %T", rt.rt)
206         }
207 }
208
209 func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
210
211 // These correspond to the headers used in pkg/apis/authentication.  We don't want the package dependency,
212 // but you must not change the values.
213 const (
214         // ImpersonateUserHeader is used to impersonate a particular user during an API server request
215         ImpersonateUserHeader = "Impersonate-User"
216
217         // ImpersonateGroupHeader is used to impersonate a particular group during an API server request.
218         // It can be repeated multiplied times for multiple groups.
219         ImpersonateGroupHeader = "Impersonate-Group"
220
221         // ImpersonateUserExtraHeaderPrefix is a prefix for a header used to impersonate an entry in the
222         // extra map[string][]string for user.Info.  The key for the `extra` map is suffix.
223         // The same key can be repeated multiple times to have multiple elements in the slice under a single key.
224         // For instance:
225         // Impersonate-Extra-Foo: one
226         // Impersonate-Extra-Foo: two
227         // results in extra["Foo"] = []string{"one", "two"}
228         ImpersonateUserExtraHeaderPrefix = "Impersonate-Extra-"
229 )
230
231 type impersonatingRoundTripper struct {
232         impersonate ImpersonationConfig
233         delegate    http.RoundTripper
234 }
235
236 // NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set.
237 func NewImpersonatingRoundTripper(impersonate ImpersonationConfig, delegate http.RoundTripper) http.RoundTripper {
238         return &impersonatingRoundTripper{impersonate, delegate}
239 }
240
241 func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
242         // use the user header as marker for the rest.
243         if len(req.Header.Get(ImpersonateUserHeader)) != 0 {
244                 return rt.delegate.RoundTrip(req)
245         }
246         req = utilnet.CloneRequest(req)
247         req.Header.Set(ImpersonateUserHeader, rt.impersonate.UserName)
248
249         for _, group := range rt.impersonate.Groups {
250                 req.Header.Add(ImpersonateGroupHeader, group)
251         }
252         for k, vv := range rt.impersonate.Extra {
253                 for _, v := range vv {
254                         req.Header.Add(ImpersonateUserExtraHeaderPrefix+headerKeyEscape(k), v)
255                 }
256         }
257
258         return rt.delegate.RoundTrip(req)
259 }
260
261 func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) {
262         if canceler, ok := rt.delegate.(requestCanceler); ok {
263                 canceler.CancelRequest(req)
264         } else {
265                 klog.Errorf("CancelRequest not implemented by %T", rt.delegate)
266         }
267 }
268
269 func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.delegate }
270
271 type bearerAuthRoundTripper struct {
272         bearer string
273         source oauth2.TokenSource
274         rt     http.RoundTripper
275 }
276
277 // NewBearerAuthRoundTripper adds the provided bearer token to a request
278 // unless the authorization header has already been set.
279 func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
280         return &bearerAuthRoundTripper{bearer, nil, rt}
281 }
282
283 // NewBearerAuthRoundTripper adds the provided bearer token to a request
284 // unless the authorization header has already been set.
285 // If tokenFile is non-empty, it is periodically read,
286 // and the last successfully read content is used as the bearer token.
287 // If tokenFile is non-empty and bearer is empty, the tokenFile is read
288 // immediately to populate the initial bearer token.
289 func NewBearerAuthWithRefreshRoundTripper(bearer string, tokenFile string, rt http.RoundTripper) (http.RoundTripper, error) {
290         if len(tokenFile) == 0 {
291                 return &bearerAuthRoundTripper{bearer, nil, rt}, nil
292         }
293         source := NewCachedFileTokenSource(tokenFile)
294         if len(bearer) == 0 {
295                 token, err := source.Token()
296                 if err != nil {
297                         return nil, err
298                 }
299                 bearer = token.AccessToken
300         }
301         return &bearerAuthRoundTripper{bearer, source, rt}, nil
302 }
303
304 func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
305         if len(req.Header.Get("Authorization")) != 0 {
306                 return rt.rt.RoundTrip(req)
307         }
308
309         req = utilnet.CloneRequest(req)
310         token := rt.bearer
311         if rt.source != nil {
312                 if refreshedToken, err := rt.source.Token(); err == nil {
313                         token = refreshedToken.AccessToken
314                 }
315         }
316         req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
317         return rt.rt.RoundTrip(req)
318 }
319
320 func (rt *bearerAuthRoundTripper) CancelRequest(req *http.Request) {
321         if canceler, ok := rt.rt.(requestCanceler); ok {
322                 canceler.CancelRequest(req)
323         } else {
324                 klog.Errorf("CancelRequest not implemented by %T", rt.rt)
325         }
326 }
327
328 func (rt *bearerAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
329
330 // requestInfo keeps track of information about a request/response combination
331 type requestInfo struct {
332         RequestHeaders http.Header
333         RequestVerb    string
334         RequestURL     string
335
336         ResponseStatus  string
337         ResponseHeaders http.Header
338         ResponseErr     error
339
340         Duration time.Duration
341 }
342
343 // newRequestInfo creates a new RequestInfo based on an http request
344 func newRequestInfo(req *http.Request) *requestInfo {
345         return &requestInfo{
346                 RequestURL:     req.URL.String(),
347                 RequestVerb:    req.Method,
348                 RequestHeaders: req.Header,
349         }
350 }
351
352 // complete adds information about the response to the requestInfo
353 func (r *requestInfo) complete(response *http.Response, err error) {
354         if err != nil {
355                 r.ResponseErr = err
356                 return
357         }
358         r.ResponseStatus = response.Status
359         r.ResponseHeaders = response.Header
360 }
361
362 // toCurl returns a string that can be run as a command in a terminal (minus the body)
363 func (r *requestInfo) toCurl() string {
364         headers := ""
365         for key, values := range r.RequestHeaders {
366                 for _, value := range values {
367                         headers += fmt.Sprintf(` -H %q`, fmt.Sprintf("%s: %s", key, value))
368                 }
369         }
370
371         return fmt.Sprintf("curl -k -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL)
372 }
373
374 // debuggingRoundTripper will display information about the requests passing
375 // through it based on what is configured
376 type debuggingRoundTripper struct {
377         delegatedRoundTripper http.RoundTripper
378
379         levels map[debugLevel]bool
380 }
381
382 type debugLevel int
383
384 const (
385         debugJustURL debugLevel = iota
386         debugURLTiming
387         debugCurlCommand
388         debugRequestHeaders
389         debugResponseStatus
390         debugResponseHeaders
391 )
392
393 func newDebuggingRoundTripper(rt http.RoundTripper, levels ...debugLevel) *debuggingRoundTripper {
394         drt := &debuggingRoundTripper{
395                 delegatedRoundTripper: rt,
396                 levels:                make(map[debugLevel]bool, len(levels)),
397         }
398         for _, v := range levels {
399                 drt.levels[v] = true
400         }
401         return drt
402 }
403
404 func (rt *debuggingRoundTripper) CancelRequest(req *http.Request) {
405         if canceler, ok := rt.delegatedRoundTripper.(requestCanceler); ok {
406                 canceler.CancelRequest(req)
407         } else {
408                 klog.Errorf("CancelRequest not implemented by %T", rt.delegatedRoundTripper)
409         }
410 }
411
412 func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
413         reqInfo := newRequestInfo(req)
414
415         if rt.levels[debugJustURL] {
416                 klog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL)
417         }
418         if rt.levels[debugCurlCommand] {
419                 klog.Infof("%s", reqInfo.toCurl())
420
421         }
422         if rt.levels[debugRequestHeaders] {
423                 klog.Infof("Request Headers:")
424                 for key, values := range reqInfo.RequestHeaders {
425                         for _, value := range values {
426                                 klog.Infof("    %s: %s", key, value)
427                         }
428                 }
429         }
430
431         startTime := time.Now()
432         response, err := rt.delegatedRoundTripper.RoundTrip(req)
433         reqInfo.Duration = time.Since(startTime)
434
435         reqInfo.complete(response, err)
436
437         if rt.levels[debugURLTiming] {
438                 klog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
439         }
440         if rt.levels[debugResponseStatus] {
441                 klog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
442         }
443         if rt.levels[debugResponseHeaders] {
444                 klog.Infof("Response Headers:")
445                 for key, values := range reqInfo.ResponseHeaders {
446                         for _, value := range values {
447                                 klog.Infof("    %s: %s", key, value)
448                         }
449                 }
450         }
451
452         return response, err
453 }
454
455 func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper {
456         return rt.delegatedRoundTripper
457 }
458
459 func legalHeaderByte(b byte) bool {
460         return int(b) < len(legalHeaderKeyBytes) && legalHeaderKeyBytes[b]
461 }
462
463 func shouldEscape(b byte) bool {
464         // url.PathUnescape() returns an error if any '%' is not followed by two
465         // hexadecimal digits, so we'll intentionally encode it.
466         return !legalHeaderByte(b) || b == '%'
467 }
468
469 func headerKeyEscape(key string) string {
470         buf := strings.Builder{}
471         for i := 0; i < len(key); i++ {
472                 b := key[i]
473                 if shouldEscape(b) {
474                         // %-encode bytes that should be escaped:
475                         // https://tools.ietf.org/html/rfc3986#section-2.1
476                         fmt.Fprintf(&buf, "%%%02X", b)
477                         continue
478                 }
479                 buf.WriteByte(b)
480         }
481         return buf.String()
482 }
483
484 // legalHeaderKeyBytes was copied from net/http/lex.go's isTokenTable.
485 // See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
486 var legalHeaderKeyBytes = [127]bool{
487         '%':  true,
488         '!':  true,
489         '#':  true,
490         '$':  true,
491         '&':  true,
492         '\'': true,
493         '*':  true,
494         '+':  true,
495         '-':  true,
496         '.':  true,
497         '0':  true,
498         '1':  true,
499         '2':  true,
500         '3':  true,
501         '4':  true,
502         '5':  true,
503         '6':  true,
504         '7':  true,
505         '8':  true,
506         '9':  true,
507         'A':  true,
508         'B':  true,
509         'C':  true,
510         'D':  true,
511         'E':  true,
512         'F':  true,
513         'G':  true,
514         'H':  true,
515         'I':  true,
516         'J':  true,
517         'K':  true,
518         'L':  true,
519         'M':  true,
520         'N':  true,
521         'O':  true,
522         'P':  true,
523         'Q':  true,
524         'R':  true,
525         'S':  true,
526         'T':  true,
527         'U':  true,
528         'W':  true,
529         'V':  true,
530         'X':  true,
531         'Y':  true,
532         'Z':  true,
533         '^':  true,
534         '_':  true,
535         '`':  true,
536         'a':  true,
537         'b':  true,
538         'c':  true,
539         'd':  true,
540         'e':  true,
541         'f':  true,
542         'g':  true,
543         'h':  true,
544         'i':  true,
545         'j':  true,
546         'k':  true,
547         'l':  true,
548         'm':  true,
549         'n':  true,
550         'o':  true,
551         'p':  true,
552         'q':  true,
553         'r':  true,
554         's':  true,
555         't':  true,
556         'u':  true,
557         'v':  true,
558         'w':  true,
559         'x':  true,
560         'y':  true,
561         'z':  true,
562         '|':  true,
563         '~':  true,
564 }