From f39a68c7af69a22a656aa74fbe1d7eac36f245ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Cie=C5=9Blak?= Date: Tue, 17 Sep 2024 11:26:06 +0200 Subject: [PATCH] chore: Adjust authentication policy (#3068) ## Changes * Addressed comments from https://github.com/Snowflake-Labs/terraform-provider-snowflake/pull/2937 * Fixed failing tests caused by this change * Changed and added multiple tests connected to auth policies * Adjusted a few parts of the SDK implementation (using enums where possible, added a few missing parts, etc.) ## TODO * Mention in https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2880 that the SDK for Auth Policies is ready --- .../authentication_policy_snowflake_ext.go | 19 + .../authentication_policy_snowflake_gen.go | 119 +++++ .../assert/objectassert/gen/sdk_object_def.go | 5 + .../helpers/authentication_policy_client.go | 18 +- .../resource_monitor_acceptance_test.go | 2 +- pkg/resources/user.go | 18 +- pkg/sdk/accounts_test.go | 36 ++ pkg/sdk/authentication_policies_def.go | 83 ++- ...uthentication_policies_dto_builders_gen.go | 9 +- pkg/sdk/authentication_policies_dto_gen.go | 5 +- pkg/sdk/authentication_policies_gen.go | 46 +- pkg/sdk/authentication_policies_gen_test.go | 78 ++- pkg/sdk/authentication_policies_impl_gen.go | 13 +- ...authentication_policies_validations_gen.go | 3 + pkg/sdk/policy_references.go | 11 +- pkg/sdk/testint/accounts_integration_test.go | 2 +- ...ntication_policies_gen_integration_test.go | 487 ++++++++---------- pkg/sdk/testint/users_integration_test.go | 126 +++-- pkg/sdk/users.go | 24 +- pkg/sdk/users_test.go | 59 ++- 20 files changed, 749 insertions(+), 414 deletions(-) create mode 100644 pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_ext.go create mode 100644 pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_gen.go diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_ext.go b/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_ext.go new file mode 100644 index 0000000000..3a3393a644 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_ext.go @@ -0,0 +1,19 @@ +package objectassert + +import ( + "fmt" + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +func (a *AuthenticationPolicyAssert) HasCreatedOnNotEmpty() *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.CreatedOn == "" { + return fmt.Errorf("expected create_on to be not empty") + } + return nil + }) + return a +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_gen.go b/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_gen.go new file mode 100644 index 0000000000..fb0da08f36 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/authentication_policy_snowflake_gen.go @@ -0,0 +1,119 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package objectassert + +import ( + "fmt" + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" +) + +type AuthenticationPolicyAssert struct { + *assert.SnowflakeObjectAssert[sdk.AuthenticationPolicy, sdk.SchemaObjectIdentifier] +} + +func AuthenticationPolicy(t *testing.T, id sdk.SchemaObjectIdentifier) *AuthenticationPolicyAssert { + t.Helper() + return &AuthenticationPolicyAssert{ + assert.NewSnowflakeObjectAssertWithProvider(sdk.ObjectTypeAuthenticationPolicy, id, acc.TestClient().AuthenticationPolicy.Show), + } +} + +func AuthenticationPolicyFromObject(t *testing.T, authenticationPolicy *sdk.AuthenticationPolicy) *AuthenticationPolicyAssert { + t.Helper() + return &AuthenticationPolicyAssert{ + assert.NewSnowflakeObjectAssertWithObject(sdk.ObjectTypeAuthenticationPolicy, authenticationPolicy.ID(), authenticationPolicy), + } +} + +func (a *AuthenticationPolicyAssert) HasCreatedOn(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.CreatedOn != expected { + return fmt.Errorf("expected created on: %v; got: %v", expected, o.CreatedOn) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasName(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.Name != expected { + return fmt.Errorf("expected name: %v; got: %v", expected, o.Name) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasComment(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.Comment != expected { + return fmt.Errorf("expected comment: %v; got: %v", expected, o.Comment) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasDatabaseName(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.DatabaseName != expected { + return fmt.Errorf("expected database name: %v; got: %v", expected, o.DatabaseName) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasSchemaName(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.SchemaName != expected { + return fmt.Errorf("expected schema name: %v; got: %v", expected, o.SchemaName) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasOwner(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.Owner != expected { + return fmt.Errorf("expected owner: %v; got: %v", expected, o.Owner) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasOwnerRoleType(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.OwnerRoleType != expected { + return fmt.Errorf("expected owner role type: %v; got: %v", expected, o.OwnerRoleType) + } + return nil + }) + return a +} + +func (a *AuthenticationPolicyAssert) HasOptions(expected string) *AuthenticationPolicyAssert { + a.AddAssertion(func(t *testing.T, o *sdk.AuthenticationPolicy) error { + t.Helper() + if o.Options != expected { + return fmt.Errorf("expected options: %v; got: %v", expected, o.Options) + } + return nil + }) + return a +} diff --git a/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go b/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go index 019edbaca2..c0da90f4cd 100644 --- a/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go +++ b/pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go @@ -47,6 +47,11 @@ var allStructs = []SdkObjectDef{ ObjectType: sdk.ObjectTypeResourceMonitor, ObjectStruct: sdk.ResourceMonitor{}, }, + { + IdType: "sdk.SchemaObjectIdentifier", + ObjectType: sdk.ObjectTypeAuthenticationPolicy, + ObjectStruct: sdk.AuthenticationPolicy{}, + }, } func GetSdkObjectDetails() []genhelpers.SdkObjectDetails { diff --git a/pkg/acceptance/helpers/authentication_policy_client.go b/pkg/acceptance/helpers/authentication_policy_client.go index 0a82a28042..e8e195b3dd 100644 --- a/pkg/acceptance/helpers/authentication_policy_client.go +++ b/pkg/acceptance/helpers/authentication_policy_client.go @@ -24,26 +24,26 @@ func (c *AuthenticationPolicyClient) client() sdk.AuthenticationPolicies { return c.context.client.AuthenticationPolicies } -func (c *AuthenticationPolicyClient) CreateAuthenticationPolicy(t *testing.T) (*sdk.AuthenticationPolicy, func()) { +func (c *AuthenticationPolicyClient) Create(t *testing.T) (*sdk.AuthenticationPolicy, func()) { t.Helper() id := c.ids.RandomSchemaObjectIdentifier() - return c.CreateAuthenticationPolicyWithOptions(t, id, sdk.NewCreateAuthenticationPolicyRequest(id)) + return c.CreateWithOptions(t, id, sdk.NewCreateAuthenticationPolicyRequest(id)) } -func (c *AuthenticationPolicyClient) CreateAuthenticationPolicyWithOptions(t *testing.T, id sdk.SchemaObjectIdentifier, request *sdk.CreateAuthenticationPolicyRequest) (*sdk.AuthenticationPolicy, func()) { +func (c *AuthenticationPolicyClient) CreateWithOptions(t *testing.T, id sdk.SchemaObjectIdentifier, request *sdk.CreateAuthenticationPolicyRequest) (*sdk.AuthenticationPolicy, func()) { t.Helper() ctx := context.Background() err := c.client().Create(ctx, request) require.NoError(t, err) - sessionPolicy, err := c.client().ShowByID(ctx, id) + authenticationPolicy, err := c.client().ShowByID(ctx, id) require.NoError(t, err) - return sessionPolicy, c.DropAuthenticationPolicyFunc(t, id) + return authenticationPolicy, c.DropFunc(t, id) } -func (c *AuthenticationPolicyClient) DropAuthenticationPolicyFunc(t *testing.T, id sdk.SchemaObjectIdentifier) func() { +func (c *AuthenticationPolicyClient) DropFunc(t *testing.T, id sdk.SchemaObjectIdentifier) func() { t.Helper() ctx := context.Background() @@ -52,3 +52,9 @@ func (c *AuthenticationPolicyClient) DropAuthenticationPolicyFunc(t *testing.T, require.NoError(t, err) } } + +func (c *AuthenticationPolicyClient) Show(t *testing.T, id sdk.SchemaObjectIdentifier) (*sdk.AuthenticationPolicy, error) { + t.Helper() + ctx := context.Background() + return c.client().ShowByID(ctx, id) +} diff --git a/pkg/resources/resource_monitor_acceptance_test.go b/pkg/resources/resource_monitor_acceptance_test.go index c9461d9345..3904bb4d15 100644 --- a/pkg/resources/resource_monitor_acceptance_test.go +++ b/pkg/resources/resource_monitor_acceptance_test.go @@ -758,7 +758,7 @@ func TestAcc_ResourceMonitor_Issue1500_AlteringWithOnlyTriggers(t *testing.T) { }, Config: config.FromModel(t, configModelWithoutTriggers), // For some reason, not returning the correct error (SQL compilation error should be returned in this case; most likely update was processed incorrectly) - ExpectError: regexp.MustCompile(`at least one of AlterResourceMonitorOptions fields [Set Triggers] must be set`), + ExpectError: regexp.MustCompile(`at least one of AlterResourceMonitorOptions fields \[Set Triggers] must be set`), }, // Upgrade to the latest version { diff --git a/pkg/resources/user.go b/pkg/resources/user.go index 557e51c827..77d5fcf418 100644 --- a/pkg/resources/user.go +++ b/pkg/resources/user.go @@ -548,24 +548,12 @@ func UpdateUser(ctx context.Context, d *schema.ResourceData, meta any) diag.Diag return diag.FromErr(err) } } - // unset is split into two because: - // 1. this is how it's written in the docs https://docs.snowflake.com/en/sql-reference/sql/alter-user#syntax - // 2. current implementation of sdk.UserUnset makes distinction between user and session parameters, - // so adding a comma between them is not trivial in the current SQL builder implementation - if (*unset.SessionParameters != sdk.SessionParametersUnset{}) { + + if (*unset.SessionParameters != sdk.SessionParametersUnset{}) || (*unset.ObjectParameters != sdk.UserObjectParametersUnset{}) { err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ Unset: &sdk.UserUnset{ SessionParameters: unset.SessionParameters, - }, - }) - if err != nil { - return diag.FromErr(err) - } - } - if (*unset.ObjectParameters != sdk.UserObjectParametersUnset{}) { - err := client.Users.Alter(ctx, id, &sdk.AlterUserOptions{ - Unset: &sdk.UserUnset{ - ObjectParameters: unset.ObjectParameters, + ObjectParameters: unset.ObjectParameters, }, }) if err != nil { diff --git a/pkg/sdk/accounts_test.go b/pkg/sdk/accounts_test.go index bb1b33b7eb..3168e02d98 100644 --- a/pkg/sdk/accounts_test.go +++ b/pkg/sdk/accounts_test.go @@ -52,6 +52,42 @@ func TestAccountCreate(t *testing.T) { } func TestAccountAlter(t *testing.T) { + t.Run("validation: exactly one value set in AccountSet - nothing set", func(t *testing.T) { + opts := &AlterAccountOptions{ + Set: &AccountSet{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AccountSet", "Parameters", "ResourceMonitor", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + + t.Run("validation: exactly one value set in AccountSet - multiple set", func(t *testing.T) { + opts := &AlterAccountOptions{ + Set: &AccountSet{ + PasswordPolicy: randomSchemaObjectIdentifier(), + SessionPolicy: randomSchemaObjectIdentifier(), + AuthenticationPolicy: randomSchemaObjectIdentifier(), + }, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AccountSet", "Parameters", "ResourceMonitor", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + + t.Run("validation: exactly one value set in AccountUnset - nothing set", func(t *testing.T) { + opts := &AlterAccountOptions{ + Unset: &AccountUnset{}, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AccountUnset", "Parameters", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + + t.Run("validation: exactly one value set in AccountUnset - multiple set", func(t *testing.T) { + opts := &AlterAccountOptions{ + Unset: &AccountUnset{ + PasswordPolicy: Bool(true), + SessionPolicy: Bool(true), + AuthenticationPolicy: Bool(true), + }, + } + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AccountUnset", "Parameters", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + t.Run("with set params", func(t *testing.T) { opts := &AlterAccountOptions{ Set: &AccountSet{ diff --git a/pkg/sdk/authentication_policies_def.go b/pkg/sdk/authentication_policies_def.go index 92665f4ab2..2d283c45dd 100644 --- a/pkg/sdk/authentication_policies_def.go +++ b/pkg/sdk/authentication_policies_def.go @@ -4,11 +4,66 @@ import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/gen //go:generate go run ./poc/main.go +type AuthenticationMethodsOption string + +const ( + AuthenticationMethodsAll AuthenticationMethodsOption = "ALL" + AuthenticationMethodsSaml AuthenticationMethodsOption = "SAML" + AuthenticationMethodsPassword AuthenticationMethodsOption = "PASSWORD" + AuthenticationMethodsOauth AuthenticationMethodsOption = "OAUTH" + AuthenticationMethodsKeyPair AuthenticationMethodsOption = "KEYPAIR" +) + +var AllAuthenticationMethods = []AuthenticationMethodsOption{ + AuthenticationMethodsAll, + AuthenticationMethodsSaml, + AuthenticationMethodsPassword, + AuthenticationMethodsOauth, + AuthenticationMethodsKeyPair, +} + +type MfaAuthenticationMethodsOption string + +const ( + MfaAuthenticationMethodsAll MfaAuthenticationMethodsOption = "ALL" + MfaAuthenticationMethodsSaml MfaAuthenticationMethodsOption = "SAML" + MfaAuthenticationMethodsPassword MfaAuthenticationMethodsOption = "PASSWORD" +) + +var AllMfaAuthenticationMethods = []MfaAuthenticationMethodsOption{ + MfaAuthenticationMethodsAll, + MfaAuthenticationMethodsSaml, + MfaAuthenticationMethodsPassword, +} + +type MfaEnrollmentOption string + +const ( + MfaEnrollmentRequired MfaEnrollmentOption = "REQUIRED" + MfaEnrollmentOptional MfaEnrollmentOption = "OPTIONAL" +) + +type ClientTypesOption string + +const ( + ClientTypesAll ClientTypesOption = "ALL" + ClientTypesSnowflakeUi ClientTypesOption = "SNOWFLAKE_UI" + ClientTypesDrivers ClientTypesOption = "DRIVERS" + ClientTypesSnowSql ClientTypesOption = "SNOWSQL" +) + +var AllClientTypes = []ClientTypesOption{ + ClientTypesAll, + ClientTypesSnowflakeUi, + ClientTypesDrivers, + ClientTypesSnowSql, +} + var ( - AuthenticationMethodsOptionDef = g.NewQueryStruct("AuthenticationMethods").Text("Method", g.KeywordOptions().SingleQuotes()) - MfaAuthenticationMethodsOptionDef = g.NewQueryStruct("MfaAuthenticationMethods").Text("Method", g.KeywordOptions().SingleQuotes()) - ClientTypesOptionDef = g.NewQueryStruct("ClientTypes").Text("ClientType", g.KeywordOptions().SingleQuotes()) - SecurityIntegrationsOptionDef = g.NewQueryStruct("SecurityIntegrationsOption").Text("Name", g.KeywordOptions().SingleQuotes()) + AuthenticationMethodsOptionDef = g.NewQueryStruct("AuthenticationMethods").PredefinedQueryStructField("Method", g.KindOfT[AuthenticationMethodsOption](), g.KeywordOptions().SingleQuotes().Required()) + MfaAuthenticationMethodsOptionDef = g.NewQueryStruct("MfaAuthenticationMethods").PredefinedQueryStructField("Method", g.KindOfT[MfaAuthenticationMethods](), g.KeywordOptions().SingleQuotes().Required()) + ClientTypesOptionDef = g.NewQueryStruct("ClientTypes").PredefinedQueryStructField("ClientType", g.KindOfT[ClientTypesOption](), g.KeywordOptions().SingleQuotes().Required()) + SecurityIntegrationsOptionDef = g.NewQueryStruct("SecurityIntegrationsOption").Identifier("Name", g.KindOfT[AccountObjectIdentifier](), g.IdentifierOptions().Required()) ) var AuthenticationPoliciesDef = g.NewInterface( @@ -22,14 +77,16 @@ var AuthenticationPoliciesDef = g.NewInterface( Create(). OrReplace(). SQL("AUTHENTICATION POLICY"). + IfNotExists(). Name(). ListAssignment("AUTHENTICATION_METHODS", "AuthenticationMethods", g.ParameterOptions().Parentheses()). ListAssignment("MFA_AUTHENTICATION_METHODS", "MfaAuthenticationMethods", g.ParameterOptions().Parentheses()). - OptionalTextAssignment("MFA_ENROLLMENT", g.ParameterOptions()). + PredefinedQueryStructField("MfaEnrollment", g.KindOfTPointer[MfaEnrollmentOption](), g.ParameterOptions().SQL("MFA_ENROLLMENT")). ListAssignment("CLIENT_TYPES", "ClientTypes", g.ParameterOptions().Parentheses()). ListAssignment("SECURITY_INTEGRATIONS", "SecurityIntegrationsOption", g.ParameterOptions().Parentheses()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). - WithValidation(g.ValidIdentifier, "name"), + WithValidation(g.ValidIdentifier, "name"). + WithValidation(g.ConflictingFields, "IfNotExists", "OrReplace"), AuthenticationMethodsOptionDef, MfaAuthenticationMethodsOptionDef, ClientTypesOptionDef, @@ -47,7 +104,7 @@ var AuthenticationPoliciesDef = g.NewInterface( g.NewQueryStruct("AuthenticationPolicySet"). ListAssignment("AUTHENTICATION_METHODS", "AuthenticationMethods", g.ParameterOptions().Parentheses()). ListAssignment("MFA_AUTHENTICATION_METHODS", "MfaAuthenticationMethods", g.ParameterOptions().Parentheses()). - OptionalTextAssignment("MFA_ENROLLMENT", g.ParameterOptions().SingleQuotes()). + PredefinedQueryStructField("MfaEnrollment", g.KindOfTPointer[MfaEnrollmentOption](), g.ParameterOptions().SQL("MFA_ENROLLMENT")). ListAssignment("CLIENT_TYPES", "ClientTypes", g.ParameterOptions().Parentheses()). ListAssignment("SECURITY_INTEGRATIONS", "SecurityIntegrationsOption", g.ParameterOptions().Parentheses()). OptionalTextAssignment("COMMENT", g.ParameterOptions().SingleQuotes()). @@ -113,11 +170,15 @@ var AuthenticationPoliciesDef = g.NewInterface( g.DescriptionMappingKindSlice, "https://docs.snowflake.com/en/sql-reference/sql/desc-authentication-policy", g.DbStruct("describeAuthenticationPolicyDBRow"). - Field("property", "string"). - Field("value", "string"), + Text("property"). + Text("value"). + Text("default"). + Text("description"), g.PlainStruct("AuthenticationPolicyDescription"). - Field("Property", "string"). - Field("Value", "string"), + Text("Property"). + Text("Value"). + Text("Default"). + Text("Description"), g.NewQueryStruct("DescribeAuthenticationPolicy"). Describe(). SQL("AUTHENTICATION POLICY"). diff --git a/pkg/sdk/authentication_policies_dto_builders_gen.go b/pkg/sdk/authentication_policies_dto_builders_gen.go index 7a5cda7882..18738d4717 100644 --- a/pkg/sdk/authentication_policies_dto_builders_gen.go +++ b/pkg/sdk/authentication_policies_dto_builders_gen.go @@ -17,6 +17,11 @@ func (s *CreateAuthenticationPolicyRequest) WithOrReplace(OrReplace bool) *Creat return s } +func (s *CreateAuthenticationPolicyRequest) WithIfNotExists(IfNotExists bool) *CreateAuthenticationPolicyRequest { + s.IfNotExists = &IfNotExists + return s +} + func (s *CreateAuthenticationPolicyRequest) WithAuthenticationMethods(AuthenticationMethods []AuthenticationMethods) *CreateAuthenticationPolicyRequest { s.AuthenticationMethods = AuthenticationMethods return s @@ -27,7 +32,7 @@ func (s *CreateAuthenticationPolicyRequest) WithMfaAuthenticationMethods(MfaAuth return s } -func (s *CreateAuthenticationPolicyRequest) WithMfaEnrollment(MfaEnrollment string) *CreateAuthenticationPolicyRequest { +func (s *CreateAuthenticationPolicyRequest) WithMfaEnrollment(MfaEnrollment MfaEnrollmentOption) *CreateAuthenticationPolicyRequest { s.MfaEnrollment = &MfaEnrollment return s } @@ -89,7 +94,7 @@ func (s *AuthenticationPolicySetRequest) WithMfaAuthenticationMethods(MfaAuthent return s } -func (s *AuthenticationPolicySetRequest) WithMfaEnrollment(MfaEnrollment string) *AuthenticationPolicySetRequest { +func (s *AuthenticationPolicySetRequest) WithMfaEnrollment(MfaEnrollment MfaEnrollmentOption) *AuthenticationPolicySetRequest { s.MfaEnrollment = &MfaEnrollment return s } diff --git a/pkg/sdk/authentication_policies_dto_gen.go b/pkg/sdk/authentication_policies_dto_gen.go index f15e9c251a..bf2e579b7d 100644 --- a/pkg/sdk/authentication_policies_dto_gen.go +++ b/pkg/sdk/authentication_policies_dto_gen.go @@ -12,10 +12,11 @@ var ( type CreateAuthenticationPolicyRequest struct { OrReplace *bool + IfNotExists *bool name SchemaObjectIdentifier // required AuthenticationMethods []AuthenticationMethods MfaAuthenticationMethods []MfaAuthenticationMethods - MfaEnrollment *string + MfaEnrollment *MfaEnrollmentOption ClientTypes []ClientTypes SecurityIntegrations []SecurityIntegrationsOption Comment *string @@ -32,7 +33,7 @@ type AlterAuthenticationPolicyRequest struct { type AuthenticationPolicySetRequest struct { AuthenticationMethods []AuthenticationMethods MfaAuthenticationMethods []MfaAuthenticationMethods - MfaEnrollment *string + MfaEnrollment *MfaEnrollmentOption ClientTypes []ClientTypes SecurityIntegrations []SecurityIntegrationsOption Comment *string diff --git a/pkg/sdk/authentication_policies_gen.go b/pkg/sdk/authentication_policies_gen.go index e9a12ea297..f67c041f27 100644 --- a/pkg/sdk/authentication_policies_gen.go +++ b/pkg/sdk/authentication_policies_gen.go @@ -16,30 +16,30 @@ type CreateAuthenticationPolicyOptions struct { create bool `ddl:"static" sql:"CREATE"` OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` authenticationPolicy bool `ddl:"static" sql:"AUTHENTICATION POLICY"` + IfNotExists *bool `ddl:"keyword" sql:"IF NOT EXISTS"` name SchemaObjectIdentifier `ddl:"identifier"` AuthenticationMethods []AuthenticationMethods `ddl:"parameter,parentheses" sql:"AUTHENTICATION_METHODS"` MfaAuthenticationMethods []MfaAuthenticationMethods `ddl:"parameter,parentheses" sql:"MFA_AUTHENTICATION_METHODS"` - MfaEnrollment *string `ddl:"parameter" sql:"MFA_ENROLLMENT"` + MfaEnrollment *MfaEnrollmentOption `ddl:"parameter" sql:"MFA_ENROLLMENT"` ClientTypes []ClientTypes `ddl:"parameter,parentheses" sql:"CLIENT_TYPES"` SecurityIntegrations []SecurityIntegrationsOption `ddl:"parameter,parentheses" sql:"SECURITY_INTEGRATIONS"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` } -func (r *CreateAuthenticationPolicyRequest) GetName() SchemaObjectIdentifier { - return r.name -} - type AuthenticationMethods struct { - Method string `ddl:"keyword,single_quotes"` + Method AuthenticationMethodsOption `ddl:"keyword,single_quotes"` } + type MfaAuthenticationMethods struct { - Method string `ddl:"keyword,single_quotes"` + Method MfaAuthenticationMethodsOption `ddl:"keyword,single_quotes"` } + type ClientTypes struct { - ClientType string `ddl:"keyword,single_quotes"` + ClientType ClientTypesOption `ddl:"keyword,single_quotes"` } + type SecurityIntegrationsOption struct { - Name string `ddl:"keyword,single_quotes"` + Name AccountObjectIdentifier `ddl:"identifier"` } // AlterAuthenticationPolicyOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-authentication-policy. @@ -52,14 +52,16 @@ type AlterAuthenticationPolicyOptions struct { Unset *AuthenticationPolicyUnset `ddl:"list,no_parentheses" sql:"UNSET"` RenameTo *SchemaObjectIdentifier `ddl:"identifier" sql:"RENAME TO"` } + type AuthenticationPolicySet struct { AuthenticationMethods []AuthenticationMethods `ddl:"parameter,parentheses" sql:"AUTHENTICATION_METHODS"` MfaAuthenticationMethods []MfaAuthenticationMethods `ddl:"parameter,parentheses" sql:"MFA_AUTHENTICATION_METHODS"` - MfaEnrollment *string `ddl:"parameter,single_quotes" sql:"MFA_ENROLLMENT"` + MfaEnrollment *MfaEnrollmentOption `ddl:"parameter" sql:"MFA_ENROLLMENT"` ClientTypes []ClientTypes `ddl:"parameter,parentheses" sql:"CLIENT_TYPES"` SecurityIntegrations []SecurityIntegrationsOption `ddl:"parameter,parentheses" sql:"SECURITY_INTEGRATIONS"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` } + type AuthenticationPolicyUnset struct { ClientTypes *bool `ddl:"keyword" sql:"CLIENT_TYPES"` AuthenticationMethods *bool `ddl:"keyword" sql:"AUTHENTICATION_METHODS"` @@ -86,6 +88,7 @@ type ShowAuthenticationPolicyOptions struct { StartsWith *string `ddl:"parameter,single_quotes,no_equals" sql:"STARTS WITH"` Limit *LimitFrom `ddl:"keyword" sql:"LIMIT"` } + type showAuthenticationPolicyDBRow struct { CreatedOn string `db:"created_on"` Name string `db:"name"` @@ -96,6 +99,7 @@ type showAuthenticationPolicyDBRow struct { OwnerRoleType string `db:"owner_role_type"` Options string `db:"options"` } + type AuthenticationPolicy struct { CreatedOn string Name string @@ -107,21 +111,27 @@ type AuthenticationPolicy struct { Options string } +func (v *AuthenticationPolicy) ID() SchemaObjectIdentifier { + return NewSchemaObjectIdentifier(v.DatabaseName, v.SchemaName, v.Name) +} + // DescribeAuthenticationPolicyOptions is based on https://docs.snowflake.com/en/sql-reference/sql/desc-authentication-policy. type DescribeAuthenticationPolicyOptions struct { describe bool `ddl:"static" sql:"DESCRIBE"` authenticationPolicy bool `ddl:"static" sql:"AUTHENTICATION POLICY"` name SchemaObjectIdentifier `ddl:"identifier"` } + type describeAuthenticationPolicyDBRow struct { - Property string `db:"property"` - Value string `db:"value"` -} -type AuthenticationPolicyDescription struct { - Property string - Value string + Property string `db:"property"` + Value string `db:"value"` + Default string `db:"default"` + Description string `db:"description"` } -func (v *AuthenticationPolicy) ID() SchemaObjectIdentifier { - return NewSchemaObjectIdentifier(v.DatabaseName, v.SchemaName, v.Name) +type AuthenticationPolicyDescription struct { + Property string + Value string + Default string + Description string } diff --git a/pkg/sdk/authentication_policies_gen_test.go b/pkg/sdk/authentication_policies_gen_test.go index 135936d223..9e69a780af 100644 --- a/pkg/sdk/authentication_policies_gen_test.go +++ b/pkg/sdk/authentication_policies_gen_test.go @@ -15,15 +15,25 @@ func TestAuthenticationPolicies_Create(t *testing.T) { var opts *CreateAuthenticationPolicyOptions = nil assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) }) + t.Run("validation: conflicting fields for [opts.IfNotExists opts.OrReplace]", func(t *testing.T) { + opts := defaultOpts() + opts.IfNotExists = Bool(true) + opts.OrReplace = Bool(true) + assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateAuthenticationPolicyOptions", "IfNotExists", "OrReplace")) + }) + t.Run("basic", func(t *testing.T) { opts := defaultOpts() - opts.AuthenticationMethods = []AuthenticationMethods{{Method: "ALL"}} + opts.AuthenticationMethods = []AuthenticationMethods{ + {Method: AuthenticationMethodsAll}, + } opts.Comment = String("some comment") assertOptsValidAndSQLEquals(t, opts, "CREATE AUTHENTICATION POLICY %s AUTHENTICATION_METHODS = ('ALL') COMMENT = 'some comment'", id.FullyQualifiedName()) }) @@ -31,13 +41,23 @@ func TestAuthenticationPolicies_Create(t *testing.T) { t.Run("all options", func(t *testing.T) { opts := defaultOpts() opts.OrReplace = Bool(true) - opts.AuthenticationMethods = []AuthenticationMethods{{Method: "SAML"}, {Method: "PASSWORD"}} - opts.MfaAuthenticationMethods = []MfaAuthenticationMethods{{Method: "PASSWORD"}} - opts.MfaEnrollment = String("OPTIONAL") - opts.ClientTypes = []ClientTypes{{ClientType: "DRIVERS"}, {ClientType: "SNOWSQL"}} - opts.SecurityIntegrations = []SecurityIntegrationsOption{{Name: "security_integration"}} + opts.AuthenticationMethods = []AuthenticationMethods{ + {Method: AuthenticationMethodsSaml}, + {Method: AuthenticationMethodsPassword}, + } + opts.MfaAuthenticationMethods = []MfaAuthenticationMethods{ + {Method: MfaAuthenticationMethodsPassword}, + } + opts.MfaEnrollment = Pointer(MfaEnrollmentOptional) + opts.ClientTypes = []ClientTypes{ + {ClientType: ClientTypesDrivers}, + {ClientType: ClientTypesSnowSql}, + } + opts.SecurityIntegrations = []SecurityIntegrationsOption{ + {Name: NewAccountObjectIdentifier("security_integration")}, + } opts.Comment = String("some comment") - assertOptsValidAndSQLEquals(t, opts, "CREATE OR REPLACE AUTHENTICATION POLICY %s AUTHENTICATION_METHODS = ('SAML', 'PASSWORD') MFA_AUTHENTICATION_METHODS = ('PASSWORD') MFA_ENROLLMENT = OPTIONAL CLIENT_TYPES = ('DRIVERS', 'SNOWSQL') SECURITY_INTEGRATIONS = ('security_integration') COMMENT = 'some comment'", id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, "CREATE OR REPLACE AUTHENTICATION POLICY %s AUTHENTICATION_METHODS = ('SAML', 'PASSWORD') MFA_AUTHENTICATION_METHODS = ('PASSWORD') MFA_ENROLLMENT = OPTIONAL CLIENT_TYPES = ('DRIVERS', 'SNOWSQL') SECURITY_INTEGRATIONS = (\"security_integration\") COMMENT = 'some comment'", id.FullyQualifiedName()) }) } @@ -54,6 +74,7 @@ func TestAuthenticationPolicies_Alter(t *testing.T) { var opts *AlterAuthenticationPolicyOptions = nil assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier @@ -86,7 +107,9 @@ func TestAuthenticationPolicies_Alter(t *testing.T) { t.Run("alter: set basic", func(t *testing.T) { opts := defaultOpts() opts.Set = &AuthenticationPolicySet{ - AuthenticationMethods: []AuthenticationMethods{{Method: "SAML"}}, + AuthenticationMethods: []AuthenticationMethods{ + {Method: AuthenticationMethodsSaml}, + }, } assertOptsValidAndSQLEquals(t, opts, "ALTER AUTHENTICATION POLICY %s SET AUTHENTICATION_METHODS = ('SAML')", id.FullyQualifiedName()) }) @@ -95,14 +118,21 @@ func TestAuthenticationPolicies_Alter(t *testing.T) { opts := defaultOpts() opts.IfExists = Bool(true) opts.Set = &AuthenticationPolicySet{ - AuthenticationMethods: []AuthenticationMethods{{Method: "SAML"}}, - MfaAuthenticationMethods: []MfaAuthenticationMethods{{Method: "PASSWORD"}}, - MfaEnrollment: String("OPTIONAL"), - ClientTypes: []ClientTypes{{ClientType: "DRIVERS"}, {ClientType: "SNOWSQL"}}, - SecurityIntegrations: []SecurityIntegrationsOption{{Name: "security_integration"}}, - Comment: String("some comment"), + AuthenticationMethods: []AuthenticationMethods{ + {Method: AuthenticationMethodsSaml}, + }, + MfaAuthenticationMethods: []MfaAuthenticationMethods{ + {Method: MfaAuthenticationMethodsPassword}, + }, + MfaEnrollment: Pointer(MfaEnrollmentOptional), + ClientTypes: []ClientTypes{ + {ClientType: ClientTypesDrivers}, + {ClientType: ClientTypesSnowSql}, + }, + SecurityIntegrations: []SecurityIntegrationsOption{{Name: NewAccountObjectIdentifier("security_integration")}}, + Comment: String("some comment"), } - assertOptsValidAndSQLEquals(t, opts, "ALTER AUTHENTICATION POLICY IF EXISTS %s SET AUTHENTICATION_METHODS = ('SAML') MFA_AUTHENTICATION_METHODS = ('PASSWORD') MFA_ENROLLMENT = 'OPTIONAL' CLIENT_TYPES = ('DRIVERS', 'SNOWSQL') SECURITY_INTEGRATIONS = ('security_integration') COMMENT = 'some comment'", id.FullyQualifiedName()) + assertOptsValidAndSQLEquals(t, opts, "ALTER AUTHENTICATION POLICY IF EXISTS %s SET AUTHENTICATION_METHODS = ('SAML') MFA_AUTHENTICATION_METHODS = ('PASSWORD') MFA_ENROLLMENT = OPTIONAL CLIENT_TYPES = ('DRIVERS', 'SNOWSQL') SECURITY_INTEGRATIONS = (\"security_integration\") COMMENT = 'some comment'", id.FullyQualifiedName()) }) t.Run("alter: unset basic", func(t *testing.T) { @@ -162,6 +192,7 @@ func TestAuthenticationPolicies_Drop(t *testing.T) { } func TestAuthenticationPolicies_Show(t *testing.T) { + id := randomSchemaObjectIdentifier() // Minimal valid ShowAuthenticationPolicyOptions defaultOpts := func() *ShowAuthenticationPolicyOptions { return &ShowAuthenticationPolicyOptions{} @@ -176,6 +207,22 @@ func TestAuthenticationPolicies_Show(t *testing.T) { opts := defaultOpts() assertOptsValidAndSQLEquals(t, opts, "SHOW AUTHENTICATION POLICIES") }) + + t.Run("complete", func(t *testing.T) { + opts := defaultOpts() + opts.Like = &Like{ + Pattern: String("like-pattern"), + } + opts.StartsWith = String("starts-with-pattern") + opts.In = &In{ + Schema: id.SchemaId(), + } + opts.Limit = &LimitFrom{ + Rows: Int(10), + From: String("limit-from"), + } + assertOptsValidAndSQLEquals(t, opts, "SHOW AUTHENTICATION POLICIES LIKE 'like-pattern' IN SCHEMA %s STARTS WITH 'starts-with-pattern' LIMIT 10 FROM 'limit-from'", id.SchemaId().FullyQualifiedName()) + }) } func TestAuthenticationPolicies_Describe(t *testing.T) { @@ -191,6 +238,7 @@ func TestAuthenticationPolicies_Describe(t *testing.T) { var opts *DescribeAuthenticationPolicyOptions = nil assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) }) + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { opts := defaultOpts() opts.name = emptySchemaObjectIdentifier diff --git a/pkg/sdk/authentication_policies_impl_gen.go b/pkg/sdk/authentication_policies_impl_gen.go index 077033854c..5311be8ff0 100644 --- a/pkg/sdk/authentication_policies_impl_gen.go +++ b/pkg/sdk/authentication_policies_impl_gen.go @@ -38,7 +38,11 @@ func (v *authenticationPolicies) Show(ctx context.Context, request *ShowAuthenti } func (v *authenticationPolicies) ShowByID(ctx context.Context, id SchemaObjectIdentifier) (*AuthenticationPolicy, error) { - authenticationPolicies, err := v.Show(ctx, NewShowAuthenticationPolicyRequest()) + authenticationPolicies, err := v.Show(ctx, NewShowAuthenticationPolicyRequest().WithIn(In{ + Schema: id.SchemaId(), + }).WithLike(Like{ + Pattern: String(id.Name()), + })) if err != nil { return nil, err } @@ -59,6 +63,7 @@ func (v *authenticationPolicies) Describe(ctx context.Context, id SchemaObjectId func (r *CreateAuthenticationPolicyRequest) toOpts() *CreateAuthenticationPolicyOptions { opts := &CreateAuthenticationPolicyOptions{ OrReplace: r.OrReplace, + IfNotExists: r.IfNotExists, name: r.name, AuthenticationMethods: r.AuthenticationMethods, MfaAuthenticationMethods: r.MfaAuthenticationMethods, @@ -143,7 +148,9 @@ func (r *DescribeAuthenticationPolicyRequest) toOpts() *DescribeAuthenticationPo func (r describeAuthenticationPolicyDBRow) convert() *AuthenticationPolicyDescription { return &AuthenticationPolicyDescription{ - Property: r.Property, - Value: r.Value, + Property: r.Property, + Value: r.Value, + Default: r.Default, + Description: r.Description, } } diff --git a/pkg/sdk/authentication_policies_validations_gen.go b/pkg/sdk/authentication_policies_validations_gen.go index 74e87fdbcf..61012620dd 100644 --- a/pkg/sdk/authentication_policies_validations_gen.go +++ b/pkg/sdk/authentication_policies_validations_gen.go @@ -16,6 +16,9 @@ func (opts *CreateAuthenticationPolicyOptions) validate() error { if !ValidObjectIdentifier(opts.name) { errs = append(errs, ErrInvalidObjectIdentifier) } + if everyValueSet(opts.IfNotExists, opts.OrReplace) { + errs = append(errs, errOneOf("CreateAuthenticationPolicyOptions", "IfNotExists", "OrReplace")) + } return JoinErrors(errs...) } diff --git a/pkg/sdk/policy_references.go b/pkg/sdk/policy_references.go index 0a3d17299f..b82e6e3d40 100644 --- a/pkg/sdk/policy_references.go +++ b/pkg/sdk/policy_references.go @@ -71,11 +71,12 @@ type policyReferenceFunctionArguments struct { type PolicyKind string const ( - PolicyKindAggregationPolicy PolicyKind = "AGGREGATION_POLICY" - PolicyKindRowAccessPolicy PolicyKind = "ROW_ACCESS_POLICY" - PolicyKindPasswordPolicy PolicyKind = "PASSWORD_POLICY" - PolicyKindMaskingPolicy PolicyKind = "MASKING_POLICY" - PolicyKindProjectionPolicy PolicyKind = "PROJECTION_POLICY" + PolicyKindAggregationPolicy PolicyKind = "AGGREGATION_POLICY" + PolicyKindRowAccessPolicy PolicyKind = "ROW_ACCESS_POLICY" + PolicyKindPasswordPolicy PolicyKind = "PASSWORD_POLICY" + PolicyKindMaskingPolicy PolicyKind = "MASKING_POLICY" + PolicyKindProjectionPolicy PolicyKind = "PROJECTION_POLICY" + PolicyKindAuthenticationPolicy PolicyKind = "AUTHENTICATION_POLICY" ) type PolicyReference struct { diff --git a/pkg/sdk/testint/accounts_integration_test.go b/pkg/sdk/testint/accounts_integration_test.go index f41771fa4d..232465509c 100644 --- a/pkg/sdk/testint/accounts_integration_test.go +++ b/pkg/sdk/testint/accounts_integration_test.go @@ -269,7 +269,7 @@ func TestInt_AccountAlter(t *testing.T) { t.Run("set and unset authentication policy", func(t *testing.T) { t.Skipf("Skipping the test for now TODO: add ticket number") - authenticationPolicyTest, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.CreateAuthenticationPolicy(t) + authenticationPolicyTest, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.Create(t) t.Cleanup(authenticationPolicyCleanup) opts := &sdk.AlterAccountOptions{ Set: &sdk.AccountSet{ diff --git a/pkg/sdk/testint/authentication_policies_gen_integration_test.go b/pkg/sdk/testint/authentication_policies_gen_integration_test.go index 50d4e9cc3c..67cf9efd92 100644 --- a/pkg/sdk/testint/authentication_policies_gen_integration_test.go +++ b/pkg/sdk/testint/authentication_policies_gen_integration_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + assertions "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -14,331 +16,274 @@ import ( func TestInt_AuthenticationPolicies(t *testing.T) { client := testClient(t) ctx := testContext(t) - cert := random.GenerateX509(t) - assertAuthenticationPolicy := func(t *testing.T, authenticationPolicy *sdk.AuthenticationPolicy, id sdk.SchemaObjectIdentifier, expectedComment string) { + assertAuthenticationPolicy := func(t *testing.T, id sdk.SchemaObjectIdentifier, expectedComment string) { t.Helper() - assert.NotEmpty(t, authenticationPolicy.CreatedOn) - assert.Equal(t, id.Name(), authenticationPolicy.Name) - assert.Equal(t, id.SchemaName(), authenticationPolicy.SchemaName) - assert.Equal(t, id.DatabaseName(), authenticationPolicy.DatabaseName) - assert.Equal(t, "", authenticationPolicy.Options) - assert.Equal(t, "ACCOUNTADMIN", authenticationPolicy.Owner) - assert.Equal(t, expectedComment, authenticationPolicy.Comment) - assert.Equal(t, "ROLE", authenticationPolicy.OwnerRoleType) + assertions.AssertThat(t, + objectassert.AuthenticationPolicy(t, id). + HasCreatedOnNotEmpty(). + HasName(id.Name()). + HasDatabaseName(id.DatabaseName()). + HasSchemaName(id.SchemaName()). + HasOptions(""). + HasOwner("ACCOUNTADMIN"). + HasComment(expectedComment). + HasOwnerRoleType("ROLE"), + ) } - cleanupAuthenticationPolicyProvider := func(id sdk.SchemaObjectIdentifier) func() { - return func() { - err := client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(id).WithIfExists(true)) - require.NoError(t, err) - } - } - - cleanupSecurityIntegration := func(t *testing.T, id sdk.AccountObjectIdentifier) { + assertProperty := func(t *testing.T, descriptions []sdk.AuthenticationPolicyDescription, name string, value string) { t.Helper() - t.Cleanup(func() { - err := client.SecurityIntegrations.Drop(ctx, sdk.NewDropSecurityIntegrationRequest(id).WithIfExists(true)) - assert.NoError(t, err) + description, err := collections.FindFirst(descriptions, func(description sdk.AuthenticationPolicyDescription) bool { + return description.Property == name }) + require.NoError(t, err, fmt.Sprintf("unable to find property %s", name)) + assert.Equal(t, value, description.Value) } - createAuthenticationPolicy := func(t *testing.T) *sdk.AuthenticationPolicy { - t.Helper() - id := testClientHelper().Ids.RandomSchemaObjectIdentifier() - - err := client.AuthenticationPolicies.Create(ctx, sdk.NewCreateAuthenticationPolicyRequest(id)) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(id)) - - authenticationPolicy, err := client.AuthenticationPolicies.ShowByID(ctx, id) - require.NoError(t, err) - - return authenticationPolicy - } - - defaultCreateRequest := func() *sdk.CreateAuthenticationPolicyRequest { - id := testClientHelper().Ids.RandomSchemaObjectIdentifier() - comment := "some_comment" - return sdk.NewCreateAuthenticationPolicyRequest(id). - WithOrReplace(true). - WithComment(comment) - } - - createSAML2Integration := func(t *testing.T, with func(*sdk.CreateSaml2SecurityIntegrationRequest)) sdk.AccountObjectIdentifier { - t.Helper() - id := testClientHelper().Ids.RandomAccountObjectIdentifier() - issuer := testClientHelper().Ids.Alpha() - saml2Req := sdk.NewCreateSaml2SecurityIntegrationRequest(id, issuer, "https://example.com", sdk.Saml2SecurityIntegrationSaml2ProviderCustom, cert) - if with != nil { - with(saml2Req) - } - err := client.SecurityIntegrations.CreateSaml2(ctx, saml2Req) - require.NoError(t, err) - cleanupSecurityIntegration(t, id) - _, showErr := client.SecurityIntegrations.ShowByID(ctx, id) - require.NoError(t, showErr) - - return id - } - - t.Run("Create", func(t *testing.T) { + t.Run("Create - basic", func(t *testing.T) { id := testClientHelper().Ids.RandomSchemaObjectIdentifier() comment := random.Comment() - request := sdk.NewCreateAuthenticationPolicyRequest(id). - WithAuthenticationMethods([]sdk.AuthenticationMethods{{Method: "Password"}}). - WithComment(comment) - - err := client.AuthenticationPolicies.Create(ctx, request) + err := client.AuthenticationPolicies.Create(ctx, sdk.NewCreateAuthenticationPolicyRequest(id). + WithAuthenticationMethods([]sdk.AuthenticationMethods{ + {Method: sdk.AuthenticationMethodsPassword}, + }). + WithComment(comment)) require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(id)) + t.Cleanup(testClientHelper().AuthenticationPolicy.DropFunc(t, id)) - authenticationPolicy, err := client.AuthenticationPolicies.ShowByID(ctx, id) - - require.NoError(t, err) - assertAuthenticationPolicy(t, authenticationPolicy, id, comment) + assertAuthenticationPolicy(t, id, comment) }) - t.Run("Alter - set authentication methods", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithAuthenticationMethods([]sdk.AuthenticationMethods{{Method: "PASSWORD"}}))) - require.NoError(t, alterErr) - - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "AUTHENTICATION_METHODS", Value: "[PASSWORD]"}) - }) - - t.Run("Alter - set client types", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithClientTypes([]sdk.ClientTypes{{ClientType: "DRIVERS"}, {ClientType: "SNOWSQL"}}))) - require.NoError(t, alterErr) - - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "CLIENT_TYPES", Value: "[DRIVERS, SNOWSQL]"}) - }) - - t.Run("Alter - set security integrations", func(t *testing.T) { - secId := createSAML2Integration(t, func(r *sdk.CreateSaml2SecurityIntegrationRequest) { - r.WithEnabled(true) - }) - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithSecurityIntegrations([]sdk.SecurityIntegrationsOption{{Name: secId.Name()}}))) - require.NoError(t, alterErr) - - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "SECURITY_INTEGRATIONS", Value: fmt.Sprintf("[%s]", secId.Name())}) - }) - - t.Run("Alter - set mfa authentication methods", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithMfaAuthenticationMethods([]sdk.MfaAuthenticationMethods{{Method: "PASSWORD"}}))) - require.NoError(t, alterErr) - - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "MFA_AUTHENTICATION_METHODS", Value: "[PASSWORD]"}) - }) - - t.Run("Alter - set mfa enrollment", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithMfaEnrollment("REQUIRED"))) - require.NoError(t, alterErr) + t.Run("Create - complete", func(t *testing.T) { + id := testClientHelper().Ids.RandomSchemaObjectIdentifier() + saml2Id := testClientHelper().Ids.RandomAccountObjectIdentifier() + comment := random.Comment() - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "MFA_ENROLLMENT", Value: "REQUIRED"}) + _, cleanupSamlIntegration := testClientHelper().SecurityIntegration.CreateSaml2(t, saml2Id) + t.Cleanup(cleanupSamlIntegration) + + err := client.AuthenticationPolicies.Create(ctx, sdk.NewCreateAuthenticationPolicyRequest(id). + WithComment(comment). + WithMfaEnrollment(sdk.MfaEnrollmentOptional). + WithMfaAuthenticationMethods([]sdk.MfaAuthenticationMethods{ + {Method: sdk.MfaAuthenticationMethodsPassword}, + {Method: sdk.MfaAuthenticationMethodsSaml}, + }). + WithSecurityIntegrations([]sdk.SecurityIntegrationsOption{ + {Name: saml2Id}, + }). + WithClientTypes([]sdk.ClientTypes{ + {ClientType: sdk.ClientTypesDrivers}, + {ClientType: sdk.ClientTypesSnowSql}, + }). + WithAuthenticationMethods([]sdk.AuthenticationMethods{ + {Method: sdk.AuthenticationMethodsPassword}, + {Method: sdk.AuthenticationMethodsSaml}, + })) + require.NoError(t, err) + t.Cleanup(testClientHelper().AuthenticationPolicy.DropFunc(t, id)) + + assertAuthenticationPolicy(t, id, comment) + + desc, err := client.AuthenticationPolicies.Describe(ctx, id) + require.NoError(t, err) + + assertProperty(t, desc, "COMMENT", comment) + assertProperty(t, desc, "MFA_ENROLLMENT", "OPTIONAL") + assertProperty(t, desc, "MFA_AUTHENTICATION_METHODS", "[PASSWORD, SAML]") + assertProperty(t, desc, "SECURITY_INTEGRATIONS", fmt.Sprintf("[%s]", saml2Id.Name())) + assertProperty(t, desc, "CLIENT_TYPES", "[DRIVERS, SNOWSQL]") + assertProperty(t, desc, "AUTHENTICATION_METHODS", "[PASSWORD, SAML]") }) - t.Run("Alter - set comment", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithSet(*sdk.NewAuthenticationPolicySetRequest().WithComment("new comment"))) - require.NoError(t, alterErr) + t.Run("Alter - set and unset properties", func(t *testing.T) { + saml2Id := testClientHelper().Ids.RandomAccountObjectIdentifier() + comment := random.Comment() - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "COMMENT", Value: "new comment"}) + authenticationPolicy, cleanupAuthPolicy := testClientHelper().AuthenticationPolicy.Create(t) + t.Cleanup(cleanupAuthPolicy) + + _, cleanupSamlIntegration := testClientHelper().SecurityIntegration.CreateSaml2(t, saml2Id) + t.Cleanup(cleanupSamlIntegration) + + err := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(authenticationPolicy.ID()). + WithSet(*sdk.NewAuthenticationPolicySetRequest(). + WithComment(comment). + WithMfaEnrollment(sdk.MfaEnrollmentRequired). + WithMfaAuthenticationMethods([]sdk.MfaAuthenticationMethods{ + {Method: sdk.MfaAuthenticationMethodsPassword}, + {Method: sdk.MfaAuthenticationMethodsSaml}, + }). + WithSecurityIntegrations([]sdk.SecurityIntegrationsOption{ + {Name: saml2Id}, + }). + WithClientTypes([]sdk.ClientTypes{ + {ClientType: sdk.ClientTypesDrivers}, + {ClientType: sdk.ClientTypesSnowSql}, + {ClientType: sdk.ClientTypesSnowflakeUi}, + }). + WithAuthenticationMethods([]sdk.AuthenticationMethods{ + {Method: sdk.AuthenticationMethodsPassword}, + {Method: sdk.AuthenticationMethodsSaml}, + }))) + require.NoError(t, err) + + desc, err := client.AuthenticationPolicies.Describe(ctx, authenticationPolicy.ID()) + require.NoError(t, err) + + assertProperty(t, desc, "COMMENT", comment) + assertProperty(t, desc, "MFA_ENROLLMENT", "REQUIRED") + assertProperty(t, desc, "MFA_AUTHENTICATION_METHODS", "[PASSWORD, SAML]") + assertProperty(t, desc, "SECURITY_INTEGRATIONS", fmt.Sprintf("[%s]", saml2Id.Name())) + assertProperty(t, desc, "CLIENT_TYPES", "[DRIVERS, SNOWSQL, SNOWFLAKE_UI]") + assertProperty(t, desc, "AUTHENTICATION_METHODS", "[PASSWORD, SAML]") + + err = client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(authenticationPolicy.ID()). + WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest(). + WithComment(true). + WithMfaEnrollment(true). + WithMfaAuthenticationMethods(true). + WithSecurityIntegrations(true). + WithClientTypes(true). + WithAuthenticationMethods(true))) + require.NoError(t, err) + + desc, err = client.AuthenticationPolicies.Describe(ctx, authenticationPolicy.ID()) + require.NoError(t, err) + + assertProperty(t, desc, "COMMENT", "null") + assertProperty(t, desc, "MFA_ENROLLMENT", "OPTIONAL") + assertProperty(t, desc, "MFA_AUTHENTICATION_METHODS", "[PASSWORD, SAML]") + assertProperty(t, desc, "SECURITY_INTEGRATIONS", "[ALL]") + assertProperty(t, desc, "CLIENT_TYPES", "[ALL]") + assertProperty(t, desc, "AUTHENTICATION_METHODS", "[ALL]") }) - t.Run("Alter - unset authentication methods", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithAuthenticationMethods(true))) - require.NoError(t, alterErr) + t.Run("Alter - rename", func(t *testing.T) { + newId := testClientHelper().Ids.RandomSchemaObjectIdentifier() - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "AUTHENTICATION_METHODS", Value: "[ALL]"}) - }) + authenticationPolicy, cleanupAuthPolicy := testClientHelper().AuthenticationPolicy.Create(t) + t.Cleanup(cleanupAuthPolicy) + t.Cleanup(testClientHelper().AuthenticationPolicy.DropFunc(t, newId)) - t.Run("Alter - unset client types", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) + err := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(authenticationPolicy.ID()).WithRenameTo(newId)) require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithClientTypes(true))) - require.NoError(t, alterErr) + _, err = client.AuthenticationPolicies.Describe(ctx, authenticationPolicy.ID()) + assert.ErrorIs(t, err, sdk.ErrObjectNotExistOrAuthorized) - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "CLIENT_TYPES", Value: "[ALL]"}) + _, err = client.AuthenticationPolicies.Describe(ctx, newId) + assert.NoError(t, err) }) - t.Run("Alter - unset security integrations", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithSecurityIntegrations(true))) - require.NoError(t, alterErr) + t.Run("Drop - existing", func(t *testing.T) { + id := testClientHelper().Ids.RandomSchemaObjectIdentifier() - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) + err := client.AuthenticationPolicies.Create(ctx, sdk.NewCreateAuthenticationPolicyRequest(id)) require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "SECURITY_INTEGRATIONS", Value: "[ALL]"}) - }) - t.Run("Alter - unset mfa authentication methods", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) + err = client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(id)) require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithMfaAuthenticationMethods(true))) - require.NoError(t, alterErr) - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "MFA_AUTHENTICATION_METHODS", Value: "[PASSWORD, SAML]"}) + _, err = client.AuthenticationPolicies.ShowByID(ctx, id) + assert.ErrorIs(t, err, collections.ErrObjectNotFound) }) - t.Run("Alter - unset mfa enrollment", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithMfaEnrollment(true))) - require.NoError(t, alterErr) - - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "MFA_ENROLLMENT", Value: "OPTIONAL"}) + t.Run("Drop - non-existing", func(t *testing.T) { + err := client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(NonExistingSchemaObjectIdentifier)) + assert.ErrorIs(t, err, sdk.ErrObjectNotExistOrAuthorized) }) - t.Run("Alter - unset comment", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) - - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithUnset(*sdk.NewAuthenticationPolicyUnsetRequest().WithComment(true))) - require.NoError(t, alterErr) + t.Run("Show", func(t *testing.T) { + db, dbCleanup := testClientHelper().Database.CreateDatabase(t) + t.Cleanup(dbCleanup) - desc, err := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - require.NoError(t, err) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "COMMENT", Value: "null"}) - }) + id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithPrefix("test_auth_policyzzz") + id2 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithPrefix("test_auth_policy_2_") + id3 := testClientHelper().Ids.RandomSchemaObjectIdentifierWithPrefix("test_auth_policy_3_") + id4 := testClientHelper().Ids.RandomSchemaObjectIdentifierInSchema(sdk.NewDatabaseObjectIdentifier(db.Name, "PUBLIC")) - t.Run("Alter - rename", func(t *testing.T) { - req := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, req) - require.NoError(t, err) - t.Cleanup(cleanupAuthenticationPolicyProvider(req.GetName())) + _, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.CreateWithOptions(t, id, sdk.NewCreateAuthenticationPolicyRequest(id)) + t.Cleanup(authenticationPolicyCleanup) - newId := testClientHelper().Ids.RandomSchemaObjectIdentifier() - t.Cleanup(cleanupAuthenticationPolicyProvider(newId)) - alterErr := client.AuthenticationPolicies.Alter(ctx, sdk.NewAlterAuthenticationPolicyRequest(req.GetName()). - WithRenameTo(newId)) - require.NoError(t, alterErr) + _, authenticationPolicyCleanup2 := testClientHelper().AuthenticationPolicy.CreateWithOptions(t, id2, sdk.NewCreateAuthenticationPolicyRequest(id2)) + t.Cleanup(authenticationPolicyCleanup2) - _, descErr := client.AuthenticationPolicies.Describe(ctx, req.GetName()) - assert.ErrorIs(t, descErr, sdk.ErrObjectNotExistOrAuthorized) - }) + _, authenticationPolicyCleanup3 := testClientHelper().AuthenticationPolicy.CreateWithOptions(t, id3, sdk.NewCreateAuthenticationPolicyRequest(id3)) + t.Cleanup(authenticationPolicyCleanup3) - t.Run("Drop: existing", func(t *testing.T) { - id := testClientHelper().Ids.RandomSchemaObjectIdentifier() + _, authenticationPolicyCleanup4 := testClientHelper().AuthenticationPolicy.CreateWithOptions(t, id4, sdk.NewCreateAuthenticationPolicyRequest(id4)) + t.Cleanup(authenticationPolicyCleanup4) - err := client.AuthenticationPolicies.Create(ctx, sdk.NewCreateAuthenticationPolicyRequest(id)) - require.NoError(t, err) + t.Run("like", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest(). + WithLike(sdk.Like{Pattern: sdk.String("test_auth_policy_2_%")}). + WithIn(sdk.In{Schema: id.SchemaId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 1) + }) - err = client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(id)) - require.NoError(t, err) + // TODO(SNOW-1663343): starts_with doesn't work (returns all) + t.Run("starts_with", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest(). + WithStartsWith("test_auth_policy_"). + WithIn(sdk.In{Schema: id.SchemaId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 3) + }) - _, err = client.AuthenticationPolicies.ShowByID(ctx, id) - assert.ErrorIs(t, err, collections.ErrObjectNotFound) - }) + t.Run("in_account", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest().WithIn(sdk.In{Account: sdk.Bool(true)})) + require.NoError(t, err) + assert.Greater(t, len(authenticationPolicies), 3) + }) - t.Run("Drop: non-existing", func(t *testing.T) { - err := client.AuthenticationPolicies.Drop(ctx, sdk.NewDropAuthenticationPolicyRequest(NonExistingSchemaObjectIdentifier)) - assert.ErrorIs(t, err, sdk.ErrObjectNotExistOrAuthorized) - }) + t.Run("in_database", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest().WithIn(sdk.In{Database: id.DatabaseId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 3) + }) - t.Run("Show", func(t *testing.T) { - authenticationPolicy1 := createAuthenticationPolicy(t) - authenticationPolicy2 := createAuthenticationPolicy(t) + t.Run("in_schema", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest().WithIn(sdk.In{Schema: id.SchemaId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 3) + }) - showRequest := sdk.NewShowAuthenticationPolicyRequest() - returnedAuthenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, showRequest) - require.NoError(t, err) + t.Run("limit", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest(). + WithLimit(sdk.LimitFrom{Rows: sdk.Int(1)}). + WithIn(sdk.In{Schema: id.SchemaId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 1) + }) - assert.LessOrEqual(t, 2, len(returnedAuthenticationPolicies)) - assert.Contains(t, returnedAuthenticationPolicies, *authenticationPolicy1) - assert.Contains(t, returnedAuthenticationPolicies, *authenticationPolicy2) + // TODO(SNOW-1663343): limit from doesn't work (should return 0 elements because alphabetically test_auth_policyzzz is last in the output) + t.Run("limit from", func(t *testing.T) { + authenticationPolicies, err := client.AuthenticationPolicies.Show(ctx, sdk.NewShowAuthenticationPolicyRequest(). + WithLimit(sdk.LimitFrom{Rows: sdk.Int(2), From: sdk.String(id.Name())}). + WithIn(sdk.In{Schema: id.SchemaId()})) + require.NoError(t, err) + assert.Len(t, authenticationPolicies, 2) + }) }) t.Run("Describe", func(t *testing.T) { - request := defaultCreateRequest() - err := client.AuthenticationPolicies.Create(ctx, request) - require.NoError(t, err) + id := testClientHelper().Ids.RandomSchemaObjectIdentifier() + authenticationPolicy, cleanupAuthPolicy := testClientHelper().AuthenticationPolicy.CreateWithOptions(t, id, sdk.NewCreateAuthenticationPolicyRequest(id).WithComment("some_comment")) + t.Cleanup(cleanupAuthPolicy) - desc, err := client.AuthenticationPolicies.Describe(ctx, request.GetName()) + desc, err := client.AuthenticationPolicies.Describe(ctx, authenticationPolicy.ID()) require.NoError(t, err) - assert.Equal(t, 8, len(desc)) - assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{Property: "COMMENT", Value: "some_comment"}) + assert.GreaterOrEqual(t, 8, len(desc)) + assert.Contains(t, desc, sdk.AuthenticationPolicyDescription{ + Property: "COMMENT", + Value: "some_comment", + Default: "null", + Description: "Comment associated with authentication policy.", + }) }) } diff --git a/pkg/sdk/testint/users_integration_test.go b/pkg/sdk/testint/users_integration_test.go index 115bffe084..ea5388c341 100644 --- a/pkg/sdk/testint/users_integration_test.go +++ b/pkg/sdk/testint/users_integration_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + assertions "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/objectassert" @@ -47,46 +49,6 @@ func TestInt_Users(t *testing.T) { tag2, tag2Cleanup := testClientHelper().Tag.CreateTag(t) t.Cleanup(tag2Cleanup) - /* - // TODO(SNOW-1528557): Uncomment next pr - func TestInt_UserAlter(t *testing.T) { - client := testClient(t) - ctx := testContext(t) - - randomPrefix := random.AlphaN(6) - - userTest, userCleanup := testClientHelper().User.CreateUserWithPrefix(t, randomPrefix+"_") - t.Cleanup(userCleanup) - - t.Run("set and unset authentication policy", func(t *testing.T) { - authenticationPolicyTest, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.CreateAuthenticationPolicy(t) - t.Cleanup(authenticationPolicyCleanup) - - alterOptions := &sdk.AlterUserOptions{ - Set: &sdk.UserSet{ - AuthenticationPolicy: authenticationPolicyTest.ID(), - }, - } - - err := client.Users.Alter(ctx, userTest.ID(), alterOptions) - require.NoError(t, err) - - unsetOptions := &sdk.AlterUserOptions{ - Unset: &sdk.UserUnset{ - AuthenticationPolicy: sdk.Bool(true), - }, - } - - unsetErr := client.Users.Alter(ctx, userTest.ID(), unsetOptions) - require.NoError(t, unsetErr) - }) - } - - func TestInt_UserCreate(t *testing.T) { - client := testClient(t) - ctx := testContext(t) - */ - networkPolicy, networkPolicyCleanup := testClientHelper().NetworkPolicy.CreateNetworkPolicy(t) t.Cleanup(networkPolicyCleanup) @@ -764,6 +726,41 @@ func TestInt_Users(t *testing.T) { ) }) + t.Run("set and unset authentication policy", func(t *testing.T) { + authenticationPolicyTest, authenticationPolicyCleanup := testClientHelper().AuthenticationPolicy.Create(t) + t.Cleanup(authenticationPolicyCleanup) + + err := client.Users.Alter(ctx, user.ID(), &sdk.AlterUserOptions{ + Set: &sdk.UserSet{ + AuthenticationPolicy: sdk.Pointer(authenticationPolicyTest.ID()), + }, + }) + require.NoError(t, err) + + policies, err := testClientHelper().PolicyReferences.GetPolicyReferences(t, user.ID(), sdk.PolicyEntityDomainUser) + require.NoError(t, err) + + _, err = collections.FindFirst(policies, func(reference sdk.PolicyReference) bool { + return reference.PolicyKind == sdk.PolicyKindAuthenticationPolicy + }) + require.NoError(t, err) + + err = client.Users.Alter(ctx, user.ID(), &sdk.AlterUserOptions{ + Unset: &sdk.UserUnset{ + AuthenticationPolicy: sdk.Bool(true), + }, + }) + require.NoError(t, err) + + policies, err = testClientHelper().PolicyReferences.GetPolicyReferences(t, user.ID(), sdk.PolicyEntityDomainUser) + require.NoError(t, err) + + _, err = collections.FindFirst(policies, func(reference sdk.PolicyReference) bool { + return reference.PolicyKind == sdk.PolicyKindAuthenticationPolicy + }) + require.ErrorIs(t, err, sdk.ErrObjectNotFound) + }) + t.Run("alter: set and unset parameters", func(t *testing.T) { id := testClientHelper().Ids.RandomAccountObjectIdentifier() @@ -848,10 +845,6 @@ func TestInt_Users(t *testing.T) { require.NoError(t, err) assertParametersSet(objectparametersassert.UserParametersPrefetched(t, id, parameters)) - // unset is split into two because: - // 1. this is how it's written in the docs https://docs.snowflake.com/en/sql-reference/sql/alter-user#syntax - // 2. current implementation of sdk.UserUnset makes distinction between user and session parameters, - // so adding a comma between them is not trivial in the current SQL builder implementation alterOpts = &sdk.AlterUserOptions{ Unset: &sdk.UserUnset{ SessionParameters: &sdk.SessionParametersUnset{ @@ -911,14 +904,6 @@ func TestInt_Users(t *testing.T) { WeekOfYearPolicy: sdk.Bool(true), WeekStart: sdk.Bool(true), }, - }, - } - - err = client.Users.Alter(ctx, id, alterOpts) - require.NoError(t, err) - - alterOpts = &sdk.AlterUserOptions{ - Unset: &sdk.UserUnset{ ObjectParameters: &sdk.UserObjectParametersUnset{ EnableUnredactedQuerySyntaxError: sdk.Bool(true), NetworkPolicy: sdk.Bool(true), @@ -944,6 +929,43 @@ func TestInt_Users(t *testing.T) { ) }) + t.Run("alter: set and unset properties and parameters at the same time", func(t *testing.T) { + user, userCleanup := testClientHelper().User.CreateUser(t) + t.Cleanup(userCleanup) + + err := client.Users.Alter(ctx, user.ID(), &sdk.AlterUserOptions{ + Set: &sdk.UserSet{ + SessionParameters: &sdk.SessionParameters{ + Autocommit: sdk.Bool(false), + }, + ObjectParameters: &sdk.UserObjectParameters{ + NetworkPolicy: sdk.Pointer(networkPolicy.ID()), + }, + ObjectProperties: &sdk.UserAlterObjectProperties{ + UserObjectProperties: sdk.UserObjectProperties{ + Comment: sdk.String("some comment"), + }, + }, + }, + }) + require.NoError(t, err) + + err = client.Users.Alter(ctx, user.ID(), &sdk.AlterUserOptions{ + Unset: &sdk.UserUnset{ + SessionParameters: &sdk.SessionParametersUnset{ + Autocommit: sdk.Bool(true), + }, + ObjectParameters: &sdk.UserObjectParametersUnset{ + NetworkPolicy: sdk.Bool(true), + }, + ObjectProperties: &sdk.UserObjectPropertiesUnset{ + Comment: sdk.Bool(true), + }, + }, + }) + require.NoError(t, err) + }) + t.Run("alter: set and unset tags", func(t *testing.T) { user, userCleanup := testClientHelper().User.CreateUser(t) t.Cleanup(userCleanup) diff --git a/pkg/sdk/users.go b/pkg/sdk/users.go index b7ed9d4e23..ba56f23a92 100644 --- a/pkg/sdk/users.go +++ b/pkg/sdk/users.go @@ -313,7 +313,7 @@ type AlterUserOptions struct { AddDelegatedAuthorization *AddDelegatedAuthorization `ddl:"keyword"` RemoveDelegatedAuthorization *RemoveDelegatedAuthorization `ddl:"keyword"` Set *UserSet `ddl:"keyword" sql:"SET"` - Unset *UserUnset `ddl:"keyword" sql:"UNSET"` + Unset *UserUnset `ddl:"list" sql:"UNSET"` SetTag []TagAssociation `ddl:"keyword" sql:"SET TAG"` UnsetTag []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` } @@ -390,15 +390,21 @@ func (opts *RemoveDelegatedAuthorization) validate() error { type UserSet struct { PasswordPolicy *SchemaObjectIdentifier `ddl:"identifier" sql:"PASSWORD POLICY"` SessionPolicy *string `ddl:"parameter" sql:"SESSION POLICY"` - AuthenticationPolicy SchemaObjectIdentifier `ddl:"identifier" sql:"AUTHENTICATION POLICY"` + AuthenticationPolicy *SchemaObjectIdentifier `ddl:"identifier" sql:"AUTHENTICATION POLICY"` ObjectProperties *UserAlterObjectProperties `ddl:"keyword"` ObjectParameters *UserObjectParameters `ddl:"keyword"` SessionParameters *SessionParameters `ddl:"keyword"` } func (opts *UserSet) validate() error { - if !exactlyOneValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy, opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters) { - return errExactlyOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters") + if !anyValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy, opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters) { + return errAtLeastOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters") + } + if moreThanOneValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy) { + return errOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy") + } + if anyValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy) && anyValueSet(opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters) { + return NewError("policies cannot be set with user properties or parameters at the same time") } if valueSet(opts.ObjectProperties) && valueSet(opts.ObjectProperties.DefaultSecondaryRoles) { if err := opts.ObjectProperties.DefaultSecondaryRoles.validate(); err != nil { @@ -426,8 +432,14 @@ type UserUnset struct { func (opts *UserUnset) validate() error { // TODO [SNOW-1645875]: change validations with policies - if !exactlyOneValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters, opts.AuthenticationPolicy) { - return errExactlyOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters", "AuthenticationPolicy") + if !anyValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters, opts.AuthenticationPolicy) { + return errAtLeastOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters") + } + if moreThanOneValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy) { + return errOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy") + } + if anyValueSet(opts.PasswordPolicy, opts.SessionPolicy, opts.AuthenticationPolicy) && anyValueSet(opts.ObjectProperties, opts.ObjectParameters, opts.SessionParameters) { + return NewError("policies cannot be unset with user properties or parameters at the same time") } return nil } diff --git a/pkg/sdk/users_test.go b/pkg/sdk/users_test.go index ea6695b96b..74fd0851fa 100644 --- a/pkg/sdk/users_test.go +++ b/pkg/sdk/users_test.go @@ -1,6 +1,7 @@ package sdk import ( + "errors" "fmt" "testing" @@ -116,7 +117,31 @@ func TestUserAlter(t *testing.T) { name: id, Set: &UserSet{}, } - assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters")) + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters")) + }) + + t.Run("validation: set more than one policy", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Set: &UserSet{ + AuthenticationPolicy: Pointer(randomSchemaObjectIdentifier()), + PasswordPolicy: Pointer(randomSchemaObjectIdentifier()), + }, + } + assertOptsInvalidJoinedErrors(t, opts, errOneOf("UserSet", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + + t.Run("validation: set policy with user parameters and properties", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Set: &UserSet{ + AuthenticationPolicy: Pointer(randomSchemaObjectIdentifier()), + SessionParameters: &SessionParameters{AbortDetachedQuery: Bool(true)}, + ObjectParameters: &UserObjectParameters{EnableUnredactedQuerySyntaxError: Bool(true)}, + ObjectProperties: &UserAlterObjectProperties{DisableMfa: Bool(true)}, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errors.New("policies cannot be set with user properties or parameters at the same time")) }) t.Run("two sets", func(t *testing.T) { @@ -135,18 +160,40 @@ func TestUserAlter(t *testing.T) { name: id, Unset: &UserUnset{}, } - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters")) + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters")) }) - t.Run("validation: two incompatible unsets", func(t *testing.T) { + t.Run("validation: unset property with policy", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Unset: &UserUnset{ + PasswordPolicy: Bool(true), + ObjectParameters: &UserObjectParametersUnset{EnableUnredactedQuerySyntaxError: Bool(true)}, + }, + } + assertOptsInvalidJoinedErrors(t, opts, errors.New("policies cannot be unset with user properties or parameters at the same time")) + }) + + t.Run("validation: unset two policies", func(t *testing.T) { + opts := &AlterUserOptions{ + name: id, + Unset: &UserUnset{ + PasswordPolicy: Bool(true), + AuthenticationPolicy: Bool(true), + }, + } + assertOptsInvalidJoinedErrors(t, opts, errOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "AuthenticationPolicy")) + }) + + t.Run("two compatible unsets", func(t *testing.T) { opts := &AlterUserOptions{ name: id, Unset: &UserUnset{ - SessionParameters: &SessionParametersUnset{BinaryOutputFormat: Bool(true)}, ObjectParameters: &UserObjectParametersUnset{EnableUnredactedQuerySyntaxError: Bool(true)}, + SessionParameters: &SessionParametersUnset{BinaryOutputFormat: Bool(true)}, }, } - assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("UserUnset", "PasswordPolicy", "SessionPolicy", "ObjectProperties", "ObjectParameters", "SessionParameters")) + assertOptsValidAndSQLEquals(t, opts, "ALTER USER %s UNSET ENABLE_UNREDACTED_QUERY_SYNTAX_ERROR, BINARY_OUTPUT_FORMAT", id.FullyQualifiedName()) }) t.Run("with setting a policy", func(t *testing.T) { @@ -165,7 +212,7 @@ func TestUserAlter(t *testing.T) { opts := &AlterUserOptions{ name: id, Set: &UserSet{ - AuthenticationPolicy: authenticationPolicy, + AuthenticationPolicy: &authenticationPolicy, }, } assertOptsValidAndSQLEquals(t, opts, "ALTER USER %s SET AUTHENTICATION POLICY %s", id.FullyQualifiedName(), authenticationPolicy.FullyQualifiedName())