diff --git a/cmd/saml.go b/cmd/saml.go index e58c17e..d6acc34 100755 --- a/cmd/saml.go +++ b/cmd/saml.go @@ -13,12 +13,14 @@ import ( "github.com/DevLabFoundry/aws-cli-auth/internal/web" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/sts" + validator "github.com/rezakhademix/govalidator/v2" "github.com/spf13/cobra" "gopkg.in/ini.v1" ) var ( ErrUnableToCreateSession = errors.New("sts - cannot start a new session") + ErrValidationFailed = errors.New("missing values") ) const ( @@ -219,5 +221,24 @@ func ConfigFromFlags(fileConfig *credentialexchange.CredentialConfig, rf *RootCm fileConfig.BaseConfig = baseConf fileConfig.Duration = d + + return configValid(fileConfig) +} + +func configValid(config *credentialexchange.CredentialConfig) error { + v := validator.New() + ssoVal := !config.IsSso + if config.IsSso { + ssoVal = len(config.SsoRole) > 0 && len(config.SsoRegion) > 0 + } + v.RequiredString(config.ProviderUrl, "provider-url", "provider url must be specified"). + // RequiredString(config.BaseConfig.Role, "role", "role must be provided"). + RequiredString(config.PrincipalArn, "principal-arn", "principal ARN must be provided"). + CustomRule(ssoVal, "is-sso", "sso-role must be specified when is-sso is set"). + CustomRule((len(config.BaseConfig.Role) > 1 && len(config.SsoRole) < 1) || (len(config.BaseConfig.Role) < 1 && len(config.SsoRole) > 1), "role", "sso-role cannot be specified when role is also set") + + if v.IsFailed() { + return fmt.Errorf("%w %#q", ErrValidationFailed, v.Errors()) + } return nil } diff --git a/cmd/saml_test.go b/cmd/saml_test.go index bd7735f..275e693 100644 --- a/cmd/saml_test.go +++ b/cmd/saml_test.go @@ -1,6 +1,7 @@ package cmd_test import ( + "errors" "testing" "github.com/DevLabFoundry/aws-cli-auth/cmd" @@ -8,14 +9,15 @@ import ( "github.com/go-test/deep" ) -func Test_ConfigMerge(t *testing.T) { +func Test_ConfigMerge_succeeds(t *testing.T) { conf := &credentialexchange.CredentialConfig{ BaseConfig: credentialexchange.BaseConfig{ BrowserExecutablePath: "/foo/path", Role: "role1", RoleChain: []string{"role-123"}, }, - ProviderUrl: "https://my-idp.com/?app_id=testdd", + PrincipalArn: "aw:arn:....123", + ProviderUrl: "https://my-idp.com/?app_id=testdd", } if err := cmd.ConfigFromFlags(conf, &cmd.RootCmdFlags{}, &cmd.SamlCmdFlags{Role: "role-overridden-from-flags"}, "me"); err != nil { t.Fatal(err) @@ -28,8 +30,79 @@ func Test_ConfigMerge(t *testing.T) { RoleChain: []string{"role-123"}, Username: "me", }, + PrincipalArn: "aw:arn:....123", } if diff := deep.Equal(conf, want); len(diff) > 0 { t.Errorf("diff: %v", diff) } } + +func Test_ConfigMerge_fails_with_missing(t *testing.T) { + t.Run("provider not provided", func(t *testing.T) { + + conf := &credentialexchange.CredentialConfig{ + BaseConfig: credentialexchange.BaseConfig{ + BrowserExecutablePath: "/foo/path", + Role: "", + RoleChain: []string{"role-123"}, + }, + ProviderUrl: "", + } + err := cmd.ConfigFromFlags(conf, &cmd.RootCmdFlags{}, &cmd.SamlCmdFlags{Role: "role-overridden-from-flags"}, "me") + if !errors.Is(err, cmd.ErrValidationFailed) { + t.Error(err) + } + }) + t.Run("role not provided", func(t *testing.T) { + + conf := &credentialexchange.CredentialConfig{ + BaseConfig: credentialexchange.BaseConfig{ + BrowserExecutablePath: "/foo/path", + Role: "", + RoleChain: []string{"role-123"}, + }, + ProviderUrl: "https://my-idp.com/?app_id=testdd", + } + err := cmd.ConfigFromFlags(conf, &cmd.RootCmdFlags{}, &cmd.SamlCmdFlags{}, "me") + if !errors.Is(err, cmd.ErrValidationFailed) { + t.Error(err) + } + }) + t.Run("is-sso set but sso-role not set", func(t *testing.T) { + + conf := &credentialexchange.CredentialConfig{ + BaseConfig: credentialexchange.BaseConfig{ + BrowserExecutablePath: "/foo/path", + Role: "", + RoleChain: []string{"role-123"}, + }, + PrincipalArn: "some-arn", + IsSso: true, + SsoRegion: "", + SsoRole: "foo:bar", + ProviderUrl: "https://my-idp.com/?app_id=testdd", + } + err := cmd.ConfigFromFlags(conf, &cmd.RootCmdFlags{}, &cmd.SamlCmdFlags{}, "me") + if !errors.Is(err, cmd.ErrValidationFailed) { + t.Error(err) + } + }) + t.Run("role and sso-role both provided", func(t *testing.T) { + + conf := &credentialexchange.CredentialConfig{ + BaseConfig: credentialexchange.BaseConfig{ + BrowserExecutablePath: "/foo/path", + Role: "", + RoleChain: []string{"role-123"}, + }, + PrincipalArn: "some-arn", + SsoRegion: "foo", + SsoRole: "foo:bar", + ProviderUrl: "https://my-idp.com/?app_id=testdd", + } + err := cmd.ConfigFromFlags(conf, &cmd.RootCmdFlags{}, &cmd.SamlCmdFlags{Role: "wrong-role"}, "me") + if !errors.Is(err, cmd.ErrValidationFailed) { + t.Error(err) + } + }) +} diff --git a/go.mod b/go.mod index 77132d8..104f769 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/DevLabFoundry/aws-cli-auth -go 1.25.4 +go 1.25.5 require ( github.com/aws/aws-sdk-go-v2 v1.39.6 @@ -8,6 +8,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 github.com/aws/smithy-go v1.23.2 github.com/go-rod/rod v0.116.2 + github.com/rezakhademix/govalidator/v2 v2.1.2 github.com/spf13/cobra v1.10.1 github.com/werf/lockgate v0.1.1 github.com/zalando/go-keyring v0.2.6 diff --git a/go.sum b/go.sum index 30bbfee..4dd7409 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,8 @@ github.com/Ensono/eirctl v0.9.6 h1:G6S0ZJ2VtedGW2/nn8sbMQnNbLVXgjwNJnuLEHUjJRc= github.com/Ensono/eirctl v0.9.6/go.mod h1:pxX1iE+guf8Lyvs98FkNnMKqyTtHaLrJgB3f4foEROk= github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk= github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= -github.com/aws/aws-sdk-go-v2/config v1.31.19 h1:qdUtOw4JhZr2YcKO3g0ho/IcFXfXrrb8xlX05Y6EvSw= -github.com/aws/aws-sdk-go-v2/config v1.31.19/go.mod h1:tMJ8bur01t8eEm0atLadkIIFA154OJ4JCKZeQ+o+R7k= github.com/aws/aws-sdk-go-v2/config v1.31.20 h1:/jWF4Wu90EhKCgjTdy1DGxcbcbNrjfBHvksEL79tfQc= github.com/aws/aws-sdk-go-v2/config v1.31.20/go.mod h1:95Hh1Tc5VYKL9NJ7tAkDcqeKt+MCXQB1hQZaRdJIZE0= -github.com/aws/aws-sdk-go-v2/credentials v1.18.23 h1:IQILcxVgMO2BVLaJ2aAv21dKWvE1MduNrbvuK43XL2Q= -github.com/aws/aws-sdk-go-v2/credentials v1.18.23/go.mod h1:JRodHszhVdh5TPUknxDzJzrMiznG+M+FfR3WSWKgCI8= github.com/aws/aws-sdk-go-v2/credentials v1.18.24 h1:iJ2FmPT35EaIB0+kMa6TnQ+PwG5A1prEdAw+PsMzfHg= github.com/aws/aws-sdk-go-v2/credentials v1.18.24/go.mod h1:U91+DrfjAiXPDEGYhh/x29o4p0qHX5HDqG7y5VViv64= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= @@ -26,16 +22,10 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/A github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.2 h1:/p6MxkbQoCzaGQT3WO0JwG0FlQyG9RD8VmdmoKc5xqU= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.2/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ= github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.6 h1:0dES42T2dhICCbVB3JSTTn7+Bz93wfJEK1b7jksZIyQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.6/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= -github.com/aws/aws-sdk-go-v2/service/sts v1.40.1 h1:5sbIM57lHLaEaNWdIx23JH30LNBsSDkjN/QXGcRLAFc= -github.com/aws/aws-sdk-go-v2/service/sts v1.40.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 h1:HK5ON3KmQV2HcAunnx4sKLB9aPf3gKGwVAf7xnx0QT0= github.com/aws/aws-sdk-go-v2/service/sts v1.40.2/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= @@ -85,6 +75,8 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2Em github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rezakhademix/govalidator/v2 v2.1.2 h1:qqCIkWC6sWr8zeW9zCkYEJxbZMt/Dn1ASXkGIQe3rDI= +github.com/rezakhademix/govalidator/v2 v2.1.2/go.mod h1:be7JrYM3STiL5jYt1WrQN5ArR8xTov/DvWJ9yXtULj8= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=