From 69f81573e1e3117a755c46a945bf83c68cdda9e5 Mon Sep 17 00:00:00 2001 From: Laura Brehm Date: Tue, 13 Aug 2024 13:54:16 +0100 Subject: [PATCH] fallback to regular login if oauth login fails to start Signed-off-by: Laura Brehm --- cli/command/registry/login.go | 12 +++++++++--- cli/internal/oauth/manager/manager.go | 9 +++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cli/command/registry/login.go b/cli/command/registry/login.go index 1a6c28bfaf20..0ef71350649d 100644 --- a/cli/command/registry/login.go +++ b/cli/command/registry/login.go @@ -143,10 +143,16 @@ func loginWithStoredCredentials(ctx context.Context, dockerCli command.Cli, auth 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 == "" { - return loginWithDeviceCodeFlow(ctx, dockerCli) - } else { - return loginWithUsernameAndPassword(ctx, dockerCli, opts, defaultUsername, serverAddress) + 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 + if !errors.Is(err, manager.ErrDeviceLoginStartFail) { + return response, err + } + fmt.Fprint(dockerCli.Err(), "Failed to start web-based login - falling back to command line login...\n\n") } + + return loginWithUsernameAndPassword(ctx, dockerCli, opts, defaultUsername, serverAddress) } func loginWithUsernameAndPassword(ctx context.Context, dockerCli command.Cli, opts loginOptions, defaultUsername, serverAddress string) (*registrytypes.AuthenticateOKBody, error) { diff --git a/cli/internal/oauth/manager/manager.go b/cli/internal/oauth/manager/manager.go index 9f5bf9260195..8b8f3b058666 100644 --- a/cli/internal/oauth/manager/manager.go +++ b/cli/internal/oauth/manager/manager.go @@ -15,6 +15,7 @@ import ( "github.com/docker/cli/cli/internal/oauth/api" "github.com/docker/docker/registry" "github.com/morikuni/aec" + "github.com/sirupsen/logrus" "github.com/pkg/browser" ) @@ -66,6 +67,8 @@ func New(options OAuthManagerOptions) *OAuthManager { } } +var ErrDeviceLoginStartFail = errors.New("failed to start device code flow login") + // LoginDevice launches the device authentication flow with the tenant, // printing instructions to the provided writer and attempting to open the // browser for the user to authenticate. @@ -76,11 +79,13 @@ func New(options OAuthManagerOptions) *OAuthManager { func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.AuthConfig, error) { state, err := m.api.GetDeviceCode(ctx, m.audience) if err != nil { - return nil, fmt.Errorf("failed to get device code: %w", err) + logrus.Debugf("failed to start device code login: %v", err) + return nil, ErrDeviceLoginStartFail } if state.UserCode == "" { - return nil, errors.New("no user code returned") + logrus.Debugf("failed to start device code login: missing user code") + return nil, ErrDeviceLoginStartFail } _, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB BASED LOGIN"))