podman/test/e2e/login_logout_test.go

513 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package integration
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
. "github.com/containers/podman/v4/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman login and logout", func() {
var (
tempdir string
err error
podmanTest *PodmanTestIntegration
authPath string
certPath string
certDirPath string
server string
testImg string
registriesConfWithSearch []byte
)
BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
}
podmanTest = PodmanTestCreate(tempdir)
authPath = filepath.Join(podmanTest.TempDir, "auth")
err := os.Mkdir(authPath, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if IsCommandAvailable("getenforce") {
ge := SystemExec("getenforce", []string{})
ge.WaitWithDefaultTimeout()
if ge.OutputToString() == "Enforcing" {
se := SystemExec("setenforce", []string{"0"})
se.WaitWithDefaultTimeout()
if se.ExitCode() != 0 {
Skip("Cannot disable selinux, this may cause problem for reading cert files inside container.")
}
defer SystemExec("setenforce", []string{"1"})
}
}
htpasswd := SystemExec("htpasswd", []string{"-Bbn", "podmantest", "test"})
htpasswd.WaitWithDefaultTimeout()
Expect(htpasswd).Should(Exit(0))
f, err := os.Create(filepath.Join(authPath, "htpasswd"))
Expect(err).ToNot(HaveOccurred())
defer f.Close()
_, err = f.WriteString(htpasswd.OutputToString())
Expect(err).ToNot(HaveOccurred())
err = f.Sync()
Expect(err).ToNot(HaveOccurred())
port := GetPort()
server = strings.Join([]string{"localhost", strconv.Itoa(port)}, ":")
registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server))
testImg = strings.Join([]string{server, "test-alpine"}, "/")
certDirPath = filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", server)
err = os.MkdirAll(certDirPath, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
cwd, _ := os.Getwd()
certPath = filepath.Join(cwd, "../", "certs")
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDirPath, "ca.crt")})
setup.WaitWithDefaultTimeout()
session := podmanTest.Podman([]string{"run", "-d", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"),
"-e", strings.Join([]string{"REGISTRY_HTTP_ADDR=0.0.0.0", strconv.Itoa(port)}, ":"), "--name", "registry", "-v",
strings.Join([]string{authPath, "/auth:Z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
"-v", strings.Join([]string{certPath, "/certs:Z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
"-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
Skip("Cannot start docker registry.")
}
})
AfterEach(func() {
podmanTest.Cleanup()
os.RemoveAll(authPath)
os.RemoveAll(certDirPath)
})
readAuthInfo := func(filePath string) map[string]interface{} {
authBytes, err := ioutil.ReadFile(filePath)
Expect(err).To(BeNil())
var authInfo map[string]interface{}
err = json.Unmarshal(authBytes, &authInfo)
Expect(err).To(BeNil())
fmt.Println(authInfo)
const authsKey = "auths"
Expect(authInfo).To(HaveKey(authsKey))
auths, ok := authInfo[authsKey].(map[string]interface{})
Expect(ok).To(BeTrue())
return auths
}
It("podman login and logout", func() {
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
It("podman login and logout without registry parameter", func() {
registriesConf, err := ioutil.TempFile("", "TestLoginWithoutParameter")
Expect(err).To(BeNil())
defer registriesConf.Close()
defer os.Remove(registriesConf.Name())
err = ioutil.WriteFile(registriesConf.Name(), registriesConfWithSearch, os.ModePerm)
Expect(err).To(BeNil())
// Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not
// run in parallel unless they opt in by calling t.Parallel(). So dont do that.
oldRCP, hasRCP := os.LookupEnv("CONTAINERS_REGISTRIES_CONF")
defer func() {
if hasRCP {
os.Setenv("CONTAINERS_REGISTRIES_CONF", oldRCP)
} else {
os.Unsetenv("CONTAINERS_REGISTRIES_CONF")
}
}()
os.Setenv("CONTAINERS_REGISTRIES_CONF", registriesConf.Name())
session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman login and logout with flag --authfile", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--authfile", authFile, server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
readAuthInfo(authFile)
// push should fail with nonexistent authfile
session = podmanTest.Podman([]string{"push", "--authfile", "/tmp/nonexistent", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{"push", "--authfile", authFile, ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"run", "--authfile", authFile, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
// logout should fail with nonexistent authfile
session = podmanTest.Podman([]string{"logout", "--authfile", "/tmp/nonexistent", server})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{"logout", "--authfile", authFile, server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman login and logout with --tls-verify", func() {
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--tls-verify=false", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman login and logout with --cert-dir", func() {
certDir := filepath.Join(podmanTest.TempDir, "certs")
err := os.MkdirAll(certDir, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")})
setup.WaitWithDefaultTimeout()
session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--cert-dir", certDir, server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", "--cert-dir", certDir, ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman login and logout with multi registry", func() {
certDir := filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", "localhost:9001")
err = os.MkdirAll(certDir, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
cwd, _ := os.Getwd()
certPath = filepath.Join(cwd, "../", "certs")
setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")})
setup.WaitWithDefaultTimeout()
defer os.RemoveAll(certDir)
// N/B: This second registry container shares the same auth and cert dirs
// as the registry started from BeforeEach(). Since this one starts
// second, re-labeling the volumes should keep SELinux happy.
session := podmanTest.Podman([]string{"run", "-d", "-p", "9001:9001", "-e", "REGISTRY_HTTP_ADDR=0.0.0.0:9001", "--name", "registry1", "-v",
strings.Join([]string{authPath, "/auth:z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
"-v", strings.Join([]string{certPath, "/certs:z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
"-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
if !WaitContainerReady(podmanTest, "registry1", "listening on", 20, 1) {
Skip("Cannot start docker registry.")
}
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout", server})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"logout", "-a"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{"push", ALPINE, testImg})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{"push", ALPINE, "localhost:9001/test-alpine"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
It("podman login and logout with repository", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
testRepository := server + "/podmantest"
session := podmanTest.Podman([]string{
"login",
"-u", "podmantest",
"-p", "test",
"--authfile", authFile,
testRepository,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
authInfo := readAuthInfo(authFile)
Expect(authInfo).To(HaveKey(testRepository))
session = podmanTest.Podman([]string{
"logout",
"--authfile", authFile,
testRepository,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
authInfo = readAuthInfo(authFile)
Expect(authInfo).NotTo(HaveKey(testRepository))
})
It("podman login and logout with repository and specified image", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
testTarget := server + "/podmantest/test-alpine"
session := podmanTest.Podman([]string{
"login",
"-u", "podmantest",
"-p", "test",
"--authfile", authFile,
testTarget,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
authInfo := readAuthInfo(authFile)
Expect(authInfo).To(HaveKey(testTarget))
session = podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, testTarget,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
It("podman login and logout with repository with fallback", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
testRepos := []string{
server + "/podmantest",
server,
}
for _, testRepo := range testRepos {
session := podmanTest.Podman([]string{
"login",
"-u", "podmantest",
"-p", "test",
"--authfile", authFile,
testRepo,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
}
authInfo := readAuthInfo(authFile)
Expect(authInfo).To(HaveKey(testRepos[0]))
Expect(authInfo).To(HaveKey(testRepos[1]))
session := podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, testRepos[0] + "/test-image-alpine",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{
"logout",
"--authfile", authFile,
testRepos[0],
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, testRepos[0] + "/test-image-alpine",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{
"logout",
"--authfile", authFile,
testRepos[1],
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
authInfo = readAuthInfo(authFile)
Expect(authInfo).NotTo(HaveKey(testRepos[0]))
Expect(authInfo).NotTo(HaveKey(testRepos[1]))
})
It("podman login with http{s} prefix", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
for _, invalidArg := range []string{
"https://" + server + "/podmantest",
"http://" + server + "/podmantest/image:latest",
} {
session := podmanTest.Podman([]string{
"login",
"-u", "podmantest",
"-p", "test",
"--authfile", authFile,
invalidArg,
})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
}
})
It("podman login and logout with repository push with invalid auth.json credentials", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
// only `server` contains the correct login data
err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
}}`, server, server)), 0644)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, server + "/podmantest/test-image",
})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
session = podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, server + "/test-image",
})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
})
It("podman login and logout with repository pull with wrong auth.json credentials", func() {
authFile := filepath.Join(podmanTest.TempDir, "auth.json")
testTarget := server + "/podmantest/test-alpine"
session := podmanTest.Podman([]string{
"login",
"-u", "podmantest",
"-p", "test",
"--authfile", authFile,
testTarget,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
session = podmanTest.Podman([]string{
"push",
"--authfile", authFile,
ALPINE, testTarget,
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
// only `server + /podmantest` and `server` have the correct login data
err := ioutil.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": {
"%s/podmantest/test-alpine": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" },
"%s/podmantest": { "auth": "cG9kbWFudGVzdDp0ZXN0" },
"%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" }
}}`, server, server, server)), 0644)
Expect(err).To(BeNil())
session = podmanTest.Podman([]string{
"pull",
"--authfile", authFile,
server + "/podmantest/test-alpine",
})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
})