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