Skip to content

Commit c25115e

Browse files
authored
Merge pull request #4190 from thaJeztah/command_auth_cleanups
cli/command: some cleanups / refactoring, and fixes related to auth
2 parents 400b9a6 + 5d856a5 commit c25115e

8 files changed

Lines changed: 67 additions & 78 deletions

File tree

cli/command/container/create.go

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import (
1212
"github.com/docker/cli/cli/command"
1313
"github.com/docker/cli/cli/command/completion"
1414
"github.com/docker/cli/cli/command/image"
15+
"github.com/docker/cli/cli/streams"
1516
"github.com/docker/cli/opts"
1617
"github.com/docker/distribution/reference"
1718
"github.com/docker/docker/api/types"
1819
"github.com/docker/docker/api/types/container"
1920
"github.com/docker/docker/api/types/versions"
2021
apiclient "github.com/docker/docker/client"
2122
"github.com/docker/docker/pkg/jsonmessage"
22-
"github.com/docker/docker/registry"
2323
specs "github.com/opencontainers/image-spec/specs-go/v1"
2424
"github.com/pkg/errors"
2525
"github.com/spf13/cobra"
@@ -112,41 +112,27 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, options *createOptio
112112
return nil
113113
}
114114

115-
func pullImage(ctx context.Context, dockerCli command.Cli, image string, platform string, out io.Writer) error {
116-
ref, err := reference.ParseNormalizedNamed(image)
115+
// FIXME(thaJeztah): this is the only code-path that uses APIClient.ImageCreate. Rewrite this to use the regular "pull" code (or vice-versa).
116+
func pullImage(ctx context.Context, dockerCli command.Cli, image string, opts *createOptions) error {
117+
encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, image)
117118
if err != nil {
118119
return err
119120
}
120121

121-
// Resolve the Repository name from fqn to RepositoryInfo
122-
repoInfo, err := registry.ParseRepositoryInfo(ref)
123-
if err != nil {
124-
return err
125-
}
126-
127-
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
128-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
129-
if err != nil {
130-
return err
131-
}
132-
133-
options := types.ImageCreateOptions{
122+
responseBody, err := dockerCli.Client().ImageCreate(ctx, image, types.ImageCreateOptions{
134123
RegistryAuth: encodedAuth,
135-
Platform: platform,
136-
}
137-
138-
responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options)
124+
Platform: opts.platform,
125+
})
139126
if err != nil {
140127
return err
141128
}
142129
defer responseBody.Close()
143130

144-
return jsonmessage.DisplayJSONMessagesStream(
145-
responseBody,
146-
out,
147-
dockerCli.Out().FD(),
148-
dockerCli.Out().IsTerminal(),
149-
nil)
131+
out := dockerCli.Err()
132+
if opts.quiet {
133+
out = io.Discard
134+
}
135+
return jsonmessage.DisplayJSONMessagesToStream(responseBody, streams.NewOut(out), nil)
150136
}
151137

152138
type cidFile struct {
@@ -236,11 +222,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerCfg *c
236222
}
237223

238224
pullAndTagImage := func() error {
239-
pullOut := dockerCli.Err()
240-
if opts.quiet {
241-
pullOut = io.Discard
242-
}
243-
if err := pullImage(ctx, dockerCli, config.Image, opts.platform, pullOut); err != nil {
225+
if err := pullImage(ctx, dockerCli, config.Image, opts); err != nil {
244226
return err
245227
}
246228
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {

cli/command/image/push.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/docker/cli/cli/streams"
1212
"github.com/docker/distribution/reference"
1313
"github.com/docker/docker/api/types"
14+
registrytypes "github.com/docker/docker/api/types/registry"
1415
"github.com/docker/docker/pkg/jsonmessage"
1516
"github.com/docker/docker/registry"
1617
"github.com/pkg/errors"
@@ -76,7 +77,7 @@ func RunPush(dockerCli command.Cli, opts pushOptions) error {
7677

7778
// Resolve the Auth config relevant for this server
7879
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
79-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
80+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
8081
if err != nil {
8182
return err
8283
}

cli/command/image/trust.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,20 +262,17 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
262262

263263
// imagePullPrivileged pulls the image and displays it to the output
264264
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts PullOptions) error {
265-
ref := reference.FamiliarString(imgRefAndAuth.Reference())
266-
267-
encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig())
265+
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
268266
if err != nil {
269267
return err
270268
}
271269
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
272-
options := types.ImagePullOptions{
270+
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), types.ImagePullOptions{
273271
RegistryAuth: encodedAuth,
274272
PrivilegeFunc: requestPrivilege,
275273
All: opts.all,
276274
Platform: opts.platform,
277-
}
278-
responseBody, err := cli.Client().ImagePull(ctx, ref, options)
275+
})
279276
if err != nil {
280277
return err
281278
}

cli/command/plugin/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/docker/cli/cli/command/image"
1111
"github.com/docker/distribution/reference"
1212
"github.com/docker/docker/api/types"
13+
registrytypes "github.com/docker/docker/api/types/registry"
1314
"github.com/docker/docker/pkg/jsonmessage"
1415
"github.com/docker/docker/registry"
1516
"github.com/pkg/errors"
@@ -86,8 +87,7 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
8687
}
8788

