mirror of https://github.com/containers/podman.git
513 lines
16 KiB
Go
513 lines
16 KiB
Go
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 don’t 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())
|
||
})
|
||
})
|