From dc80267b594e41cf7e223821dc1446683f0cae36 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 13 May 2020 13:44:29 +0200 Subject: compat handlers: add X-Registry-Auth header support * Support the `X-Registry-Auth` http-request header. * The content of the header is a base64 encoded JSON payload which can either be a single auth config or a map of auth configs (user+pw or token) with the corresponding registries being the keys. Vanilla Docker, projectatomic Docker and the bindings are transparantly supported. * Add a hidden `--registries-conf` flag. Buildah exposes the same flag, mostly for testing purposes. * Do all credential parsing in the client (i.e., `cmd/podman`) pass the username and password in the backend instead of unparsed credentials. * Add a `pkg/auth` which handles most of the heavy lifting. * Go through the authentication-handling code of most commands, bindings and endpoints. Migrate them to the new code and fix issues as seen. A final evaluation and more tests is still required *after* this change. * The manifest-push endpoint is missing certain parameters and should use the ABI function instead. Adding auth-support isn't really possible without these parts working. * The container commands and endpoints (i.e., create and run) have not been changed yet. The APIs don't yet account for the authfile. * Add authentication tests to `pkg/bindings`. Fixes: #6384 Signed-off-by: Valentin Rothberg --- pkg/bindings/connection.go | 7 +- pkg/bindings/containers/checkpoint.go | 4 +- pkg/bindings/containers/commit.go | 2 +- pkg/bindings/containers/containers.go | 34 ++++---- pkg/bindings/containers/create.go | 2 +- pkg/bindings/containers/diff.go | 2 +- pkg/bindings/containers/exec.go | 4 +- pkg/bindings/containers/healthcheck.go | 2 +- pkg/bindings/containers/logs.go | 2 +- pkg/bindings/containers/mount.go | 6 +- pkg/bindings/generate/generate.go | 2 +- pkg/bindings/images/diff.go | 2 +- pkg/bindings/images/images.go | 58 ++++++++----- pkg/bindings/images/rm.go | 4 +- pkg/bindings/manifests/manifests.go | 10 +-- pkg/bindings/network/network.go | 8 +- pkg/bindings/play/play.go | 9 ++- pkg/bindings/pods/pods.go | 28 +++---- pkg/bindings/system/info.go | 2 +- pkg/bindings/system/system.go | 8 +- pkg/bindings/test/auth_test.go | 143 +++++++++++++++++++++++++++++++++ pkg/bindings/volumes/volumes.go | 10 +-- 22 files changed, 262 insertions(+), 87 deletions(-) create mode 100644 pkg/bindings/test/auth_test.go (limited to 'pkg/bindings') diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index d30698c1d..e9032f083 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -150,7 +150,7 @@ func pingNewConnection(ctx context.Context) error { return err } // the ping endpoint sits at / in this case - response, err := client.DoRequest(nil, http.MethodGet, "../../../_ping", nil) + response, err := client.DoRequest(nil, http.MethodGet, "../../../_ping", nil, nil) if err != nil { return err } @@ -250,7 +250,7 @@ func unixClient(_url *url.URL) (Connection, error) { } // DoRequest assembles the http request and returns the response -func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string, queryParams url.Values, pathValues ...string) (*APIResponse, error) { +func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string, queryParams url.Values, header map[string]string, pathValues ...string) (*APIResponse, error) { var ( err error response *http.Response @@ -271,6 +271,9 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string, if len(queryParams) > 0 { req.URL.RawQuery = queryParams.Encode() } + for key, val := range header { + req.Header.Set(key, val) + } req = req.WithContext(context.WithValue(context.Background(), clientKey, c)) // Give the Do three chances in the case of a comm/service hiccup for i := 0; i < 3; i++ { diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go index 84924587b..f483a9297 100644 --- a/pkg/bindings/containers/checkpoint.go +++ b/pkg/bindings/containers/checkpoint.go @@ -34,7 +34,7 @@ func Checkpoint(ctx context.Context, nameOrId string, keep, leaveRunning, tcpEst if export != nil { params.Set("export", *export) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nameOrId) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrId) if err != nil { return nil, err } @@ -71,7 +71,7 @@ func Restore(ctx context.Context, nameOrId string, keep, tcpEstablished, ignoreR if importArchive != nil { params.Set("import", *importArchive) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nameOrId) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrId) if err != nil { return nil, err } diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go index 12c25f842..780d42272 100644 --- a/pkg/bindings/containers/commit.go +++ b/pkg/bindings/containers/commit.go @@ -41,7 +41,7 @@ func Commit(ctx context.Context, nameOrId string, options CommitOptions) (handle if options.Tag != nil { params.Set("tag", *options.Tag) } - response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params) + response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params, nil) if err != nil { return id, err } diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 81e213d2b..516f3d282 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -61,7 +61,7 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int } params.Set("filters", filterString) } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params, nil) if err != nil { return containers, err } @@ -86,7 +86,7 @@ func Prune(ctx context.Context, filters map[string][]string) (*entities.Containe } params.Set("filters", filterString) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params, nil) if err != nil { return nil, err } @@ -108,7 +108,7 @@ func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error { if volumes != nil { params.Set("vols", strconv.FormatBool(*volumes)) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID) if err != nil { return err } @@ -128,7 +128,7 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectC if size != nil { params.Set("size", strconv.FormatBool(*size)) } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nil, nameOrID) if err != nil { return nil, err } @@ -146,7 +146,7 @@ func Kill(ctx context.Context, nameOrID string, sig string) error { } params := url.Values{} params.Set("signal", sig) - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID) if err != nil { return err } @@ -161,7 +161,7 @@ func Pause(ctx context.Context, nameOrID string) error { if err != nil { return err } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/pause", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/pause", nil, nil, nameOrID) if err != nil { return err } @@ -180,7 +180,7 @@ func Restart(ctx context.Context, nameOrID string, timeout *int) error { if timeout != nil { params.Set("t", strconv.Itoa(*timeout)) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID) if err != nil { return err } @@ -199,7 +199,7 @@ func Start(ctx context.Context, nameOrID string, detachKeys *string) error { if detachKeys != nil { params.Set("detachKeys", *detachKeys) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nil, nameOrID) if err != nil { return err } @@ -221,7 +221,7 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, // flatten the slice into one string params.Set("ps_args", strings.Join(descriptors, ",")) } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nil, nameOrID) if err != nil { return nil, err } @@ -249,7 +249,7 @@ func Unpause(ctx context.Context, nameOrID string) error { if err != nil { return err } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unpause", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unpause", nil, nil, nameOrID) if err != nil { return err } @@ -269,7 +269,7 @@ func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatu if condition != nil { params.Set("condition", condition.String()) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID) if err != nil { return exitCode, err } @@ -284,7 +284,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) { if err != nil { return false, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nil, nameOrID) if err != nil { return false, err } @@ -302,7 +302,7 @@ func Stop(ctx context.Context, nameOrID string, timeout *uint) error { if timeout != nil { params.Set("t", strconv.Itoa(int(*timeout))) } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nil, nameOrID) if err != nil { return err } @@ -317,7 +317,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer) error { if err != nil { return err } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/export", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/export", params, nil, nameOrID) if err != nil { return err } @@ -336,7 +336,7 @@ func ContainerInit(ctx context.Context, nameOrID string) error { if err != nil { return err } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/init", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/init", nil, nil, nameOrID) if err != nil { return err } @@ -443,7 +443,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre }() } - response, err := conn.DoRequest(stdin, http.MethodPost, "/containers/%s/attach", params, nameOrId) + response, err := conn.DoRequest(stdin, http.MethodPost, "/containers/%s/attach", params, nil, nameOrId) if err != nil { return err } @@ -572,7 +572,7 @@ func resizeTTY(ctx context.Context, endpoint string, height *int, width *int) er if width != nil { params.Set("w", strconv.Itoa(*width)) } - rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params) + rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params, nil) if err != nil { return err } diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go index 21355f24b..4603b8653 100644 --- a/pkg/bindings/containers/create.go +++ b/pkg/bindings/containers/create.go @@ -22,7 +22,7 @@ func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator) (entities.Con return ccr, err } stringReader := strings.NewReader(specgenString) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/containers/create", nil) + response, err := conn.DoRequest(stringReader, http.MethodPost, "/containers/create", nil, nil) if err != nil { return ccr, err } diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go index 82070ca9a..06a828c30 100644 --- a/pkg/bindings/containers/diff.go +++ b/pkg/bindings/containers/diff.go @@ -15,7 +15,7 @@ func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nameOrId) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nil, nameOrId) if err != nil { return nil, err } diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go index 48f9ed697..2aeeae1f8 100644 --- a/pkg/bindings/containers/exec.go +++ b/pkg/bindings/containers/exec.go @@ -34,7 +34,7 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat } jsonReader := strings.NewReader(string(requestJSON)) - resp, err := conn.DoRequest(jsonReader, http.MethodPost, "/containers/%s/exec", nil, nameOrID) + resp, err := conn.DoRequest(jsonReader, http.MethodPost, "/containers/%s/exec", nil, nil, nameOrID) if err != nil { return "", err } @@ -57,7 +57,7 @@ func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSess logrus.Debugf("Inspecting session ID %q", sessionID) - resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, sessionID) + resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, nil, sessionID) if err != nil { return nil, err } diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go index 2b783ac73..b726acf49 100644 --- a/pkg/bindings/containers/healthcheck.go +++ b/pkg/bindings/containers/healthcheck.go @@ -18,7 +18,7 @@ func RunHealthCheck(ctx context.Context, nameOrID string) (*define.HealthCheckRe var ( status define.HealthCheckResults ) - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/healthcheck", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/healthcheck", nil, nil, nameOrID) if err != nil { return nil, err } diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index 7fea30003..bec4ebb3c 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -46,7 +46,7 @@ func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, std if opts.Stdout == nil && opts.Stderr == nil { params.Set("stdout", strconv.FormatBool(true)) } - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nil, nameOrID) if err != nil { return err } diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go index e0627d9a3..2d553142f 100644 --- a/pkg/bindings/containers/mount.go +++ b/pkg/bindings/containers/mount.go @@ -17,7 +17,7 @@ func Mount(ctx context.Context, nameOrID string) (string, error) { var ( path string ) - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/mount", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/mount", nil, nil, nameOrID) if err != nil { return path, err } @@ -31,7 +31,7 @@ func Unmount(ctx context.Context, nameOrID string) error { if err != nil { return err } - response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unmount", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unmount", nil, nil, nameOrID) if err != nil { return err } @@ -45,7 +45,7 @@ func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) { return nil, err } mounts := make(map[string]string) - response, err := conn.DoRequest(nil, http.MethodGet, "/containers/showmounted", nil) + response, err := conn.DoRequest(nil, http.MethodGet, "/containers/showmounted", nil, nil) if err != nil { return mounts, err } diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go index d3177133f..161b722f3 100644 --- a/pkg/bindings/generate/generate.go +++ b/pkg/bindings/generate/generate.go @@ -18,7 +18,7 @@ func GenerateKube(ctx context.Context, nameOrID string, options entities.Generat params := url.Values{} params.Set("service", strconv.FormatBool(options.Service)) - response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nil, nameOrID) if err != nil { return nil, err } diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go index cfdd06a97..e2d344ea0 100644 --- a/pkg/bindings/images/diff.go +++ b/pkg/bindings/images/diff.go @@ -15,7 +15,7 @@ func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nameOrId) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nil, nameOrId) if err != nil { return nil, err } diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index f9c02d199..e0802a6e1 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -12,6 +12,7 @@ import ( "github.com/containers/buildah" "github.com/containers/image/v5/types" "github.com/containers/libpod/pkg/api/handlers" + "github.com/containers/libpod/pkg/auth" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" "github.com/docker/go-units" @@ -26,7 +27,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) { if err != nil { return false, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/exists", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/exists", nil, nil, nameOrID) if err != nil { return false, err } @@ -52,7 +53,7 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit } params.Set("filters", strFilters) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil) if err != nil { return imageSummary, err } @@ -71,7 +72,7 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image params.Set("size", strconv.FormatBool(*size)) } inspectedData := entities.ImageInspectReport{} - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID) if err != nil { return &inspectedData, err } @@ -89,7 +90,7 @@ func Tree(ctx context.Context, nameOrId string, whatRequires *bool) (*entities.I if whatRequires != nil { params.Set("size", strconv.FormatBool(*whatRequires)) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nameOrId) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrId) if err != nil { return nil, err } @@ -103,7 +104,7 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/history", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/history", nil, nil, nameOrID) if err != nil { return history, err } @@ -120,7 +121,7 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe if name != nil { params.Set("reference", *name) } - response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params) + response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil) if err != nil { return nil, err } @@ -141,7 +142,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c if compress != nil { params.Set("compress", strconv.FormatBool(*compress)) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID) if err != nil { return err } @@ -174,7 +175,7 @@ func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]strin } params.Set("filters", stringFilter) } - response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params) + response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil) if err != nil { return deleted, err } @@ -190,7 +191,7 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error { params := url.Values{} params.Set("tag", tag) params.Set("repo", repo) - response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/tag", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/tag", params, nil, nameOrID) if err != nil { return err } @@ -206,7 +207,7 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error { params := url.Values{} params.Set("tag", tag) params.Set("repo", repo) - response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/untag", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/untag", params, nil, nameOrID) if err != nil { return err } @@ -297,7 +298,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } // TODO outputs? - response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params) + response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params, nil) if err != nil { return nil, err } @@ -341,7 +342,7 @@ func Import(ctx context.Context, changes []string, message, reference, u *string if u != nil { params.Set("url", *u) } - response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params) + response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil) if err != nil { return nil, err } @@ -359,7 +360,6 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption } params := url.Values{} params.Set("reference", rawImage) - params.Set("credentials", options.Credentials) params.Set("overrideArch", options.OverrideArch) params.Set("overrideOS", options.OverrideOS) if options.SkipTLSVerify != types.OptionalBoolUndefined { @@ -369,7 +369,13 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption } params.Set("allTags", strconv.FormatBool(options.AllTags)) - response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params) + // TODO: have a global system context we can pass around (1st argument) + header, err := auth.Header(nil, options.Authfile, options.Username, options.Password) + if err != nil { + return nil, err + } + + response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params, header) if err != nil { return nil, err } @@ -397,8 +403,14 @@ func Push(ctx context.Context, source string, destination string, options entiti if err != nil { return err } + + // TODO: have a global system context we can pass around (1st argument) + header, err := auth.Header(nil, options.Authfile, options.Username, options.Password) + if err != nil { + return err + } + params := url.Values{} - params.Set("credentials", options.Credentials) params.Set("destination", destination) if options.SkipTLSVerify != types.OptionalBoolUndefined { // Note: we have to verify if skipped is false. @@ -407,8 +419,12 @@ func Push(ctx context.Context, source string, destination string, options entiti } path := fmt.Sprintf("/images/%s/push", source) - _, err = conn.DoRequest(nil, http.MethodPost, path, params) - return err + response, err := conn.DoRequest(nil, http.MethodPost, path, params, header) + if err != nil { + return err + } + + return response.Process(err) } // Search is the binding for libpod's v2 endpoints for Search images. @@ -430,7 +446,13 @@ func Search(ctx context.Context, term string, opts entities.ImageSearchOptions) params.Set("tlsVerify", strconv.FormatBool(verifyTLS)) } - response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params) + // TODO: have a global system context we can pass around (1st argument) + header, err := auth.Header(nil, opts.Authfile, "", "") + if err != nil { + return nil, err + } + + response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params, header) if err != nil { return nil, err } diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go index 05aa3f9ca..c315bfce7 100644 --- a/pkg/bindings/images/rm.go +++ b/pkg/bindings/images/rm.go @@ -30,7 +30,7 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove params.Add("images", i) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params) + response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil) if err != nil { return nil, []error{err} } @@ -52,7 +52,7 @@ func Remove(ctx context.Context, nameOrID string, force bool) (*entities.ImageRe params := url.Values{} params.Set("force", strconv.FormatBool(force)) - response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID) if err != nil { return nil, err } diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go index f5ee31d93..e89624667 100644 --- a/pkg/bindings/manifests/manifests.go +++ b/pkg/bindings/manifests/manifests.go @@ -39,7 +39,7 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err params.Add("image", i) } - response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/create", params) + response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/create", params, nil) if err != nil { return "", err } @@ -53,7 +53,7 @@ func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/manifests/%s/json", nil, name) + response, err := conn.DoRequest(nil, http.MethodGet, "/manifests/%s/json", nil, nil, name) if err != nil { return nil, err } @@ -73,7 +73,7 @@ func Add(ctx context.Context, name string, options image.ManifestAddOpts) (strin return "", err } stringReader := strings.NewReader(optionsString) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/add", nil, name) + response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/add", nil, nil, name) if err != nil { return "", err } @@ -90,7 +90,7 @@ func Remove(ctx context.Context, name, digest string) (string, error) { } params := url.Values{} params.Set("digest", digest) - response, err := conn.DoRequest(nil, http.MethodDelete, "/manifests/%s", params, name) + response, err := conn.DoRequest(nil, http.MethodDelete, "/manifests/%s", params, nil, name) if err != nil { return "", err } @@ -118,7 +118,7 @@ func Push(ctx context.Context, name string, destination *string, all *bool) (str if all != nil { params.Set("all", strconv.FormatBool(*all)) } - _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, name) + _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name) if err != nil { return "", err } diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go index 7bba4f478..34881b524 100644 --- a/pkg/bindings/network/network.go +++ b/pkg/bindings/network/network.go @@ -28,7 +28,7 @@ func Create(ctx context.Context, options entities.NetworkCreateOptions, name *st return nil, err } stringReader := strings.NewReader(networkConfig) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/create", params) + response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/create", params, nil) if err != nil { return nil, err } @@ -42,7 +42,7 @@ func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectRep if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/networks/%s/json", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/networks/%s/json", nil, nil, nameOrID) if err != nil { return nil, err } @@ -62,7 +62,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.Netw if force != nil { params.Set("size", strconv.FormatBool(*force)) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nil, nameOrID) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func List(ctx context.Context) ([]*entities.NetworkListReport, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", nil) + response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", nil, nil) if err != nil { return netList, err } diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go index 653558a3c..288cca454 100644 --- a/pkg/bindings/play/play.go +++ b/pkg/bindings/play/play.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/containers/image/v5/types" + "github.com/containers/libpod/pkg/auth" "github.com/containers/libpod/pkg/bindings" "github.com/containers/libpod/pkg/domain/entities" ) @@ -31,7 +32,13 @@ func PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify == types.OptionalBoolTrue)) } - response, err := conn.DoRequest(f, http.MethodPost, "/play/kube", params) + // TODO: have a global system context we can pass around (1st argument) + header, err := auth.Header(nil, options.Authfile, options.Username, options.Password) + if err != nil { + return nil, err + } + + response, err := conn.DoRequest(f, http.MethodPost, "/play/kube", params, header) if err != nil { return nil, err } diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go index b213c8c73..fb273fdf3 100644 --- a/pkg/bindings/pods/pods.go +++ b/pkg/bindings/pods/pods.go @@ -28,7 +28,7 @@ func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator) (*entit return nil, err } stringReader := strings.NewReader(specgenString) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil) + response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil, nil) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) { if err != nil { return false, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/exists", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/exists", nil, nil, nameOrID) if err != nil { return false, err } @@ -57,7 +57,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport, if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/json", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/json", nil, nil, nameOrID) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKi if signal != nil { params.Set("signal", *signal) } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nil, nameOrID) if err != nil { return nil, err } @@ -92,7 +92,7 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/pause", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/pause", nil, nil, nameOrID) if err != nil { return nil, err } @@ -107,7 +107,7 @@ func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil, nil) if err != nil { return nil, err } @@ -132,7 +132,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPod } params.Set("filters", stringFilter) } - response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params, nil) if err != nil { return podsReports, err } @@ -146,7 +146,7 @@ func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport, if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/restart", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/restart", nil, nil, nameOrID) if err != nil { return nil, err } @@ -165,7 +165,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmR if force != nil { params.Set("force", strconv.FormatBool(*force)) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nil, nameOrID) if err != nil { return nil, err } @@ -179,7 +179,7 @@ func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, erro if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/start", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/start", nil, nil, nameOrID) if err != nil { return nil, err } @@ -202,7 +202,7 @@ func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStop if timeout != nil { params.Set("t", strconv.Itoa(*timeout)) } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nil, nameOrID) if err != nil { return nil, err } @@ -226,7 +226,7 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string, // flatten the slice into one string params.Set("ps_args", strings.Join(descriptors, ",")) } - response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nil, nameOrID) if err != nil { return nil, err } @@ -254,7 +254,7 @@ func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport, if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/unpause", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/unpause", nil, nil, nameOrID) if err != nil { return nil, err } @@ -277,7 +277,7 @@ func Stats(ctx context.Context, namesOrIDs []string, options entities.PodStatsOp params.Set("all", strconv.FormatBool(options.All)) var reports []*entities.PodStatsReport - response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params, nil) if err != nil { return nil, err } diff --git a/pkg/bindings/system/info.go b/pkg/bindings/system/info.go index 13e12645d..8ad704f84 100644 --- a/pkg/bindings/system/info.go +++ b/pkg/bindings/system/info.go @@ -15,7 +15,7 @@ func Info(ctx context.Context) (*define.Info, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/info", nil) + response, err := conn.DoRequest(nil, http.MethodGet, "/info", nil, nil) if err != nil { return nil, err } diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go index 2cd894228..010762bef 100644 --- a/pkg/bindings/system/system.go +++ b/pkg/bindings/system/system.go @@ -42,7 +42,7 @@ func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan } params.Set("filters", filterString) } - response, err := conn.DoRequest(nil, http.MethodGet, "/events", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/events", params, nil) if err != nil { return err } @@ -89,7 +89,7 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport if volumes != nil { params.Set("Volumes", strconv.FormatBool(*volumes)) } - response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params) + response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params, nil) if err != nil { return nil, err } @@ -110,7 +110,7 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/version", nil) + response, err := conn.DoRequest(nil, http.MethodGet, "/version", nil, nil) if err != nil { return nil, err } @@ -139,7 +139,7 @@ func DiskUsage(ctx context.Context) (*entities.SystemDfReport, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/system/df", nil) + response, err := conn.DoRequest(nil, http.MethodGet, "/system/df", nil, nil) if err != nil { return nil, err } diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go new file mode 100644 index 000000000..fdb190551 --- /dev/null +++ b/pkg/bindings/test/auth_test.go @@ -0,0 +1,143 @@ +package test_bindings + +import ( + "io/ioutil" + "os" + "time" + + "github.com/containers/common/pkg/auth" + "github.com/containers/image/v5/types" + podmanRegistry "github.com/containers/libpod/hack/podman-registry-go" + "github.com/containers/libpod/pkg/bindings/images" + "github.com/containers/libpod/pkg/domain/entities" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Podman images", func() { + var ( + registry *podmanRegistry.Registry + bt *bindingTest + s *gexec.Session + err error + ) + + BeforeEach(func() { + // Note: we need to start the registry **before** setting up + // the test. Otherwise, the registry is not reachable for + // currently unknown reasons. + registry, err = podmanRegistry.Start() + Expect(err).To(BeNil()) + + bt = newBindingTest() + bt.RestoreImagesFromCache() + s = bt.startAPIService() + time.Sleep(1 * time.Second) + err := bt.NewConnection() + Expect(err).To(BeNil()) + }) + + AfterEach(func() { + s.Kill() + bt.cleanup() + registry.Stop() + }) + + // Test using credentials. + It("tag + push + pull (with credentials)", func() { + + imageRep := "localhost:" + registry.Port + "/test" + imageTag := "latest" + imageRef := imageRep + ":" + imageTag + + // Tag the alpine image and verify it has worked. + err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep) + Expect(err).To(BeNil()) + _, err = images.GetImage(bt.conn, imageRef, nil) + Expect(err).To(BeNil()) + + // Now push the image. + pushOpts := entities.ImagePushOptions{ + Username: registry.User, + Password: registry.Password, + SkipTLSVerify: types.OptionalBoolTrue, + } + err = images.Push(bt.conn, imageRef, imageRef, pushOpts) + Expect(err).To(BeNil()) + + // Now pull the image. + pullOpts := entities.ImagePullOptions{ + Username: registry.User, + Password: registry.Password, + SkipTLSVerify: types.OptionalBoolTrue, + } + _, err = images.Pull(bt.conn, imageRef, pullOpts) + Expect(err).To(BeNil()) + }) + + // Test using authfile. + It("tag + push + pull + search (with authfile)", func() { + + imageRep := "localhost:" + registry.Port + "/test" + imageTag := "latest" + imageRef := imageRep + ":" + imageTag + + // Create a temporary authentication file. + tmpFile, err := ioutil.TempFile("", "auth.json.") + Expect(err).To(BeNil()) + _, err = tmpFile.Write([]byte{'{', '}'}) + Expect(err).To(BeNil()) + err = tmpFile.Close() + Expect(err).To(BeNil()) + + authFilePath := tmpFile.Name() + + // Now login to a) test the credentials and to b) store them in + // the authfile for later use. + sys := types.SystemContext{ + AuthFilePath: authFilePath, + DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, + } + loginOptions := auth.LoginOptions{ + Username: registry.User, + Password: registry.Password, + AuthFile: authFilePath, + Stdin: os.Stdin, + Stdout: os.Stdout, + } + err = auth.Login(bt.conn, &sys, &loginOptions, []string{imageRep}) + Expect(err).To(BeNil()) + + // Tag the alpine image and verify it has worked. + err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep) + Expect(err).To(BeNil()) + _, err = images.GetImage(bt.conn, imageRef, nil) + Expect(err).To(BeNil()) + + // Now push the image. + pushOpts := entities.ImagePushOptions{ + Authfile: authFilePath, + SkipTLSVerify: types.OptionalBoolTrue, + } + err = images.Push(bt.conn, imageRef, imageRef, pushOpts) + Expect(err).To(BeNil()) + + // Now pull the image. + pullOpts := entities.ImagePullOptions{ + Authfile: authFilePath, + SkipTLSVerify: types.OptionalBoolTrue, + } + _, err = images.Pull(bt.conn, imageRef, pullOpts) + Expect(err).To(BeNil()) + + // Last, but not least, exercise search. + searchOptions := entities.ImageSearchOptions{ + Authfile: authFilePath, + SkipTLSVerify: types.OptionalBoolTrue, + } + _, err = images.Search(bt.conn, imageRef, searchOptions) + Expect(err).To(BeNil()) + }) + +}) diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go index cef9246cb..ebe19794a 100644 --- a/pkg/bindings/volumes/volumes.go +++ b/pkg/bindings/volumes/volumes.go @@ -26,7 +26,7 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities return nil, err } stringReader := strings.NewReader(createString) - response, err := conn.DoRequest(stringReader, http.MethodPost, "/volumes/create", nil) + response, err := conn.DoRequest(stringReader, http.MethodPost, "/volumes/create", nil, nil) if err != nil { return nil, err } @@ -42,7 +42,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigRespon if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/%s/json", nil, nameOrID) + response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/%s/json", nil, nil, nameOrID) if err != nil { return &inspect, err } @@ -67,7 +67,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL } params.Set("filters", strFilters) } - response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params) + response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params, nil) if err != nil { return vols, err } @@ -83,7 +83,7 @@ func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) { if err != nil { return nil, err } - response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil) + response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil, nil) if err != nil { return nil, err } @@ -101,7 +101,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) error { if force != nil { params.Set("force", strconv.FormatBool(*force)) } - response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nameOrID) + response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nil, nameOrID) if err != nil { return err } -- cgit v1.2.3-54-g00ecf