k8s.io/apiserver@v0.31.1/pkg/server/options/authentication_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package options 18 19 import ( 20 "io/ioutil" 21 "net/http" 22 "os" 23 "reflect" 24 "testing" 25 26 "k8s.io/apiserver/pkg/authentication/authenticatorfactory" 27 "k8s.io/apiserver/pkg/authentication/request/headerrequest" 28 "k8s.io/apiserver/pkg/server" 29 openapicommon "k8s.io/kube-openapi/pkg/common" 30 ) 31 32 func TestToAuthenticationRequestHeaderConfig(t *testing.T) { 33 testCases := []struct { 34 name string 35 testOptions *RequestHeaderAuthenticationOptions 36 expectConfig *authenticatorfactory.RequestHeaderConfig 37 }{ 38 { 39 name: "test when ClientCAFile is nil", 40 testOptions: &RequestHeaderAuthenticationOptions{ 41 UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, 42 GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, 43 ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, 44 AllowedNames: headerrequest.StaticStringSlice{"kube-aggregator"}, 45 }, 46 }, 47 { 48 name: "test when ClientCAFile is not nil", 49 testOptions: &RequestHeaderAuthenticationOptions{ 50 ClientCAFile: "testdata/root.pem", 51 UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, 52 GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, 53 ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, 54 AllowedNames: headerrequest.StaticStringSlice{"kube-aggregator"}, 55 }, 56 expectConfig: &authenticatorfactory.RequestHeaderConfig{ 57 UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, 58 GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, 59 ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, 60 CAContentProvider: nil, // this is nil because you can't compare functions 61 AllowedClientNames: headerrequest.StaticStringSlice{"kube-aggregator"}, 62 }, 63 }, 64 } 65 66 for _, testcase := range testCases { 67 t.Run(testcase.name, func(t *testing.T) { 68 resultConfig, err := testcase.testOptions.ToAuthenticationRequestHeaderConfig() 69 if err != nil { 70 t.Fatal(err) 71 } 72 if resultConfig != nil { 73 if resultConfig.CAContentProvider == nil { 74 t.Error("missing requestheader verify") 75 } 76 resultConfig.CAContentProvider = nil 77 } 78 79 if !reflect.DeepEqual(resultConfig, testcase.expectConfig) { 80 t.Errorf("got RequestHeaderConfig: %#v, expected RequestHeaderConfig: %#v", resultConfig, testcase.expectConfig) 81 } 82 }) 83 } 84 } 85 86 func TestApplyToFallback(t *testing.T) { 87 88 f, err := ioutil.TempFile("", "authkubeconfig") 89 if err != nil { 90 t.Fatal(err) 91 } 92 defer os.Remove(f.Name()) 93 94 if err := ioutil.WriteFile(f.Name(), []byte(` 95 apiVersion: v1 96 kind: Config 97 clusters: 98 - cluster: 99 server: http://localhost:56789 100 name: cluster 101 contexts: 102 - context: 103 cluster: cluster 104 name: cluster 105 current-context: cluster 106 `), os.FileMode(0755)); err != nil { 107 t.Fatal(err) 108 } 109 remoteKubeconfig := f.Name() 110 111 testcases := []struct { 112 name string 113 options *DelegatingAuthenticationOptions 114 expectError bool 115 expectAuthenticator bool 116 expectTokenAnonymous bool 117 expectTokenErrors bool 118 }{ 119 { 120 name: "empty", 121 options: nil, 122 expectError: false, 123 expectAuthenticator: false, 124 }, 125 { 126 name: "default", 127 options: NewDelegatingAuthenticationOptions(), 128 expectError: true, // in-cluster client building fails, no kubeconfig provided 129 expectAuthenticator: false, 130 }, 131 { 132 name: "optional kubeconfig", 133 options: func() *DelegatingAuthenticationOptions { 134 opts := NewDelegatingAuthenticationOptions() 135 opts.RemoteKubeConfigFileOptional = true 136 return opts 137 }(), 138 expectError: false, // in-cluster client building fails, no kubeconfig required 139 expectAuthenticator: true, 140 expectTokenAnonymous: true, // no token validator available 141 }, 142 { 143 name: "valid client, failed cluster info lookup", 144 options: func() *DelegatingAuthenticationOptions { 145 opts := NewDelegatingAuthenticationOptions() 146 opts.RemoteKubeConfigFile = remoteKubeconfig 147 return opts 148 }(), 149 expectError: true, // client building is valid, remote config lookup fails 150 expectAuthenticator: false, 151 }, 152 { 153 name: "valid client, skip cluster info lookup", 154 options: func() *DelegatingAuthenticationOptions { 155 opts := NewDelegatingAuthenticationOptions() 156 opts.RemoteKubeConfigFile = remoteKubeconfig 157 opts.SkipInClusterLookup = true 158 return opts 159 }(), 160 expectError: false, // client building is valid, skipped cluster lookup 161 expectAuthenticator: true, 162 expectTokenErrors: true, // client fails making tokenreview calls 163 }, 164 { 165 name: "valid client, tolerate failed cluster info lookup", 166 options: func() *DelegatingAuthenticationOptions { 167 opts := NewDelegatingAuthenticationOptions() 168 opts.RemoteKubeConfigFile = remoteKubeconfig 169 opts.TolerateInClusterLookupFailure = true 170 return opts 171 }(), 172 expectError: false, // client is valid, skipped cluster lookup 173 expectAuthenticator: true, // anonymous auth 174 expectTokenErrors: true, // client fails making tokenreview calls 175 }, 176 } 177 178 for _, tc := range testcases { 179 t.Run(tc.name, func(t *testing.T) { 180 c := &server.AuthenticationInfo{} 181 servingInfo := &server.SecureServingInfo{} 182 openAPIConfig := &openapicommon.Config{} 183 184 err := tc.options.ApplyTo(c, servingInfo, openAPIConfig) 185 if (err != nil) != tc.expectError { 186 t.Errorf("expected error=%v, got %v", tc.expectError, err) 187 } 188 if (c.Authenticator != nil) != tc.expectAuthenticator { 189 t.Errorf("expected authenticator=%v, got %#v", tc.expectError, c.Authenticator) 190 } 191 if c.Authenticator != nil { 192 { 193 result, ok, err := c.Authenticator.AuthenticateRequest(&http.Request{}) 194 if err != nil || !ok || result == nil || result.User.GetName() != "system:anonymous" { 195 t.Errorf("expected anonymous, got %#v, %#v, %#v", result, ok, err) 196 } 197 } 198 { 199 result, ok, err := c.Authenticator.AuthenticateRequest(&http.Request{Header: http.Header{"Authorization": []string{"Bearer foo"}}}) 200 if tc.expectTokenAnonymous { 201 if err != nil || !ok || result == nil || result.User.GetName() != "system:anonymous" { 202 t.Errorf("expected anonymous, got %#v, %#v, %#v", result, ok, err) 203 } 204 } 205 if tc.expectTokenErrors != (err != nil) { 206 t.Errorf("expected error=%v, got %#v, %#v, %#v", tc.expectTokenErrors, result, ok, err) 207 } 208 } 209 } 210 }) 211 } 212 }