From 6c7191355aaf2fd63999318ae2a5b8d358cba4bc Mon Sep 17 00:00:00 2001 From: Jesse Kinkead Date: Mon, 5 Sep 2022 15:33:09 -0700 Subject: [PATCH 1/3] Use the same output for surveys as for logs. Add a package variable to hold the survey output writer and a setter for it. Add a helper to generate a survey option using the writer for stdout. Initialize the survey output to be the same as for the log module. --- cmd/saml2aws/main.go | 2 ++ pkg/prompter/survey.go | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/cmd/saml2aws/main.go b/cmd/saml2aws/main.go index d6ee181e3..bc15a7594 100644 --- a/cmd/saml2aws/main.go +++ b/cmd/saml2aws/main.go @@ -12,6 +12,7 @@ import ( "github.com/sirupsen/logrus" "github.com/versent/saml2aws/v2/cmd/saml2aws/commands" "github.com/versent/saml2aws/v2/pkg/flags" + "github.com/versent/saml2aws/v2/pkg/prompter" ) var ( @@ -46,6 +47,7 @@ func buildCmdList(s kingpin.Settings) (target *[]string) { func main() { log.SetOutput(os.Stderr) + prompter.SetOutputWriter(os.Stderr) log.SetFlags(0) logrus.SetOutput(os.Stderr) diff --git a/pkg/prompter/survey.go b/pkg/prompter/survey.go index 686a835fb..35485d539 100644 --- a/pkg/prompter/survey.go +++ b/pkg/prompter/survey.go @@ -3,14 +3,29 @@ package prompter import ( "errors" "fmt" + "os" survey "github.com/AlecAivazis/survey/v2" + survey_terminal "github.com/AlecAivazis/survey/v2/terminal" ) +// outputWriter is where for all prompts will be printed. Defaults to os.Stder. +var outputWriter survey_terminal.FileWriter = os.Stderr + // CliPrompter used to prompt for cli input type CliPrompter struct { } +// SetOutputWriter sets the output writer to use for all survey operations +func SetOutputWriter(writer survey_terminal.FileWriter) { + outputWriter = writer +} + +// stdioOption returns the IO option to use for survey functions +func stdioOption() survey.AskOpt { + return survey.WithStdio(os.Stdin, outputWriter, os.Stderr) +} + // NewCli builds a new cli prompter func NewCli() *CliPrompter { return &CliPrompter{} @@ -22,7 +37,7 @@ func (cli *CliPrompter) RequestSecurityCode(pattern string) string { prompt := &survey.Input{ Message: fmt.Sprintf("Security Token [%s]", pattern), } - _ = survey.AskOne(prompt, &token, survey.WithValidator(survey.Required)) + _ = survey.AskOne(prompt, &token, survey.WithValidator(survey.Required), stdioOption()) return token } @@ -34,7 +49,7 @@ func (cli *CliPrompter) ChooseWithDefault(pr string, defaultValue string, option Options: options, Default: defaultValue, } - _ = survey.AskOne(prompt, &selected, survey.WithValidator(survey.Required)) + _ = survey.AskOne(prompt, &selected, survey.WithValidator(survey.Required), stdioOption()) // return the selected element index for i, option := range options { @@ -52,7 +67,7 @@ func (cli *CliPrompter) Choose(pr string, options []string) int { Message: pr, Options: options, } - _ = survey.AskOne(prompt, &selected, survey.WithValidator(survey.Required)) + _ = survey.AskOne(prompt, &selected, survey.WithValidator(survey.Required), stdioOption()) // return the selected element index for i, option := range options { @@ -70,7 +85,7 @@ func (cli *CliPrompter) String(pr string, defaultValue string) string { Message: pr, Default: defaultValue, } - _ = survey.AskOne(prompt, &val) + _ = survey.AskOne(prompt, &val, stdioOption()) return val } @@ -80,7 +95,7 @@ func (cli *CliPrompter) StringRequired(pr string) string { prompt := &survey.Input{ Message: pr, } - _ = survey.AskOne(prompt, &val, survey.WithValidator(survey.Required)) + _ = survey.AskOne(prompt, &val, survey.WithValidator(survey.Required), stdioOption()) return val } @@ -90,6 +105,6 @@ func (cli *CliPrompter) Password(pr string) string { prompt := &survey.Password{ Message: pr, } - _ = survey.AskOne(prompt, &val) + _ = survey.AskOne(prompt, &val, stdioOption()) return val } From a1fccdea9928b1dd980a1337ee10b8b753bc9a98 Mon Sep 17 00:00:00 2001 From: Keith Barlow Date: Thu, 26 Oct 2023 11:15:54 -0400 Subject: [PATCH 2/3] Add 5m timeout to page.WaitForRequest --- pkg/provider/browser/browser.go | 8 +++++++- pkg/provider/browser/browser_test.go | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/provider/browser/browser.go b/pkg/provider/browser/browser.go index dd8cbc744..f0da0dbcd 100644 --- a/pkg/provider/browser/browser.go +++ b/pkg/provider/browser/browser.go @@ -13,6 +13,8 @@ import ( var logger = logrus.WithField("provider", "browser") +var TimeoutPageWaitForRequest = newPageWaitForRequestOptions(300000) + // Client client for browser based Identity Provider type Client struct { Headless bool @@ -94,7 +96,7 @@ var getSAMLResponse = func(page playwright.Page, loginDetails *creds.LoginDetail } logger.Info("waiting ...") - r, _ := page.WaitForRequest(signin_re) + r, _ := page.WaitForRequest(signin_re, TimeoutPageWaitForRequest) data, err := r.PostData() if err != nil { return "", err @@ -123,3 +125,7 @@ func (cl *Client) Validate(loginDetails *creds.LoginDetails) error { return nil } + +func newPageWaitForRequestOptions(timeout float64) playwright.PageWaitForRequestOptions { + return playwright.PageWaitForRequestOptions{Timeout: &timeout} +} diff --git a/pkg/provider/browser/browser_test.go b/pkg/provider/browser/browser_test.go index 8027215b0..05797aa7b 100644 --- a/pkg/provider/browser/browser_test.go +++ b/pkg/provider/browser/browser_test.go @@ -107,7 +107,7 @@ func TestGetSAMLResponse(t *testing.T) { regex, err := signinRegex() assert.Nil(t, err) page.Mock.On("Goto", url).Return(resp, nil) - page.Mock.On("WaitForRequest", regex).Return(req) + page.Mock.On("WaitForRequest", regex, TimeoutPageWaitForRequest).Return(req) req.Mock.On("PostData").Return(params.Encode(), nil) // loginDetails := &creds.LoginDetails{ // URL: url, From 915af83d8e47c8d7309e48953fcca4eb0abb14fe Mon Sep 17 00:00:00 2001 From: Keith Barlow Date: Tue, 31 Oct 2023 20:58:16 -0400 Subject: [PATCH 3/3] Make timeout configurable --- pkg/provider/browser/browser.go | 16 +++++++--- pkg/provider/browser/browser_test.go | 48 ++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/pkg/provider/browser/browser.go b/pkg/provider/browser/browser.go index f0da0dbcd..6a930ef11 100644 --- a/pkg/provider/browser/browser.go +++ b/pkg/provider/browser/browser.go @@ -13,13 +13,14 @@ import ( var logger = logrus.WithField("provider", "browser") -var TimeoutPageWaitForRequest = newPageWaitForRequestOptions(300000) +const DEFAULT_TIMEOUT float64 = 300000 // Client client for browser based Identity Provider type Client struct { Headless bool // Setup alternative directory to download playwright browsers to BrowserDriverDir string + Timeout int } // New create new browser based client @@ -27,6 +28,7 @@ func New(idpAccount *cfg.IDPAccount) (*Client, error) { return &Client{ Headless: idpAccount.Headless, BrowserDriverDir: idpAccount.BrowserDriverDir, + Timeout: idpAccount.Timeout, }, nil } @@ -77,10 +79,10 @@ func (cl *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) } }() - return getSAMLResponse(page, loginDetails) + return getSAMLResponse(page, loginDetails, cl) } -var getSAMLResponse = func(page playwright.Page, loginDetails *creds.LoginDetails) (string, error) { +var getSAMLResponse = func(page playwright.Page, loginDetails *creds.LoginDetails, client *Client) (string, error) { logger.WithField("URL", loginDetails.URL).Info("opening browser") if _, err := page.Goto(loginDetails.URL); err != nil { @@ -96,7 +98,7 @@ var getSAMLResponse = func(page playwright.Page, loginDetails *creds.LoginDetail } logger.Info("waiting ...") - r, _ := page.WaitForRequest(signin_re, TimeoutPageWaitForRequest) + r, _ := page.WaitForRequest(signin_re, client.waitForRequestTimeout()) data, err := r.PostData() if err != nil { return "", err @@ -126,6 +128,10 @@ func (cl *Client) Validate(loginDetails *creds.LoginDetails) error { return nil } -func newPageWaitForRequestOptions(timeout float64) playwright.PageWaitForRequestOptions { +func (cl *Client) waitForRequestTimeout() playwright.PageWaitForRequestOptions { + timeout := float64(cl.Timeout) + if timeout < 30000 { + timeout = DEFAULT_TIMEOUT + } return playwright.PageWaitForRequestOptions{Timeout: &timeout} } diff --git a/pkg/provider/browser/browser_test.go b/pkg/provider/browser/browser_test.go index 05797aa7b..3832e7696 100644 --- a/pkg/provider/browser/browser_test.go +++ b/pkg/provider/browser/browser_test.go @@ -62,7 +62,7 @@ func TestNoBrowserDriverFail(t *testing.T) { assert.ErrorContains(t, err, "could not start driver") } -func fakeSAMLResponse(page playwright.Page, loginDetails *creds.LoginDetails) (string, error) { +func fakeSAMLResponse(page playwright.Page, loginDetails *creds.LoginDetails, client *Client) (string, error) { return response, nil } @@ -96,6 +96,14 @@ func TestGetSAMLResponse(t *testing.T) { ` + + idpAccount := cfg.IDPAccount{ + Headless: true, + Timeout: 100000, + } + + client, err := New(&idpAccount) + assert.Nil(t, err) params := url.Values{} params.Add("foo1", "bar1") params.Add("SAMLResponse", samlp) @@ -107,12 +115,46 @@ func TestGetSAMLResponse(t *testing.T) { regex, err := signinRegex() assert.Nil(t, err) page.Mock.On("Goto", url).Return(resp, nil) - page.Mock.On("WaitForRequest", regex, TimeoutPageWaitForRequest).Return(req) + page.Mock.On("WaitForRequest", regex, client.waitForRequestTimeout()).Return(req) req.Mock.On("PostData").Return(params.Encode(), nil) // loginDetails := &creds.LoginDetails{ // URL: url, //} - // samlResp, err := getSAMLResponse(page, loginDetails) + // samlResp, err := getSAMLResponse(page, loginDetails, client) // assert.Nil(t, err) // assert.Equal(t, samlp, samlResp) } + +func TestWaitForRequestOptions(t *testing.T) { + timeout := float64(100000) + idpAccount := cfg.IDPAccount{ + Headless: true, + Timeout: int(timeout), + } + + client, err := New(&idpAccount) + assert.Nil(t, err) + + options := client.waitForRequestTimeout() + if *options.Timeout != timeout { + t.Errorf("Unexpected value for timeout [%.0f]: expected [%.0f]", *options.Timeout, timeout) + } +} + +func TestWaitForRequestOptionsDefaultTimeout(t *testing.T) { + idpAccount := cfg.IDPAccount{ + Headless: true, + Timeout: 1000, + } + + client, err := New(&idpAccount) + + if err != nil { + t.Errorf("Unable to create browser") + } + + options := client.waitForRequestTimeout() + if *options.Timeout != DEFAULT_TIMEOUT { + t.Errorf("Unexpected value for timeout [%.0f]: expected [%.0f]", *options.Timeout, DEFAULT_TIMEOUT) + } +}