Skip to content

Commit

Permalink
feat: Add flag --sso-launch-browser to login and relogin comman…
Browse files Browse the repository at this point in the history
…ds (issue #16208) (#18865)

* Add flag `--sso-launch-browser` to `login` and `relogin` commands

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Run `make codegen`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Add `ssoBrowserFlow()` and refactor `oauth2Login()`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Update references to "default browser" to "system default browser"

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Add test case for `ssoBrowserFlow()` with `ssoLaunchBrowser` as `false`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Run `make codegen`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Update `Test_ssoBrowserFlow_ssoLaunchBrowser_false()`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Fix typo in unit test

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Fix linting issues

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

* Rename `ssoBrowserFlow()` to `ssoAuthFlow()`

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>

---------

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>
Co-authored-by: pasha-codefresh <pavel@codefresh.io>
  • Loading branch information
david-wu-octopus and pasha-codefresh authored Jul 3, 2024
1 parent b96be4c commit 18ccd7a
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 24 deletions.
32 changes: 21 additions & 11 deletions cmd/argocd/commands/#.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ import (
// NewLoginCommand returns a new instance of `argocd login` command
func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
ctxName string
username string
password string
sso bool
ssoPort int
skipTestTLS bool
ctxName string
username string
password string
sso bool
ssoPort int
skipTestTLS bool
ssoLaunchBrowser bool
)
command := &cobra.Command{
Use: "login SERVER",
Expand Down Expand Up @@ -135,7 +136,7 @@ argocd login cd.argoproj.io --core`,
errors.CheckError(err)
oauth2conf, provider, err := acdClient.OIDCConfig(ctx, acdSet)
errors.CheckError(err)
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider)
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider, ssoLaunchBrowser)
}
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
claims := jwt.MapClaims{}
Expand Down Expand Up @@ -184,6 +185,7 @@ argocd login cd.argoproj.io --core`,
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application")
command.Flags().
BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)")
command.Flags().BoolVar(&ssoLaunchBrowser, "sso-launch-browser", true, "Automatically launch the system default browser when performing SSO login")
return command
}

Expand All @@ -205,6 +207,7 @@ func oauth2Login(
oidcSettings *settingspkg.OIDCConfig,
oauth2conf *oauth2.Config,
provider *oidc.Provider,
ssoLaunchBrowser bool,
) (string, string) {
oauth2conf.RedirectURL = fmt.Sprintf("http://localhost:%d/auth/callback", port)
oidcConf, err := oidcutil.ParseConfig(provider)
Expand Down Expand Up @@ -304,8 +307,6 @@ func oauth2Login(
http.HandleFunc("/auth/callback", callbackHandler)

// Redirect user to login & consent page to ask for permission for the scopes specified above.
fmt.Printf("Opening browser for authentication\n")

var url string
var oidcconfig oidcconfig.OIDCConfig
grantType := oidcutil.InferGrantType(oidcConf)
Expand All @@ -330,8 +331,7 @@ func oauth2Login(
}
fmt.Printf("Performing %s flow login: %s\n", grantType, url)
time.Sleep(1 * time.Second)
err = open.Start(url)
errors.CheckError(err)
ssoAuthFlow(url, ssoLaunchBrowser)
go func() {
log.Debugf("Listen: %s", srv.Addr)
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
Expand Down Expand Up @@ -363,3 +363,13 @@ func passwordLogin(ctx context.Context, acdClient argocdclient.Client, username,
errors.CheckError(err)
return createdSession.Token
}

func ssoAuthFlow(url string, ssoLaunchBrowser bool) {
if ssoLaunchBrowser {
fmt.Printf("Opening system default browser for authentication\n")
err := open.Start(url)
errors.CheckError(err)
} else {
fmt.Printf("To authenticate, copy-and-paste the following URL into your preferred browser: %s\n", url)
}
}
35 changes: 35 additions & 0 deletions cmd/argocd/commands/#_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
package commands

import (
"io"
"os"
"testing"

utils "github.com/argoproj/argo-cd/v2/util/io"

"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/assert"
)

func captureStdout(callback func()) (string, error) {
oldStdout := os.Stdout
oldStderr := os.Stderr
r, w, err := os.Pipe()
if err != nil {
return "", err
}
os.Stdout = w
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
}()

callback()
utils.Close(w)

data, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(data), err
}

func Test_userDisplayName_email(t *testing.T) {
claims := jwt.MapClaims{"iss": "qux", "sub": "foo", "email": "firstname.lastname@example.com", "groups": []string{"baz"}}
actualName := userDisplayName(claims)
Expand All @@ -27,3 +54,11 @@ func Test_userDisplayName_sub(t *testing.T) {
expectedName := "foo"
assert.Equal(t, expectedName, actualName)
}

func Test_ssoAuthFlow_ssoLaunchBrowser_false(t *testing.T) {
out, _ := captureStdout(func() {
ssoAuthFlow("http://test-sso-browser-flow.com", false)
})

assert.Contains(t, out, "To authenticate, copy-and-paste the following URL into your preferred browser: http://test-sso-browser-flow.com")
}
8 changes: 5 additions & 3 deletions cmd/argocd/commands/relogin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import (
// NewReloginCommand returns a new instance of `argocd relogin` command
func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
password string
ssoPort int
password string
ssoPort int
ssoLaunchBrowser bool
)
command := &cobra.Command{
Use: "relogin",
Expand Down Expand Up @@ -72,7 +73,7 @@ func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comm
errors.CheckError(err)
oauth2conf, provider, err := acdClient.OIDCConfig(ctx, acdSet)
errors.CheckError(err)
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider)
tokenString, refreshToken = oauth2Login(ctx, ssoPort, acdSet.GetOIDCConfig(), oauth2conf, provider, ssoLaunchBrowser)
}

localCfg.UpsertUser(localconfig.User{
Expand All @@ -99,5 +100,6 @@ argocd login cd.argoproj.io --core
}
command.Flags().StringVar(&password, "password", "", "The password of an account to authenticate")
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application")
command.Flags().BoolVar(&ssoLaunchBrowser, "sso-launch-browser", true, "Automatically launch the default browser when performing SSO login")
return command
}
15 changes: 8 additions & 7 deletions docs/user-guide/commands/argocd_login.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ argocd login cd.argoproj.io --core
### Options

```
-h, --help help for login
--name string Name to use for the context
--password string The password of an account to authenticate
--skip-test-tls Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)
--sso Perform SSO login
--sso-port int Port to run local OAuth2 login application (default 8085)
--username string The username of an account to authenticate
-h, --help help for login
--name string Name to use for the context
--password string The password of an account to authenticate
--skip-test-tls Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)
--sso Perform SSO login
--sso-launch-browser Automatically launch the system default browser when performing SSO login (default true)
--sso-port int Port to run local OAuth2 login application (default 8085)
--username string The username of an account to authenticate
```

### Options inherited from parent commands
Expand Down
7 changes: 4 additions & 3 deletions docs/user-guide/commands/argocd_relogin.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ argocd login cd.argoproj.io --core
### Options

```
-h, --help help for relogin
--password string The password of an account to authenticate
--sso-port int Port to run local OAuth2 login application (default 8085)
-h, --help help for relogin
--password string The password of an account to authenticate
--sso-launch-browser Automatically launch the default browser when performing SSO login (default true)
--sso-port int Port to run local OAuth2 login application (default 8085)
```

### Options inherited from parent commands
Expand Down

0 comments on commit 18ccd7a

Please # to comment.