@@ -25,9 +25,18 @@ import (
25
25
"net/http/httputil"
26
26
"reflect"
27
27
"testing"
28
+ "time"
28
29
30
+ "github.com/google/go-cmp/cmp"
29
31
"k8s.io/apimachinery/pkg/util/json"
30
32
"k8s.io/apimachinery/pkg/util/sets"
33
+ "k8s.io/apimachinery/pkg/util/waitgroup"
34
+ auditinternal "k8s.io/apiserver/pkg/apis/audit"
35
+ "k8s.io/apiserver/pkg/audit"
36
+ "k8s.io/apiserver/pkg/audit/policy"
37
+ "k8s.io/apiserver/pkg/authentication/authenticator"
38
+ "k8s.io/apiserver/pkg/authentication/user"
39
+ "k8s.io/apiserver/pkg/endpoints/request"
31
40
"k8s.io/apiserver/pkg/server/healthz"
32
41
"k8s.io/client-go/informers"
33
42
"k8s.io/client-go/kubernetes/fake"
@@ -241,3 +250,84 @@ func checkExpectedPathsAtRoot(url string, expectedPaths []string, t *testing.T)
241
250
}
242
251
})
243
252
}
253
+
254
+ func TestAuthenticationAuditAnnotationsDefaultChain (t * testing.T ) {
255
+ authn := authenticator .RequestFunc (func (req * http.Request ) (* authenticator.Response , bool , error ) {
256
+ // confirm that we can set an audit annotation in a handler before WithAudit
257
+ audit .AddAuditAnnotation (req .Context (), "pandas" , "are awesome" )
258
+
259
+ // confirm that trying to use the audit event directly would never work
260
+ if ae := request .AuditEventFrom (req .Context ()); ae != nil {
261
+ t .Errorf ("expected nil audit event, got %v" , ae )
262
+ }
263
+
264
+ return & authenticator.Response {User : & user.DefaultInfo {}}, true , nil
265
+ })
266
+ backend := & testBackend {}
267
+ c := & Config {
268
+ Authentication : AuthenticationInfo {Authenticator : authn },
269
+ AuditBackend : backend ,
270
+ AuditPolicyChecker : policy .FakeChecker (auditinternal .LevelMetadata , nil ),
271
+
272
+ // avoid nil panics
273
+ HandlerChainWaitGroup : & waitgroup.SafeWaitGroup {},
274
+ RequestInfoResolver : & request.RequestInfoFactory {},
275
+ RequestTimeout : 10 * time .Second ,
276
+ LongRunningFunc : func (_ * http.Request , _ * request.RequestInfo ) bool { return false },
277
+ }
278
+
279
+ h := DefaultBuildHandlerChain (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
280
+ // confirm this is a no-op
281
+ if r .Context () != audit .WithAuditAnnotations (r .Context ()) {
282
+ t .Error ("unexpected double wrapping of context" )
283
+ }
284
+
285
+ // confirm that we have an audit event
286
+ ae := request .AuditEventFrom (r .Context ())
287
+ if ae == nil {
288
+ t .Error ("unexpected nil audit event" )
289
+ }
290
+
291
+ // confirm that the direct way of setting audit annotations later in the chain works as expected
292
+ audit .LogAnnotation (ae , "snorlax" , "is cool too" )
293
+
294
+ // confirm that the indirect way of setting audit annotations later in the chain also works
295
+ audit .AddAuditAnnotation (r .Context (), "dogs" , "are okay" )
296
+
297
+ if _ , err := w .Write ([]byte ("done" )); err != nil {
298
+ t .Errorf ("failed to write response: %v" , err )
299
+ }
300
+ }), c )
301
+ w := httptest .NewRecorder ()
302
+
303
+ h .ServeHTTP (w , httptest .NewRequest ("GET" , "https://ignored.com" , nil ))
304
+
305
+ r := w .Result ()
306
+ if ok := r .StatusCode == http .StatusOK && w .Body .String () == "done" && len (r .Header .Get (auditinternal .HeaderAuditID )) > 0 ; ! ok {
307
+ t .Errorf ("invalid response: %#v" , w )
308
+ }
309
+ if len (backend .events ) == 0 {
310
+ t .Error ("expected audit events, got none" )
311
+ }
312
+ // these should all be the same because the handler chain mutates the event in place
313
+ want := map [string ]string {"pandas" : "are awesome" , "snorlax" : "is cool too" , "dogs" : "are okay" }
314
+ for _ , event := range backend .events {
315
+ if event .Stage != auditinternal .StageResponseComplete {
316
+ t .Errorf ("expected event stage to be complete, got: %s" , event .Stage )
317
+ }
318
+ if diff := cmp .Diff (want , event .Annotations ); diff != "" {
319
+ t .Errorf ("event has unexpected annotations (-want +got): %s" , diff )
320
+ }
321
+ }
322
+ }
323
+
324
+ type testBackend struct {
325
+ events []* auditinternal.Event
326
+
327
+ audit.Backend // nil panic if anything other than ProcessEvents called
328
+ }
329
+
330
+ func (b * testBackend ) ProcessEvents (events ... * auditinternal.Event ) bool {
331
+ b .events = append (b .events , events ... )
332
+ return true
333
+ }
0 commit comments