8889
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
89-
90-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
90+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
9191
if err != nil {
9292
return types.PluginInstallOptions{}, err
9393
}

cli/command/plugin/push.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/docker/cli/cli/command"
88
"github.com/docker/cli/cli/command/image"
99
"github.com/docker/distribution/reference"
10+
registrytypes "github.com/docker/docker/api/types/registry"
1011
"github.com/docker/docker/pkg/jsonmessage"
1112
"github.com/docker/docker/registry"
1213
"github.com/pkg/errors"
@@ -55,8 +56,7 @@ func runPush(dockerCli command.Cli, opts pushOptions) error {
5556
return err
5657
}
5758
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
58-
59-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
59+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
6060
if err != nil {
6161
return err
6262
}

cli/command/registry.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package command
33
import (
44
"bufio"
55
"context"
6-
"encoding/base64"
7-
"encoding/json"
86
"fmt"
97
"io"
108
"os"
@@ -21,13 +19,9 @@ import (
2119
"github.com/pkg/errors"
2220
)
2321

24-
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
22+
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload.
2523
func EncodeAuthToBase64(authConfig registrytypes.AuthConfig) (string, error) {
26-
buf, err := json.Marshal(authConfig)
27-
if err != nil {
28-
return "", err
29-
}
30-
return base64.URLEncoding.EncodeToString(buf), nil
24+
return registrytypes.EncodeAuthConfig(authConfig)
3125
}
3226

3327
// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
@@ -45,7 +39,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
4539
if err != nil {
4640
return "", err
4741
}
48-
return EncodeAuthToBase64(authConfig)
42+
return registrytypes.EncodeAuthConfig(authConfig)
4943
}
5044
}
5145

@@ -89,7 +83,14 @@ func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, is
8983

9084
// ConfigureAuth handles prompting of user's username and password if needed
9185
func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes.AuthConfig, isDefaultRegistry bool) error {
92-
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
86+
// On Windows, force the use of the regular OS stdin stream.
87+
//
88+
// See:
89+
// - https://github.com/moby/moby/issues/14336
90+
// - https://github.com/moby/moby/issues/14210
91+
// - https://github.com/moby/moby/pull/17738
92+
//
93+
// TODO(thaJeztah): we need to confirm if this special handling is still needed, as we may not be doing this in other places.
9394
if runtime.GOOS == "windows" {
9495
cli.SetIn(streams.NewIn(os.Stdin))
9596
}
@@ -113,8 +114,11 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
113114
fmt.Fprintln(cli.Out(), "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.")
114115
}
115116
promptWithDefault(cli.Out(), "Username", authconfig.Username)
116-
flUser = readInput(cli.In(), cli.Out())
117-
flUser = strings.TrimSpace(flUser)
117+
var err error
118+
flUser, err = readInput(cli.In())
119+
if err != nil {
120+
return err
121+
}
118122
if flUser == "" {
119123
flUser = authconfig.Username
120124
}
@@ -128,12 +132,15 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
128132
return err
129133
}
130134
fmt.Fprintf(cli.Out(), "Password: ")
131-
term.DisableEcho(cli.In().FD(), oldState)
132-
133-
flPassword = readInput(cli.In(), cli.Out())
135+
_ = term.DisableEcho(cli.In().FD(), oldState)
136+
defer func() {
137+
_ = term.RestoreTerminal(cli.In().FD(), oldState)
138+
}()
139+
flPassword, err = readInput(cli.In())
140+
if err != nil {
141+
return err
142+
}
134143
fmt.Fprint(cli.Out(), "\n")
135-
136-
term.RestoreTerminal(cli.In().FD(), oldState)
137144
if flPassword == "" {
138145
return errors.Errorf("Error: Password Required")
139146
}
@@ -145,14 +152,15 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
145152
return nil
146153
}
147154

