k8s.io/apiserver@v0.31.1/pkg/authentication/request/bearertoken/bearertoken_test.go (about)

     1  /*
     2  Copyright 2014 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 bearertoken
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"net/http"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"k8s.io/apiserver/pkg/authentication/authenticator"
    27  	"k8s.io/apiserver/pkg/authentication/user"
    28  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    29  	"k8s.io/apiserver/pkg/warning"
    30  )
    31  
    32  func TestAuthenticateRequest(t *testing.T) {
    33  	auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
    34  		if token != "token" {
    35  			t.Errorf("unexpected token: %s", token)
    36  		}
    37  		return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil
    38  	}))
    39  	resp, ok, err := auth.AuthenticateRequest(&http.Request{
    40  		Header: http.Header{"Authorization": []string{"Bearer token"}},
    41  	})
    42  	if !ok || resp == nil || err != nil {
    43  		t.Errorf("expected valid user")
    44  	}
    45  }
    46  
    47  func TestAuthenticateRequestIncludingValueAfterToken(t *testing.T) {
    48  	testCases := []struct {
    49  		Req *http.Request
    50  	}{
    51  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer token a"}}}},
    52  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer token a b c"}}}},
    53  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer token   a"}}}},
    54  	}
    55  	for i, testCase := range testCases {
    56  		auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
    57  			if token != "token" {
    58  				t.Errorf("unexpected token: %s", token)
    59  			}
    60  			return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil
    61  		}))
    62  		resp, ok, err := auth.AuthenticateRequest(testCase.Req)
    63  		if !ok || resp == nil || err != nil {
    64  			t.Errorf("%d: expected valid user", i)
    65  		}
    66  	}
    67  }
    68  
    69  func TestAuthenticateRequestTokenInvalid(t *testing.T) {
    70  	auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
    71  		return nil, false, nil
    72  	}))
    73  	resp, ok, err := auth.AuthenticateRequest(&http.Request{
    74  		Header: http.Header{"Authorization": []string{"Bearer token"}},
    75  	})
    76  	if ok || resp != nil {
    77  		t.Errorf("expected not authenticated user")
    78  	}
    79  	if err != invalidToken {
    80  		t.Errorf("expected invalidToken error, got %v", err)
    81  	}
    82  }
    83  
    84  func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) {
    85  	customError := errors.New("custom")
    86  	auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
    87  		return nil, false, customError
    88  	}))
    89  	resp, ok, err := auth.AuthenticateRequest(&http.Request{
    90  		Header: http.Header{"Authorization": []string{"Bearer token"}},
    91  	})
    92  	if ok || resp != nil {
    93  		t.Errorf("expected not authenticated user")
    94  	}
    95  	if err != customError {
    96  		t.Errorf("expected custom error, got %v", err)
    97  	}
    98  }
    99  
   100  func TestAuthenticateRequestTokenError(t *testing.T) {
   101  	auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
   102  		return nil, false, errors.New("error")
   103  	}))
   104  	resp, ok, err := auth.AuthenticateRequest(&http.Request{
   105  		Header: http.Header{"Authorization": []string{"Bearer token"}},
   106  	})
   107  	if ok || resp != nil || err == nil {
   108  		t.Errorf("expected error")
   109  	}
   110  }
   111  
   112  func TestAuthenticateRequestBadValue(t *testing.T) {
   113  	testCases := []struct {
   114  		Req *http.Request
   115  	}{
   116  		{Req: &http.Request{}},
   117  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer"}}}},
   118  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"bear token"}}}},
   119  		{Req: &http.Request{Header: http.Header{"Authorization": []string{"Bearer: token"}}}},
   120  	}
   121  	for i, testCase := range testCases {
   122  		auth := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
   123  			t.Errorf("authentication should not have been called")
   124  			return nil, false, nil
   125  		}))
   126  		user, ok, err := auth.AuthenticateRequest(testCase.Req)
   127  		if ok || user != nil || err != nil {
   128  			t.Errorf("%d: expected not authenticated (no token)", i)
   129  		}
   130  	}
   131  }
   132  
   133  type dummyRecorder struct {
   134  	agent string
   135  	text  string
   136  }
   137  
   138  func (r *dummyRecorder) AddWarning(agent, text string) {
   139  	r.agent = agent
   140  	r.text = text
   141  	return
   142  }
   143  
   144  func (r *dummyRecorder) getWarning() string {
   145  	return r.text
   146  }
   147  
   148  var _ warning.Recorder = &dummyRecorder{}
   149  
   150  func TestBearerToken(t *testing.T) {
   151  	tests := map[string]struct {
   152  		AuthorizationHeaders []string
   153  		TokenAuth            authenticator.Token
   154  
   155  		ExpectedUserName             string
   156  		ExpectedOK                   bool
   157  		ExpectedErr                  bool
   158  		ExpectedAuthorizationHeaders []string
   159  		ExpectedRecordedWarning      string
   160  	}{
   161  		"no header": {
   162  			AuthorizationHeaders:         nil,
   163  			ExpectedUserName:             "",
   164  			ExpectedOK:                   false,
   165  			ExpectedErr:                  false,
   166  			ExpectedAuthorizationHeaders: nil,
   167  		},
   168  		"empty header": {
   169  			AuthorizationHeaders:         []string{""},
   170  			ExpectedUserName:             "",
   171  			ExpectedOK:                   false,
   172  			ExpectedErr:                  false,
   173  			ExpectedAuthorizationHeaders: []string{""},
   174  		},
   175  		"non-bearer header": {
   176  			AuthorizationHeaders:         []string{"Basic 123"},
   177  			ExpectedUserName:             "",
   178  			ExpectedOK:                   false,
   179  			ExpectedErr:                  false,
   180  			ExpectedAuthorizationHeaders: []string{"Basic 123"},
   181  		},
   182  		"empty bearer token": {
   183  			AuthorizationHeaders:         []string{"Bearer "},
   184  			ExpectedUserName:             "",
   185  			ExpectedOK:                   false,
   186  			ExpectedErr:                  false,
   187  			ExpectedAuthorizationHeaders: []string{"Bearer "},
   188  		},
   189  		"valid bearer token removing header": {
   190  			AuthorizationHeaders: []string{"Bearer 123"},
   191  			TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
   192  				return &authenticator.Response{User: &user.DefaultInfo{Name: "myuser"}}, true, nil
   193  			}),
   194  			ExpectedUserName:             "myuser",
   195  			ExpectedOK:                   true,
   196  			ExpectedErr:                  false,
   197  			ExpectedAuthorizationHeaders: nil,
   198  		},
   199  		"invalid bearer token": {
   200  			AuthorizationHeaders:         []string{"Bearer 123"},
   201  			TokenAuth:                    authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) { return nil, false, nil }),
   202  			ExpectedUserName:             "",
   203  			ExpectedOK:                   false,
   204  			ExpectedErr:                  true,
   205  			ExpectedAuthorizationHeaders: []string{"Bearer 123"},
   206  		},
   207  		"valid bearer token with a space": {
   208  			AuthorizationHeaders:         []string{"Bearer  token"},
   209  			ExpectedUserName:             "",
   210  			ExpectedOK:                   false,
   211  			ExpectedErr:                  false,
   212  			ExpectedAuthorizationHeaders: []string{"Bearer  token"},
   213  			ExpectedRecordedWarning:      invalidTokenWithSpaceWarning,
   214  		},
   215  		"error bearer token": {
   216  			AuthorizationHeaders: []string{"Bearer 123"},
   217  			TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) {
   218  				return nil, false, errors.New("error")
   219  			}),
   220  			ExpectedUserName:             "",
   221  			ExpectedOK:                   false,
   222  			ExpectedErr:                  true,
   223  			ExpectedAuthorizationHeaders: []string{"Bearer 123"},
   224  		},
   225  	}
   226  
   227  	for k, tc := range tests {
   228  		dc := dummyRecorder{agent: "", text: ""}
   229  		ctx := genericapirequest.NewDefaultContext()
   230  		ctxWithRecorder := warning.WithWarningRecorder(ctx, &dc)
   231  		req, _ := http.NewRequestWithContext(ctxWithRecorder, "GET", "/", nil)
   232  		for _, h := range tc.AuthorizationHeaders {
   233  			req.Header.Add("Authorization", h)
   234  		}
   235  
   236  		bearerAuth := New(tc.TokenAuth)
   237  		resp, ok, err := bearerAuth.AuthenticateRequest(req)
   238  		if tc.ExpectedErr != (err != nil) {
   239  			t.Errorf("%s: Expected err=%v, got %v", k, tc.ExpectedErr, err)
   240  			continue
   241  		}
   242  		if ok != tc.ExpectedOK {
   243  			t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok)
   244  			continue
   245  		}
   246  		if ok && resp.User.GetName() != tc.ExpectedUserName {
   247  			t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
   248  			continue
   249  		}
   250  		if len(tc.ExpectedRecordedWarning) > 0 && tc.ExpectedRecordedWarning != dc.getWarning() {
   251  			t.Errorf("%s: Expected recorded warning=%v, got %v", k, tc.ExpectedRecordedWarning, dc.getWarning())
   252  			continue
   253  		}
   254  		if !reflect.DeepEqual(req.Header["Authorization"], tc.ExpectedAuthorizationHeaders) {
   255  			t.Errorf("%s: Expected headers=%#v, got %#v", k, tc.ExpectedAuthorizationHeaders, req.Header["Authorization"])
   256  			continue
   257  		}
   258  	}
   259  }