...

Source file src/k8s.io/kubernetes/test/integration/auth/selfsubjectreview_test.go

Documentation: k8s.io/kubernetes/test/integration/auth

     1  /*
     2  Copyright 2022 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 auth
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"reflect"
    24  	"sync"
    25  	"sync/atomic"
    26  	"testing"
    27  
    28  	authenticationv1 "k8s.io/api/authentication/v1"
    29  	authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
    30  	authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/apiserver/pkg/authentication/authenticator"
    33  	"k8s.io/apiserver/pkg/authentication/user"
    34  	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
    35  	"k8s.io/kubernetes/pkg/controlplane"
    36  	"k8s.io/kubernetes/test/integration/framework"
    37  	"k8s.io/kubernetes/test/utils/ktesting"
    38  )
    39  
    40  func TestGetsSelfAttributes(t *testing.T) {
    41  	tests := []struct {
    42  		name           string
    43  		userInfo       *user.DefaultInfo
    44  		expectedName   string
    45  		expectedUID    string
    46  		expectedGroups []string
    47  		expectedExtra  map[string]authenticationv1.ExtraValue
    48  	}{
    49  		{
    50  			name: "Username",
    51  			userInfo: &user.DefaultInfo{
    52  				Name: "alice",
    53  			},
    54  			expectedName: "alice",
    55  		},
    56  		{
    57  			name: "Username with groups and UID",
    58  			userInfo: &user.DefaultInfo{
    59  				Name:   "alice",
    60  				UID:    "unique-id",
    61  				Groups: []string{"devs", "admins"},
    62  			},
    63  			expectedName:   "alice",
    64  			expectedUID:    "unique-id",
    65  			expectedGroups: []string{"devs", "admins"},
    66  		},
    67  		{
    68  			name: "Username with extra attributes",
    69  			userInfo: &user.DefaultInfo{
    70  				Name: "alice",
    71  				Extra: map[string][]string{
    72  					"nicknames": {"cutie", "bestie"},
    73  				},
    74  			},
    75  			expectedName: "alice",
    76  			expectedExtra: map[string]authenticationv1.ExtraValue{
    77  				"nicknames": authenticationv1.ExtraValue([]string{"cutie", "bestie"}),
    78  			},
    79  		},
    80  		{
    81  			name: "Without username",
    82  			userInfo: &user.DefaultInfo{
    83  				UID: "unique-id",
    84  			},
    85  			expectedUID: "unique-id",
    86  		},
    87  	}
    88  
    89  	tCtx := ktesting.Init(t)
    90  	var respMu sync.RWMutex
    91  	response := &user.DefaultInfo{
    92  		Name: "stub",
    93  	}
    94  
    95  	kubeClient, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
    96  		ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
    97  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
    98  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1beta1=true")
    99  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1=true")
   100  			opts.Authorization.Modes = []string{"AlwaysAllow"}
   101  		},
   102  		ModifyServerConfig: func(config *controlplane.Config) {
   103  			// Unset BearerToken to disable BearerToken authenticator.
   104  			config.GenericConfig.LoopbackClientConfig.BearerToken = ""
   105  			config.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
   106  				respMu.RLock()
   107  				defer respMu.RUnlock()
   108  				return &authenticator.Response{User: response}, true, nil
   109  			})
   110  		},
   111  	})
   112  	defer tearDownFn()
   113  
   114  	for _, tc := range tests {
   115  		t.Run(tc.name, func(t *testing.T) {
   116  			respMu.Lock()
   117  			response = tc.userInfo
   118  			respMu.Unlock()
   119  
   120  			res, err := kubeClient.AuthenticationV1alpha1().
   121  				SelfSubjectReviews().
   122  				Create(tCtx, &authenticationv1alpha1.SelfSubjectReview{}, metav1.CreateOptions{})
   123  			if err != nil {
   124  				t.Fatalf("unexpected error: %v", err)
   125  			}
   126  
   127  			if res == nil {
   128  				t.Fatalf("empty response")
   129  			}
   130  
   131  			if res.Status.UserInfo.Username != tc.expectedName {
   132  				t.Fatalf("unexpected username: wanted %s, got %s", tc.expectedName, res.Status.UserInfo.Username)
   133  			}
   134  
   135  			if res.Status.UserInfo.UID != tc.expectedUID {
   136  				t.Fatalf("unexpected uid: wanted %s, got %s", tc.expectedUID, res.Status.UserInfo.UID)
   137  			}
   138  
   139  			if !reflect.DeepEqual(res.Status.UserInfo.Groups, tc.expectedGroups) {
   140  				t.Fatalf("unexpected groups: wanted %v, got %v", tc.expectedGroups, res.Status.UserInfo.Groups)
   141  			}
   142  
   143  			if !reflect.DeepEqual(res.Status.UserInfo.Extra, tc.expectedExtra) {
   144  				t.Fatalf("unexpected extra: wanted %v, got %v", tc.expectedExtra, res.Status.UserInfo.Extra)
   145  			}
   146  
   147  			res2, err := kubeClient.AuthenticationV1beta1().
   148  				SelfSubjectReviews().
   149  				Create(tCtx, &authenticationv1beta1.SelfSubjectReview{}, metav1.CreateOptions{})
   150  			if err != nil {
   151  				t.Fatalf("unexpected error: %v", err)
   152  			}
   153  
   154  			if res2 == nil {
   155  				t.Fatalf("empty response")
   156  			}
   157  
   158  			if res2.Status.UserInfo.Username != tc.expectedName {
   159  				t.Fatalf("unexpected username: wanted %s, got %s", tc.expectedName, res.Status.UserInfo.Username)
   160  			}
   161  
   162  			if res2.Status.UserInfo.UID != tc.expectedUID {
   163  				t.Fatalf("unexpected uid: wanted %s, got %s", tc.expectedUID, res.Status.UserInfo.UID)
   164  			}
   165  
   166  			if !reflect.DeepEqual(res2.Status.UserInfo.Groups, tc.expectedGroups) {
   167  				t.Fatalf("unexpected groups: wanted %v, got %v", tc.expectedGroups, res.Status.UserInfo.Groups)
   168  			}
   169  
   170  			if !reflect.DeepEqual(res2.Status.UserInfo.Extra, tc.expectedExtra) {
   171  				t.Fatalf("unexpected extra: wanted %v, got %v", tc.expectedExtra, res.Status.UserInfo.Extra)
   172  			}
   173  
   174  			res3, err := kubeClient.AuthenticationV1().
   175  				SelfSubjectReviews().
   176  				Create(context.TODO(), &authenticationv1.SelfSubjectReview{}, metav1.CreateOptions{})
   177  			if err != nil {
   178  				t.Fatalf("unexpected error: %v", err)
   179  			}
   180  
   181  			if res3 == nil {
   182  				t.Fatalf("empty response")
   183  			}
   184  
   185  			if res3.Status.UserInfo.Username != tc.expectedName {
   186  				t.Fatalf("unexpected username: wanted %s, got %s", tc.expectedName, res.Status.UserInfo.Username)
   187  			}
   188  
   189  			if res3.Status.UserInfo.UID != tc.expectedUID {
   190  				t.Fatalf("unexpected uid: wanted %s, got %s", tc.expectedUID, res.Status.UserInfo.UID)
   191  			}
   192  
   193  			if !reflect.DeepEqual(res3.Status.UserInfo.Groups, tc.expectedGroups) {
   194  				t.Fatalf("unexpected groups: wanted %v, got %v", tc.expectedGroups, res.Status.UserInfo.Groups)
   195  			}
   196  
   197  			if !reflect.DeepEqual(res3.Status.UserInfo.Extra, tc.expectedExtra) {
   198  				t.Fatalf("unexpected extra: wanted %v, got %v", tc.expectedExtra, res.Status.UserInfo.Extra)
   199  			}
   200  		})
   201  	}
   202  }
   203  
   204  func TestGetsSelfAttributesError(t *testing.T) {
   205  	toggle := &atomic.Value{}
   206  	toggle.Store(true)
   207  
   208  	tCtx := ktesting.Init(t)
   209  	kubeClient, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
   210  		ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
   211  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
   212  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1beta1=true")
   213  			opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1=true")
   214  			opts.Authorization.Modes = []string{"AlwaysAllow"}
   215  		},
   216  		ModifyServerConfig: func(config *controlplane.Config) {
   217  			// Unset BearerToken to disable BearerToken authenticator.
   218  			config.GenericConfig.LoopbackClientConfig.BearerToken = ""
   219  			config.GenericConfig.Authentication.Authenticator = authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) {
   220  				if toggle.Load().(bool) {
   221  					return &authenticator.Response{
   222  						User: &user.DefaultInfo{
   223  							Name: "alice",
   224  						},
   225  					}, true, nil
   226  				}
   227  
   228  				return nil, false, fmt.Errorf("test error")
   229  			})
   230  		},
   231  	})
   232  	defer tearDownFn()
   233  
   234  	expected := fmt.Errorf("Unauthorized")
   235  
   236  	{ // v1alpha1
   237  		toggle.Store(!toggle.Load().(bool))
   238  
   239  		_, err := kubeClient.AuthenticationV1alpha1().
   240  			SelfSubjectReviews().
   241  			Create(tCtx, &authenticationv1alpha1.SelfSubjectReview{}, metav1.CreateOptions{})
   242  		if err == nil {
   243  			t.Fatalf("expected error: %v, got nil", err)
   244  		}
   245  
   246  		toggle.Store(!toggle.Load().(bool))
   247  		if expected.Error() != err.Error() {
   248  			t.Fatalf("expected error: %v, got %v", expected, err)
   249  		}
   250  	}
   251  
   252  	{ // v1beta1
   253  		toggle.Store(!toggle.Load().(bool))
   254  
   255  		_, err := kubeClient.AuthenticationV1beta1().
   256  			SelfSubjectReviews().
   257  			Create(tCtx, &authenticationv1beta1.SelfSubjectReview{}, metav1.CreateOptions{})
   258  		if err == nil {
   259  			t.Fatalf("expected error: %v, got nil", err)
   260  		}
   261  
   262  		toggle.Store(!toggle.Load().(bool))
   263  		if expected.Error() != err.Error() {
   264  			t.Fatalf("expected error: %v, got %v", expected, err)
   265  		}
   266  	}
   267  
   268  	{ // v1
   269  		toggle.Store(!toggle.Load().(bool))
   270  
   271  		_, err := kubeClient.AuthenticationV1().
   272  			SelfSubjectReviews().
   273  			Create(context.TODO(), &authenticationv1.SelfSubjectReview{}, metav1.CreateOptions{})
   274  		if err == nil {
   275  			t.Fatalf("expected error: %v, got nil", err)
   276  		}
   277  
   278  		toggle.Store(!toggle.Load().(bool))
   279  		if expected.Error() != err.Error() {
   280  			t.Fatalf("expected error: %v, got %v", expected, err)
   281  		}
   282  	}
   283  }
   284  

View as plain text