From f7860e93da6c2b277556c13ca4653d47ad7e7ceb Mon Sep 17 00:00:00 2001 From: Dan Pantry Date: Thu, 11 Jan 2024 13:51:01 -0800 Subject: [PATCH] Squashed 'keyconjurer-v2/' changes from 7c2fb08..f186716 f186716 UX improvements (#103) d2672b3 Fix moving content on large screens ec2d4bf Add sentinel error if we cant find a SAML response git-subtree-dir: keyconjurer-v2 git-subtree-split: f1867160fdc77633933e11d87309b2d0eaa72e86 --- cli/config.go | 9 +++++---- cli/consts.go | 2 +- cli/get.go | 22 ++++++++++++++++------ cli/oauth2.go | 6 ++++-- frontend/src/App.module.css | 4 +--- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/cli/config.go b/cli/config.go index 57fcc5a3..c2408d6e 100644 --- a/cli/config.go +++ b/cli/config.go @@ -197,10 +197,11 @@ func (a accountSet) WriteTable(w io.Writer, withHeaders bool) { // Config stores all information related to the user type Config struct { - Accounts *accountSet `json:"accounts"` - TTL uint `json:"ttl"` - TimeRemaining uint `json:"time_remaining"` - Tokens *TokenSet `json:"tokens"` + Accounts *accountSet `json:"accounts"` + TTL uint `json:"ttl"` + TimeRemaining uint `json:"time_remaining"` + Tokens *TokenSet `json:"tokens"` + LastUsedAccount *string `json:"last_used_account"` } func (c Config) GetOAuthToken() (*TokenSet, bool) { diff --git a/cli/consts.go b/cli/consts.go index 7dfd8e32..4866d86f 100644 --- a/cli/consts.go +++ b/cli/consts.go @@ -12,7 +12,7 @@ var ( const ( // DefaultTTL for requested credentials in hours - DefaultTTL uint = 1 + DefaultTTL uint = 8 // DefaultTimeRemaining for new key requests in minutes DefaultTimeRemaining uint = 5 LinuxAmd64BinaryName string = "keyconjurer-linux-amd64" diff --git a/cli/get.go b/cli/get.go index c59231a4..b88c128d 100644 --- a/cli/get.go +++ b/cli/get.go @@ -67,7 +67,6 @@ var getCmd = &cobra.Command{ Long: `Retrieves temporary cloud API credentials for the specified account. It sends a push request to the first Duo device it finds associated with your account. A role must be specified when using this command through the --role flag. You may list the roles you can assume through the roles command.`, - Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { config := ConfigFromCommand(cmd) ctx := cmd.Context() @@ -101,10 +100,20 @@ A role must be specified when using this command through the --role flag. You ma ttl = 8 } + var accountID string + if len(args) > 0 { + accountID = args[0] + } else if config.LastUsedAccount != nil { + // No account specified. Can we use the most recent one? + accountID = *config.LastUsedAccount + } else { + return cmd.Usage() + } + bypassCache, _ := cmd.Flags().GetBool(FlagBypassCache) - account, ok := resolveApplicationInfo(config, bypassCache, args[0]) + account, ok := resolveApplicationInfo(config, bypassCache, accountID) if !ok { - cmd.PrintErrf("%q is not a known account name in your account cache. Your cache can be refreshed by entering executing `keyconjurer accounts`. If the value provided is an Okta application ID, you may provide %s as an option to this command and try again.", args[0], FlagBypassCache) + cmd.PrintErrf("%q is not a known account name in your account cache. Your cache can be refreshed by entering executing `keyconjurer accounts`. If the value provided is an Okta application ID, you may provide %s as an option to this command and try again.", accountID, FlagBypassCache) return nil } @@ -128,7 +137,7 @@ A role must be specified when using this command through the --role flag. You ma } if credentials.ValidUntil(account, time.Duration(timeRemaining)*time.Minute) { - return echoCredentials(args[0], args[0], credentials, outputType, shellType, awsCliPath, tencentCliPath) + return echoCredentials(accountID, accountID, credentials, outputType, shellType, awsCliPath, tencentCliPath) } oauthCfg, err := DiscoverOAuth2Config(cmd.Context(), oidcDomain, clientID) @@ -158,7 +167,7 @@ A role must be specified when using this command through the --role flag. You ma pair, ok := FindRoleInSAML(roleName, samlResponse) if !ok { - cmd.PrintErrf("you do not have access to the role %s on application %s\n", roleName, args[0]) + cmd.PrintErrf("you do not have access to the role %s on application %s\n", roleName, accountID) return nil } @@ -197,8 +206,9 @@ A role must be specified when using this command through the --role flag. You ma if account != nil { account.MostRecentRole = roleName } + config.LastUsedAccount = &accountID - return echoCredentials(args[0], args[0], credentials, outputType, shellType, awsCliPath, tencentCliPath) + return echoCredentials(accountID, accountID, credentials, outputType, shellType, awsCliPath, tencentCliPath) }} func echoCredentials(id, name string, credentials CloudCredentials, outputType, shellType, awsCliPath, tencentCliPath string) error { diff --git a/cli/oauth2.go b/cli/oauth2.go index dee77baa..e9d86249 100644 --- a/cli/oauth2.go +++ b/cli/oauth2.go @@ -19,6 +19,8 @@ import ( "golang.org/x/oauth2" ) +var ErrNoSAMLAssertion = errors.New("no saml assertion") + // stateBufSize is the size of the buffer used to generate the state parameter. // 43 is a magic number - It generates states that are not too short or long for Okta's validation. const stateBufSize = 43 @@ -231,12 +233,12 @@ func ExchangeWebSSOTokenForSAMLAssertion(ctx context.Context, client *http.Clien doc, _ := html.Parse(resp.Body) form, ok := FindFirstForm(doc) if !ok { - return nil, errors.New("could not find form") + return nil, ErrNoSAMLAssertion } saml, ok := form.Inputs["SAMLResponse"] if !ok { - return nil, errors.New("no SAML assertion") + return nil, ErrNoSAMLAssertion } return []byte(saml), nil diff --git a/frontend/src/App.module.css b/frontend/src/App.module.css index d7bd9fc0..41930a51 100644 --- a/frontend/src/App.module.css +++ b/frontend/src/App.module.css @@ -5,9 +5,7 @@ .Content { display: grid; - grid-template-columns: 2 2fr; - grid-template-rows: 2; - + grid-template-columns: auto 100%; padding: 10px; }