Merge pull request #5361 from laurazard/add-oauth-login-escape-hatch

login: add oauth escape hatch
This commit is contained in:
Laura Brehm 2024-08-20 12:31:07 +01:00 committed by GitHub
commit 986b077a53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 133 additions and 1 deletions

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"os"
"strconv"
"strings" "strings"
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
@ -141,9 +143,22 @@ func loginWithStoredCredentials(ctx context.Context, dockerCli command.Cli, auth
return &response, err 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) { 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 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) response, err := loginWithDeviceCodeFlow(ctx, dockerCli)
// if the error represents a failure to initiate the device-code flow, // if the error represents a failure to initiate the device-code flow,
// then we fallback to regular cli credentials login // then we fallback to regular cli credentials login

View File

@ -228,3 +228,47 @@ func TestLoginTermination(t *testing.T) {
assert.ErrorIs(t, err, command.ErrPromptTerminated) 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)
}
}

View File

@ -0,0 +1,56 @@
package registry
import (
"io"
"os/exec"
"strings"
"syscall"
"testing"
"time"
"github.com/creack/pty"
"gotest.tools/v3/assert"
)
func TestOauthLogin(t *testing.T) {
t.Parallel()
loginCmd := exec.Command("docker", "login")
p, err := pty.Start(loginCmd)
assert.NilError(t, err)
defer func() {
_ = loginCmd.Wait()
_ = p.Close()
}()
time.Sleep(1 * time.Second)
pid := loginCmd.Process.Pid
t.Logf("terminating PID %d", pid)
err = syscall.Kill(pid, syscall.SIGTERM)
assert.NilError(t, err)
output, _ := io.ReadAll(p)
assert.Check(t, strings.Contains(string(output), "USING WEB BASED LOGIN"), string(output))
}
func TestLoginWithEscapeHatch(t *testing.T) {
t.Parallel()
loginCmd := exec.Command("docker", "login")
loginCmd.Env = append(loginCmd.Env, "DOCKER_CLI_DISABLE_OAUTH_LOGIN=1")
p, err := pty.Start(loginCmd)
assert.NilError(t, err)
defer func() {
_ = loginCmd.Wait()
_ = p.Close()
}()
time.Sleep(1 * time.Second)
pid := loginCmd.Process.Pid
t.Logf("terminating PID %d", pid)
err = syscall.Kill(pid, syscall.SIGTERM)
assert.NilError(t, err)
output, _ := io.ReadAll(p)
assert.Check(t, strings.Contains(string(output), "Username:"), string(output))
}

17
e2e/registry/main_test.go Normal file
View File

@ -0,0 +1,17 @@
package registry
import (
"fmt"
"os"
"testing"
"github.com/docker/cli/internal/test/environment"
)
func TestMain(m *testing.M) {
if err := environment.Setup(); err != nil {
fmt.Println(err.Error())
os.Exit(3)
}
os.Exit(m.Run())
}