Skip to content

Commit c4309d9

Browse files
committed
Add AuthUrlAction to override UrlAction for SSO auth
This basically reverts #491 and goes back to unique Firefox containers for each SSO provider/AWS SSO instance. The AuthUrlAction does allow you to pick a single SSO instance to use your default browser via `open` to re-use the existing session cookies you might already have. Fixes: #524
1 parent b616c68 commit c4309d9

File tree

5 files changed

+110
-6
lines changed

5 files changed

+110
-6
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
* Guided setup is now more simple unless user provides the `--advanced` flag #530
1818
* Guided setup now strips leading and trailing spaces for string input
19+
* Revert #491 so SSO auth uses Firefox containers
1920

2021
### New Features
2122

@@ -25,6 +26,8 @@
2526
* `config-profiles` now supports the `--aws-config` flag
2627
* Added [ecs list](docs/ecs-server.md#listing-profiles) command to list
2728
profiles in named slots #517
29+
* Add [AuthUrlAction](docs/config.md#authurlaction) to override [UrlAction](docs/config.md#urlaction)
30+
during SSO Authentication. #524
2831

2932
## [v1.12.0] - 2023-08-12
3033

docs/config.md

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SSOConfig:
1515
SSORegion: <AWS Region where AWS SSO is deployed>
1616
StartUrl: <URL for AWS SSO Portal>
1717
DefaultRegion: <AWS_DEFAULT_REGION>
18+
AuthUrlAction: [clip|exec|print|printurl|open|granted-containers|open-url-in-container]
1819
Accounts: # optional block for specifying tags & overrides
1920
<AccountId>:
2021
Name: <Friendly Name of Account>
@@ -129,6 +130,12 @@ selected (most specific to most generic):
129130
1. At the AWS SSO Instance level: `SSOConfig -> <AWS SSO Instance>`
130131
1. At the config file level (default is `us-east-1`)
131132

133+
### AuthUrlAction
134+
135+
Override the global [UrlAction](#urlaction) when authenticating with your SSO provider
136+
to retrieve an AWS SSO token. Generally only useful when you wish to use your default
137+
browser with one `SSOConfig` block to re-use your existing SSO browser authentication cookie.
138+
132139
### Accounts
133140

134141
The `Accounts` block is completely optional! The only purpose of this block

sso/awssso_auth.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,13 @@ func (as *AWSSSO) reauthenticate() error {
110110
return fmt.Errorf("Unable to get device auth info from AWS SSO: %s", err.Error())
111111
}
112112

113-
urlOpener := url.NewHandleUrl(url.SSOAuthAction(as.urlAction), auth.VerificationUriComplete,
114-
as.browser, as.urlExecCommand)
113+
action := as.urlAction
114+
if as.SSOConfig.AuthUrlAction != url.Undef {
115+
// specific action for authentication?
116+
action = as.SSOConfig.AuthUrlAction
117+
}
118+
119+
urlOpener := url.NewHandleUrl(action, auth.VerificationUriComplete, as.browser, as.urlExecCommand)
115120
urlOpener.ContainerSettings(as.StoreKey(), DEFAULT_AUTH_COLOR, DEFAULT_AUTH_ICON)
116121

117122
if err = urlOpener.Open(); err != nil {
@@ -262,7 +267,7 @@ func (as *AWSSSO) createToken() error {
262267
} else if errors.As(err, &ape) {
263268
time.Sleep(retryInterval)
264269
} else {
265-
return err
270+
return fmt.Errorf("createToken: %s", err.Error())
266271
}
267272
}
268273

sso/awssso_auth_test.go

+82-3
Original file line numberDiff line numberDiff line change
@@ -344,17 +344,96 @@ func TestAuthenticateFailure(t *testing.T) {
344344
CreateToken: &ssooidc.CreateTokenOutput{},
345345
Error: fmt.Errorf("some error"),
346346
},
347+
// fourth test
348+
{
349+
RegisterClient: &ssooidc.RegisterClientOutput{
350+
AuthorizationEndpoint: nil,
351+
ClientId: aws.String("this-is-my-client-id"),
352+
ClientSecret: aws.String("this-is-my-client-secret"),
353+
ClientIdIssuedAt: time.Now().Unix(),
354+
ClientSecretExpiresAt: int64(expires),
355+
TokenEndpoint: nil,
356+
},
357+
Error: nil,
358+
},
359+
{
360+
StartDeviceAuthorization: &ssooidc.StartDeviceAuthorizationOutput{
361+
DeviceCode: aws.String("device-code"),
362+
UserCode: aws.String("user-code"),
363+
VerificationUri: aws.String(""),
364+
VerificationUriComplete: aws.String("verification-uri-complete"),
365+
ExpiresIn: int32(expires),
366+
Interval: 5,
367+
},
368+
Error: nil,
369+
},
370+
// fifth test
371+
{
372+
RegisterClient: &ssooidc.RegisterClientOutput{
373+
AuthorizationEndpoint: nil,
374+
ClientId: aws.String("this-is-my-client-id"),
375+
ClientSecret: aws.String("this-is-my-client-secret"),
376+
ClientIdIssuedAt: time.Now().Unix(),
377+
ClientSecretExpiresAt: int64(expires),
378+
TokenEndpoint: nil,
379+
},
380+
Error: nil,
381+
},
382+
{
383+
StartDeviceAuthorization: &ssooidc.StartDeviceAuthorizationOutput{
384+
DeviceCode: aws.String("device-code"),
385+
UserCode: aws.String("user-code"),
386+
VerificationUri: aws.String("verification-uri"),
387+
VerificationUriComplete: aws.String("verification-uri-complete"),
388+
ExpiresIn: int32(expires),
389+
Interval: 5,
390+
},
391+
Error: nil,
392+
},
393+
// sixth test
394+
{
395+
RegisterClient: &ssooidc.RegisterClientOutput{
396+
AuthorizationEndpoint: nil,
397+
ClientId: aws.String("this-is-my-client-id"),
398+
ClientSecret: aws.String("this-is-my-client-secret"),
399+
ClientIdIssuedAt: time.Now().Unix(),
400+
ClientSecretExpiresAt: int64(expires),
401+
TokenEndpoint: nil,
402+
},
403+
Error: nil,
404+
},
405+
{
406+
StartDeviceAuthorization: &ssooidc.StartDeviceAuthorizationOutput{
407+
DeviceCode: aws.String("device-code"),
408+
UserCode: aws.String("user-code"),
409+
VerificationUri: aws.String("verification-uri"),
410+
VerificationUriComplete: aws.String("verification-uri-complete"),
411+
ExpiresIn: int32(expires),
412+
Interval: 5,
413+
},
414+
Error: nil,
415+
},
347416
},
348417
}
349418

350419
err = as.Authenticate("print", "fake-browser")
351-
assert.Contains(t, err.Error(), "some error")
420+
assert.Contains(t, err.Error(), "Unable to register client with AWS SSO")
421+
422+
err = as.Authenticate("print", "fake-browser")
423+
assert.Contains(t, err.Error(), "Unable to start device authorization")
424+
425+
err = as.Authenticate("print", "fake-browser")
426+
assert.Contains(t, err.Error(), "createToken:")
352427

353428
err = as.Authenticate("print", "fake-browser")
354-
assert.Contains(t, err.Error(), "some error")
429+
assert.Contains(t, err.Error(), "No valid verification url")
430+
431+
err = as.Authenticate("invalid", "fake-browser")
432+
assert.Contains(t, err.Error(), "Unsupported Open action")
355433

434+
as.SSOConfig.AuthUrlAction = "invalid"
356435
err = as.Authenticate("print", "fake-browser")
357-
assert.Contains(t, err.Error(), "some error")
436+
assert.Contains(t, err.Error(), "Unsupported Open action")
358437
}
359438

