k8s.io/apiserver@v0.31.1/pkg/authentication/request/websocket/protocol_test.go (about) 1 /* 2 Copyright 2017 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 websocket 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 ) 29 30 func TestAuthenticateRequest(t *testing.T) { 31 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 32 if token != "token" { 33 t.Errorf("unexpected token: %s", token) 34 } 35 return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil 36 })) 37 resp, ok, err := auth.AuthenticateRequest(&http.Request{ 38 Header: http.Header{ 39 "Connection": []string{"upgrade"}, 40 "Upgrade": []string{"websocket"}, 41 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 42 }, 43 }) 44 if !ok || resp == nil || err != nil { 45 t.Errorf("expected valid user") 46 } 47 } 48 49 func TestAuthenticateRequestMultipleConnectionHeaders(t *testing.T) { 50 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 51 if token != "token" { 52 t.Errorf("unexpected token: %s", token) 53 } 54 return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}}, true, nil 55 })) 56 resp, ok, err := auth.AuthenticateRequest(&http.Request{ 57 Header: http.Header{ 58 "Connection": []string{"not", "upgrade"}, 59 "Upgrade": []string{"websocket"}, 60 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 61 }, 62 }) 63 if !ok || resp == nil || err != nil { 64 t.Errorf("expected valid user") 65 } 66 } 67 68 func TestAuthenticateRequestTokenInvalid(t *testing.T) { 69 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 70 return nil, false, nil 71 })) 72 resp, ok, err := auth.AuthenticateRequest(&http.Request{ 73 Header: http.Header{ 74 "Connection": []string{"upgrade"}, 75 "Upgrade": []string{"websocket"}, 76 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 77 }, 78 }) 79 if ok || resp != nil { 80 t.Errorf("expected not authenticated user") 81 } 82 if err != errInvalidToken { 83 t.Errorf("expected errInvalidToken error, got %v", err) 84 } 85 } 86 87 func TestAuthenticateRequestTokenInvalidCustomError(t *testing.T) { 88 customError := errors.New("custom") 89 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 90 return nil, false, customError 91 })) 92 resp, ok, err := auth.AuthenticateRequest(&http.Request{ 93 Header: http.Header{ 94 "Connection": []string{"upgrade"}, 95 "Upgrade": []string{"websocket"}, 96 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 97 }, 98 }) 99 if ok || resp != nil { 100 t.Errorf("expected not authenticated user") 101 } 102 if err != customError { 103 t.Errorf("expected custom error, got %v", err) 104 } 105 } 106 107 func TestAuthenticateRequestTokenError(t *testing.T) { 108 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 109 return nil, false, errors.New("error") 110 })) 111 resp, ok, err := auth.AuthenticateRequest(&http.Request{ 112 Header: http.Header{ 113 "Connection": []string{"upgrade"}, 114 "Upgrade": []string{"websocket"}, 115 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 116 }, 117 }) 118 if ok || resp != nil || err == nil { 119 t.Errorf("expected error") 120 } 121 } 122 123 func TestAuthenticateRequestBadValue(t *testing.T) { 124 testCases := []struct { 125 Req *http.Request 126 }{ 127 {Req: &http.Request{}}, 128 {Req: &http.Request{Header: http.Header{ 129 "Connection": []string{"upgrade"}, 130 "Upgrade": []string{"websocket"}, 131 "Sec-Websocket-Protocol": []string{"other-protocol"}}}, 132 }, 133 {Req: &http.Request{Header: http.Header{ 134 "Connection": []string{"upgrade"}, 135 "Upgrade": []string{"websocket"}, 136 "Sec-Websocket-Protocol": []string{"base64url.bearer.authorization.k8s.io."}}}, 137 }, 138 } 139 for i, testCase := range testCases { 140 auth := NewProtocolAuthenticator(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { 141 t.Errorf("authentication should not have been called") 142 return nil, false, nil 143 })) 144 resp, ok, err := auth.AuthenticateRequest(testCase.Req) 145 if ok || resp != nil || err != nil { 146 t.Errorf("%d: expected not authenticated (no token)", i) 147 } 148 } 149 } 150 151 func TestBearerToken(t *testing.T) { 152 tests := map[string]struct { 153 ProtocolHeaders []string 154 TokenAuth authenticator.Token 155 156 ExpectedUserName string 157 ExpectedOK bool 158 ExpectedErr bool 159 ExpectedProtocolHeaders []string 160 }{ 161 "no header": { 162 ProtocolHeaders: nil, 163 ExpectedUserName: "", 164 ExpectedOK: false, 165 ExpectedErr: false, 166 ExpectedProtocolHeaders: nil, 167 }, 168 "empty header": { 169 ProtocolHeaders: []string{""}, 170 ExpectedUserName: "", 171 ExpectedOK: false, 172 ExpectedErr: false, 173 ExpectedProtocolHeaders: []string{""}, 174 }, 175 "non-bearer header": { 176 ProtocolHeaders: []string{"undefined"}, 177 ExpectedUserName: "", 178 ExpectedOK: false, 179 ExpectedErr: false, 180 ExpectedProtocolHeaders: []string{"undefined"}, 181 }, 182 "empty bearer token": { 183 ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io."}, 184 ExpectedUserName: "", 185 ExpectedOK: false, 186 ExpectedErr: false, 187 ExpectedProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io."}, 188 }, 189 "valid bearer token removing header": { 190 ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4", "dummy, dummy2"}, 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 ExpectedProtocolHeaders: []string{"dummy,dummy2"}, 198 }, 199 "invalid bearer token": { 200 ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 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 ExpectedProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 206 }, 207 "error bearer token": { 208 ProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 209 TokenAuth: authenticator.TokenFunc(func(ctx context.Context, t string) (*authenticator.Response, bool, error) { 210 return nil, false, errors.New("error") 211 }), 212 ExpectedUserName: "", 213 ExpectedOK: false, 214 ExpectedErr: true, 215 ExpectedProtocolHeaders: []string{"base64url.bearer.authorization.k8s.io.dG9rZW4,dummy"}, 216 }, 217 } 218 219 for k, tc := range tests { 220 req, _ := http.NewRequest("GET", "/", nil) 221 req.Header.Set("Connection", "upgrade") 222 req.Header.Set("Upgrade", "websocket") 223 for _, h := range tc.ProtocolHeaders { 224 req.Header.Add("Sec-Websocket-Protocol", h) 225 } 226 227 bearerAuth := NewProtocolAuthenticator(tc.TokenAuth) 228 resp, ok, err := bearerAuth.AuthenticateRequest(req) 229 if tc.ExpectedErr != (err != nil) { 230 t.Errorf("%s: Expected err=%v, got %v", k, tc.ExpectedErr, err) 231 continue 232 } 233 if ok != tc.ExpectedOK { 234 t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok) 235 continue 236 } 237 if ok && resp.User.GetName() != tc.ExpectedUserName { 238 t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName()) 239 continue 240 } 241 if !reflect.DeepEqual(req.Header["Sec-Websocket-Protocol"], tc.ExpectedProtocolHeaders) { 242 t.Errorf("%s: Expected headers=%#v, got %#v", k, tc.ExpectedProtocolHeaders, req.Header["Sec-Websocket-Protocol"]) 243 continue 244 } 245 } 246 }