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  }