Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v23.2.x] rpk: add no-browser to cloud login #14944

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/go/rpk/pkg/cli/cloud/byoc/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ func loginAndEnsurePluginVersion(ctx context.Context, fs afero.Fs, cfg *config.C
if overrides.CloudToken != "" {
token = overrides.CloudToken
} else {
token, err = oauth.LoadFlow(ctx, fs, cfg, auth0.NewClient(overrides))
token, err = oauth.LoadFlow(ctx, fs, cfg, auth0.NewClient(overrides), false)
if err != nil {
return "", "", false, fmt.Errorf("unable to load the cloud token: %w", err)
return "", "", false, fmt.Errorf("unable to load the cloud token: %w. You may need to logout with 'rpk cloud logout --clear-credentials' and try again", err)
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/go/rpk/pkg/cli/cloud/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
)

func newLoginCommand(fs afero.Fs, p *config.Params) *cobra.Command {
var save, noProfile bool
var save, noProfile, noBrowser bool
cmd := &cobra.Command{
Use: "login",
Short: "Log in to the Redpanda cloud",
Expand All @@ -49,6 +49,8 @@ This will automatically launch your default web browser and prompt you to
authenticate via our Redpanda Cloud page. Once you have successfully
authenticated, you will be ready to use rpk cloud commands.

You may opt out of auto-opening the browser by passing the '--no-browser' flag.

CLIENT CREDENTIALS

Cloud client credentials can be used to login to Redpanda, they can be created
Expand Down Expand Up @@ -82,12 +84,14 @@ want to disable automatic profile creation and selection, use --no-profile.
if auth != nil {
cc = auth.HasClientCredentials()
}
_, err = oauth.LoadFlow(cmd.Context(), fs, cfg, auth0.NewClient(cfg.DevOverrides()))
_, err = oauth.LoadFlow(cmd.Context(), fs, cfg, auth0.NewClient(cfg.DevOverrides()), noBrowser)
if err != nil {
fmt.Printf("Unable to login to Redpanda Cloud (%v).\n", err)
if e := (*oauth.BadClientTokenError)(nil); errors.As(err, &e) && cc {
fmt.Println(`You may need to clear your client ID and secret with 'rpk cloud logout --clear-credentials',
and then re-specify the client credentials next time you log in.`)
} else {
fmt.Println(`You may need to clear your credentials with 'rpk cloud logout --clear-credentials', and login again`)
}
os.Exit(1)
}
Expand Down Expand Up @@ -116,6 +120,7 @@ and then re-specify the client credentials next time you log in.`)

p.InstallCloudFlags(cmd)
cmd.Flags().BoolVar(&noProfile, "no-profile", false, "Skip automatic profile creation and any associated prompts")
cmd.Flags().BoolVar(&noBrowser, "no-browser", false, "Opt out of auto-opening authentication URL")
cmd.Flags().BoolVar(&save, "save", false, "Save environment or flag specified client ID and client secret to the configuration file")
return cmd
}
Expand Down
6 changes: 3 additions & 3 deletions src/go/rpk/pkg/oauth/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
//
// This function is expected to be called at the start of most commands, and it
// saves the token and client ID to the passed cloud config.
func LoadFlow(ctx context.Context, fs afero.Fs, cfg *config.Config, cl Client) (token string, err error) {
func LoadFlow(ctx context.Context, fs afero.Fs, cfg *config.Config, cl Client, noUI bool) (token string, err error) {
// We want to avoid creating a root owned file. If the file exists, we
// just chmod with rpkos.ReplaceFile and keep old perms even with sudo.
// If the file does not exist, we will always be creating it to write
Expand All @@ -30,7 +30,7 @@ func LoadFlow(ctx context.Context, fs afero.Fs, cfg *config.Config, cl Client) (
if authVir.HasClientCredentials() {
resp, err = ClientCredentialFlow(ctx, cl, authVir)
} else {
resp, err = DeviceFlow(ctx, cl, authVir)
resp, err = DeviceFlow(ctx, cl, authVir, noUI)
}
if err != nil {
return "", fmt.Errorf("unable to retrieve a cloud token: %w", err)
Expand All @@ -39,7 +39,7 @@ func LoadFlow(ctx context.Context, fs afero.Fs, cfg *config.Config, cl Client) (
// We want to update the actual auth.
yAct, err := cfg.ActualRpkYamlOrEmpty()
if err != nil {
return "", err
return "", fmt.Errorf("unable to load your rpk.yaml file: %v", err)
}
authAct := yAct.Auth(yAct.CurrentCloudAuth)
if authAct == nil {
Expand Down
2 changes: 1 addition & 1 deletion src/go/rpk/pkg/oauth/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func TestLoadFlow(t *testing.T) {
}
cfg, err := p.Load(fs)
require.NoError(t, err)
gotToken, err := LoadFlow(context.Background(), fs, cfg, &m)
gotToken, err := LoadFlow(context.Background(), fs, cfg, &m, false)
if tt.expErr {
require.Error(t, err)
return
Expand Down
18 changes: 11 additions & 7 deletions src/go/rpk/pkg/oauth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func ClientCredentialFlow(ctx context.Context, cl Client, auth *config.RpkCloudA
if auth.AuthToken != "" && auth.ClientID != "" {
expired, err := ValidateToken(auth.AuthToken, cl.Audience(), auth.ClientID)
if err != nil {
return Token{}, err
return Token{}, fmt.Errorf("unable to validate your authorization token: %v", err)
}
if !expired {
return Token{AccessToken: auth.AuthToken}, nil
Expand All @@ -75,7 +75,7 @@ func ClientCredentialFlow(ctx context.Context, cl Client, auth *config.RpkCloudA

// DeviceFlow follows the OAuth 2.0 device authentication flow. First it
// validates whether the configuration already have a valid token.
func DeviceFlow(ctx context.Context, cl Client, auth *config.RpkCloudAuth) (Token, error) {
func DeviceFlow(ctx context.Context, cl Client, auth *config.RpkCloudAuth, noUI bool) (Token, error) {
// We only validate the token if we have the client ID, if one of them is
// not present we just start the login flow again.
if auth.AuthToken != "" && auth.ClientID != "" {
Expand All @@ -95,12 +95,16 @@ func DeviceFlow(ctx context.Context, cl Client, auth *config.RpkCloudAuth) (Toke
if !isURL(dcode.VerificationURLComplete) {
return Token{}, fmt.Errorf("authorization server returned an invalid URL: %s; please contact Redpanda support", dcode.VerificationURLComplete)
}
err = cl.URLOpener(dcode.VerificationURLComplete)
if err != nil {
return Token{}, fmt.Errorf("unable to open the web browser: %v", err)
}

fmt.Printf("Opening your browser for authentication, if does not open automatically, please open %q and proceed to login.\n", dcode.VerificationURLComplete)
if noUI {
fmt.Printf("For authentication, go to %q and log in.\n", dcode.VerificationURLComplete)
} else {
fmt.Printf("Opening your browser for authentication, if does not open automatically, please open %q and proceed to login.\n", dcode.VerificationURLComplete)
err = cl.URLOpener(dcode.VerificationURLComplete)
if err != nil {
return Token{}, fmt.Errorf("unable to open the web browser: %v; you may login using 'rpk cloud login --no-browser'", err)
}
}

token, err := waitForDeviceToken(ctx, cl, dcode)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion src/go/rpk/pkg/oauth/oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func TestDeviceFlow(t *testing.T) {
mockDeviceToken: tt.mDevToken,
mockDevice: tt.mDevice,
}
got, err := DeviceFlow(context.Background(), &cl, tt.auth)
got, err := DeviceFlow(context.Background(), &cl, tt.auth, false)
if tt.expErr {
require.Error(t, err)
return
Expand Down
Loading