-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
webhook.go
126 lines (102 loc) · 3.73 KB
/
webhook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package authentication
import (
"context"
"errors"
"net/http"
"sync"
"github.com/go-logr/logr"
authenticationv1 "k8s.io/api/authentication/v1"
"k8s.io/klog/v2"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
var (
errUnableToEncodeResponse = errors.New("unable to encode response")
)
// Request defines the input for an authentication handler.
// It contains information to identify the object in
// question (group, version, kind, resource, subresource,
// name, namespace), as well as the operation in question
// (e.g. Get, Create, etc), and the object itself.
type Request struct {
authenticationv1.TokenReview
}
// Response is the output of an authentication handler.
// It contains a response indicating if a given
// operation is allowed.
type Response struct {
authenticationv1.TokenReview
}
// Complete populates any fields that are yet to be set in
// the underlying TokenResponse, It mutates the response.
func (r *Response) Complete(req Request) error {
r.UID = req.UID
return nil
}
// Handler can handle an TokenReview.
type Handler interface {
// Handle yields a response to an TokenReview.
//
// The supplied context is extracted from the received http.Request, allowing wrapping
// http.Handlers to inject values into and control cancelation of downstream request processing.
Handle(context.Context, Request) Response
}
// HandlerFunc implements Handler interface using a single function.
type HandlerFunc func(context.Context, Request) Response
var _ Handler = HandlerFunc(nil)
// Handle process the TokenReview by invoking the underlying function.
func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
return f(ctx, req)
}
// Webhook represents each individual webhook.
type Webhook struct {
// Handler actually processes an authentication request returning whether it was authenticated or unauthenticated,
// and potentially patches to apply to the handler.
Handler Handler
// WithContextFunc will allow you to take the http.Request.Context() and
// add any additional information such as passing the request path or
// headers thus allowing you to read them from within the handler
WithContextFunc func(context.Context, *http.Request) context.Context
setupLogOnce sync.Once
log logr.Logger
}
// Handle processes TokenReview.
func (wh *Webhook) Handle(ctx context.Context, req Request) Response {
resp := wh.Handler.Handle(ctx, req)
if err := resp.Complete(req); err != nil {
wh.getLogger(&req).Error(err, "unable to encode response")
return Errored(errUnableToEncodeResponse)
}
return resp
}
// getLogger constructs a logger from the injected log and LogConstructor.
func (wh *Webhook) getLogger(req *Request) logr.Logger {
wh.setupLogOnce.Do(func() {
if wh.log.GetSink() == nil {
wh.log = logf.Log.WithName("authentication")
}
})
return logConstructor(wh.log, req)
}
// logConstructor adds some commonly interesting fields to the given logger.
func logConstructor(base logr.Logger, req *Request) logr.Logger {
if req != nil {
return base.WithValues("object", klog.KRef(req.Namespace, req.Name),
"namespace", req.Namespace, "name", req.Name,
"user", req.Status.User.Username,
"requestID", req.UID,
)
}
return base
}