Skip to content

Commit 33df08e

Browse files
committed
fix: add time spefication before a reload is done
user specified reload before int changed type to int from int64 and only cast in a place where it needs to be converted added unit test
1 parent e264c00 commit 33df08e

File tree

7 files changed

+77
-19
lines changed

7 files changed

+77
-19
lines changed

cmd/saml.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,44 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
46
"github.com/dnitsch/aws-cli-auth/internal/auth"
57
"github.com/dnitsch/aws-cli-auth/internal/config"
68
"github.com/dnitsch/aws-cli-auth/internal/util"
79
"github.com/spf13/cobra"
810
)
911

1012
var (
11-
providerUrl string
12-
principalArn string
13-
acsUrl string
14-
role string
15-
duration int64
16-
samlCmd = &cobra.Command{
13+
providerUrl string
14+
principalArn string
15+
acsUrl string
16+
role string
17+
duration int
18+
reloadBeforeTime int
19+
samlCmd = &cobra.Command{
1720
Use: "saml <SAML ProviderUrl>",
1821
Short: "Get AWS credentials and out to stdout",
1922
Long: `Get AWS credentials and out to stdout through your SAML provider authentication.`,
2023
Run: getSaml,
24+
PreRunE: func(cmd *cobra.Command, args []string) error {
25+
if reloadBeforeTime != 0 && reloadBeforeTime > duration {
26+
return fmt.Errorf("reload-before: %v, must be less than duration (-d): %v", reloadBeforeTime, duration)
27+
}
28+
return nil
29+
},
2130
}
2231
)
2332

2433
func init() {
2534
samlCmd.PersistentFlags().StringVarP(&providerUrl, "provider", "p", "", "Saml Entity StartSSO Url")
35+
samlCmd.MarkPersistentFlagRequired("provider")
2636
samlCmd.PersistentFlags().StringVarP(&principalArn, "principal", "", "", "Principal Arn of the SAML IdP in AWS")
37+
samlCmd.MarkPersistentFlagRequired("principal")
2738
samlCmd.PersistentFlags().StringVarP(&acsUrl, "acsurl", "a", "https://signin.aws.amazon.com/saml", "Override the default ACS Url, used for checkin the post of the SAMLResponse")
28-
samlCmd.PersistentFlags().Int64VarP(&duration, "max-duration", "d", 900, "Override default max session duration, in seconds, of the role session [900-43200]")
39+
samlCmd.PersistentFlags().IntVarP(&duration, "max-duration", "d", 900, "Override default max session duration, in seconds, of the role session [900-43200]")
40+
samlCmd.MarkPersistentFlagRequired("max-duration")
41+
samlCmd.PersistentFlags().IntVarP(&reloadBeforeTime, "reload-before", "", 0, "Triggers a credentials refresh before the specified max-duration. Value provided in seconds. Should be less than the max-duration of the session")
2942
rootCmd.AddCommand(samlCmd)
3043
}
3144

@@ -35,7 +48,13 @@ func getSaml(cmd *cobra.Command, args []string) {
3548
PrincipalArn: principalArn,
3649
Duration: duration,
3750
AcsUrl: acsUrl,
38-
BaseConfig: config.BaseConfig{StoreInProfile: storeInProfile, Role: role, CfgSectionName: cfgSectionName, DoKillHangingProcess: killHangingProcess},
51+
BaseConfig: config.BaseConfig{
52+
StoreInProfile: storeInProfile,
53+
Role: role,
54+
CfgSectionName: cfgSectionName,
55+
DoKillHangingProcess: killHangingProcess,
56+
ReloadBeforeTime: reloadBeforeTime,
57+
},
3958
}
4059

4160
auth.GetSamlCreds(conf)

internal/auth/awssts.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func LoginStsSaml(samlResponse string, role *util.AWSRole) (*util.AWSCredentials
3333
PrincipalArn: aws.String(role.PrincipalARN), // Required
3434
RoleArn: aws.String(role.RoleARN), // Required
3535
SAMLAssertion: aws.String(samlResponse), // Required
36-
DurationSeconds: aws.Int64(role.Duration),
36+
DurationSeconds: aws.Int64(int64(role.Duration)),
3737
}
3838

3939
resp, err := svc.AssumeRoleWithSAML(params)

internal/auth/saml.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func GetSamlCreds(conf config.SamlConfig) {
2323
// Try to reuse stored credential in secret
2424
awsCreds, err = secretStore.AWSCredential()
2525

26-
if !util.IsValid(awsCreds) || err != nil {
26+
if !util.IsValid(awsCreds, conf.BaseConfig.ReloadBeforeTime) || err != nil {
2727
webBrowser = web.New()
2828

2929
t, err := webBrowser.GetSamlLogin(conf)

internal/config/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ type BaseConfig struct {
1212
CfgSectionName string
1313
StoreInProfile bool
1414
DoKillHangingProcess bool
15+
ReloadBeforeTime int
1516
}
1617

1718
type SamlConfig struct {
1819
BaseConfig BaseConfig
1920
ProviderUrl string
2021
PrincipalArn string
2122
AcsUrl string
22-
Duration int64
23+
Duration int
2324
}

internal/util/helper.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"path"
99
"strings"
10+
"time"
1011

1112
"github.com/aws/aws-sdk-go/aws"
1213
"github.com/aws/aws-sdk-go/aws/credentials"
@@ -25,7 +26,7 @@ func HomeDir() string {
2526
}
2627

2728
func ConfigIniFile(basePath string) string {
28-
var base = ""
29+
var base string
2930
if basePath != "" {
3031
base = basePath
3132
} else {
@@ -105,8 +106,12 @@ func GetWebIdTokenFileContents() (string, error) {
105106
return string(content), nil
106107
}
107108

108-
func IsValid(cred *AWSCredentials) bool {
109-
if cred == nil {
109+
// IsValid checks current credentials and
110+
// returns them if they are still valid
111+
// if reloadTimeBefore is less than time left on the creds
112+
// then it will re-request a login
113+
func IsValid(currentCreds *AWSCredentials, relaodBeforeTime int) bool {
114+
if currentCreds == nil {
110115
return false
111116
}
112117

@@ -117,9 +122,9 @@ func IsValid(cred *AWSCredentials) bool {
117122
}
118123

119124
creds := credentials.NewStaticCredentialsFromCreds(credentials.Value{
120-
AccessKeyID: cred.AWSAccessKey,
121-
SecretAccessKey: cred.AWSSecretKey,
122-
SessionToken: cred.AWSSessionToken,
125+
AccessKeyID: currentCreds.AWSAccessKey,
126+
SecretAccessKey: currentCreds.AWSSecretKey,
127+
SessionToken: currentCreds.AWSSessionToken,
123128
})
124129

125130
svc := sts.New(sess, aws.NewConfig().WithCredentials(creds))
@@ -132,7 +137,17 @@ func IsValid(cred *AWSCredentials) bool {
132137
Writeln("The previous credential isn't valid")
133138
}
134139

135-
return err == nil
140+
return err == nil && !reloadBeforeExpiry(currentCreds.Expires, relaodBeforeTime)
141+
}
142+
143+
// reloadBeforeExpiry returns true if the time
144+
// to expiry is less than the specified time in seconds
145+
// false if there is more than required time in seconds
146+
// before needing to recycle credentials
147+
func reloadBeforeExpiry(expiry time.Time, reloadBeforeSeconds int) bool {
148+
now := time.Now()
149+
diff := expiry.Sub(now)
150+
return diff.Seconds() < float64(reloadBeforeSeconds)
136151
}
137152

138153
// WriteIniSection update ini sections in own config file

internal/util/helper_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66
"testing"
7+
"time"
78

89
"github.com/dnitsch/aws-cli-auth/internal/config"
910
ini "gopkg.in/ini.v1"
@@ -52,3 +53,25 @@ func TestCreateEntryInIni(t *testing.T) {
5253
t.Errorf("Not found nothing to do")
5354
}
5455
}
56+
57+
func TestReloadBeforeExpirySuccess(t *testing.T) {
58+
59+
expiry := (time.Now()).Add(time.Second * 305)
60+
61+
got := reloadBeforeExpiry(expiry, 300)
62+
63+
if got {
64+
t.Errorf("Expected %v, got: %v", false, got)
65+
}
66+
}
67+
68+
func TestReloadBeforeExpiryNeedToRefresh(t *testing.T) {
69+
70+
expiry := (time.Now()).Add(time.Second * 299)
71+
72+
got := reloadBeforeExpiry(expiry, 300)
73+
74+
if !got {
75+
t.Errorf("Expected %v, got: %v", false, got)
76+
}
77+
}

internal/util/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ type AWSRole struct {
1717
RoleARN string
1818
PrincipalARN string
1919
Name string
20-
Duration int64
20+
Duration int
2121
}

0 commit comments

Comments
 (0)