11
. "github.com/containers/podman/v5/test/utils"
12
. "github.com/onsi/ginkgo/v2"
13
. "github.com/onsi/gomega"
16
var _ = Describe("Podman login and logout", func() {
24
registriesConfWithSearch []byte
28
authPath = filepath.Join(podmanTest.TempDir, "auth")
29
err := os.Mkdir(authPath, os.ModePerm)
30
Expect(err).ToNot(HaveOccurred())
32
htpasswd := SystemExec("htpasswd", []string{"-Bbn", "podmantest", "test"})
33
htpasswd.WaitWithDefaultTimeout()
34
Expect(htpasswd).Should(ExitCleanly())
36
f, err := os.Create(filepath.Join(authPath, "htpasswd"))
37
Expect(err).ToNot(HaveOccurred())
40
_, err = f.WriteString(htpasswd.OutputToString())
41
Expect(err).ToNot(HaveOccurred())
43
Expect(err).ToNot(HaveOccurred())
45
server = strings.Join([]string{"localhost", strconv.Itoa(port)}, ":")
47
registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server))
49
testImg = strings.Join([]string{server, "test-alpine"}, "/")
51
certDirPath = filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", server)
52
err = os.MkdirAll(certDirPath, os.ModePerm)
53
Expect(err).ToNot(HaveOccurred())
55
certPath = filepath.Join(cwd, "../", "certs")
57
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDirPath, "ca.crt")})
58
setup.WaitWithDefaultTimeout()
60
session := podmanTest.Podman([]string{"run", "-d", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"),
61
"-e", strings.Join([]string{"REGISTRY_HTTP_ADDR=0.0.0.0", strconv.Itoa(port)}, ":"), "--name", "registry", "-v",
62
strings.Join([]string{authPath, "/auth:Z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
63
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
64
"-v", strings.Join([]string{certPath, "/certs:Z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
65
"-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
66
session.WaitWithDefaultTimeout()
67
Expect(session).Should(ExitCleanly())
69
if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
70
Skip("Cannot start docker registry.")
74
os.Setenv("REGISTRY_AUTH_FILE", filepath.Join(podmanTest.TempDir, "default-auth.json"))
78
os.Unsetenv("REGISTRY_AUTH_FILE")
79
os.RemoveAll(authPath)
80
os.RemoveAll(certDirPath)
83
readAuthInfo := func(filePath string) map[string]interface{} {
84
authBytes, err := os.ReadFile(filePath)
85
Expect(err).ToNot(HaveOccurred())
87
var authInfo map[string]interface{}
88
err = json.Unmarshal(authBytes, &authInfo)
89
Expect(err).ToNot(HaveOccurred())
90
GinkgoWriter.Println(authInfo)
92
const authsKey = "auths"
93
Expect(authInfo).To(HaveKey(authsKey))
95
auths, ok := authInfo[authsKey].(map[string]interface{})
96
Expect(ok).To(BeTrue(), "authInfo[%s]", authsKey)
101
It("podman login and logout", func() {
102
authFile := os.Getenv("REGISTRY_AUTH_FILE")
103
Expect(authFile).NotTo(BeEmpty(), "$REGISTRY_AUTH_FILE")
105
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test", server})
106
session.WaitWithDefaultTimeout()
107
Expect(session).Should(ExitCleanly())
110
auths := readAuthInfo(authFile)
111
Expect(auths).To(HaveKey(server))
113
Expect(auths[server]).To(HaveKeyWithValue("auth", "cG9kbWFudGVzdDp0ZXN0"))
115
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
116
session.WaitWithDefaultTimeout()
117
Expect(session).Should(ExitCleanly())
119
session = podmanTest.Podman([]string{"logout", server})
120
session.WaitWithDefaultTimeout()
121
Expect(session).Should(ExitCleanly())
123
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
124
session.WaitWithDefaultTimeout()
125
Expect(session).To(ExitWithError())
126
Expect(session.ErrorToString()).To(ContainSubstring(": authentication required"))
129
It("podman login and logout without registry parameter", func() {
130
registriesConf, err := os.CreateTemp("", "TestLoginWithoutParameter")
131
Expect(err).ToNot(HaveOccurred())
132
defer registriesConf.Close()
133
defer os.Remove(registriesConf.Name())
135
err = os.WriteFile(registriesConf.Name(), registriesConfWithSearch, os.ModePerm)
136
Expect(err).ToNot(HaveOccurred())
140
oldRCP, hasRCP := os.LookupEnv("CONTAINERS_REGISTRIES_CONF")
143
os.Setenv("CONTAINERS_REGISTRIES_CONF", oldRCP)
145
os.Unsetenv("CONTAINERS_REGISTRIES_CONF")
148
os.Setenv("CONTAINERS_REGISTRIES_CONF", registriesConf.Name())
150
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test"})
151
session.WaitWithDefaultTimeout()
152
Expect(session).Should(ExitCleanly())
154
session = podmanTest.Podman([]string{"logout"})
155
session.WaitWithDefaultTimeout()
156
Expect(session).Should(ExitCleanly())
159
It("podman login and logout with flag --authfile", func() {
160
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
161
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--authfile", authFile, server})
162
session.WaitWithDefaultTimeout()
163
Expect(session).Should(ExitCleanly())
165
readAuthInfo(authFile)
168
session = podmanTest.Podman([]string{"push", "-q", "--authfile", "/tmp/nonexistent", ALPINE, testImg})
169
session.WaitWithDefaultTimeout()
170
Expect(session).To(ExitWithError())
171
Expect(session.ErrorToString()).To(Equal("Error: credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory"))
173
session = podmanTest.Podman([]string{"push", "-q", "--authfile", authFile, ALPINE, testImg})
174
session.WaitWithDefaultTimeout()
175
Expect(session).Should(ExitCleanly())
177
session = podmanTest.Podman([]string{"run", "-q", "--authfile", authFile, testImg})
178
session.WaitWithDefaultTimeout()
179
Expect(session).Should(ExitCleanly())
182
session = podmanTest.Podman([]string{"logout", "--authfile", "/tmp/nonexistent", server})
183
session.WaitWithDefaultTimeout()
184
Expect(session).To(ExitWithError())
185
Expect(session.ErrorToString()).To(Equal("Error: credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory"))
186
session = podmanTest.Podman([]string{"logout", "--authfile", authFile, server})
187
session.WaitWithDefaultTimeout()
188
Expect(session).Should(ExitCleanly())
191
It("podman login and logout --compat-auth-file flag handling", func() {
193
compatAuthFile := filepath.Join(podmanTest.TempDir, "config.json")
194
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--compat-auth-file", compatAuthFile, server})
195
session.WaitWithDefaultTimeout()
196
Expect(session).Should(ExitCleanly())
198
readAuthInfo(compatAuthFile)
200
session = podmanTest.Podman([]string{"logout", "--compat-auth-file", compatAuthFile, server})
201
session.WaitWithDefaultTimeout()
202
Expect(session).Should(ExitCleanly())
205
session = podmanTest.Podman([]string{"logout", "--compat-auth-file", "/tmp/nonexistent", server})
206
session.WaitWithDefaultTimeout()
207
Expect(session).To(ExitWithError())
208
Expect(session.ErrorToString()).To(Equal("Error: credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory"))
212
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
213
err := os.WriteFile(authFile, []byte("{}"), 0o700)
214
Expect(err).ToNot(HaveOccurred())
215
err = os.WriteFile(compatAuthFile, []byte("{}"), 0o700)
216
Expect(err).ToNot(HaveOccurred())
218
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test",
219
"--authfile", authFile, "--compat-auth-file", compatAuthFile, server})
220
session.WaitWithDefaultTimeout()
221
Expect(session).To(ExitWithError())
222
Expect(session.ErrorToString()).To(Equal("Error: options for paths to the credential file and to the Docker-compatible credential file can not be set simultaneously"))
224
session = podmanTest.Podman([]string{"logout", "--authfile", authFile, "--compat-auth-file", compatAuthFile, server})
225
session.WaitWithDefaultTimeout()
226
Expect(session).To(ExitWithError())
227
Expect(session.ErrorToString()).To(Equal("Error: options for paths to the credential file and to the Docker-compatible credential file can not be set simultaneously"))
230
It("podman manifest with --authfile", func() {
231
os.Unsetenv("REGISTRY_AUTH_FILE")
233
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
234
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--authfile", authFile, server})
235
session.WaitWithDefaultTimeout()
236
Expect(session).Should(ExitCleanly())
238
readAuthInfo(authFile)
240
session = podmanTest.Podman([]string{"manifest", "create", testImg})
241
session.WaitWithDefaultTimeout()
242
Expect(session).Should(ExitCleanly())
244
session = podmanTest.Podman([]string{"manifest", "push", "-q", testImg})
245
session.WaitWithDefaultTimeout()
246
Expect(session).To(ExitWithError())
247
Expect(session.ErrorToString()).To(ContainSubstring(": authentication required"))
249
session = podmanTest.Podman([]string{"manifest", "push", "-q", "--authfile", authFile, testImg})
250
session.WaitWithDefaultTimeout()
251
Expect(session).Should(ExitCleanly())
254
session = podmanTest.Podman([]string{"manifest", "rm", testImg})
255
session.WaitWithDefaultTimeout()
256
Expect(session).Should(ExitCleanly())
258
session = podmanTest.Podman([]string{"manifest", "inspect", testImg})
259
session.WaitWithDefaultTimeout()
260
Expect(session).To(ExitWithError())
261
Expect(session.ErrorToString()).To(ContainSubstring(": authentication required"))
263
session = podmanTest.Podman([]string{"manifest", "inspect", "--authfile", authFile, testImg})
264
session.WaitWithDefaultTimeout()
265
Expect(session).Should(ExitCleanly())
268
It("podman login and logout with --tls-verify", func() {
269
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--tls-verify=false", server})
270
session.WaitWithDefaultTimeout()
271
Expect(session).Should(ExitCleanly())
273
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
274
session.WaitWithDefaultTimeout()
275
Expect(session).Should(ExitCleanly())
277
session = podmanTest.Podman([]string{"logout", server})
278
session.WaitWithDefaultTimeout()
279
Expect(session).Should(ExitCleanly())
281
It("podman login and logout with --cert-dir", func() {
282
certDir := filepath.Join(podmanTest.TempDir, "certs")
283
err := os.MkdirAll(certDir, os.ModePerm)
284
Expect(err).ToNot(HaveOccurred())
286
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")})
287
setup.WaitWithDefaultTimeout()
289
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--cert-dir", certDir, server})
290
session.WaitWithDefaultTimeout()
291
Expect(session).Should(ExitCleanly())
293
session = podmanTest.Podman([]string{"push", "-q", "--cert-dir", certDir, ALPINE, testImg})
294
session.WaitWithDefaultTimeout()
295
Expect(session).Should(ExitCleanly())
297
session = podmanTest.Podman([]string{"logout", server})
298
session.WaitWithDefaultTimeout()
299
Expect(session).Should(ExitCleanly())
301
It("podman login and logout with multi registry", func() {
302
certDir := filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", "localhost:9001")
303
err = os.MkdirAll(certDir, os.ModePerm)
304
Expect(err).ToNot(HaveOccurred())
307
certPath = filepath.Join(cwd, "../", "certs")
309
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")})
310
setup.WaitWithDefaultTimeout()
311
defer os.RemoveAll(certDir)
316
session := podmanTest.Podman([]string{"run", "-d", "-p", "9001:9001", "-e", "REGISTRY_HTTP_ADDR=0.0.0.0:9001", "--name", "registry1", "-v",
317
strings.Join([]string{authPath, "/auth:z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
318
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
319
"-v", strings.Join([]string{certPath, "/certs:z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
320
"-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
321
session.WaitWithDefaultTimeout()
322
Expect(session).Should(ExitCleanly())
324
if !WaitContainerReady(podmanTest, "registry1", "listening on", 20, 1) {
325
Skip("Cannot start docker registry.")
328
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", server})
329
session.WaitWithDefaultTimeout()
330
Expect(session).Should(ExitCleanly())
332
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
333
session.WaitWithDefaultTimeout()
334
Expect(session).Should(ExitCleanly())
336
session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"})
337
session.WaitWithDefaultTimeout()
338
Expect(session).To(ExitWithError())
339
Expect(session.ErrorToString()).To(ContainSubstring("/test-alpine: authentication required"))
341
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"})
342
session.WaitWithDefaultTimeout()
343
Expect(session).Should(ExitCleanly())
345
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
346
session.WaitWithDefaultTimeout()
347
Expect(session).Should(ExitCleanly())
349
session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"})
350
session.WaitWithDefaultTimeout()
351
Expect(session).Should(ExitCleanly())
353
session = podmanTest.Podman([]string{"logout", server})
354
session.WaitWithDefaultTimeout()
355
Expect(session).Should(ExitCleanly())
357
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
358
session.WaitWithDefaultTimeout()
359
Expect(session).To(ExitWithError())
360
Expect(session.ErrorToString()).To(ContainSubstring("/test-alpine: authentication required"))
362
session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"})
363
session.WaitWithDefaultTimeout()
364
Expect(session).Should(ExitCleanly())
366
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"})
367
session.WaitWithDefaultTimeout()
368
Expect(session).Should(ExitCleanly())
370
session = podmanTest.Podman([]string{"logout", "-a"})
371
session.WaitWithDefaultTimeout()
372
Expect(session).Should(ExitCleanly())
374
session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg})
375
session.WaitWithDefaultTimeout()
376
Expect(session).To(ExitWithError())
377
Expect(session.ErrorToString()).To(ContainSubstring("/test-alpine: authentication required"))
379
session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"})
380
session.WaitWithDefaultTimeout()
381
Expect(session).To(ExitWithError())
382
Expect(session.ErrorToString()).To(ContainSubstring("/test-alpine: authentication required"))
385
It("podman login and logout with repository", func() {
386
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
388
testRepository := server + "/podmantest"
389
session := podmanTest.Podman([]string{
393
"--authfile", authFile,
396
session.WaitWithDefaultTimeout()
397
Expect(session).Should(ExitCleanly())
399
authInfo := readAuthInfo(authFile)
400
Expect(authInfo).To(HaveKey(testRepository))
402
session = podmanTest.Podman([]string{
404
"--authfile", authFile,
407
session.WaitWithDefaultTimeout()
408
Expect(session).Should(ExitCleanly())
410
authInfo = readAuthInfo(authFile)
411
Expect(authInfo).NotTo(HaveKey(testRepository))
414
It("podman login and logout with repository and specified image", func() {
415
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
417
testTarget := server + "/podmantest/test-alpine"
418
session := podmanTest.Podman([]string{
422
"--authfile", authFile,
425
session.WaitWithDefaultTimeout()
426
Expect(session).Should(ExitCleanly())
428
authInfo := readAuthInfo(authFile)
429
Expect(authInfo).To(HaveKey(testTarget))
431
session = podmanTest.Podman([]string{
433
"--authfile", authFile,
436
session.WaitWithDefaultTimeout()
437
Expect(session).Should(ExitCleanly())
441
It("podman login and logout with repository with fallback", func() {
442
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
444
testRepos := []string{
445
server + "/podmantest",
448
for _, testRepo := range testRepos {
449
session := podmanTest.Podman([]string{
453
"--authfile", authFile,
456
session.WaitWithDefaultTimeout()
457
Expect(session).Should(ExitCleanly())
460
authInfo := readAuthInfo(authFile)
461
Expect(authInfo).To(HaveKey(testRepos[0]))
462
Expect(authInfo).To(HaveKey(testRepos[1]))
464
session := podmanTest.Podman([]string{
466
"--authfile", authFile,
467
ALPINE, testRepos[0] + "/test-image-alpine",
469
session.WaitWithDefaultTimeout()
470
Expect(session).Should(ExitCleanly())
472
session = podmanTest.Podman([]string{
474
"--authfile", authFile,
477
session.WaitWithDefaultTimeout()
478
Expect(session).Should(ExitCleanly())
480
session = podmanTest.Podman([]string{
482
"--authfile", authFile,
483
ALPINE, testRepos[0] + "/test-image-alpine",
485
session.WaitWithDefaultTimeout()
486
Expect(session).Should(ExitCleanly())
488
session = podmanTest.Podman([]string{
490
"--authfile", authFile,
493
session.WaitWithDefaultTimeout()
494
Expect(session).Should(ExitCleanly())
496
authInfo = readAuthInfo(authFile)
497
Expect(authInfo).NotTo(HaveKey(testRepos[0]))
498
Expect(authInfo).NotTo(HaveKey(testRepos[1]))
501
It("podman login with http{s} prefix", func() {
502
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
504
for _, invalidArg := range []string{
505
"https://" + server + "/podmantest",
506
"http://" + server + "/podmantest/image:latest",
508
session := podmanTest.Podman([]string{
512
"--authfile", authFile,
515
session.WaitWithDefaultTimeout()
516
Expect(session).To(ExitCleanly())
520
It("podman login and logout with repository push with invalid auth.json credentials", func() {
521
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
523
err := os.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
524
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
525
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
526
}}`, server, server)), 0644)
527
Expect(err).ToNot(HaveOccurred())
529
session := podmanTest.Podman([]string{
531
"--authfile", authFile,
532
ALPINE, server + "/podmantest/test-image",
534
session.WaitWithDefaultTimeout()
535
Expect(session).To(ExitWithError())
536
Expect(session.ErrorToString()).To(ContainSubstring("/test-image: authentication required"))
538
session = podmanTest.Podman([]string{
540
"--authfile", authFile,
541
ALPINE, server + "/test-image",
543
session.WaitWithDefaultTimeout()
544
Expect(session).To(ExitCleanly())
547
It("podman login and logout with repository pull with wrong auth.json credentials", func() {
548
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
550
testTarget := server + "/podmantest/test-alpine"
551
session := podmanTest.Podman([]string{
555
"--authfile", authFile,
558
session.WaitWithDefaultTimeout()
559
Expect(session).Should(ExitCleanly())
561
session = podmanTest.Podman([]string{
563
"--authfile", authFile,
566
session.WaitWithDefaultTimeout()
567
Expect(session).Should(ExitCleanly())
570
err := os.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
571
"%s/podmantest/test-alpine": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
572
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp0ZXN0" },
573
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
574
}}`, server, server, server)), 0644)
575
Expect(err).ToNot(HaveOccurred())
577
session = podmanTest.Podman([]string{
579
"--authfile", authFile,
580
server + "/podmantest/test-alpine",
582
session.WaitWithDefaultTimeout()
583
Expect(session).To(ExitWithError())
584
Expect(session.ErrorToString()).To(ContainSubstring("/test-alpine: authentication required"))