1/*
2Copyright 2016 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package filters
18
19import (
20	"bufio"
21	"net"
22	"net/http"
23	"net/http/httptest"
24	"reflect"
25	"sync"
26	"testing"
27	"time"
28
29	"github.com/google/uuid"
30
31	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32	"k8s.io/apimachinery/pkg/types"
33	"k8s.io/apimachinery/pkg/util/wait"
34	auditinternal "k8s.io/apiserver/pkg/apis/audit"
35	"k8s.io/apiserver/pkg/audit/policy"
36	"k8s.io/apiserver/pkg/authentication/user"
37	"k8s.io/apiserver/pkg/endpoints/request"
38)
39
40type fakeAuditSink struct {
41	lock   sync.Mutex
42	events []*auditinternal.Event
43}
44
45func (s *fakeAuditSink) ProcessEvents(evs ...*auditinternal.Event) bool {
46	s.lock.Lock()
47	defer s.lock.Unlock()
48	for _, e := range evs {
49		event := e.DeepCopy()
50		s.events = append(s.events, event)
51	}
52	return true
53}
54
55func (s *fakeAuditSink) Events() []*auditinternal.Event {
56	s.lock.Lock()
57	defer s.lock.Unlock()
58	return append([]*auditinternal.Event{}, s.events...)
59}
60
61func (s *fakeAuditSink) Pop(timeout time.Duration) (*auditinternal.Event, error) {
62	var result *auditinternal.Event
63	err := wait.Poll(50*time.Millisecond, wait.ForeverTestTimeout, wait.ConditionFunc(func() (done bool, err error) {
64		s.lock.Lock()
65		defer s.lock.Unlock()
66		if len(s.events) == 0 {
67			return false, nil
68		}
69		result = s.events[0]
70		s.events = s.events[1:]
71		return true, nil
72	}))
73	return result, err
74}
75
76type simpleResponseWriter struct{}
77
78var _ http.ResponseWriter = &simpleResponseWriter{}
79
80func (*simpleResponseWriter) WriteHeader(code int)         {}
81func (*simpleResponseWriter) Write(bs []byte) (int, error) { return len(bs), nil }
82func (*simpleResponseWriter) Header() http.Header          { return http.Header{} }
83
84type fancyResponseWriter struct {
85	simpleResponseWriter
86}
87
88func (*fancyResponseWriter) CloseNotify() <-chan bool { return nil }
89
90func (*fancyResponseWriter) Flush() {}
91
92func (*fancyResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return nil, nil, nil }
93
94func TestConstructResponseWriter(t *testing.T) {
95	actual := decorateResponseWriter(&simpleResponseWriter{}, nil, nil, nil)
96	switch v := actual.(type) {
97	case *auditResponseWriter:
98	default:
99		t.Errorf("Expected auditResponseWriter, got %v", reflect.TypeOf(v))
100	}
101
102	actual = decorateResponseWriter(&fancyResponseWriter{}, nil, nil, nil)
103	switch v := actual.(type) {
104	case *fancyResponseWriterDelegator:
105	default:
106		t.Errorf("Expected fancyResponseWriterDelegator, got %v", reflect.TypeOf(v))
107	}
108}
109
110func TestDecorateResponseWriterWithoutChannel(t *testing.T) {
111	ev := &auditinternal.Event{}
112	actual := decorateResponseWriter(&simpleResponseWriter{}, ev, nil, nil)
113
114	// write status. This will not block because firstEventSentCh is nil
115	actual.WriteHeader(42)
116	if ev.ResponseStatus == nil {
117		t.Fatalf("Expected ResponseStatus to be non-nil")
118	}
119	if ev.ResponseStatus.Code != 42 {
120		t.Errorf("expected status code 42, got %d", ev.ResponseStatus.Code)
121	}
122}
123
124func TestDecorateResponseWriterWithImplicitWrite(t *testing.T) {
125	ev := &auditinternal.Event{}
126	actual := decorateResponseWriter(&simpleResponseWriter{}, ev, nil, nil)
127
128	// write status. This will not block because firstEventSentCh is nil
129	actual.Write([]byte("foo"))
130	if ev.ResponseStatus == nil {
131		t.Fatalf("Expected ResponseStatus to be non-nil")
132	}
133	if ev.ResponseStatus.Code != 200 {
134		t.Errorf("expected status code 200, got %d", ev.ResponseStatus.Code)
135	}
136}
137
138func TestDecorateResponseWriterChannel(t *testing.T) {
139	sink := &fakeAuditSink{}
140	ev := &auditinternal.Event{}
141	actual := decorateResponseWriter(&simpleResponseWriter{}, ev, sink, nil)
142
143	done := make(chan struct{})
144	go func() {
145		t.Log("Writing status code 42")
146		actual.WriteHeader(42)
147		t.Log("Finished writing status code 42")
148		close(done)
149
150		actual.Write([]byte("foo"))
151	}()
152
153	// sleep some time to give write the possibility to do wrong stuff
154	time.Sleep(100 * time.Millisecond)
155
156	t.Log("Waiting for event in the channel")
157	ev1, err := sink.Pop(time.Second)
158	if err != nil {
159		t.Fatal("Timeout waiting for events")
160	}
161	t.Logf("Seen event with status %v", ev1.ResponseStatus)
162
163	if !reflect.DeepEqual(ev, ev1) {
164		t.Fatalf("ev1 and ev must be equal")
165	}
166
167	<-done
168	t.Log("Seen the go routine finished")
169
170	// write again
171	_, err = actual.Write([]byte("foo"))
172	if err != nil {
173		t.Errorf("unexpected error: %v", err)
174	}
175}
176
177type fakeHTTPHandler struct{}
178
179func (*fakeHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
180	w.WriteHeader(200)
181}
182
183func TestAudit(t *testing.T) {
184	shortRunningPath := "/api/v1/namespaces/default/pods/foo"
185	longRunningPath := "/api/v1/namespaces/default/pods?watch=true"
186
187	delay := 500 * time.Millisecond
188
189	for _, test := range []struct {
190		desc       string
191		path       string
192		verb       string
193		auditID    string
194		omitStages []auditinternal.Stage
195		handler    func(http.ResponseWriter, *http.Request)
196		expected   []auditinternal.Event
197		respHeader bool
198	}{
199		// short running requests with read-only verb
200		{
201			"read-only empty",
202			shortRunningPath,
203			"GET",
204			"",
205			nil,
206			func(http.ResponseWriter, *http.Request) {},
207			[]auditinternal.Event{
208				{
209					Stage:      auditinternal.StageRequestReceived,
210					Verb:       "get",
211					RequestURI: shortRunningPath,
212				},
213				{
214					Stage:          auditinternal.StageResponseComplete,
215					Verb:           "get",
216					RequestURI:     shortRunningPath,
217					ResponseStatus: &metav1.Status{Code: 200},
218				},
219			},
220			false,
221		},
222		{
223			"short running with auditID",
224			shortRunningPath,
225			"GET",
226			uuid.New().String(),
227			nil,
228			func(w http.ResponseWriter, req *http.Request) {
229				w.Write([]byte("foo"))
230			},
231			[]auditinternal.Event{
232				{
233					Stage:      auditinternal.StageRequestReceived,
234					Verb:       "get",
235					RequestURI: shortRunningPath,
236				},
237				{
238					Stage:          auditinternal.StageResponseComplete,
239					Verb:           "get",
240					RequestURI:     shortRunningPath,
241					ResponseStatus: &metav1.Status{Code: 200},
242				},
243			},
244			true,
245		},
246		{
247			"read-only panic",
248			shortRunningPath,
249			"GET",
250			"",
251			nil,
252			func(w http.ResponseWriter, req *http.Request) {
253				panic("kaboom")
254			},
255			[]auditinternal.Event{
256				{
257					Stage:      auditinternal.StageRequestReceived,
258					Verb:       "get",
259					RequestURI: shortRunningPath,
260				},
261				{
262					Stage:          auditinternal.StagePanic,
263					Verb:           "get",
264					RequestURI:     shortRunningPath,
265					ResponseStatus: &metav1.Status{Code: 500},
266				},
267			},
268			false,
269		},
270		// short running request with non-read-only verb
271		{
272			"writing empty",
273			shortRunningPath,
274			"PUT",
275			"",
276			nil,
277			func(http.ResponseWriter, *http.Request) {},
278			[]auditinternal.Event{
279				{
280					Stage:      auditinternal.StageRequestReceived,
281					Verb:       "update",
282					RequestURI: shortRunningPath,
283				},
284				{
285					Stage:          auditinternal.StageResponseComplete,
286					Verb:           "update",
287					RequestURI:     shortRunningPath,
288					ResponseStatus: &metav1.Status{Code: 200},
289				},
290			},
291			false,
292		},
293		{
294			"writing sleep",
295			shortRunningPath,
296			"PUT",
297			"",
298			nil,
299			func(w http.ResponseWriter, req *http.Request) {
300				w.Write([]byte("foo"))
301				time.Sleep(delay)
302			},
303			[]auditinternal.Event{
304				{
305					Stage:      auditinternal.StageRequestReceived,
306					Verb:       "update",
307					RequestURI: shortRunningPath,
308				},
309				{
310					Stage:          auditinternal.StageResponseComplete,
311					Verb:           "update",
312					RequestURI:     shortRunningPath,
313					ResponseStatus: &metav1.Status{Code: 200},
314				},
315			},
316			true,
317		},
318		{
319			"writing 403+write",
320			shortRunningPath,
321			"PUT",
322			"",
323			nil,
324			func(w http.ResponseWriter, req *http.Request) {
325				w.WriteHeader(403)
326				w.Write([]byte("foo"))
327			},
328			[]auditinternal.Event{
329				{
330					Stage:      auditinternal.StageRequestReceived,
331					Verb:       "update",
332					RequestURI: shortRunningPath,
333				},
334				{
335					Stage:          auditinternal.StageResponseComplete,
336					Verb:           "update",
337					RequestURI:     shortRunningPath,
338					ResponseStatus: &metav1.Status{Code: 403},
339				},
340			},
341			true,
342		},
343		{
344			"writing panic",
345			shortRunningPath,
346			"PUT",
347			"",
348			nil,
349			func(w http.ResponseWriter, req *http.Request) {
350				panic("kaboom")
351			},
352			[]auditinternal.Event{
353				{
354					Stage:      auditinternal.StageRequestReceived,
355					Verb:       "update",
356					RequestURI: shortRunningPath,
357				},
358				{
359					Stage:          auditinternal.StagePanic,
360					Verb:           "update",
361					RequestURI:     shortRunningPath,
362					ResponseStatus: &metav1.Status{Code: 500},
363				},
364			},
365			false,
366		},
367		{
368			"writing write+panic",
369			shortRunningPath,
370			"PUT",
371			"",
372			nil,
373			func(w http.ResponseWriter, req *http.Request) {
374				w.Write([]byte("foo"))
375				panic("kaboom")
376			},
377			[]auditinternal.Event{
378				{
379					Stage:      auditinternal.StageRequestReceived,
380					Verb:       "update",
381					RequestURI: shortRunningPath,
382				},
383				{
384					Stage:          auditinternal.StagePanic,
385					Verb:           "update",
386					RequestURI:     shortRunningPath,
387					ResponseStatus: &metav1.Status{Code: 500},
388				},
389			},
390			true,
391		},
392		// long running requests
393		{
394			"empty longrunning",
395			longRunningPath,
396			"GET",
397			"",
398			nil,
399			func(http.ResponseWriter, *http.Request) {},
400			[]auditinternal.Event{
401				{
402					Stage:      auditinternal.StageRequestReceived,
403					Verb:       "watch",
404					RequestURI: longRunningPath,
405				},
406				{
407					Stage:          auditinternal.StageResponseStarted,
408					Verb:           "watch",
409					RequestURI:     longRunningPath,
410					ResponseStatus: &metav1.Status{Code: 200},
411				},
412				{
413					Stage:          auditinternal.StageResponseComplete,
414					Verb:           "watch",
415					RequestURI:     longRunningPath,
416					ResponseStatus: &metav1.Status{Code: 200},
417				},
418			},
419			false,
420		},
421		{
422			"empty longrunning with audit id",
423			longRunningPath,
424			"GET",
425			uuid.New().String(),
426			nil,
427			func(w http.ResponseWriter, req *http.Request) {
428				w.Write([]byte("foo"))
429			},
430			[]auditinternal.Event{
431				{
432					Stage:      auditinternal.StageRequestReceived,
433					Verb:       "watch",
434					RequestURI: longRunningPath,
435				},
436				{
437					Stage:          auditinternal.StageResponseStarted,
438					Verb:           "watch",
439					RequestURI:     longRunningPath,
440					ResponseStatus: &metav1.Status{Code: 200},
441				},
442				{
443					Stage:          auditinternal.StageResponseComplete,
444					Verb:           "watch",
445					RequestURI:     longRunningPath,
446					ResponseStatus: &metav1.Status{Code: 200},
447				},
448			},
449			true,
450		},
451		{
452			"sleep longrunning",
453			longRunningPath,
454			"GET",
455			"",
456			nil,
457			func(http.ResponseWriter, *http.Request) {
458				time.Sleep(delay)
459			},
460			[]auditinternal.Event{
461				{
462					Stage:      auditinternal.StageRequestReceived,
463					Verb:       "watch",
464					RequestURI: longRunningPath,
465				},
466				{
467					Stage:          auditinternal.StageResponseStarted,
468					Verb:           "watch",
469					RequestURI:     longRunningPath,
470					ResponseStatus: &metav1.Status{Code: 200},
471				},
472				{
473					Stage:          auditinternal.StageResponseComplete,
474					Verb:           "watch",
475					RequestURI:     longRunningPath,
476					ResponseStatus: &metav1.Status{Code: 200},
477				},
478			},
479			false,
480		},
481		{
482			"sleep+403 longrunning",
483			longRunningPath,
484			"GET",
485			"",
486			nil,
487			func(w http.ResponseWriter, req *http.Request) {
488				time.Sleep(delay)
489				w.WriteHeader(403)
490			},
491			[]auditinternal.Event{
492				{
493					Stage:      auditinternal.StageRequestReceived,
494					Verb:       "watch",
495					RequestURI: longRunningPath,
496				},
497				{
498					Stage:          auditinternal.StageResponseStarted,
499					Verb:           "watch",
500					RequestURI:     longRunningPath,
501					ResponseStatus: &metav1.Status{Code: 403},
502				},
503				{
504					Stage:          auditinternal.StageResponseComplete,
505					Verb:           "watch",
506					RequestURI:     longRunningPath,
507					ResponseStatus: &metav1.Status{Code: 403},
508				},
509			},
510			true,
511		},
512		{
513			"write longrunning",
514			longRunningPath,
515			"GET",
516			"",
517			nil,
518			func(w http.ResponseWriter, req *http.Request) {
519				w.Write([]byte("foo"))
520			},
521			[]auditinternal.Event{
522				{
523					Stage:      auditinternal.StageRequestReceived,
524					Verb:       "watch",
525					RequestURI: longRunningPath,
526				},
527				{
528					Stage:          auditinternal.StageResponseStarted,
529					Verb:           "watch",
530					RequestURI:     longRunningPath,
531					ResponseStatus: &metav1.Status{Code: 200},
532				},
533				{
534					Stage:          auditinternal.StageResponseComplete,
535					Verb:           "watch",
536					RequestURI:     longRunningPath,
537					ResponseStatus: &metav1.Status{Code: 200},
538				},
539			},
540			true,
541		},
542		{
543			"403+write longrunning",
544			longRunningPath,
545			"GET",
546			"",
547			nil,
548			func(w http.ResponseWriter, req *http.Request) {
549				w.WriteHeader(403)
550				w.Write([]byte("foo"))
551			},
552			[]auditinternal.Event{
553				{
554					Stage:      auditinternal.StageRequestReceived,
555					Verb:       "watch",
556					RequestURI: longRunningPath,
557				},
558				{
559					Stage:          auditinternal.StageResponseStarted,
560					Verb:           "watch",
561					RequestURI:     longRunningPath,
562					ResponseStatus: &metav1.Status{Code: 403},
563				},
564				{
565					Stage:          auditinternal.StageResponseComplete,
566					Verb:           "watch",
567					RequestURI:     longRunningPath,
568					ResponseStatus: &metav1.Status{Code: 403},
569				},
570			},
571			true,
572		},
573		{
574			"panic longrunning",
575			longRunningPath,
576			"GET",
577			"",
578			nil,
579			func(w http.ResponseWriter, req *http.Request) {
580				panic("kaboom")
581			},
582			[]auditinternal.Event{
583				{
584					Stage:      auditinternal.StageRequestReceived,
585					Verb:       "watch",
586					RequestURI: longRunningPath,
587				},
588				{
589					Stage:          auditinternal.StagePanic,
590					Verb:           "watch",
591					RequestURI:     longRunningPath,
592					ResponseStatus: &metav1.Status{Code: 500},
593				},
594			},
595			false,
596		},
597		{
598			"write+panic longrunning",
599			longRunningPath,
600			"GET",
601			"",
602			nil,
603			func(w http.ResponseWriter, req *http.Request) {
604				w.Write([]byte("foo"))
605				panic("kaboom")
606			},
607			[]auditinternal.Event{
608				{
609					Stage:      auditinternal.StageRequestReceived,
610					Verb:       "watch",
611					RequestURI: longRunningPath,
612				},
613				{
614					Stage:          auditinternal.StageResponseStarted,
615					Verb:           "watch",
616					RequestURI:     longRunningPath,
617					ResponseStatus: &metav1.Status{Code: 200},
618				},
619				{
620					Stage:          auditinternal.StagePanic,
621					Verb:           "watch",
622					RequestURI:     longRunningPath,
623					ResponseStatus: &metav1.Status{Code: 500},
624				},
625			},
626			true,
627		},
628		{
629			"omit RequestReceived",
630			shortRunningPath,
631			"GET",
632			"",
633			[]auditinternal.Stage{auditinternal.StageRequestReceived},
634			func(w http.ResponseWriter, req *http.Request) {
635				w.Write([]byte("foo"))
636			},
637			[]auditinternal.Event{
638				{
639					Stage:          auditinternal.StageResponseComplete,
640					Verb:           "get",
641					RequestURI:     shortRunningPath,
642					ResponseStatus: &metav1.Status{Code: 200},
643				},
644			},
645			true,
646		},
647		{
648			"emit Panic only",
649			longRunningPath,
650			"GET",
651			"",
652			[]auditinternal.Stage{auditinternal.StageRequestReceived, auditinternal.StageResponseStarted, auditinternal.StageResponseComplete},
653			func(w http.ResponseWriter, req *http.Request) {
654				w.Write([]byte("foo"))
655				panic("kaboom")
656			},
657			[]auditinternal.Event{
658				{
659					Stage:          auditinternal.StagePanic,
660					Verb:           "watch",
661					RequestURI:     longRunningPath,
662					ResponseStatus: &metav1.Status{Code: 500},
663				},
664			},
665			true,
666		},
667	} {
668		t.Run(test.desc, func(t *testing.T) {
669			sink := &fakeAuditSink{}
670			policyChecker := policy.FakeChecker(auditinternal.LevelRequestResponse, test.omitStages)
671			handler := WithAudit(http.HandlerFunc(test.handler), sink, policyChecker, func(r *http.Request, ri *request.RequestInfo) bool {
672				// simplified long-running check
673				return ri.Verb == "watch"
674			})
675
676			req, _ := http.NewRequest(test.verb, test.path, nil)
677			req = withTestContext(req, &user.DefaultInfo{Name: "admin"}, nil)
678			if test.auditID != "" {
679				req.Header.Add("Audit-ID", test.auditID)
680			}
681			req.RemoteAddr = "127.0.0.1"
682
683			func() {
684				defer func() {
685					recover()
686				}()
687				handler.ServeHTTP(httptest.NewRecorder(), req)
688			}()
689
690			events := sink.Events()
691			t.Logf("audit log: %v", events)
692
693			if len(events) != len(test.expected) {
694				t.Fatalf("Unexpected amount of lines in audit log: %d", len(events))
695			}
696			expectedID := types.UID("")
697			for i, expect := range test.expected {
698				event := events[i]
699				if "admin" != event.User.Username {
700					t.Errorf("Unexpected username: %s", event.User.Username)
701				}
702				if event.Stage != expect.Stage {
703					t.Errorf("Unexpected Stage: %s", event.Stage)
704				}
705				if event.Verb != expect.Verb {
706					t.Errorf("Unexpected Verb: %s", event.Verb)
707				}
708				if event.RequestURI != expect.RequestURI {
709					t.Errorf("Unexpected RequestURI: %s", event.RequestURI)
710				}
711
712				if test.auditID != "" && event.AuditID != types.UID(test.auditID) {
713					t.Errorf("Unexpected AuditID in audit event, AuditID should be the same with Audit-ID http header")
714				}
715				if expectedID == types.UID("") {
716					expectedID = event.AuditID
717				} else if expectedID != event.AuditID {
718					t.Errorf("Audits for one request should share the same AuditID, %s differs from %s", expectedID, event.AuditID)
719				}
720				if event.ObjectRef.APIVersion != "v1" {
721					t.Errorf("Unexpected apiVersion: %s", event.ObjectRef.APIVersion)
722				}
723				if event.ObjectRef.APIGroup != "" {
724					t.Errorf("Unexpected apiGroup: %s", event.ObjectRef.APIGroup)
725				}
726				if (event.ResponseStatus == nil) != (expect.ResponseStatus == nil) {
727					t.Errorf("Unexpected ResponseStatus: %v", event.ResponseStatus)
728					continue
729				}
730				if (event.ResponseStatus != nil) && (event.ResponseStatus.Code != expect.ResponseStatus.Code) {
731					t.Errorf("Unexpected status code : %d", event.ResponseStatus.Code)
732				}
733			}
734		})
735	}
736}
737
738func TestAuditNoPanicOnNilUser(t *testing.T) {
739	policyChecker := policy.FakeChecker(auditinternal.LevelRequestResponse, nil)
740	handler := WithAudit(&fakeHTTPHandler{}, &fakeAuditSink{}, policyChecker, nil)
741	req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
742	req = withTestContext(req, nil, nil)
743	req.RemoteAddr = "127.0.0.1"
744	handler.ServeHTTP(httptest.NewRecorder(), req)
745}
746
747func TestAuditLevelNone(t *testing.T) {
748	sink := &fakeAuditSink{}
749	var handler http.Handler
750	handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
751		w.WriteHeader(200)
752	})
753	policyChecker := policy.FakeChecker(auditinternal.LevelNone, nil)
754	handler = WithAudit(handler, sink, policyChecker, nil)
755
756	req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
757	req.RemoteAddr = "127.0.0.1"
758	req = withTestContext(req, &user.DefaultInfo{Name: "admin"}, nil)
759
760	handler.ServeHTTP(httptest.NewRecorder(), req)
761	if len(sink.events) > 0 {
762		t.Errorf("Generated events, but should not have: %#v", sink.events)
763	}
764}
765
766func TestAuditIDHttpHeader(t *testing.T) {
767	for _, test := range []struct {
768		desc           string
769		requestHeader  string
770		level          auditinternal.Level
771		expectedHeader bool
772	}{
773		{
774			"no http header when there is no audit",
775			"",
776			auditinternal.LevelNone,
777			false,
778		},
779		{
780			"no http header when there is no audit even the request header specified",
781			uuid.New().String(),
782			auditinternal.LevelNone,
783			false,
784		},
785		{
786			"server generated header",
787			"",
788			auditinternal.LevelRequestResponse,
789			true,
790		},
791		{
792			"user provided header",
793			uuid.New().String(),
794			auditinternal.LevelRequestResponse,
795			true,
796		},
797	} {
798		sink := &fakeAuditSink{}
799		var handler http.Handler
800		handler = http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
801			w.WriteHeader(200)
802		})
803		policyChecker := policy.FakeChecker(test.level, nil)
804		handler = WithAudit(handler, sink, policyChecker, nil)
805
806		req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
807		req.RemoteAddr = "127.0.0.1"
808		req = withTestContext(req, &user.DefaultInfo{Name: "admin"}, nil)
809		if test.requestHeader != "" {
810			req.Header.Add("Audit-ID", test.requestHeader)
811		}
812
813		w := httptest.NewRecorder()
814		handler.ServeHTTP(w, req)
815		resp := w.Result()
816		if test.expectedHeader {
817			if resp.Header.Get("Audit-ID") == "" {
818				t.Errorf("[%s] expected Audit-ID http header returned, but not returned", test.desc)
819				continue
820			}
821			// if get Audit-ID returned, it should be the same with the requested one
822			if test.requestHeader != "" && resp.Header.Get("Audit-ID") != test.requestHeader {
823				t.Errorf("[%s] returned audit http header is not the same with the requested http header, expected: %s, get %s", test.desc, test.requestHeader, resp.Header.Get("Audit-ID"))
824			}
825		} else {
826			if resp.Header.Get("Audit-ID") != "" {
827				t.Errorf("[%s] expected no Audit-ID http header returned, but got %s", test.desc, resp.Header.Get("Audit-ID"))
828			}
829		}
830	}
831}
832
833func withTestContext(req *http.Request, user user.Info, audit *auditinternal.Event) *http.Request {
834	ctx := req.Context()
835	if user != nil {
836		ctx = request.WithUser(ctx, user)
837	}
838	if audit != nil {
839		ctx = request.WithAuditEvent(ctx, audit)
840	}
841	if info, err := newTestRequestInfoResolver().NewRequestInfo(req); err == nil {
842		ctx = request.WithRequestInfo(ctx, info)
843	}
844	return req.WithContext(ctx)
845}
846