k8s.io/kubernetes@v1.29.3/pkg/credentialprovider/config_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 credentialprovider 18 19 import ( 20 "encoding/base64" 21 "encoding/json" 22 "os" 23 "path/filepath" 24 "reflect" 25 "testing" 26 ) 27 28 func TestReadDockerConfigFile(t *testing.T) { 29 configJSONFileName := "config.json" 30 var fileInfo *os.File 31 32 //test dockerconfig json 33 inputDockerconfigJSONFile := "{ \"auths\": { \"http://foo.example.com\":{\"auth\":\"Zm9vOmJhcgo=\",\"email\":\"foo@example.com\"}}}" 34 35 preferredPath, err := os.MkdirTemp("", "test_foo_bar_dockerconfigjson_") 36 if err != nil { 37 t.Fatalf("Creating tmp dir fail: %v", err) 38 return 39 } 40 defer os.RemoveAll(preferredPath) 41 absDockerConfigFileLocation, err := filepath.Abs(filepath.Join(preferredPath, configJSONFileName)) 42 if err != nil { 43 t.Fatalf("While trying to canonicalize %s: %v", preferredPath, err) 44 } 45 46 if _, err := os.Stat(absDockerConfigFileLocation); os.IsNotExist(err) { 47 //create test cfg file 48 fileInfo, err = os.OpenFile(absDockerConfigFileLocation, os.O_CREATE|os.O_RDWR, 0664) 49 if err != nil { 50 t.Fatalf("While trying to create file %s: %v", absDockerConfigFileLocation, err) 51 } 52 defer fileInfo.Close() 53 } 54 55 fileInfo.WriteString(inputDockerconfigJSONFile) 56 57 orgPreferredPath := GetPreferredDockercfgPath() 58 SetPreferredDockercfgPath(preferredPath) 59 defer SetPreferredDockercfgPath(orgPreferredPath) 60 if _, err := ReadDockerConfigFile(); err != nil { 61 t.Errorf("Getting docker config file fail : %v preferredPath : %q", err, preferredPath) 62 } 63 } 64 func TestDockerConfigJsonJSONDecode(t *testing.T) { 65 // Fake values for testing. 66 input := []byte(`{"auths": {"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"}, "http://bar.example.com":{"username": "bar", "password": "baz", "email": "bar@example.com"}}}`) 67 68 expect := DockerConfigJSON{ 69 Auths: DockerConfig(map[string]DockerConfigEntry{ 70 "http://foo.example.com": { 71 Username: "foo", 72 Password: "bar", 73 Email: "foo@example.com", 74 }, 75 "http://bar.example.com": { 76 Username: "bar", 77 Password: "baz", 78 Email: "bar@example.com", 79 }, 80 }), 81 } 82 83 var output DockerConfigJSON 84 err := json.Unmarshal(input, &output) 85 if err != nil { 86 t.Errorf("Received unexpected error: %v", err) 87 } 88 89 if !reflect.DeepEqual(expect, output) { 90 t.Errorf("Received unexpected output. Expected %#v, got %#v", expect, output) 91 } 92 } 93 94 func TestDockerConfigJSONDecode(t *testing.T) { 95 // Fake values for testing. 96 input := []byte(`{"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"}, "http://bar.example.com":{"username": "bar", "password": "baz", "email": "bar@example.com"}}`) 97 98 expect := DockerConfig(map[string]DockerConfigEntry{ 99 "http://foo.example.com": { 100 Username: "foo", 101 Password: "bar", 102 Email: "foo@example.com", 103 }, 104 "http://bar.example.com": { 105 Username: "bar", 106 Password: "baz", 107 Email: "bar@example.com", 108 }, 109 }) 110 111 var output DockerConfig 112 err := json.Unmarshal(input, &output) 113 if err != nil { 114 t.Errorf("Received unexpected error: %v", err) 115 } 116 117 if !reflect.DeepEqual(expect, output) { 118 t.Errorf("Received unexpected output. Expected %#v, got %#v", expect, output) 119 } 120 } 121 122 func TestDockerConfigEntryJSONDecode(t *testing.T) { 123 tests := []struct { 124 input []byte 125 expect DockerConfigEntry 126 fail bool 127 }{ 128 // simple case, just decode the fields 129 { 130 // Fake values for testing. 131 input: []byte(`{"username": "foo", "password": "bar", "email": "foo@example.com"}`), 132 expect: DockerConfigEntry{ 133 Username: "foo", 134 Password: "bar", 135 Email: "foo@example.com", 136 }, 137 fail: false, 138 }, 139 140 // auth field decodes to username & password 141 { 142 input: []byte(`{"auth": "Zm9vOmJhcg==", "email": "foo@example.com"}`), 143 expect: DockerConfigEntry{ 144 Username: "foo", 145 Password: "bar", 146 Email: "foo@example.com", 147 }, 148 fail: false, 149 }, 150 151 // auth field overrides username & password 152 { 153 // Fake values for testing. 154 input: []byte(`{"username": "foo", "password": "bar", "auth": "cGluZzpwb25n", "email": "foo@example.com"}`), 155 expect: DockerConfigEntry{ 156 Username: "ping", 157 Password: "pong", 158 Email: "foo@example.com", 159 }, 160 fail: false, 161 }, 162 163 // poorly-formatted auth causes failure 164 { 165 input: []byte(`{"auth": "pants", "email": "foo@example.com"}`), 166 expect: DockerConfigEntry{ 167 Username: "", 168 Password: "", 169 Email: "foo@example.com", 170 }, 171 fail: true, 172 }, 173 174 // invalid JSON causes failure 175 { 176 input: []byte(`{"email": false}`), 177 expect: DockerConfigEntry{ 178 Username: "", 179 Password: "", 180 Email: "", 181 }, 182 fail: true, 183 }, 184 } 185 186 for i, tt := range tests { 187 var output DockerConfigEntry 188 err := json.Unmarshal(tt.input, &output) 189 if (err != nil) != tt.fail { 190 t.Errorf("case %d: expected fail=%t, got err=%v", i, tt.fail, err) 191 } 192 193 if !reflect.DeepEqual(tt.expect, output) { 194 t.Errorf("case %d: expected output %#v, got %#v", i, tt.expect, output) 195 } 196 } 197 } 198 199 func TestDecodeDockerConfigFieldAuth(t *testing.T) { 200 tests := []struct { 201 input string 202 username string 203 password string 204 fail bool 205 }{ 206 // auth field decodes to username & password 207 { 208 input: "Zm9vOmJhcg==", 209 username: "foo", 210 password: "bar", 211 }, 212 213 // some test as before but with field not well padded 214 { 215 input: "Zm9vOmJhcg", 216 username: "foo", 217 password: "bar", 218 }, 219 220 // some test as before but with new line characters 221 { 222 input: "Zm9vOm\nJhcg==\n", 223 username: "foo", 224 password: "bar", 225 }, 226 227 // standard encoding (with padding) 228 { 229 input: base64.StdEncoding.EncodeToString([]byte("foo:bar")), 230 username: "foo", 231 password: "bar", 232 }, 233 234 // raw encoding (without padding) 235 { 236 input: base64.RawStdEncoding.EncodeToString([]byte("foo:bar")), 237 username: "foo", 238 password: "bar", 239 }, 240 241 // the input is encoded with encodeDockerConfigFieldAuth (standard encoding) 242 { 243 input: encodeDockerConfigFieldAuth("foo", "bar"), 244 username: "foo", 245 password: "bar", 246 }, 247 248 // good base64 data, but no colon separating username & password 249 { 250 input: "cGFudHM=", 251 fail: true, 252 }, 253 254 // only new line characters are ignored 255 { 256 input: "Zm9vOmJhcg== ", 257 fail: true, 258 }, 259 260 // bad base64 data 261 { 262 input: "pants", 263 fail: true, 264 }, 265 } 266 267 for i, tt := range tests { 268 username, password, err := decodeDockerConfigFieldAuth(tt.input) 269 if (err != nil) != tt.fail { 270 t.Errorf("case %d: expected fail=%t, got err=%v", i, tt.fail, err) 271 } 272 273 if tt.username != username { 274 t.Errorf("case %d: expected username %q, got %q", i, tt.username, username) 275 } 276 277 if tt.password != password { 278 t.Errorf("case %d: expected password %q, got %q", i, tt.password, password) 279 } 280 } 281 } 282 283 func TestDockerConfigEntryJSONCompatibleEncode(t *testing.T) { 284 tests := []struct { 285 input DockerConfigEntry 286 expect []byte 287 }{ 288 // simple case, just decode the fields 289 { 290 // Fake values for testing. 291 expect: []byte(`{"username":"foo","password":"bar","email":"foo@example.com","auth":"Zm9vOmJhcg=="}`), 292 input: DockerConfigEntry{ 293 Username: "foo", 294 Password: "bar", 295 Email: "foo@example.com", 296 }, 297 }, 298 } 299 300 for i, tt := range tests { 301 actual, err := json.Marshal(tt.input) 302 if err != nil { 303 t.Errorf("case %d: unexpected error: %v", i, err) 304 } 305 306 if string(tt.expect) != string(actual) { 307 t.Errorf("case %d: expected %v, got %v", i, string(tt.expect), string(actual)) 308 } 309 } 310 } 311 312 func TestReadDockerConfigFileFromBytes(t *testing.T) { 313 testCases := []struct { 314 id string 315 input []byte 316 expectedCfg DockerConfig 317 errorExpected bool 318 expectedErrorMsg string 319 }{ 320 { 321 id: "valid input, no error expected", 322 input: []byte(`{"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"}}`), 323 expectedCfg: DockerConfig(map[string]DockerConfigEntry{ 324 "http://foo.example.com": { 325 Username: "foo", 326 Password: "bar", 327 Email: "foo@example.com", 328 }, 329 }), 330 }, 331 { 332 id: "invalid input, error expected", 333 input: []byte(`{"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"`), 334 errorExpected: true, 335 expectedErrorMsg: "error occurred while trying to unmarshal json", 336 }, 337 } 338 339 for _, tc := range testCases { 340 cfg, err := ReadDockerConfigFileFromBytes(tc.input) 341 if err != nil && !tc.errorExpected { 342 t.Fatalf("Error was not expected: %v", err) 343 } 344 if err != nil && tc.errorExpected { 345 if !reflect.DeepEqual(err.Error(), tc.expectedErrorMsg) { 346 t.Fatalf("Expected error message: `%s` got `%s`", tc.expectedErrorMsg, err.Error()) 347 } 348 } else { 349 if !reflect.DeepEqual(cfg, tc.expectedCfg) { 350 t.Fatalf("expected: %v got %v", tc.expectedCfg, cfg) 351 } 352 } 353 } 354 } 355 356 func TestReadDockerConfigJSONFileFromBytes(t *testing.T) { 357 testCases := []struct { 358 id string 359 input []byte 360 expectedCfg DockerConfig 361 errorExpected bool 362 expectedErrorMsg string 363 }{ 364 { 365 id: "valid input, no error expected", 366 input: []byte(`{"auths": {"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"}, "http://bar.example.com":{"username": "bar", "password": "baz", "email": "bar@example.com"}}}`), 367 expectedCfg: DockerConfig(map[string]DockerConfigEntry{ 368 "http://foo.example.com": { 369 Username: "foo", 370 Password: "bar", 371 Email: "foo@example.com", 372 }, 373 "http://bar.example.com": { 374 Username: "bar", 375 Password: "baz", 376 Email: "bar@example.com", 377 }, 378 }), 379 }, 380 { 381 id: "invalid input, error expected", 382 input: []byte(`{"auths": {"http://foo.example.com":{"username": "foo", "password": "bar", "email": "foo@example.com"}, "http://bar.example.com":{"username": "bar", "password": "baz", "email": "bar@example.com"`), 383 errorExpected: true, 384 expectedErrorMsg: "error occurred while trying to unmarshal json", 385 }, 386 } 387 388 for _, tc := range testCases { 389 cfg, err := readDockerConfigJSONFileFromBytes(tc.input) 390 if err != nil && !tc.errorExpected { 391 t.Fatalf("Error was not expected: %v", err) 392 } 393 if err != nil && tc.errorExpected { 394 if !reflect.DeepEqual(err.Error(), tc.expectedErrorMsg) { 395 t.Fatalf("Expected error message: `%s` got `%s`", tc.expectedErrorMsg, err.Error()) 396 } 397 } else { 398 if !reflect.DeepEqual(cfg, tc.expectedCfg) { 399 t.Fatalf("expected: %v got %v", tc.expectedCfg, cfg) 400 } 401 } 402 } 403 }