diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go index 7e8f2baa50e..4eb5aeb0f98 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication.go @@ -96,8 +96,11 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request, failed return } - // TODO(mikedanese): verify the response audience matches one of apiAuds if - // non-empty + if len(apiAuds) > 0 && len(resp.Audiences) > 0 && len(authenticator.Audiences(apiAuds).Intersect(resp.Audiences)) == 0 { + klog.Errorf("Unable to match the audience: %v , accepted: %v", resp.Audiences, apiAuds) + failed.ServeHTTP(w, req) + return + } // authorization header is not required anymore in case of a successful authentication. req.Header.Del("Authorization") diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go index 887baebc93e..2873c67cb3d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go @@ -18,15 +18,92 @@ package filters import ( "errors" - "net/http" - "net/http/httptest" - "testing" - + "github.com/stretchr/testify/assert" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "net/http" + "net/http/httptest" + "testing" ) +func TestAuthenticateRequestWithAud(t *testing.T) { + success, failed := 0, 0 + testcases := []struct { + name string + apiAuds []string + respAuds []string + expectSuccess bool + }{ + { + name: "no api audience and no audience in response", + apiAuds: nil, + respAuds: nil, + expectSuccess: true, + }, + { + name: "audience in response", + apiAuds: nil, + respAuds: []string{"other"}, + expectSuccess: true, + }, + { + name: "with api audience", + apiAuds: authenticator.Audiences([]string{"other"}), + respAuds: nil, + expectSuccess: true, + }, + { + name: "api audience matching response audience", + apiAuds: authenticator.Audiences([]string{"other"}), + respAuds: []string{"other"}, + expectSuccess: true, + }, + { + name: "api audience non-matching response audience", + apiAuds: authenticator.Audiences([]string{"other"}), + respAuds: []string{"some"}, + expectSuccess: false, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + success, failed = 0, 0 + auth := WithAuthentication( + http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) { + if tc.expectSuccess { + success = 1 + } else { + t.Errorf("unexpected call to handler") + } + }), + authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { + if req.Header.Get("Authorization") == "Something" { + return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}, Audiences: authenticator.Audiences(tc.respAuds)}, true, nil + } + return nil, false, errors.New("Authorization header is missing.") + }), + http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { + if tc.expectSuccess { + t.Errorf("unexpected call to failed") + } else { + failed = 1 + } + }), + tc.apiAuds, + ) + auth.ServeHTTP(httptest.NewRecorder(), &http.Request{Header: map[string][]string{"Authorization": {"Something"}}}) + if tc.expectSuccess { + assert.Equal(t, 1, success) + assert.Equal(t, 0, failed) + } else { + assert.Equal(t, 0, success) + assert.Equal(t, 1, failed) + } + }) + } +} + func TestAuthenticateRequest(t *testing.T) { success := make(chan struct{}) auth := WithAuthentication(