360439
func TestReauthenticate(t *testing.T) {

sso/config.go

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424

2525
"github.com/synfinatic/aws-sso-cli/internal/tags"
26+
"github.com/synfinatic/aws-sso-cli/internal/url"
2627
"github.com/synfinatic/aws-sso-cli/internal/utils"
2728
)
2829

@@ -33,6 +34,10 @@ type SSOConfig struct {
3334
StartUrl string `koanf:"StartUrl" yaml:"StartUrl"`
3435
Accounts map[string]*SSOAccount `koanf:"Accounts" yaml:"Accounts,omitempty"` // key must be a string to avoid parse errors!
3536
DefaultRegion string `koanf:"DefaultRegion" yaml:"DefaultRegion,omitempty"`
37+
38+
// overrides for this SSO Instance
39+
AuthUrlAction url.Action `koanf:"AuthUrlAction" yaml:"AuthUrlAction,omitempty"`
40+
3641
// passed to AWSSSO from our Settings
3742
MaxBackoff int `koanf:"-" yaml:"-"`
3843
MaxRetry int `koanf:"-" yaml:"-"`
@@ -62,6 +67,11 @@ type SSORole struct {
6267
func (c *SSOConfig) Refresh(s *Settings) {
6368
c.MaxBackoff = s.MaxBackoff
6469
c.MaxRetry = s.MaxRetry
70+
71+
if c.AuthUrlAction == url.Undef {
72+
c.AuthUrlAction = s.UrlAction
73+
}
74+
6575
for accountId, a := range c.Accounts {
6676
a.SetParentConfig(c)
6777
for roleName, r := range a.Roles {

0 commit comments

Comments
 (0)