From 89ecd5a4c03dec5c598c6ad51d48c8f70ed265b4 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 4 Oct 2021 10:36:44 +0530 Subject: [PATCH] Introduce --username and --password to pass credentials --- cmd/skopeo/utils.go | 22 +++++++++++++++++ cmd/skopeo/utils_test.go | 48 ++++++++++++++++++++++++++++++++++++++ completions/bash/skopeo | 16 +++++++++++++ docs/skopeo-copy.1.md | 16 +++++++++++++ docs/skopeo-delete.1.md | 8 +++++++ docs/skopeo-inspect.1.md | 8 +++++++ docs/skopeo-list-tags.1.md | 8 +++++++ docs/skopeo-sync.1.md | 16 +++++++++++++ 8 files changed, 142 insertions(+) diff --git a/cmd/skopeo/utils.go b/cmd/skopeo/utils.go index 21d3e9b24b..c4d2f70228 100644 --- a/cmd/skopeo/utils.go +++ b/cmd/skopeo/utils.go @@ -91,6 +91,8 @@ type dockerImageOptions struct { deprecatedTLSVerify *deprecatedTLSVerifyOption // May be shared across several imageOptions instances, or nil. authFilePath optionalString // Path to a */containers/auth.json (prefixed version to override shared image option). credsOption optionalString // username[:password] for accessing a registry + userName optionalString // username for accessing a registry + password optionalString // password for accessing a registry registryToken optionalString // token to be used directly as a Bearer token when accessing the registry dockerCertPath string // A directory using Docker-like *.{crt,cert,key} files for connecting to a registry or a daemon tlsVerify optionalBool // Require HTTPS and verify certificates (for docker: and docker-daemon:) @@ -122,6 +124,8 @@ func dockerImageFlags(global *globalOptions, shared *sharedImageOptions, depreca fs.Var(newOptionalStringValue(&flags.authFilePath), flagPrefix+"authfile", "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json") } fs.Var(newOptionalStringValue(&flags.credsOption), flagPrefix+"creds", "Use `USERNAME[:PASSWORD]` for accessing the registry") + fs.Var(newOptionalStringValue(&flags.userName), flagPrefix+"username", "Username for accessing the registry") + fs.Var(newOptionalStringValue(&flags.password), flagPrefix+"password", "Password for accessing the registry") if credsOptionAlias != "" { // This is horribly ugly, but we need to support the old option forms of (skopeo copy) for compatibility. // Don't add any more cases like this. @@ -180,12 +184,30 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) { if opts.credsOption.present && opts.noCreds { return nil, errors.New("creds and no-creds cannot be specified at the same time") } + if opts.userName.present && opts.noCreds { + return nil, errors.New("username and no-creds cannot be specified at the same time") + } + if opts.credsOption.present && opts.userName.present { + return nil, errors.New("creds and username cannot be specified at the same time") + } + // if any of username or password is present, then both are expected to be present + if opts.userName.present != opts.password.present { + if opts.userName.present { + return nil, errors.New("password must be specified when username is specified") + } + return nil, errors.New("username must be specified when password is specified") + } if opts.credsOption.present { var err error ctx.DockerAuthConfig, err = getDockerAuth(opts.credsOption.value) if err != nil { return nil, err } + } else if opts.userName.present { + ctx.DockerAuthConfig = &types.DockerAuthConfig{ + Username: opts.userName.value, + Password: opts.password.value, + } } if opts.registryToken.present { ctx.DockerBearerRegistryToken = opts.registryToken.value diff --git a/cmd/skopeo/utils_test.go b/cmd/skopeo/utils_test.go index a6076b94c3..6c5fada35f 100644 --- a/cmd/skopeo/utils_test.go +++ b/cmd/skopeo/utils_test.go @@ -197,6 +197,54 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) { assert.Error(t, err) } +// TestImageOptionsUsernamePassword verifies that using the username and password +// options works as expected +func TestImageOptionsUsernamePassword(t *testing.T) { + for _, command := range []struct { + commandArgs []string + expectedAuthConfig *types.DockerAuthConfig // data to expect, or nil if an error is expected + }{ + // Set only username/password (without --creds), expected to pass + { + commandArgs: []string{"--dest-username", "foo", "--dest-password", "bar"}, + expectedAuthConfig: &types.DockerAuthConfig{Username: "foo", Password: "bar"}, + }, + // no username but set password, expect error + { + commandArgs: []string{"--dest-password", "foo"}, + expectedAuthConfig: nil, + }, + // set username but no password. expected to fail (we currently don't allow a user without password) + { + commandArgs: []string{"--dest-username", "bar"}, + expectedAuthConfig: nil, + }, + // set username with --creds, expected to fail + { + commandArgs: []string{"--dest-username", "bar", "--dest-creds", "hello:world", "--dest-password", "foo"}, + expectedAuthConfig: nil, + }, + // set username with --no-creds, expected to fail + { + commandArgs: []string{"--dest-username", "bar", "--dest-no-creds", "--dest-password", "foo"}, + expectedAuthConfig: nil, + }, + } { + opts := fakeImageDestOptions(t, "dest-", true, []string{}, command.commandArgs) + // parse the command options + res, err := opts.newSystemContext() + if command.expectedAuthConfig == nil { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, &types.SystemContext{ + DockerRegistryUserAgent: defaultUserAgent, + DockerAuthConfig: command.expectedAuthConfig, + }, res) + } + } +} + func TestTLSVerifyFlags(t *testing.T) { type systemContextOpts interface { // Either *imageOptions or *imageDestOptions newSystemContext() (*types.SystemContext, error) diff --git a/completions/bash/skopeo b/completions/bash/skopeo index 70681e1ccf..f5a28918ee 100644 --- a/completions/bash/skopeo +++ b/completions/bash/skopeo @@ -51,6 +51,10 @@ _skopeo_copy() { --dest-daemon-host --src-registry-token --dest-registry-token + --src-username + --src-password + --dest-username + --dest-password " local boolean_options=" @@ -87,6 +91,10 @@ _skopeo_sync() { --src-cert-dir --src-creds --src-registry-token + --src-username + --src-password + --dest-username + --dest-password " local boolean_options=" @@ -116,6 +124,8 @@ _skopeo_inspect() { --format --retry-times --registry-token + --username + --password " local boolean_options=" --config @@ -163,6 +173,8 @@ _skopeo_delete() { --creds --cert-dir --registry-token + --username + --password " local boolean_options=" --tls-verify @@ -183,6 +195,8 @@ _skopeo_layers() { --creds --cert-dir --registry-token + --username + --password " local boolean_options=" --tls-verify @@ -197,6 +211,8 @@ _skopeo_list_repository_tags() { --creds --cert-dir --registry-token + --username + --password " local boolean_options=" diff --git a/docs/skopeo-copy.1.md b/docs/skopeo-copy.1.md index c7f62946d7..807a6c6c4c 100644 --- a/docs/skopeo-copy.1.md +++ b/docs/skopeo-copy.1.md @@ -164,6 +164,22 @@ Bearer token for accessing the destination registry. The number of times to retry. Retry wait time will be exponentially increased based on the number of failed attempts. +**--src-username** + +The username to access the source registry. + +**--src-password** + +The password to access the source registry. + +**--dest-username** + +The username to access the destination registry. + +**--dest-password** + +The password to access the destination registry. + ## EXAMPLES To just copy an image from one registry to another: diff --git a/docs/skopeo-delete.1.md b/docs/skopeo-delete.1.md index 71d7a5d3f8..eca121dd34 100644 --- a/docs/skopeo-delete.1.md +++ b/docs/skopeo-delete.1.md @@ -64,6 +64,14 @@ Directory to use to share blobs across OCI repositories. Require HTTPS and verify certificates when talking to the container registry or daemon. Default to registry.conf setting. +**--username** + +The username to access the registry. + +**--password** + +The password to access the registry. + ## EXAMPLES Mark image example/pause for deletion from the registry.example.com registry: diff --git a/docs/skopeo-inspect.1.md b/docs/skopeo-inspect.1.md index 0ceb117b17..bfd84653e5 100644 --- a/docs/skopeo-inspect.1.md +++ b/docs/skopeo-inspect.1.md @@ -69,6 +69,14 @@ Directory to use to share blobs across OCI repositories. Require HTTPS and verify certificates when talking to the container registry or daemon. Default to registry.conf setting. +**--username** + +The username to access the registry. + +**--password** + +The password to access the registry. + ## EXAMPLES To review information for the image fedora from the docker.io registry: diff --git a/docs/skopeo-list-tags.1.md b/docs/skopeo-list-tags.1.md index 83499aaf60..db189ce56a 100644 --- a/docs/skopeo-list-tags.1.md +++ b/docs/skopeo-list-tags.1.md @@ -43,6 +43,14 @@ The number of times to retry. Retry wait time will be exponentially increased ba Require HTTPS and verify certificates when talking to the container registry or daemon. Default to registry.conf setting. +**--username** + +The username to access the registry. + +**--password** + +The password to access the registry. + ## REPOSITORY NAMES Repository names are transport-specific references as each transport may have its own concept of a "repository" and "tags". Currently, only the Docker transport is supported. diff --git a/docs/skopeo-sync.1.md b/docs/skopeo-sync.1.md index 720097cc1f..83e348ac1c 100644 --- a/docs/skopeo-sync.1.md +++ b/docs/skopeo-sync.1.md @@ -91,6 +91,22 @@ Print usage statement. **--keep-going** If any errors occur during copying of images, those errors are logged and the process continues syncing rest of the images and finally fails at the end. +**--src-username** + +The username to access the source registry. + +**--src-password** + +The password to access the source registry. + +**--dest-username** + +The username to access the destination registry. + +**--dest-password** + +The password to access the destination registry. + ## EXAMPLES ### Synchronizing to a local directory