Skip to content

Commit cabd410

Browse files
authored
Merge pull request #5362 from laurazard/27.x-backport-oauth-escape-hatch
[27.x backport] login: add oauth escape hatch
2 parents cf01923 + a58af37 commit cabd410

File tree

4 files changed

+133
-1
lines changed

4 files changed

+133
-1
lines changed

cli/command/registry/login.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"os"
8+
"strconv"
79
"strings"
810

911
"github.com/docker/cli/cli"
@@ -162,9 +164,22 @@ func loginWithStoredCredentials(ctx context.Context, dockerCli command.Cli, auth
162164
return &response, err
163165
}
164166

167+
const OauthLoginEscapeHatchEnvVar = "DOCKER_CLI_DISABLE_OAUTH_LOGIN"
168+
169+
func isOauthLoginDisabled() bool {
170+
if v := os.Getenv(OauthLoginEscapeHatchEnvVar); v != "" {
171+
enabled, err := strconv.ParseBool(v)
172+
if err != nil {
173+
return false
174+
}
175+
return enabled
176+
}
177+
return false
178+
}
179+
165180
func loginUser(ctx context.Context, dockerCli command.Cli, opts loginOptions, defaultUsername, serverAddress string) (*registrytypes.AuthenticateOKBody, error) {
166181
// If we're logging into the index server and the user didn't provide a username or password, use the device flow
167-
if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" {
182+
if serverAddress == registry.IndexServer && opts.user == "" && opts.password == "" && !isOauthLoginDisabled() {
168183
response, err := loginWithDeviceCodeFlow(ctx, dockerCli)
169184
// if the error represents a failure to initiate the device-code flow,
170185
// then we fallback to regular cli credentials login

cli/command/registry/login_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,47 @@ func TestLoginTermination(t *testing.T) {
228228
assert.ErrorIs(t, err, command.ErrPromptTerminated)
229229
}
230230
}
231+
232+
func TestIsOauthLoginDisabled(t *testing.T) {
233+
testCases := []struct {
234+
envVar string
235+
disabled bool
236+
}{
237+
{
238+
envVar: "",
239+
disabled: false,
240+
},
241+
{
242+
envVar: "bork",
243+
disabled: false,
244+
},
245+
{
246+
envVar: "0",
247+
disabled: false,
248+
},
249+
{
250+
envVar: "false",
251+
disabled: false,
252+
},
253+
{
254+
envVar: "true",
255+
disabled: true,
256+
},
257+
{
258+
envVar: "TRUE",
259+
disabled: true,
260+
},
261+
{
262+
envVar: "1",
263+
disabled: true,
264+
},
265+
}
266+
267+
for _, tc := range testCases {
268+
t.Setenv(OauthLoginEscapeHatchEnvVar, tc.envVar)
269+
270+
disabled := isOauthLoginDisabled()
271+
272+
assert.Equal(t, disabled, tc.disabled)
273+
}
274+
}

e2e/registry/login_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package registry
2+
3+
import (
4+
"io"
5+
"os/exec"
6+
"strings"
7+
"syscall"
8+
"testing"
9+
"time"
10+
11+
"github.com/creack/pty"
12+
"gotest.tools/v3/assert"
13+
)
14+
15+
func TestOauthLogin(t *testing.T) {
16+
t.Parallel()
17+
loginCmd := exec.Command("docker", "login")
18+
19+
p, err := pty.Start(loginCmd)
20+
assert.NilError(t, err)
21+
defer func() {
22+
_ = loginCmd.Wait()
23+
_ = p.Close()
24+
}()
25+
26+
time.Sleep(1 * time.Second)
27+
pid := loginCmd.Process.Pid
28+
t.Logf("terminating PID %d", pid)
29+
err = syscall.Kill(pid, syscall.SIGTERM)
30+
assert.NilError(t, err)
31+
32+
output, _ := io.ReadAll(p)
33+
assert.Check(t, strings.Contains(string(output), "USING WEB BASED LOGIN"), string(output))
34+
}
35+
36+
func TestLoginWithEscapeHatch(t *testing.T) {
37+
t.Parallel()
38+
loginCmd := exec.Command("docker", "login")
39+
loginCmd.Env = append(loginCmd.Env, "DOCKER_CLI_DISABLE_OAUTH_LOGIN=1")
40+
41+
p, err := pty.Start(loginCmd)
42+
assert.NilError(t, err)
43+
defer func() {
44+
_ = loginCmd.Wait()
45+
_ = p.Close()
46+
}()
47+
48+
time.Sleep(1 * time.Second)
49+
pid := loginCmd.Process.Pid
50+
t.Logf("terminating PID %d", pid)
51+
err = syscall.Kill(pid, syscall.SIGTERM)
52+
assert.NilError(t, err)
53+
54+
output, _ := io.ReadAll(p)
55+
assert.Check(t, strings.Contains(string(output), "Username:"), string(output))
56+
}

e2e/registry/main_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package registry
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/docker/cli/internal/test/environment"
9+
)
10+
11+
func TestMain(m *testing.M) {
12+
if err := environment.Setup(); err != nil {
13+
fmt.Println(err.Error())
14+
os.Exit(3)
15+
}
16+
os.Exit(m.Run())
17+
}

0 commit comments

Comments
 (0)