From 3edd7ddd64cd863c794b35b010482448a510f5dc Mon Sep 17 00:00:00 2001 From: Cyb3r-Jak3 Date: Wed, 19 Nov 2025 20:40:09 -0500 Subject: [PATCH 1/2] Support changing the user-agent --- README.md | 2 ++ cmd/saml2aws/main.go | 2 ++ pkg/cfg/cfg.go | 2 ++ pkg/flags/flags.go | 8 +++++++ pkg/provider/http.go | 15 +++++++++--- pkg/provider/http_test.go | 48 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d91aec2b7..b4ccf09d3 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,8 @@ Flags: --disable-keychain Do not use keychain at all. This will also disable Okta sessions & remembering MFA device. (env: SAML2AWS_DISABLE_KEYCHAIN) -r, --region=REGION AWS region to use for API requests, e.g. us-east-1, us-gov-west-1, cn-north-1 (env: SAML2AWS_REGION) --prompter=PROMPTER The prompter to use for user input (default, pinentry) + --user-agent + --user-agent-override String to append to the user-agent (env: SAML2AWS_USER_AGENT") Commands: help [...] diff --git a/cmd/saml2aws/main.go b/cmd/saml2aws/main.go index 95d5cd899..becc1c0ee 100644 --- a/cmd/saml2aws/main.go +++ b/cmd/saml2aws/main.go @@ -92,6 +92,8 @@ func main() { app.Flag("region", "AWS region to use for API requests, e.g. us-east-1, us-gov-west-1, cn-north-1 (env: SAML2AWS_REGION)").Envar("SAML2AWS_REGION").Short('r').StringVar(&commonFlags.Region) app.Flag("prompter", "The prompter to use for user input (default, pinentry)").StringVar(&commonFlags.Prompter) app.Flag("kc-broker", "The kc broker to use when authenticating via keycloak").StringVar(&commonFlags.KCBroker) + app.Flag("user-agent", "String to append to the user-agent (env: SAML2AWS_USER_AGENT").Envar("SAML2AWS_USER_AGENT").StringVar(&commonFlags.UserAgent) + app.Flag("user-agent-override", "String to replace the existing user-agent with (env: SAML2AWS_USER_AGENT_OVERRIDE)").Envar("SAML2AWS_USER_AGENT_OVERRIDE").StringVar(&commonFlags.UserAgentOverride) // `configure` command and settings cmdConfigure := app.Command("configure", "Configure a new IDP account.") diff --git a/pkg/cfg/cfg.go b/pkg/cfg/cfg.go index c2b9277f5..5c1c235bf 100644 --- a/pkg/cfg/cfg.go +++ b/pkg/cfg/cfg.go @@ -70,6 +70,8 @@ type IDPAccount struct { KCAuthErrorMessage string `ini:"kc_auth_error_message,omitempty"` // used by KeyCloak; hide from user if not set KCAuthErrorElement string `ini:"kc_auth_error_element,omitempty"` // used by KeyCloak; hide from user if not set KCBroker string `ini:"kc_broker"` // used by KeyCloak; + UserAgent string `ini:"user_agent"` + UserAgentOverride string `ini:"user_agent_override"` } func (ia IDPAccount) String() string { diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go index 832fdf9be..90c631087 100644 --- a/pkg/flags/flags.go +++ b/pkg/flags/flags.go @@ -40,6 +40,8 @@ type CommonFlags struct { DisableSessions bool Prompter string KCBroker string + UserAgent string + UserAgentOverride string } // LoginExecFlags flags for the Login / Exec commands @@ -156,4 +158,10 @@ func ApplyFlagOverrides(commonFlags *CommonFlags, account *cfg.IDPAccount) { if commonFlags.Prompter != "" { account.Prompter = commonFlags.Prompter } + if commonFlags.UserAgent != "" { + account.UserAgent = commonFlags.UserAgent + } + if commonFlags.UserAgentOverride != "" { + account.UserAgentOverride = commonFlags.UserAgentOverride + } } diff --git a/pkg/provider/http.go b/pkg/provider/http.go index e89217fab..f5dbfb05a 100644 --- a/pkg/provider/http.go +++ b/pkg/provider/http.go @@ -32,9 +32,11 @@ const ( ) type HTTPClientOptions struct { - IsWithRetries bool //http retry feature switch - AttemptsCount uint - RetryDelay time.Duration + IsWithRetries bool //http retry feature switch + AttemptsCount uint + RetryDelay time.Duration + UserAgent string + UserAgentOverride string } // NewDefaultTransport configure a transport with the TLS skip verify option @@ -95,6 +97,13 @@ func (hc *HTTPClient) Do(req *http.Request) (*http.Response, error) { req.Header.Set("User-Agent", fmt.Sprintf("saml2aws/1.0 (%s %s) Versent", runtime.GOOS, runtime.GOARCH)) + if hc.Options.UserAgent != "" { + req.Header.Set("User-Agent", fmt.Sprintf("%s (%s)", req.UserAgent(), hc.Options.UserAgent)) + } + if hc.Options.UserAgentOverride != "" { + req.Header.Set("User-Agent", hc.Options.UserAgent) + } + var resp *http.Response var err error diff --git a/pkg/provider/http_test.go b/pkg/provider/http_test.go index ee16b5216..8456680fd 100644 --- a/pkg/provider/http_test.go +++ b/pkg/provider/http_test.go @@ -1,8 +1,10 @@ package provider import ( + "fmt" "net/http" "net/http/httptest" + "runtime" "testing" "github.com/stretchr/testify/require" @@ -72,3 +74,49 @@ func TestClientDoResponseCheck(t *testing.T) { require.Error(t, err) require.Equal(t, 400, res.StatusCode) } + +func TestClientDoUserAgent(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, fmt.Sprintf("saml2aws/1.0 (%s %s) Versent (Test)", runtime.GOOS, runtime.GOARCH), r.UserAgent()) + _, _ = w.Write([]byte("OK")) + })) + defer ts.Close() + + rt := NewDefaultTransport(false) + opts := &HTTPClientOptions{IsWithRetries: false, UserAgent: "Test"} + hc, err := NewHTTPClient(rt, opts) + require.Nil(t, err) + + // hc := &HTTPClient{Client: http.Client{}} + + req, err := http.NewRequest("GET", ts.URL, nil) + require.Nil(t, err) + + res, err := hc.Do(req) + require.Nil(t, err) + + require.Equal(t, 200, res.StatusCode) +} + +func TestClientDoUserAgentOverride(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "Test", r.UserAgent()) + _, _ = w.Write([]byte("OK")) + })) + defer ts.Close() + + rt := NewDefaultTransport(false) + opts := &HTTPClientOptions{IsWithRetries: false, UserAgentOverride: "Test"} + hc, err := NewHTTPClient(rt, opts) + require.Nil(t, err) + + // hc := &HTTPClient{Client: http.Client{}} + + req, err := http.NewRequest("GET", ts.URL, nil) + require.Nil(t, err) + + res, err := hc.Do(req) + require.Nil(t, err) + + require.Equal(t, 200, res.StatusCode) +} From 9367ce947b6a328e5fc79581701962f87ca7f3ec Mon Sep 17 00:00:00 2001 From: Cyb3r-Jak3 Date: Wed, 19 Nov 2025 20:49:59 -0500 Subject: [PATCH 2/2] Use shared version --- .goreleaser.macos-latest.yml | 2 +- .goreleaser.ubuntu-22.04.yml | 4 ++-- .goreleaser.ubuntu-latest.yml | 2 +- cmd/saml2aws/main.go | 8 ++------ pkg/provider/http.go | 3 ++- pkg/version/version.go | 3 +++ 6 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 pkg/version/version.go diff --git a/.goreleaser.macos-latest.yml b/.goreleaser.macos-latest.yml index 7eb698be5..53159ef73 100644 --- a/.goreleaser.macos-latest.yml +++ b/.goreleaser.macos-latest.yml @@ -8,7 +8,7 @@ builds: - -trimpath - -v ldflags: - - -s -w -X main.Version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - -s -w -X 'github.com/versent/saml2aws/v2/pkg/version.Version={{.Version}}' goos: - darwin goarch: diff --git a/.goreleaser.ubuntu-22.04.yml b/.goreleaser.ubuntu-22.04.yml index 497fe4787..c992c9f39 100644 --- a/.goreleaser.ubuntu-22.04.yml +++ b/.goreleaser.ubuntu-22.04.yml @@ -9,7 +9,7 @@ builds: - -trimpath - -v ldflags: - - -s -w -X main.Version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - -s -w -X 'github.com/versent/saml2aws/v2/pkg/version.Version={{.Version}}' goos: - linux goarch: @@ -91,4 +91,4 @@ docker_manifests: - name_template: ghcr.io/{{ .Env.IMAGE_NAME }}:latest image_templates: - ghcr.io/{{ .Env.IMAGE_NAME }}:latest-amd64 - - ghcr.io/{{ .Env.IMAGE_NAME }}:latest-arm64 \ No newline at end of file + - ghcr.io/{{ .Env.IMAGE_NAME }}:latest-arm64 diff --git a/.goreleaser.ubuntu-latest.yml b/.goreleaser.ubuntu-latest.yml index 5db45000c..cc6bae829 100644 --- a/.goreleaser.ubuntu-latest.yml +++ b/.goreleaser.ubuntu-latest.yml @@ -8,7 +8,7 @@ builds: - -trimpath - -v ldflags: - - -s -w -X main.Version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - -s -w -X 'github.com/versent/saml2aws/v2/pkg/version.Version={{.Version}}' goos: - windows - linux diff --git a/cmd/saml2aws/main.go b/cmd/saml2aws/main.go index becc1c0ee..481270627 100644 --- a/cmd/saml2aws/main.go +++ b/cmd/saml2aws/main.go @@ -14,11 +14,7 @@ import ( "github.com/versent/saml2aws/v2/cmd/saml2aws/commands" "github.com/versent/saml2aws/v2/pkg/flags" "github.com/versent/saml2aws/v2/pkg/prompter" -) - -var ( - // Version app version - Version = "1.0.0" + "github.com/versent/saml2aws/v2/pkg/version" ) // The `cmdLineList` type is used to make a `[]string` meet the requirements @@ -60,7 +56,7 @@ func main() { } app := kingpin.New("saml2aws", "A command line tool to help with SAML access to the AWS token service.") - app.Version(Version) + app.Version(version.Version) // Settings not related to commands verbose := app.Flag("verbose", "Enable verbose logging").Bool() diff --git a/pkg/provider/http.go b/pkg/provider/http.go index f5dbfb05a..bf33bd619 100644 --- a/pkg/provider/http.go +++ b/pkg/provider/http.go @@ -16,6 +16,7 @@ import ( "github.com/versent/saml2aws/v2/pkg/cfg" "github.com/versent/saml2aws/v2/pkg/cookiejar" "github.com/versent/saml2aws/v2/pkg/dump" + "github.com/versent/saml2aws/v2/pkg/version" "golang.org/x/net/publicsuffix" ) @@ -95,7 +96,7 @@ func NewHTTPClient(tr http.RoundTripper, opts *HTTPClientOptions) (*HTTPClient, // Do do the request func (hc *HTTPClient) Do(req *http.Request) (*http.Response, error) { - req.Header.Set("User-Agent", fmt.Sprintf("saml2aws/1.0 (%s %s) Versent", runtime.GOOS, runtime.GOARCH)) + req.Header.Set("User-Agent", fmt.Sprintf("saml2aws/%s (%s %s) Versent", version.Version, runtime.GOOS, runtime.GOARCH)) if hc.Options.UserAgent != "" { req.Header.Set("User-Agent", fmt.Sprintf("%s (%s)", req.UserAgent(), hc.Options.UserAgent)) diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 000000000..30ca1c4d6 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,3 @@ +package version + +var Version = "1.0"