diff --git a/cli/command/registry/login.go b/cli/command/registry/login.go index a10a58f071..76a8f457b1 100644 --- a/cli/command/registry/login.go +++ b/cli/command/registry/login.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "io" + "os" + "strconv" "strings" "github.com/docker/cli/cli" @@ -162,9 +164,22 @@ func loginWithStoredCredentials(ctx context.Context, dockerCli command.Cli, auth return &response, err } +const OauthLoginEscapeHatchEnvVar = "DOCKER_CLI_DISABLE_OAUTH_LOGIN" + +func isOauthLoginDisabled() bool { + if v := os.Getenv(OauthLoginEscapeHatchEnvVar); v != "" { + enabled, err := strconv.ParseBool(v) + if err != nil { + return false + } + return enabled + } + return false +} + func loginUser(ctx context.Context, dockerCli command.Cli, opts loginOptions, defaultUsername, serverAddress string) (*registrytypes.AuthenticateOKBody, error) { // If we're logging into the index server and the user didn't provide a username or password, use the device flow - if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" { + if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" && !isOauthLoginDisabled() { response, err := loginWithDeviceCodeFlow(ctx, dockerCli) // if the error represents a failure to initiate the device-code flow, // then we fallback to regular cli credentials login diff --git a/cli/command/registry/login_test.go b/cli/command/registry/login_test.go index 4c3003cf4b..87d1fd92fc 100644 --- a/cli/command/registry/login_test.go +++ b/cli/command/registry/login_test.go @@ -228,3 +228,47 @@ func TestLoginTermination(t *testing.T) { assert.ErrorIs(t, err, command.ErrPromptTerminated) } } + +func TestIsOauthLoginDisabled(t *testing.T) { + testCases := []struct { + envVar string + disabled bool + }{ + { + envVar: "", + disabled: false, + }, + { + envVar: "bork", + disabled: false, + }, + { + envVar: "0", + disabled: false, + }, + { + envVar: "false", + disabled: false, + }, + { + envVar: "true", + disabled: true, + }, + { + envVar: "TRUE", + disabled: true, + }, + { + envVar: "1", + disabled: true, + }, + } + + for _, tc := range testCases { + t.Setenv(OauthLoginEscapeHatchEnvVar, tc.envVar) + + disabled := isOauthLoginDisabled() + + assert.Equal(t, disabled, tc.disabled) + } +}