148-
func readInput(in io.Reader, out io.Writer) string {
149-
reader := bufio.NewReader(in)
150-
line, _, err := reader.ReadLine()
155+
// readInput reads, and returns user input from in. It tries to return a
156+
// single line, not including the end-of-line bytes, and trims leading
157+
// and trailing whitespace.
158+
func readInput(in io.Reader) (string, error) {
159+
line, _, err := bufio.NewReader(in).ReadLine()
151160
if err != nil {
152-
fmt.Fprintln(out, err.Error())
153-
os.Exit(1)
161+
return "", errors.Wrap(err, "error while reading input")
154162
}
155-
return string(line)
163+
return strings.TrimSpace(string(line)), nil
156164
}
157165

158166
func promptWithDefault(out io.Writer, prompt string, configDefault string) {
@@ -163,14 +171,19 @@ func promptWithDefault(out io.Writer, prompt string, configDefault string) {
163171
}
164172
}
165173

166-
// RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image
174+
// RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete
175+
// image. The auth configuration is serialized as a base64url encoded RFC4648,
176+
// section 5) JSON string for sending through the X-Registry-Auth header.
177+
//
178+
// For details on base64url encoding, see:
179+
// - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
167180
func RetrieveAuthTokenFromImage(ctx context.Context, cli Cli, image string) (string, error) {
168181
// Retrieve encoded auth token from the image reference
169182
authConfig, err := resolveAuthConfigFromImage(ctx, cli, image)
170183
if err != nil {
171184
return "", err
172185
}
173-
encodedAuth, err := EncodeAuthToBase64(authConfig)
186+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
174187
if err != nil {
175188
return "", err
176189
}

cli/command/registry/search.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/cli/cli/command/formatter"
99
"github.com/docker/cli/opts"
1010
"github.com/docker/docker/api/types"
11+
registrytypes "github.com/docker/docker/api/types/registry"
1112
"github.com/docker/docker/registry"
1213
"github.com/spf13/cobra"
1314
)
@@ -54,25 +55,19 @@ func runSearch(dockerCli command.Cli, options searchOptions) error {
5455
}
5556

5657
ctx := context.Background()
57-
5858
authConfig := command.ResolveAuthConfig(ctx, dockerCli, indexInfo)
59-
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
60-
61-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
59+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
6260
if err != nil {
6361
return err
6462
}
6563

66-
searchOptions := types.ImageSearchOptions{
64+
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search")
65+
results, err := dockerCli.Client().ImageSearch(ctx, options.term, types.ImageSearchOptions{
6766
RegistryAuth: encodedAuth,
6867
PrivilegeFunc: requestPrivilege,
6968
Filters: options.filter.Value(),
7069
Limit: options.limit,
71-
}
72-
73-
clnt := dockerCli.Client()
74-
75-
results, err := clnt.ImageSearch(ctx, options.term, searchOptions)
70+
})
7671
if err != nil {
7772
return err
7873
}

cli/command/trust/sign.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/docker/cli/cli/command/image"
1414
"github.com/docker/cli/cli/trust"
1515
"github.com/docker/docker/api/types"
16+
registrytypes "github.com/docker/docker/api/types/registry"
1617
"github.com/pkg/errors"
1718
"github.com/spf13/cobra"
1819
"github.com/theupdateframework/notary/client"
@@ -93,7 +94,7 @@ func runSignImage(cli command.Cli, options signOptions) error {
9394
fmt.Fprintf(cli.Err(), "Signing and pushing trust data for local image %s, may overwrite remote trust data\n", imageName)
9495

9596
authConfig := command.ResolveAuthConfig(ctx, cli, imgRefAndAuth.RepoInfo().Index)
96-
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
97+
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
9798
if err != nil {
9899
return err
99100
}

0 commit comments

Comments
 (0)