1
16
17 package credentialprovider
18
19 import (
20 "encoding/base64"
21 "fmt"
22 "reflect"
23 "testing"
24 )
25
26 func TestURLsMatch(t *testing.T) {
27 tests := []struct {
28 globURL string
29 targetURL string
30 matchExpected bool
31 }{
32
33 {
34 globURL: "*.kubernetes.io",
35 targetURL: "prefix.kubernetes.io",
36 matchExpected: true,
37 },
38 {
39 globURL: "prefix.*.io",
40 targetURL: "prefix.kubernetes.io",
41 matchExpected: true,
42 },
43 {
44 globURL: "prefix.kubernetes.*",
45 targetURL: "prefix.kubernetes.io",
46 matchExpected: true,
47 },
48 {
49 globURL: "*-good.kubernetes.io",
50 targetURL: "prefix-good.kubernetes.io",
51 matchExpected: true,
52 },
53
54 {
55 globURL: "*.kubernetes.io/blah",
56 targetURL: "prefix.kubernetes.io/blah",
57 matchExpected: true,
58 },
59 {
60 globURL: "prefix.*.io/foo",
61 targetURL: "prefix.kubernetes.io/foo/bar",
62 matchExpected: true,
63 },
64
65 {
66 globURL: "*.kubernetes.io:1111/blah",
67 targetURL: "prefix.kubernetes.io:1111/blah",
68 matchExpected: true,
69 },
70 {
71 globURL: "prefix.*.io:1111/foo",
72 targetURL: "prefix.kubernetes.io:1111/foo/bar",
73 matchExpected: true,
74 },
75
76 {
77 globURL: "*.kubernetes.io",
78 targetURL: "kubernetes.io",
79 matchExpected: false,
80 },
81 {
82 globURL: "*.*.kubernetes.io",
83 targetURL: "prefix.kubernetes.io",
84 matchExpected: false,
85 },
86 {
87 globURL: "*.*.kubernetes.io",
88 targetURL: "kubernetes.io",
89 matchExpected: false,
90 },
91 {
92 globURL: "*kubernetes.io",
93 targetURL: "a.kubernetes.io",
94 matchExpected: false,
95 },
96
97 {
98 globURL: "*kubernetes.io",
99 targetURL: "kubernetes.io",
100 matchExpected: true,
101 },
102 {
103 globURL: "*.*.*.kubernetes.io",
104 targetURL: "a.b.c.kubernetes.io",
105 matchExpected: true,
106 },
107
108 {
109 globURL: "kubernetes.io",
110 targetURL: "kubernetes.com",
111 matchExpected: false,
112 },
113 {
114 globURL: "k*.io",
115 targetURL: "quay.io",
116 matchExpected: false,
117 },
118
119 {
120 globURL: "*.kubernetes.io:1234/blah",
121 targetURL: "prefix.kubernetes.io:1111/blah",
122 matchExpected: false,
123 },
124 {
125 globURL: "prefix.*.io/foo",
126 targetURL: "prefix.kubernetes.io:1111/foo/bar",
127 matchExpected: false,
128 },
129 }
130 for _, test := range tests {
131 matched, _ := URLsMatchStr(test.globURL, test.targetURL)
132 if matched != test.matchExpected {
133 t.Errorf("Expected match result of %s and %s to be %t, but was %t",
134 test.globURL, test.targetURL, test.matchExpected, matched)
135 }
136 }
137 }
138
139 func TestDockerKeyringForGlob(t *testing.T) {
140 tests := []struct {
141 globURL string
142 targetURL string
143 }{
144 {
145 globURL: "https://hello.kubernetes.io",
146 targetURL: "hello.kubernetes.io",
147 },
148 {
149 globURL: "https://*.docker.io",
150 targetURL: "prefix.docker.io",
151 },
152 {
153 globURL: "https://prefix.*.io",
154 targetURL: "prefix.docker.io",
155 },
156 {
157 globURL: "https://prefix.docker.*",
158 targetURL: "prefix.docker.io",
159 },
160 {
161 globURL: "https://*.docker.io/path",
162 targetURL: "prefix.docker.io/path",
163 },
164 {
165 globURL: "https://prefix.*.io/path",
166 targetURL: "prefix.docker.io/path/subpath",
167 },
168 {
169 globURL: "https://prefix.docker.*/path",
170 targetURL: "prefix.docker.io/path",
171 },
172 {
173 globURL: "https://*.docker.io:8888",
174 targetURL: "prefix.docker.io:8888",
175 },
176 {
177 globURL: "https://prefix.*.io:8888",
178 targetURL: "prefix.docker.io:8888",
179 },
180 {
181 globURL: "https://prefix.docker.*:8888",
182 targetURL: "prefix.docker.io:8888",
183 },
184 {
185 globURL: "https://*.docker.io/path:1111",
186 targetURL: "prefix.docker.io/path:1111",
187 },
188 {
189 globURL: "https://*.docker.io/v1/",
190 targetURL: "prefix.docker.io/path:1111",
191 },
192 {
193 globURL: "https://*.docker.io/v2/",
194 targetURL: "prefix.docker.io/path:1111",
195 },
196 {
197 globURL: "https://prefix.docker.*/path:1111",
198 targetURL: "prefix.docker.io/path:1111",
199 },
200 {
201 globURL: "prefix.docker.io:1111",
202 targetURL: "prefix.docker.io:1111/path",
203 },
204 {
205 globURL: "*.docker.io:1111",
206 targetURL: "prefix.docker.io:1111/path",
207 },
208 }
209 for i, test := range tests {
210 email := "foo@bar.baz"
211 username := "foo"
212 password := "bar"
213 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
214 sampleDockerConfig := fmt.Sprintf(`{
215 "%s": {
216 "email": %q,
217 "auth": %q
218 }
219 }`, test.globURL, email, auth)
220
221 keyring := &BasicDockerKeyring{}
222 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
223 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
224 } else {
225 keyring.Add(cfg)
226 }
227
228 creds, ok := keyring.Lookup(test.targetURL + "/foo/bar")
229 if !ok {
230 t.Errorf("%d: Didn't find expected URL: %s", i, test.targetURL)
231 continue
232 }
233 val := creds[0]
234
235 if username != val.Username {
236 t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
237 }
238 if password != val.Password {
239 t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
240 }
241 if email != val.Email {
242 t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
243 }
244 }
245 }
246
247 func TestKeyringMiss(t *testing.T) {
248 tests := []struct {
249 globURL string
250 lookupURL string
251 }{
252 {
253 globURL: "https://hello.kubernetes.io",
254 lookupURL: "world.mesos.org/foo/bar",
255 },
256 {
257 globURL: "https://*.docker.com",
258 lookupURL: "prefix.docker.io",
259 },
260 {
261 globURL: "https://suffix.*.io",
262 lookupURL: "prefix.docker.io",
263 },
264 {
265 globURL: "https://prefix.docker.c*",
266 lookupURL: "prefix.docker.io",
267 },
268 {
269 globURL: "https://prefix.*.io/path:1111",
270 lookupURL: "prefix.docker.io/path/subpath:1111",
271 },
272 {
273 globURL: "suffix.*.io",
274 lookupURL: "prefix.docker.io",
275 },
276 }
277 for _, test := range tests {
278 email := "foo@bar.baz"
279 username := "foo"
280 password := "bar"
281 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
282 sampleDockerConfig := fmt.Sprintf(`{
283 "%s": {
284 "email": %q,
285 "auth": %q
286 }
287 }`, test.globURL, email, auth)
288
289 keyring := &BasicDockerKeyring{}
290 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
291 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
292 } else {
293 keyring.Add(cfg)
294 }
295
296 _, ok := keyring.Lookup(test.lookupURL + "/foo/bar")
297 if ok {
298 t.Errorf("Expected not to find URL %s, but found", test.lookupURL)
299 }
300 }
301
302 }
303
304 func TestKeyringMissWithDockerHubCredentials(t *testing.T) {
305 url := defaultRegistryKey
306 email := "foo@bar.baz"
307 username := "foo"
308 password := "bar"
309 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
310 sampleDockerConfig := fmt.Sprintf(`{
311 "https://%s": {
312 "email": %q,
313 "auth": %q
314 }
315 }`, url, email, auth)
316
317 keyring := &BasicDockerKeyring{}
318 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
319 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
320 } else {
321 keyring.Add(cfg)
322 }
323
324 val, ok := keyring.Lookup("world.mesos.org/foo/bar")
325 if ok {
326 t.Errorf("Found unexpected credential: %+v", val)
327 }
328 }
329
330 func TestKeyringHitWithUnqualifiedDockerHub(t *testing.T) {
331 url := defaultRegistryKey
332 email := "foo@bar.baz"
333 username := "foo"
334 password := "bar"
335 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
336 sampleDockerConfig := fmt.Sprintf(`{
337 "https://%s": {
338 "email": %q,
339 "auth": %q
340 }
341 }`, url, email, auth)
342
343 keyring := &BasicDockerKeyring{}
344 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
345 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
346 } else {
347 keyring.Add(cfg)
348 }
349
350 creds, ok := keyring.Lookup("google/docker-registry")
351 if !ok {
352 t.Errorf("Didn't find expected URL: %s", url)
353 return
354 }
355 if len(creds) > 1 {
356 t.Errorf("Got more hits than expected: %s", creds)
357 }
358 val := creds[0]
359
360 if username != val.Username {
361 t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
362 }
363 if password != val.Password {
364 t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
365 }
366 if email != val.Email {
367 t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
368 }
369 }
370
371 func TestKeyringHitWithUnqualifiedLibraryDockerHub(t *testing.T) {
372 url := defaultRegistryKey
373 email := "foo@bar.baz"
374 username := "foo"
375 password := "bar"
376 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
377 sampleDockerConfig := fmt.Sprintf(`{
378 "https://%s": {
379 "email": %q,
380 "auth": %q
381 }
382 }`, url, email, auth)
383
384 keyring := &BasicDockerKeyring{}
385 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
386 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
387 } else {
388 keyring.Add(cfg)
389 }
390
391 creds, ok := keyring.Lookup("jenkins")
392 if !ok {
393 t.Errorf("Didn't find expected URL: %s", url)
394 return
395 }
396 if len(creds) > 1 {
397 t.Errorf("Got more hits than expected: %s", creds)
398 }
399 val := creds[0]
400
401 if username != val.Username {
402 t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
403 }
404 if password != val.Password {
405 t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
406 }
407 if email != val.Email {
408 t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
409 }
410 }
411
412 func TestKeyringHitWithQualifiedDockerHub(t *testing.T) {
413 url := defaultRegistryKey
414 email := "foo@bar.baz"
415 username := "foo"
416 password := "bar"
417 auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
418 sampleDockerConfig := fmt.Sprintf(`{
419 "https://%s": {
420 "email": %q,
421 "auth": %q
422 }
423 }`, url, email, auth)
424
425 keyring := &BasicDockerKeyring{}
426 if cfg, err := ReadDockerConfigFileFromBytes([]byte(sampleDockerConfig)); err != nil {
427 t.Errorf("Error processing json blob %q, %v", sampleDockerConfig, err)
428 } else {
429 keyring.Add(cfg)
430 }
431
432 creds, ok := keyring.Lookup(url + "/google/docker-registry")
433 if !ok {
434 t.Errorf("Didn't find expected URL: %s", url)
435 return
436 }
437 if len(creds) > 2 {
438 t.Errorf("Got more hits than expected: %s", creds)
439 }
440 val := creds[0]
441
442 if username != val.Username {
443 t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
444 }
445 if password != val.Password {
446 t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
447 }
448 if email != val.Email {
449 t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
450 }
451 }
452
453 func TestIsDefaultRegistryMatch(t *testing.T) {
454 samples := []map[bool]string{
455 {true: "foo/bar"},
456 {true: "docker.io/foo/bar"},
457 {true: "index.docker.io/foo/bar"},
458 {true: "foo"},
459 {false: ""},
460 {false: "registry.tld/foo/bar"},
461 {false: "registry:5000/foo/bar"},
462 {false: "myhostdocker.io/foo/bar"},
463 }
464 for _, sample := range samples {
465 for expected, imageName := range sample {
466 if got := isDefaultRegistryMatch(imageName); got != expected {
467 t.Errorf("Expected '%s' to be %t, got %t", imageName, expected, got)
468 }
469 }
470 }
471 }
472
473 func TestProvidersDockerKeyring(t *testing.T) {
474 provider := &testProvider{
475 Count: 0,
476 }
477 keyring := &providersDockerKeyring{
478 Providers: []DockerConfigProvider{
479 provider,
480 },
481 }
482
483 if provider.Count != 0 {
484 t.Errorf("Unexpected number of Provide calls: %v", provider.Count)
485 }
486 keyring.Lookup("foo")
487 if provider.Count != 1 {
488 t.Errorf("Unexpected number of Provide calls: %v", provider.Count)
489 }
490 keyring.Lookup("foo")
491 if provider.Count != 2 {
492 t.Errorf("Unexpected number of Provide calls: %v", provider.Count)
493 }
494 keyring.Lookup("foo")
495 if provider.Count != 3 {
496 t.Errorf("Unexpected number of Provide calls: %v", provider.Count)
497 }
498 }
499
500 func TestDockerKeyringLookup(t *testing.T) {
501 ada := AuthConfig{
502 Username: "ada",
503 Password: "smash",
504 Email: "ada@example.com",
505 }
506
507 grace := AuthConfig{
508 Username: "grace",
509 Password: "squash",
510 Email: "grace@example.com",
511 }
512
513 dk := &BasicDockerKeyring{}
514 dk.Add(DockerConfig{
515 "bar.example.com/pong": DockerConfigEntry{
516 Username: grace.Username,
517 Password: grace.Password,
518 Email: grace.Email,
519 },
520 "bar.example.com": DockerConfigEntry{
521 Username: ada.Username,
522 Password: ada.Password,
523 Email: ada.Email,
524 },
525 })
526
527 tests := []struct {
528 image string
529 match []AuthConfig
530 ok bool
531 }{
532
533 {"bar.example.com", []AuthConfig{ada}, true},
534
535
536 {"bar.example.com/pong", []AuthConfig{grace, ada}, true},
537
538
539 {"bar.example.com/ping", []AuthConfig{ada}, true},
540
541
542 {"bar.example.com/pongz", []AuthConfig{grace, ada}, true},
543
544
545 {"bar.example.com/pong/pang", []AuthConfig{grace, ada}, true},
546
547
548 {"example.com", []AuthConfig{}, false},
549 {"foo.example.com", []AuthConfig{}, false},
550 }
551
552 for i, tt := range tests {
553 match, ok := dk.Lookup(tt.image)
554 if tt.ok != ok {
555 t.Errorf("case %d: expected ok=%t, got %t", i, tt.ok, ok)
556 }
557
558 if !reflect.DeepEqual(tt.match, match) {
559 t.Errorf("case %d: expected match=%#v, got %#v", i, tt.match, match)
560 }
561 }
562 }
563
564
565
566
567 func TestIssue3797(t *testing.T) {
568 rex := AuthConfig{
569 Username: "rex",
570 Password: "tiny arms",
571 Email: "rex@example.com",
572 }
573
574 dk := &BasicDockerKeyring{}
575 dk.Add(DockerConfig{
576 "https://quay.io/v1/": DockerConfigEntry{
577 Username: rex.Username,
578 Password: rex.Password,
579 Email: rex.Email,
580 },
581 })
582
583 tests := []struct {
584 image string
585 match []AuthConfig
586 ok bool
587 }{
588
589 {"quay.io", []AuthConfig{rex}, true},
590
591
592 {"quay.io/foo", []AuthConfig{rex}, true},
593 {"quay.io/foo/bar", []AuthConfig{rex}, true},
594 }
595
596 for i, tt := range tests {
597 match, ok := dk.Lookup(tt.image)
598 if tt.ok != ok {
599 t.Errorf("case %d: expected ok=%t, got %t", i, tt.ok, ok)
600 }
601
602 if !reflect.DeepEqual(tt.match, match) {
603 t.Errorf("case %d: expected match=%#v, got %#v", i, tt.match, match)
604 }
605 }
606 }
607
View as plain text