Skip to content

Commit

Permalink
feat: Allow user to use on browser for sso flow and other for aws con…
Browse files Browse the repository at this point in the history
…sole
  • Loading branch information
AndreZiviani committed Sep 21, 2023
1 parent e6fa0f7 commit dfa01a3
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 56 deletions.
29 changes: 26 additions & 3 deletions internal/awsprofile/assumer_aws_sso.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package awsprofile

import (
"context"
"os/exec"
"time"

"github.com/AndreZiviani/aws-fuzzy/internal/afconfig"
"github.com/AndreZiviani/aws-fuzzy/internal/securestorage"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
Expand Down Expand Up @@ -142,6 +144,11 @@ func (c *Profile) SSOLogin(ctx context.Context, configOpts ConfigOpts) (aws.Cred

// SSODeviceCodeFlowFromStartUrl contains all the steps to complete a device code flow to retrieve an SSO token
func SSODeviceCodeFlowFromStartUrl(ctx context.Context, cfg aws.Config, startUrl string, profile string, printOnly bool) (*securestorage.SSOToken, error) {
afcfg, err := afconfig.NewLoadedConfig()
if err != nil {
return nil, err
}

ssooidcClient := ssooidc.NewFromConfig(cfg)

register, err := ssooidcClient.RegisterClient(ctx, &ssooidc.RegisterClientInput{
Expand Down Expand Up @@ -170,9 +177,25 @@ func SSODeviceCodeFlowFromStartUrl(ctx context.Context, cfg aws.Config, startUrl
clio.Info(url)
}

err = LaunchBrowser(url, profile, "sso", printOnly)
if err != nil {
return nil, err
if afcfg.CustomSSOBrowserPath != "" {
cmd := exec.Command(afcfg.CustomSSOBrowserPath, url)
err = cmd.Start()
if err != nil {
// fail silently
clio.Debug(err.Error())
} else {
// detach from this new process because it continues to run
err = cmd.Process.Release()
if err != nil {
// fail silently
clio.Debug(err.Error())
}
}
} else {
err = LaunchBrowser(url, profile, "sso", printOnly)
if err != nil {
return nil, err
}
}

clio.Info("Awaiting authentication in the browser...")
Expand Down
18 changes: 15 additions & 3 deletions internal/awsprofile/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func LaunchBrowser(url string, profile string, flow string, printOnly bool) erro
}

var containerName string
var l gassume.Launcher
finalUrl := url

if flow == "sso" {
if p.AWSConfig.SSOSession != nil {
containerName = p.AWSConfig.SSOSession.Name
Expand All @@ -51,27 +54,28 @@ func LaunchBrowser(url string, profile string, flow string, printOnly bool) erro
containerName = p.Name
}

var l gassume.Launcher
finalUrl := url

switch cfg.DefaultBrowser {
case gbrowser.ChromeKey:
l = glauncher.ChromeProfile{
BrowserType: gbrowser.ChromeKey,
ExecutablePath: browserPath,
UserDataPath: path.Join(configDir, "chromium-profiles", "1"), // held over for backwards compatibility, "1" indicates Chrome profiles
}
case gbrowser.BraveKey:
l = glauncher.ChromeProfile{
BrowserType: gbrowser.BraveKey,
ExecutablePath: browserPath,
UserDataPath: path.Join(configDir, "chromium-profiles", "2"), // held over for backwards compatibility, "2" indicates Brave profiles
}
case gbrowser.EdgeKey:
l = glauncher.ChromeProfile{
BrowserType: gbrowser.EdgeKey,
ExecutablePath: browserPath,
UserDataPath: path.Join(configDir, "chromium-profiles", "3"), // held over for backwards compatibility, "3" indicates Edge profiles
}
case gbrowser.ChromiumKey:
l = glauncher.ChromeProfile{
BrowserType: gbrowser.ChromiumKey,
ExecutablePath: browserPath,
UserDataPath: path.Join(configDir, "chromium-profiles", "4"), // held over for backwards compatibility, "4" indicates Chromium profiles
}
Expand Down Expand Up @@ -112,6 +116,14 @@ func LaunchBrowser(url string, profile string, flow string, printOnly bool) erro
}

finalUrl = fmt.Sprintf("ext+granted-containers:name=%s&url=%s&color=%s&icon=%s", containerName, neturl.QueryEscape(url), color, icon)
case gbrowser.SafariKey:
l = glauncher.Safari{}
case gbrowser.ArcKey:
l = glauncher.Arc{}
case gbrowser.FirefoxDevEditionKey:
l = glauncher.FirefoxDevEdition{
ExecutablePath: browserPath,
}
case gbrowser.StdoutKey:
fmt.Println(finalUrl)
return nil
Expand Down
135 changes: 87 additions & 48 deletions internal/sso/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import (
gbrowser "github.com/common-fate/granted/pkg/browser"
"github.com/common-fate/granted/pkg/testable"
opentracing "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)

func NewBrowser(browser string, verbose bool) *Browser {
func NewBrowser(browser string, ssoBrowser string, verbose bool) *Browser {
b := Browser{
Browser: browser,
Verbose: verbose,
Browser: browser,
SSOBrowser: ssoBrowser,
Verbose: verbose,
}

return &b
Expand All @@ -38,77 +38,116 @@ func (p *Browser) Execute(ctx context.Context) error {
spanSso, ctx := opentracing.StartSpanFromContextWithTracer(ctx, tracer, "ssobrowsercmd")
defer spanSso.Finish()

withStdio := survey.WithStdio(os.Stdin, os.Stderr, os.Stderr)
browser := p.Browser
ssoBrowser := p.SSOBrowser

conf, err := afconfig.NewLoadedConfig()
if err != nil {
return err
}

if browser == "" {
browser, err = gbrowser.HandleManualBrowserSelection()
if err != nil {
return err
}

err, browserKey, browserPath := p.GetBrowserSelection(withStdio, browser)
if err != nil {
return err
}

conf.DefaultBrowser = browserKey
conf.CustomBrowserPath = browserPath

err = conf.Save()
if err != nil {
return err
}

clio.Successf("aws-fuzzy will default to using %s", browserKey)
}

return p.ConfigureBrowserSelection(browser, "")
if ssoBrowser == "" {
bpIn := survey.Confirm{
Message: "Use a different browser than your default browser for SSO login?",
Default: false,
Help: "For example, if you normally use a password manager in Chrome for your AWS login but Chrome is not your default browser, you would choose to use Chrome for SSO logins.",
}
var confirm bool
err := testable.AskOne(&bpIn, &confirm, withStdio)
if err != nil {
return err
}

browserPath := ""
browserKey := ""

if confirm {
ssoBrowser, err = gbrowser.HandleManualBrowserSelection()
if err != nil {
return err
}

err, browserKey, browserPath = p.GetBrowserSelection(withStdio, ssoBrowser)
if err != nil {
return err
}

clio.Successf("aws-fuzzy will use %s for SSO login prompts.", browserKey)
}

conf.CustomSSOBrowserPath = browserPath

err = conf.Save()
if err != nil {
return err
}
}

return nil

}

func (p *Browser) ConfigureBrowserSelection(browserName string, path string) error {
func (p *Browser) GetBrowserSelection(stdio survey.AskOpt, browserName string) (error, string, string) {
var browserPath string
browserKey := gbrowser.GetBrowserKey(browserName)
withStdio := survey.WithStdio(os.Stdin, os.Stderr, os.Stderr)
title := cases.Title(language.AmericanEnglish)
browserTitle := title.String(strings.ToLower(browserKey))
// We allow users to configure a custom install path is we cannot detect the installation
browserPath := path

// detect installation
if browserKey != gbrowser.FirefoxStdoutKey && browserKey != gbrowser.StdoutKey {

if browserPath != "" {
_, err := os.Stat(browserPath)
if err != nil {
return errors.Wrap(err, "provided path is invalid")
}
} else {
customBrowserPath, detected := gbrowser.DetectInstallation(browserKey)
if !detected {
clio.Warnf("aws-fuzzy could not detect an existing installation of %s at known installation paths for your system", browserTitle)
clio.Info("If you have already installed this browser, you can specify the path to the executable manually")
validPath := false
for !validPath {
// prompt for custom path
bpIn := survey.Input{Message: fmt.Sprintf("Please enter the full path to your browser installation for %s:", browserTitle)}
clio.NewLine()
err := testable.AskOne(&bpIn, &customBrowserPath, withStdio)
if err != nil {
return err
}
if _, err := os.Stat(customBrowserPath); err == nil {
validPath = true
} else {
clio.Error("The path you entered is not valid")
}
customBrowserPath, detected := gbrowser.DetectInstallation(browserKey)
if !detected {
clio.Warnf("aws-fuzzy could not detect an existing installation of %s at known installation paths for your system", browserTitle)
clio.Info("If you have already installed this browser, you can specify the path to the executable manually")
validPath := false
for !validPath {
// prompt for custom path
bpIn := survey.Input{Message: fmt.Sprintf("Please enter the full path to your browser installation for %s:", browserTitle)}
clio.NewLine()
err := testable.AskOne(&bpIn, &customBrowserPath, stdio)
if err != nil {
return err, "", ""
}
if _, err := os.Stat(customBrowserPath); err == nil {
validPath = true
} else {
clio.Error("The path you entered is not valid")
}
}
browserPath = customBrowserPath
}
browserPath = customBrowserPath

if browserKey == gbrowser.FirefoxKey {
err := gbrowser.RunFirefoxExtensionPrompts(browserPath)
if err != nil {
return err
return err, "", ""
}
}
}
//save the detected browser as the default
conf, err := afconfig.NewLoadedConfig()
if err != nil {
return err
}

conf.DefaultBrowser = browserKey
conf.CustomBrowserPath = browserPath
err = conf.Save()
if err != nil {
return err
}
clio.Successf("Granted will default to using %s", browserTitle)
return nil
return nil, browserKey, browserPath
}
7 changes: 5 additions & 2 deletions internal/sso/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ type Console struct {
}

type Browser struct {
Browser string
Verbose bool
Browser string
SSOBrowser string
Verbose bool
}

type Configure struct {
Expand Down Expand Up @@ -96,10 +97,12 @@ func Command() *cli.Command {
Usage: "Configure default browser",
Flags: []cli.Flag{
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Usage: "Specify a default browser without prompts, e.g '-b firefox', '-b chrome'"},
&cli.StringFlag{Name: "sso-browser", Aliases: []string{"s"}, Usage: "Specify a sso browser without prompts, e.g '-s firefox', '-s chrome'"},
&cli.BoolFlag{Name: "verbose", Aliases: []string{"v"}, Usage: "Enable verbose messages"},
},
Action: func(c *cli.Context) error {
browser := NewBrowser(c.String("browser"),
c.String("sso-browser"),
c.Bool("verbose"),
)

Expand Down

0 comments on commit dfa01a3

Please sign in to comment.