From 8335a322c9b39fab5986ebd01a706592f5a01485 Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Fri, 24 May 2024 13:01:09 +0200 Subject: [PATCH 1/5] Add external oauth to sdk --- pkg/acceptance/helpers/random/url.go | 12 + pkg/sdk/security_integrations_def.go | 128 ++++++++++ .../security_integrations_dto_builders_gen.go | 235 +++++++++++++++++- pkg/sdk/security_integrations_dto_gen.go | 72 +++++- pkg/sdk/security_integrations_gen.go | 89 ++++++- pkg/sdk/security_integrations_gen_test.go | 226 +++++++++++++++++ pkg/sdk/security_integrations_impl_gen.go | 96 +++++++ .../security_integrations_validations_gen.go | 58 +++++ ...urity_integrations_gen_integration_test.go | 235 +++++++++++++++++- 9 files changed, 1126 insertions(+), 25 deletions(-) create mode 100644 pkg/acceptance/helpers/random/url.go diff --git a/pkg/acceptance/helpers/random/url.go b/pkg/acceptance/helpers/random/url.go new file mode 100644 index 0000000000..9fdb114dbf --- /dev/null +++ b/pkg/acceptance/helpers/random/url.go @@ -0,0 +1,12 @@ +package random + +import ( + "fmt" + "testing" +) + +// GenerateURL generates a random valid URL +func GenerateURL(t *testing.T) string { + t.Helper() + return fmt.Sprintf("https://%s.com", AlphaN(6)) +} diff --git a/pkg/sdk/security_integrations_def.go b/pkg/sdk/security_integrations_def.go index eb543cc08c..80fef045c7 100644 --- a/pkg/sdk/security_integrations_def.go +++ b/pkg/sdk/security_integrations_def.go @@ -4,6 +4,30 @@ import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/gen //go:generate go run ./poc/main.go +type ExternalOauthSecurityIntegrationTypeOption string + +const ( + ExternalOauthSecurityIntegrationTypeOkta ExternalOauthSecurityIntegrationTypeOption = "OKTA" + ExternalOauthSecurityIntegrationTypeAzure ExternalOauthSecurityIntegrationTypeOption = "AZURE" + ExternalOauthSecurityIntegrationTypePingFederate ExternalOauthSecurityIntegrationTypeOption = "PING_FEDERATE" + ExternalOauthSecurityIntegrationTypeCustom ExternalOauthSecurityIntegrationTypeOption = "CUSTOM" +) + +type ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption string + +const ( + ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeLoginName ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption = "LOGIN_NAME" + ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeEmailAddress ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption = "EMAIL_ADDRESS" +) + +type ExternalOauthSecurityIntegrationAnyRoleModeOption string + +const ( + ExternalOauthSecurityIntegrationAnyRoleModeDisable ExternalOauthSecurityIntegrationAnyRoleModeOption = "DISABLE" + ExternalOauthSecurityIntegrationAnyRoleModeEnable ExternalOauthSecurityIntegrationAnyRoleModeOption = "ENABLE" + ExternalOauthSecurityIntegrationAnyRoleModeEnableForPrivilege ExternalOauthSecurityIntegrationAnyRoleModeOption = "ENABLE_FOR_PRIVILEGE" +) + type OauthSecurityIntegrationUseSecondaryRolesOption string const ( @@ -49,6 +73,13 @@ var ( List("PreAuthorizedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) blockedRolesListDef = g.NewQueryStruct("BlockedRolesList"). List("BlockedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) + allowedRolesListDef = g.NewQueryStruct("AllowedRolesList"). + List("AllowedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) + jwsKeysUrlDef = g.NewQueryStruct("JwsKeysUrl").Text("JwsKeyUrl", g.KeywordOptions().SingleQuotes().Required()) + audienceListItemDef = g.NewQueryStruct("AudienceListItem").Text("Item", g.KeywordOptions().SingleQuotes().Required()) + audienceListDef = g.NewQueryStruct("AudienceList"). + List("AudienceList", "AudienceListItem", g.ListOptions().MustParentheses()) + tokenUserMappingClaimDef = g.NewQueryStruct("TokenUserMappingClaim").Text("Claim", g.KeywordOptions().SingleQuotes().Required()) ) func createSecurityIntegrationOperation(structName string, opts func(qs *g.QueryStruct) *g.QueryStruct) *g.QueryStruct { @@ -78,6 +109,45 @@ func alterSecurityIntegrationOperation(structName string, opts func(qs *g.QueryS return qs } +var externalOauthIntegrationSetDef = g.NewQueryStruct("ExternalOauthIntegrationSet"). + OptionalBooleanAssignment("ENABLED", g.ParameterOptions()). + OptionalAssignment( + "EXTERNAL_OAUTH_TYPE", + g.KindOfT[ExternalOauthSecurityIntegrationTypeOption](), + g.ParameterOptions(), + ). + OptionalTextAssignment("EXTERNAL_OAUTH_ISSUER", g.ParameterOptions().SingleQuotes()). + ListAssignment("EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM", "TokenUserMappingClaim", g.ParameterOptions().Parentheses()). + OptionalAssignment( + "EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE", + g.KindOfT[ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption](), + g.ParameterOptions().SingleQuotes(), + ). + ListAssignment("EXTERNAL_OAUTH_JWS_KEYS_URL", "JwsKeysUrl", g.ParameterOptions().Parentheses()). + OptionalQueryStructField("ExternalOauthBlockedRolesList", blockedRolesListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_BLOCKED_ROLES_LIST").Parentheses()). + OptionalQueryStructField("ExternalOauthAllowedRolesList", allowedRolesListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_ALLOWED_ROLES_LIST").Parentheses()). + OptionalTextAssignment("EXTERNAL_OAUTH_RSA_PUBLIC_KEY", g.ParameterOptions().SingleQuotes()). + OptionalTextAssignment("EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2", g.ParameterOptions().SingleQuotes()). + OptionalQueryStructField("ExternalOauthAudienceList", audienceListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_AUDIENCE_LIST").Parentheses()). + OptionalAssignment( + "EXTERNAL_OAUTH_ANY_ROLE_MODE", + g.KindOfT[ExternalOauthSecurityIntegrationAnyRoleModeOption](), + g.ParameterOptions(), + ). + OptionalTextAssignment("EXTERNAL_OAUTH_SCOPE_DELIMITER", g.ParameterOptions().SingleQuotes()). + OptionalComment(). + WithValidation(g.ConflictingFields, "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList"). + WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey"). + WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2"). + WithValidation(g.AtLeastOneValueSet, "Enabled", "ExternalOauthType", "ExternalOauthIssuer", "ExternalOauthTokenUserMappingClaim", "ExternalOauthSnowflakeUserMappingAttribute", + "ExternalOauthJwsKeysUrl", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList", "ExternalOauthRsaPublicKey", "ExternalOauthRsaPublicKey2", + "ExternalOauthAudienceList", "ExternalOauthAnyRoleMode", "ExternalOauthScopeDelimiter", "Comment") + +var externalOauthIntegrationUnsetDef = g.NewQueryStruct("ExternalOauthIntegrationUnset"). + OptionalSQL("ENABLED"). + OptionalSQL("EXTERNAL_OAUTH_AUDIENCE_LIST"). + WithValidation(g.AtLeastOneValueSet, "Enabled", "ExternalOauthAudienceList") + var oauthForPartnerApplicationsIntegrationSetDef = g.NewQueryStruct("OauthForPartnerApplicationsIntegrationSet"). OptionalBooleanAssignment("ENABLED", g.ParameterOptions()). OptionalBooleanAssignment("OAUTH_ISSUE_REFRESH_TOKENS", g.ParameterOptions()). @@ -176,6 +246,49 @@ var SecurityIntegrationsDef = g.NewInterface( "SecurityIntegration", g.KindOfT[AccountObjectIdentifier](), ). + CustomOperation( + "CreateExternalOauth", + "https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-external", + createSecurityIntegrationOperation("CreateExternalOauth", func(qs *g.QueryStruct) *g.QueryStruct { + return qs. + PredefinedQueryStructField("integrationType", "string", g.StaticOptions().SQL("TYPE = EXTERNAL_OAUTH")). + BooleanAssignment("ENABLED", g.ParameterOptions().Required()). + Assignment( + "EXTERNAL_OAUTH_TYPE", + g.KindOfT[ExternalOauthSecurityIntegrationTypeOption](), + g.ParameterOptions().Required(), + ). + TextAssignment("EXTERNAL_OAUTH_ISSUER", g.ParameterOptions().Required().SingleQuotes()). + ListAssignment("EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM", "TokenUserMappingClaim", g.ParameterOptions().Required().Parentheses()). + Assignment( + "EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE", + g.KindOfT[ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption](), + g.ParameterOptions().SingleQuotes().Required(), + ). + ListAssignment("EXTERNAL_OAUTH_JWS_KEYS_URL", "JwsKeysUrl", g.ParameterOptions().Parentheses()). + OptionalQueryStructField("ExternalOauthBlockedRolesList", blockedRolesListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_BLOCKED_ROLES_LIST").Parentheses()). + OptionalQueryStructField("ExternalOauthAllowedRolesList", allowedRolesListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_ALLOWED_ROLES_LIST").Parentheses()). + OptionalTextAssignment("EXTERNAL_OAUTH_RSA_PUBLIC_KEY", g.ParameterOptions().SingleQuotes()). + OptionalTextAssignment("EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2", g.ParameterOptions().SingleQuotes()). + OptionalQueryStructField("ExternalOauthAudienceList", audienceListDef, g.ParameterOptions().SQL("EXTERNAL_OAUTH_AUDIENCE_LIST").Parentheses()). + OptionalAssignment( + "EXTERNAL_OAUTH_ANY_ROLE_MODE", + g.KindOfT[ExternalOauthSecurityIntegrationAnyRoleModeOption](), + g.ParameterOptions(), + ). + OptionalTextAssignment("EXTERNAL_OAUTH_SCOPE_DELIMITER", g.ParameterOptions().SingleQuotes()). + OptionalTextAssignment("EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE", g.ParameterOptions().SingleQuotes()). + WithValidation(g.ConflictingFields, "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList"). + WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey"). + WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2") + }), + allowedRolesListDef, + blockedRolesListDef, + jwsKeysUrlDef, + audienceListDef, + audienceListItemDef, + tokenUserMappingClaimDef, + ). CustomOperation( "CreateOauthForPartnerApplications", "https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake", @@ -278,6 +391,21 @@ var SecurityIntegrationsDef = g.NewInterface( OptionalBooleanAssignment("SYNC_PASSWORD", g.ParameterOptions()) }), ). + CustomOperation( + "AlterExternalOauth", + "https://docs.snowflake.com/en/sql-reference/sql/alter-security-integration-oauth-external", + alterSecurityIntegrationOperation("AlterExternalOauth", func(qs *g.QueryStruct) *g.QueryStruct { + return qs.OptionalQueryStructField( + "Set", + externalOauthIntegrationSetDef, + g.ListOptions().NoParentheses().SQL("SET"), + ).OptionalQueryStructField( + "Unset", + externalOauthIntegrationUnsetDef, + g.ListOptions().NoParentheses().SQL("UNSET"), + ).WithValidation(g.ExactlyOneValueSet, "Set", "Unset", "SetTags", "UnsetTags") + }), + ). CustomOperation( "AlterOauthForPartnerApplications", "https://docs.snowflake.com/en/sql-reference/sql/alter-security-integration-oauth-snowflake", diff --git a/pkg/sdk/security_integrations_dto_builders_gen.go b/pkg/sdk/security_integrations_dto_builders_gen.go index baed7353ef..f6e0a3342e 100644 --- a/pkg/sdk/security_integrations_dto_builders_gen.go +++ b/pkg/sdk/security_integrations_dto_builders_gen.go @@ -4,6 +4,111 @@ package sdk import () +func NewCreateExternalOauthSecurityIntegrationRequest( + name AccountObjectIdentifier, + Enabled bool, + ExternalOauthType ExternalOauthSecurityIntegrationTypeOption, + ExternalOauthIssuer string, + ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim, + ExternalOauthSnowflakeUserMappingAttribute ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption, +) *CreateExternalOauthSecurityIntegrationRequest { + s := CreateExternalOauthSecurityIntegrationRequest{} + s.name = name + s.Enabled = Enabled + s.ExternalOauthType = ExternalOauthType + s.ExternalOauthIssuer = ExternalOauthIssuer + s.ExternalOauthTokenUserMappingClaim = ExternalOauthTokenUserMappingClaim + s.ExternalOauthSnowflakeUserMappingAttribute = ExternalOauthSnowflakeUserMappingAttribute + return &s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithOrReplace(OrReplace bool) *CreateExternalOauthSecurityIntegrationRequest { + s.OrReplace = &OrReplace + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithIfNotExists(IfNotExists bool) *CreateExternalOauthSecurityIntegrationRequest { + s.IfNotExists = &IfNotExists + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthJwsKeysUrl(ExternalOauthJwsKeysUrl []JwsKeysUrl) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthJwsKeysUrl = ExternalOauthJwsKeysUrl + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthBlockedRolesList(ExternalOauthBlockedRolesList BlockedRolesListRequest) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthBlockedRolesList = &ExternalOauthBlockedRolesList + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthAllowedRolesList(ExternalOauthAllowedRolesList AllowedRolesListRequest) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthAllowedRolesList = &ExternalOauthAllowedRolesList + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthRsaPublicKey(ExternalOauthRsaPublicKey string) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthRsaPublicKey = &ExternalOauthRsaPublicKey + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthRsaPublicKey2(ExternalOauthRsaPublicKey2 string) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthRsaPublicKey2 = &ExternalOauthRsaPublicKey2 + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthAudienceList(ExternalOauthAudienceList AudienceListRequest) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthAudienceList = &ExternalOauthAudienceList + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthAnyRoleMode(ExternalOauthAnyRoleMode ExternalOauthSecurityIntegrationAnyRoleModeOption) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthAnyRoleMode = &ExternalOauthAnyRoleMode + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthScopeDelimiter(ExternalOauthScopeDelimiter string) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthScopeDelimiter = &ExternalOauthScopeDelimiter + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithExternalOauthScopeMappingAttribute(ExternalOauthScopeMappingAttribute string) *CreateExternalOauthSecurityIntegrationRequest { + s.ExternalOauthScopeMappingAttribute = &ExternalOauthScopeMappingAttribute + return s +} + +func (s *CreateExternalOauthSecurityIntegrationRequest) WithComment(Comment string) *CreateExternalOauthSecurityIntegrationRequest { + s.Comment = &Comment + return s +} + +func NewBlockedRolesListRequest() *BlockedRolesListRequest { + return &BlockedRolesListRequest{} +} + +func (s *BlockedRolesListRequest) WithBlockedRolesList(BlockedRolesList []AccountObjectIdentifier) *BlockedRolesListRequest { + s.BlockedRolesList = BlockedRolesList + return s +} + +func NewAllowedRolesListRequest() *AllowedRolesListRequest { + return &AllowedRolesListRequest{} +} + +func (s *AllowedRolesListRequest) WithAllowedRolesList(AllowedRolesList []AccountObjectIdentifier) *AllowedRolesListRequest { + s.AllowedRolesList = AllowedRolesList + return s +} + +func NewAudienceListRequest() *AudienceListRequest { + return &AudienceListRequest{} +} + +func (s *AudienceListRequest) WithAudienceList(AudienceList []AudienceListItem) *AudienceListRequest { + s.AudienceList = AudienceList + return s +} + func NewCreateOauthForPartnerApplicationsSecurityIntegrationRequest( name AccountObjectIdentifier, OauthClient OauthSecurityIntegrationClientOption, @@ -59,15 +164,6 @@ func (s *CreateOauthForPartnerApplicationsSecurityIntegrationRequest) WithCommen return s } -func NewBlockedRolesListRequest() *BlockedRolesListRequest { - return &BlockedRolesListRequest{} -} - -func (s *BlockedRolesListRequest) WithBlockedRolesList(BlockedRolesList []AccountObjectIdentifier) *BlockedRolesListRequest { - s.BlockedRolesList = BlockedRolesList - return s -} - func NewCreateOauthForCustomClientsSecurityIntegrationRequest( name AccountObjectIdentifier, OauthClientType OauthSecurityIntegrationClientTypeOption, @@ -286,6 +382,127 @@ func (s *CreateScimSecurityIntegrationRequest) WithComment(Comment string) *Crea return s } +func NewAlterExternalOauthSecurityIntegrationRequest( + name AccountObjectIdentifier, +) *AlterExternalOauthSecurityIntegrationRequest { + s := AlterExternalOauthSecurityIntegrationRequest{} + s.name = name + return &s +} + +func (s *AlterExternalOauthSecurityIntegrationRequest) WithIfExists(IfExists bool) *AlterExternalOauthSecurityIntegrationRequest { + s.IfExists = &IfExists + return s +} + +func (s *AlterExternalOauthSecurityIntegrationRequest) WithSetTags(SetTags []TagAssociation) *AlterExternalOauthSecurityIntegrationRequest { + s.SetTags = SetTags + return s +} + +func (s *AlterExternalOauthSecurityIntegrationRequest) WithUnsetTags(UnsetTags []ObjectIdentifier) *AlterExternalOauthSecurityIntegrationRequest { + s.UnsetTags = UnsetTags + return s +} + +func (s *AlterExternalOauthSecurityIntegrationRequest) WithSet(Set ExternalOauthIntegrationSetRequest) *AlterExternalOauthSecurityIntegrationRequest { + s.Set = &Set + return s +} + +func (s *AlterExternalOauthSecurityIntegrationRequest) WithUnset(Unset ExternalOauthIntegrationUnsetRequest) *AlterExternalOauthSecurityIntegrationRequest { + s.Unset = &Unset + return s +} + +func NewExternalOauthIntegrationSetRequest() *ExternalOauthIntegrationSetRequest { + return &ExternalOauthIntegrationSetRequest{} +} + +func (s *ExternalOauthIntegrationSetRequest) WithEnabled(Enabled bool) *ExternalOauthIntegrationSetRequest { + s.Enabled = &Enabled + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthType(ExternalOauthType ExternalOauthSecurityIntegrationTypeOption) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthType = &ExternalOauthType + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthIssuer(ExternalOauthIssuer string) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthIssuer = &ExternalOauthIssuer + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthTokenUserMappingClaim(ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthTokenUserMappingClaim = ExternalOauthTokenUserMappingClaim + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthSnowflakeUserMappingAttribute(ExternalOauthSnowflakeUserMappingAttribute ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthSnowflakeUserMappingAttribute = &ExternalOauthSnowflakeUserMappingAttribute + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthJwsKeysUrl(ExternalOauthJwsKeysUrl []JwsKeysUrl) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthJwsKeysUrl = ExternalOauthJwsKeysUrl + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthBlockedRolesList(ExternalOauthBlockedRolesList BlockedRolesListRequest) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthBlockedRolesList = &ExternalOauthBlockedRolesList + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthAllowedRolesList(ExternalOauthAllowedRolesList AllowedRolesListRequest) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthAllowedRolesList = &ExternalOauthAllowedRolesList + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthRsaPublicKey(ExternalOauthRsaPublicKey string) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthRsaPublicKey = &ExternalOauthRsaPublicKey + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthRsaPublicKey2(ExternalOauthRsaPublicKey2 string) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthRsaPublicKey2 = &ExternalOauthRsaPublicKey2 + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthAudienceList(ExternalOauthAudienceList AudienceListRequest) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthAudienceList = &ExternalOauthAudienceList + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthAnyRoleMode(ExternalOauthAnyRoleMode ExternalOauthSecurityIntegrationAnyRoleModeOption) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthAnyRoleMode = &ExternalOauthAnyRoleMode + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithExternalOauthScopeDelimiter(ExternalOauthScopeDelimiter string) *ExternalOauthIntegrationSetRequest { + s.ExternalOauthScopeDelimiter = &ExternalOauthScopeDelimiter + return s +} + +func (s *ExternalOauthIntegrationSetRequest) WithComment(Comment string) *ExternalOauthIntegrationSetRequest { + s.Comment = &Comment + return s +} + +func NewExternalOauthIntegrationUnsetRequest() *ExternalOauthIntegrationUnsetRequest { + return &ExternalOauthIntegrationUnsetRequest{} +} + +func (s *ExternalOauthIntegrationUnsetRequest) WithEnabled(Enabled bool) *ExternalOauthIntegrationUnsetRequest { + s.Enabled = &Enabled + return s +} + +func (s *ExternalOauthIntegrationUnsetRequest) WithExternalOauthAudienceList(ExternalOauthAudienceList bool) *ExternalOauthIntegrationUnsetRequest { + s.ExternalOauthAudienceList = &ExternalOauthAudienceList + return s +} + func NewAlterOauthForPartnerApplicationsSecurityIntegrationRequest( name AccountObjectIdentifier, ) *AlterOauthForPartnerApplicationsSecurityIntegrationRequest { diff --git a/pkg/sdk/security_integrations_dto_gen.go b/pkg/sdk/security_integrations_dto_gen.go index 7d119a3c10..5c9a39383c 100644 --- a/pkg/sdk/security_integrations_dto_gen.go +++ b/pkg/sdk/security_integrations_dto_gen.go @@ -3,10 +3,12 @@ package sdk //go:generate go run ./dto-builder-generator/main.go var ( + _ optionsProvider[CreateExternalOauthSecurityIntegrationOptions] = new(CreateExternalOauthSecurityIntegrationRequest) _ optionsProvider[CreateOauthForPartnerApplicationsSecurityIntegrationOptions] = new(CreateOauthForPartnerApplicationsSecurityIntegrationRequest) _ optionsProvider[CreateOauthForCustomClientsSecurityIntegrationOptions] = new(CreateOauthForCustomClientsSecurityIntegrationRequest) _ optionsProvider[CreateSaml2SecurityIntegrationOptions] = new(CreateSaml2SecurityIntegrationRequest) _ optionsProvider[CreateScimSecurityIntegrationOptions] = new(CreateScimSecurityIntegrationRequest) + _ optionsProvider[AlterExternalOauthSecurityIntegrationOptions] = new(AlterExternalOauthSecurityIntegrationRequest) _ optionsProvider[AlterOauthForPartnerApplicationsSecurityIntegrationOptions] = new(AlterOauthForPartnerApplicationsSecurityIntegrationRequest) _ optionsProvider[AlterOauthForCustomClientsSecurityIntegrationOptions] = new(AlterOauthForCustomClientsSecurityIntegrationRequest) _ optionsProvider[AlterSaml2SecurityIntegrationOptions] = new(AlterSaml2SecurityIntegrationRequest) @@ -16,6 +18,39 @@ var ( _ optionsProvider[ShowSecurityIntegrationOptions] = new(ShowSecurityIntegrationRequest) ) +type CreateExternalOauthSecurityIntegrationRequest struct { + OrReplace *bool + IfNotExists *bool + name AccountObjectIdentifier // required + Enabled bool // required + ExternalOauthType ExternalOauthSecurityIntegrationTypeOption // required + ExternalOauthIssuer string // required + ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim // required + ExternalOauthSnowflakeUserMappingAttribute ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption // required + ExternalOauthJwsKeysUrl []JwsKeysUrl + ExternalOauthBlockedRolesList *BlockedRolesListRequest + ExternalOauthAllowedRolesList *AllowedRolesListRequest + ExternalOauthRsaPublicKey *string + ExternalOauthRsaPublicKey2 *string + ExternalOauthAudienceList *AudienceListRequest + ExternalOauthAnyRoleMode *ExternalOauthSecurityIntegrationAnyRoleModeOption + ExternalOauthScopeDelimiter *string + ExternalOauthScopeMappingAttribute *string + Comment *string +} + +type BlockedRolesListRequest struct { + BlockedRolesList []AccountObjectIdentifier +} + +type AllowedRolesListRequest struct { + AllowedRolesList []AccountObjectIdentifier +} + +type AudienceListRequest struct { + AudienceList []AudienceListItem +} + type CreateOauthForPartnerApplicationsSecurityIntegrationRequest struct { OrReplace *bool IfNotExists *bool @@ -34,10 +69,6 @@ func (r *CreateOauthForPartnerApplicationsSecurityIntegrationRequest) GetName() return r.name } -type BlockedRolesListRequest struct { - BlockedRolesList []AccountObjectIdentifier -} - type CreateOauthForCustomClientsSecurityIntegrationRequest struct { OrReplace *bool IfNotExists *bool @@ -109,6 +140,37 @@ func (r *CreateScimSecurityIntegrationRequest) GetName() AccountObjectIdentifier return r.name } +type AlterExternalOauthSecurityIntegrationRequest struct { + IfExists *bool + name AccountObjectIdentifier // required + SetTags []TagAssociation + UnsetTags []ObjectIdentifier + Set *ExternalOauthIntegrationSetRequest + Unset *ExternalOauthIntegrationUnsetRequest +} + +type ExternalOauthIntegrationSetRequest struct { + Enabled *bool + ExternalOauthType *ExternalOauthSecurityIntegrationTypeOption + ExternalOauthIssuer *string + ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim + ExternalOauthSnowflakeUserMappingAttribute *ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption + ExternalOauthJwsKeysUrl []JwsKeysUrl + ExternalOauthBlockedRolesList *BlockedRolesListRequest + ExternalOauthAllowedRolesList *AllowedRolesListRequest + ExternalOauthRsaPublicKey *string + ExternalOauthRsaPublicKey2 *string + ExternalOauthAudienceList *AudienceListRequest + ExternalOauthAnyRoleMode *ExternalOauthSecurityIntegrationAnyRoleModeOption + ExternalOauthScopeDelimiter *string + Comment *string +} + +type ExternalOauthIntegrationUnsetRequest struct { + Enabled *bool + ExternalOauthAudienceList *bool +} + type AlterOauthForPartnerApplicationsSecurityIntegrationRequest struct { IfExists *bool name AccountObjectIdentifier // required @@ -161,9 +223,9 @@ type OauthForCustomClientsIntegrationSetRequest struct { type OauthForCustomClientsIntegrationUnsetRequest struct { Enabled *bool NetworkPolicy *bool - OauthUseSecondaryRoles *bool OauthClientRsaPublicKey *bool OauthClientRsaPublicKey2 *bool + OauthUseSecondaryRoles *bool } type AlterSaml2SecurityIntegrationRequest struct { diff --git a/pkg/sdk/security_integrations_gen.go b/pkg/sdk/security_integrations_gen.go index 0bbc0017d8..eb4d2b0c48 100644 --- a/pkg/sdk/security_integrations_gen.go +++ b/pkg/sdk/security_integrations_gen.go @@ -7,10 +7,12 @@ import ( ) type SecurityIntegrations interface { + CreateExternalOauth(ctx context.Context, request *CreateExternalOauthSecurityIntegrationRequest) error CreateOauthForPartnerApplications(ctx context.Context, request *CreateOauthForPartnerApplicationsSecurityIntegrationRequest) error CreateOauthForCustomClients(ctx context.Context, request *CreateOauthForCustomClientsSecurityIntegrationRequest) error CreateSaml2(ctx context.Context, request *CreateSaml2SecurityIntegrationRequest) error CreateScim(ctx context.Context, request *CreateScimSecurityIntegrationRequest) error + AlterExternalOauth(ctx context.Context, request *AlterExternalOauthSecurityIntegrationRequest) error AlterOauthForPartnerApplications(ctx context.Context, request *AlterOauthForPartnerApplicationsSecurityIntegrationRequest) error AlterOauthForCustomClients(ctx context.Context, request *AlterOauthForCustomClientsSecurityIntegrationRequest) error AlterSaml2(ctx context.Context, request *AlterSaml2SecurityIntegrationRequest) error @@ -21,6 +23,55 @@ type SecurityIntegrations interface { ShowByID(ctx context.Context, id AccountObjectIdentifier) (*SecurityIntegration, error) } +// CreateExternalOauthSecurityIntegrationOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-external. +type CreateExternalOauthSecurityIntegrationOptions struct { + create bool `ddl:"static" sql:"CREATE"` + OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"` + securityIntegration bool `ddl:"static" sql:"SECURITY INTEGRATION"` + IfNotExists *bool `ddl:"keyword" sql:"IF NOT EXISTS"` + name AccountObjectIdentifier `ddl:"identifier"` + integrationType string `ddl:"static" sql:"TYPE = EXTERNAL_OAUTH"` + Enabled bool `ddl:"parameter" sql:"ENABLED"` + ExternalOauthType ExternalOauthSecurityIntegrationTypeOption `ddl:"parameter" sql:"EXTERNAL_OAUTH_TYPE"` + ExternalOauthIssuer string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_ISSUER"` + ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM"` + ExternalOauthSnowflakeUserMappingAttribute ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE"` + ExternalOauthJwsKeysUrl []JwsKeysUrl `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_JWS_KEYS_URL"` + ExternalOauthBlockedRolesList *BlockedRolesList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_BLOCKED_ROLES_LIST"` + ExternalOauthAllowedRolesList *AllowedRolesList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_ALLOWED_ROLES_LIST"` + ExternalOauthRsaPublicKey *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_RSA_PUBLIC_KEY"` + ExternalOauthRsaPublicKey2 *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2"` + ExternalOauthAudienceList *AudienceList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_AUDIENCE_LIST"` + ExternalOauthAnyRoleMode *ExternalOauthSecurityIntegrationAnyRoleModeOption `ddl:"parameter" sql:"EXTERNAL_OAUTH_ANY_ROLE_MODE"` + ExternalOauthScopeDelimiter *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_SCOPE_DELIMITER"` + ExternalOauthScopeMappingAttribute *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` +} + +type AllowedRolesList struct { + AllowedRolesList []AccountObjectIdentifier `ddl:"list,must_parentheses"` +} + +type BlockedRolesList struct { + BlockedRolesList []AccountObjectIdentifier `ddl:"list,must_parentheses"` +} + +type JwsKeysUrl struct { + JwsKeyUrl string `ddl:"keyword,single_quotes"` +} + +type AudienceList struct { + AudienceList []AudienceListItem `ddl:"list,must_parentheses"` +} + +type AudienceListItem struct { + Item string `ddl:"keyword,single_quotes"` +} + +type TokenUserMappingClaim struct { + Claim string `ddl:"keyword,single_quotes"` +} + // CreateOauthForPartnerApplicationsSecurityIntegrationOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake. type CreateOauthForPartnerApplicationsSecurityIntegrationOptions struct { create bool `ddl:"static" sql:"CREATE"` @@ -43,10 +94,6 @@ type PreAuthorizedRolesList struct { PreAuthorizedRolesList []AccountObjectIdentifier `ddl:"list,must_parentheses"` } -type BlockedRolesList struct { - BlockedRolesList []AccountObjectIdentifier `ddl:"list,must_parentheses"` -} - // CreateOauthForCustomClientsSecurityIntegrationOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake. type CreateOauthForCustomClientsSecurityIntegrationOptions struct { create bool `ddl:"static" sql:"CREATE"` @@ -123,6 +170,40 @@ type CreateScimSecurityIntegrationOptions struct { Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` } +// AlterExternalOauthSecurityIntegrationOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-security-integration-oauth-external. +type AlterExternalOauthSecurityIntegrationOptions struct { + alter bool `ddl:"static" sql:"ALTER"` + securityIntegration bool `ddl:"static" sql:"SECURITY INTEGRATION"` + IfExists *bool `ddl:"keyword" sql:"IF EXISTS"` + name AccountObjectIdentifier `ddl:"identifier"` + SetTags []TagAssociation `ddl:"keyword" sql:"SET TAG"` + UnsetTags []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` + Set *ExternalOauthIntegrationSet `ddl:"list,no_parentheses" sql:"SET"` + Unset *ExternalOauthIntegrationUnset `ddl:"list,no_parentheses" sql:"UNSET"` +} + +type ExternalOauthIntegrationSet struct { + Enabled *bool `ddl:"parameter" sql:"ENABLED"` + ExternalOauthType *ExternalOauthSecurityIntegrationTypeOption `ddl:"parameter" sql:"EXTERNAL_OAUTH_TYPE"` + ExternalOauthIssuer *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_ISSUER"` + ExternalOauthTokenUserMappingClaim []TokenUserMappingClaim `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM"` + ExternalOauthSnowflakeUserMappingAttribute *ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeOption `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE"` + ExternalOauthJwsKeysUrl []JwsKeysUrl `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_JWS_KEYS_URL"` + ExternalOauthBlockedRolesList *BlockedRolesList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_BLOCKED_ROLES_LIST"` + ExternalOauthAllowedRolesList *AllowedRolesList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_ALLOWED_ROLES_LIST"` + ExternalOauthRsaPublicKey *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_RSA_PUBLIC_KEY"` + ExternalOauthRsaPublicKey2 *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2"` + ExternalOauthAudienceList *AudienceList `ddl:"parameter,parentheses" sql:"EXTERNAL_OAUTH_AUDIENCE_LIST"` + ExternalOauthAnyRoleMode *ExternalOauthSecurityIntegrationAnyRoleModeOption `ddl:"parameter" sql:"EXTERNAL_OAUTH_ANY_ROLE_MODE"` + ExternalOauthScopeDelimiter *string `ddl:"parameter,single_quotes" sql:"EXTERNAL_OAUTH_SCOPE_DELIMITER"` + Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` +} + +type ExternalOauthIntegrationUnset struct { + Enabled *bool `ddl:"keyword" sql:"ENABLED"` + ExternalOauthAudienceList *bool `ddl:"keyword" sql:"EXTERNAL_OAUTH_AUDIENCE_LIST"` +} + // AlterOauthForPartnerApplicationsSecurityIntegrationOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-security-integration-oauth-snowflake. type AlterOauthForPartnerApplicationsSecurityIntegrationOptions struct { alter bool `ddl:"static" sql:"ALTER"` diff --git a/pkg/sdk/security_integrations_gen_test.go b/pkg/sdk/security_integrations_gen_test.go index d22e3c5234..9580b043d2 100644 --- a/pkg/sdk/security_integrations_gen_test.go +++ b/pkg/sdk/security_integrations_gen_test.go @@ -4,6 +4,81 @@ import ( "testing" ) +func TestSecurityIntegrations_CreateExternalOauth(t *testing.T) { + id := randomAccountObjectIdentifier() + + // Minimal valid CreateExternalOauthSecurityIntegrationOptions + defaultOpts := func() *CreateExternalOauthSecurityIntegrationOptions { + return &CreateExternalOauthSecurityIntegrationOptions{ + name: id, + Enabled: false, + ExternalOauthType: ExternalOauthSecurityIntegrationTypeCustom, + ExternalOauthIssuer: "foo", + ExternalOauthTokenUserMappingClaim: []TokenUserMappingClaim{{Claim: "foo"}}, + ExternalOauthSnowflakeUserMappingAttribute: ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeEmailAddress, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + var opts *CreateExternalOauthSecurityIntegrationOptions = nil + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: conflicting fields for [opts.OrReplace opts.IfNotExists]", func(t *testing.T) { + opts := defaultOpts() + opts.OrReplace = Bool(true) + opts.IfNotExists = Bool(true) + assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "OrReplace", "IfNotExists")) + }) + + t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey]", func(t *testing.T) { + opts := defaultOpts() + opts.ExternalOauthJwsKeysUrl = []JwsKeysUrl{{JwsKeyUrl: "foo"}} + opts.ExternalOauthRsaPublicKey = Pointer("key") + assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + }) + t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey2]", func(t *testing.T) { + opts := defaultOpts() + opts.ExternalOauthJwsKeysUrl = []JwsKeysUrl{{JwsKeyUrl: "foo"}} + opts.ExternalOauthRsaPublicKey2 = Pointer("key") + assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2")) + }) + t.Run("validation: conflicting fields for [opts.ExternalOauthAllowedRolesList opts.ExternalOauthBlockedRolesList]", func(t *testing.T) { + opts := defaultOpts() + opts.ExternalOauthAllowedRolesList = &AllowedRolesList{} + opts.ExternalOauthBlockedRolesList = &BlockedRolesList{} + assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList")) + }) + t.Run("basic", func(t *testing.T) { + opts := defaultOpts() + roleID := randomAccountObjectIdentifier() + opts.OrReplace = Bool(true) + opts.ExternalOauthJwsKeysUrl = []JwsKeysUrl{{JwsKeyUrl: "foo"}} + opts.ExternalOauthBlockedRolesList = &BlockedRolesList{BlockedRolesList: []AccountObjectIdentifier{roleID}} + assertOptsValidAndSQLEquals(t, opts, "CREATE OR REPLACE SECURITY INTEGRATION %s TYPE = EXTERNAL_OAUTH ENABLED = false EXTERNAL_OAUTH_TYPE = CUSTOM EXTERNAL_OAUTH_ISSUER = 'foo'"+ + " EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = ('foo') EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'EMAIL_ADDRESS' EXTERNAL_OAUTH_JWS_KEYS_URL = ('foo')"+ + " EXTERNAL_OAUTH_BLOCKED_ROLES_LIST = (%s)", id.FullyQualifiedName(), roleID.FullyQualifiedName()) + }) + + t.Run("all options", func(t *testing.T) { + opts := defaultOpts() + roleID := randomAccountObjectIdentifier() + opts.IfNotExists = Bool(true) + opts.ExternalOauthAllowedRolesList = &AllowedRolesList{AllowedRolesList: []AccountObjectIdentifier{roleID}} + opts.ExternalOauthRsaPublicKey = Pointer("foo") + opts.ExternalOauthRsaPublicKey2 = Pointer("foo") + opts.ExternalOauthAudienceList = &AudienceList{AudienceList: []AudienceListItem{{Item: "foo"}}} + opts.ExternalOauthAnyRoleMode = Pointer(ExternalOauthSecurityIntegrationAnyRoleModeDisable) + opts.ExternalOauthScopeDelimiter = Pointer(" ") + opts.ExternalOauthScopeMappingAttribute = Pointer("foo") + opts.Comment = Pointer("foo") + assertOptsValidAndSQLEquals(t, opts, "CREATE SECURITY INTEGRATION IF NOT EXISTS %s TYPE = EXTERNAL_OAUTH ENABLED = false EXTERNAL_OAUTH_TYPE = CUSTOM EXTERNAL_OAUTH_ISSUER = 'foo'"+ + " EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = ('foo') EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'EMAIL_ADDRESS' EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = (%s)"+ + " EXTERNAL_OAUTH_RSA_PUBLIC_KEY = 'foo' EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2 = 'foo' EXTERNAL_OAUTH_AUDIENCE_LIST = ('foo') EXTERNAL_OAUTH_ANY_ROLE_MODE = DISABLE"+ + " EXTERNAL_OAUTH_SCOPE_DELIMITER = ' ' EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE = 'foo' COMMENT = 'foo'", id.FullyQualifiedName(), roleID.FullyQualifiedName()) + }) +} + func TestSecurityIntegrations_CreateOauthCustom(t *testing.T) { id := randomAccountObjectIdentifier() @@ -212,6 +287,157 @@ func TestSecurityIntegrations_CreateScim(t *testing.T) { }) } +func TestSecurityIntegrations_AlterExternalOauth(t *testing.T) { + id := randomAccountObjectIdentifier() + + // Minimal valid AlterExternalOauthSecurityIntegrationOptions + defaultOpts := func() *AlterExternalOauthSecurityIntegrationOptions { + return &AlterExternalOauthSecurityIntegrationOptions{ + name: id, + } + } + + t.Run("validation: nil options", func(t *testing.T) { + var opts *AlterExternalOauthSecurityIntegrationOptions = nil + assertOptsInvalidJoinedErrors(t, opts, ErrNilOptions) + }) + + t.Run("validation: valid identifier for [opts.name]", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{ + Enabled: Pointer(true), + } + opts.name = NewAccountObjectIdentifier("") + assertOptsInvalidJoinedErrors(t, opts, ErrInvalidObjectIdentifier) + }) + + t.Run("validation: exactly of the fields [opts.*] should be set", func(t *testing.T) { + opts := defaultOpts() + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterExternalOauthSecurityIntegrationOptions", "Set", "Unset", "SetTags", "UnsetTags")) + }) + + t.Run("validation: at least one of the fields [opts.Set.*] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{} + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "Enabled", "ExternalOauthType", + "ExternalOauthIssuer", "ExternalOauthTokenUserMappingClaim", "ExternalOauthSnowflakeUserMappingAttribute", "ExternalOauthJwsKeysUrl", + "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList", "ExternalOauthRsaPublicKey", "ExternalOauthRsaPublicKey2", "ExternalOauthAudienceList", + "ExternalOauthAnyRoleMode", "ExternalOauthScopeDelimiter", "Comment")) + }) + + t.Run("validation: at least one of the fields [opts.Unset.*] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Unset = &ExternalOauthIntegrationUnset{} + assertOptsInvalidJoinedErrors(t, opts, errAtLeastOneOf("AlterExternalOauthSecurityIntegrationOptions.Unset", + "Enabled", "ExternalOauthAudienceList")) + }) + + t.Run("validation: exactly one of the fields [opts.*] should be set", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{} + opts.Unset = &ExternalOauthIntegrationUnset{} + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("AlterExternalOauthSecurityIntegrationOptions", "Set", "Unset", "SetTags", "UnsetTags")) + }) + + t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey]", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthJwsKeysUrl: []JwsKeysUrl{{JwsKeyUrl: "foo"}}, + ExternalOauthRsaPublicKey: Pointer("key"), + } + assertOptsInvalidJoinedErrors(t, opts, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + }) + t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey2]", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthJwsKeysUrl: []JwsKeysUrl{{JwsKeyUrl: "foo"}}, + ExternalOauthRsaPublicKey2: Pointer("key"), + } + assertOptsInvalidJoinedErrors(t, opts, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2")) + }) + t.Run("validation: conflicting fields for [opts.ExternalOauthAllowedRolesList opts.ExternalOauthBlockedRolesList]", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthAllowedRolesList: &AllowedRolesList{}, + ExternalOauthBlockedRolesList: &BlockedRolesList{}, + } + assertOptsInvalidJoinedErrors(t, opts, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList")) + }) + t.Run("empty lists", func(t *testing.T) { + opts := defaultOpts() + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthBlockedRolesList: &BlockedRolesList{}, + ExternalOauthAudienceList: &AudienceList{}, + } + assertOptsValidAndSQLEquals(t, opts, "ALTER SECURITY INTEGRATION %s SET EXTERNAL_OAUTH_BLOCKED_ROLES_LIST = (), EXTERNAL_OAUTH_AUDIENCE_LIST = ()", id.FullyQualifiedName()) + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthAllowedRolesList: &AllowedRolesList{}, + } + assertOptsValidAndSQLEquals(t, opts, "ALTER SECURITY INTEGRATION %s SET EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = ()", id.FullyQualifiedName()) + }) + + t.Run("all options - set", func(t *testing.T) { + opts := defaultOpts() + roleID := randomAccountObjectIdentifier() + opts.Set = &ExternalOauthIntegrationSet{ + Enabled: Pointer(true), + ExternalOauthType: Pointer(ExternalOauthSecurityIntegrationTypeCustom), + ExternalOauthIssuer: Pointer("foo"), + ExternalOauthTokenUserMappingClaim: []TokenUserMappingClaim{{Claim: "foo"}}, + ExternalOauthSnowflakeUserMappingAttribute: Pointer(ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeEmailAddress), + ExternalOauthAllowedRolesList: &AllowedRolesList{AllowedRolesList: []AccountObjectIdentifier{roleID}}, + ExternalOauthRsaPublicKey: Pointer("foo"), + ExternalOauthRsaPublicKey2: Pointer("foo"), + ExternalOauthAudienceList: &AudienceList{AudienceList: []AudienceListItem{{Item: "foo"}}}, + ExternalOauthAnyRoleMode: Pointer(ExternalOauthSecurityIntegrationAnyRoleModeDisable), + ExternalOauthScopeDelimiter: Pointer(" "), + Comment: Pointer("foo"), + } + assertOptsValidAndSQLEquals(t, opts, "ALTER SECURITY INTEGRATION %s SET ENABLED = true, EXTERNAL_OAUTH_TYPE = CUSTOM, EXTERNAL_OAUTH_ISSUER = 'foo',"+ + " EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = ('foo'), EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'EMAIL_ADDRESS', EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = (%s),"+ + " EXTERNAL_OAUTH_RSA_PUBLIC_KEY = 'foo', EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2 = 'foo', EXTERNAL_OAUTH_AUDIENCE_LIST = ('foo'), EXTERNAL_OAUTH_ANY_ROLE_MODE = DISABLE,"+ + " EXTERNAL_OAUTH_SCOPE_DELIMITER = ' ', COMMENT = 'foo'", id.FullyQualifiedName(), roleID.FullyQualifiedName()) + opts.Set = &ExternalOauthIntegrationSet{ + ExternalOauthBlockedRolesList: &BlockedRolesList{BlockedRolesList: []AccountObjectIdentifier{roleID}}, + ExternalOauthJwsKeysUrl: []JwsKeysUrl{{JwsKeyUrl: "foo"}}, + } + assertOptsValidAndSQLEquals(t, opts, "ALTER SECURITY INTEGRATION %s SET EXTERNAL_OAUTH_JWS_KEYS_URL = ('foo'), EXTERNAL_OAUTH_BLOCKED_ROLES_LIST = (%s)", id.FullyQualifiedName(), roleID.FullyQualifiedName()) + }) + + t.Run("all options - unset", func(t *testing.T) { + opts := defaultOpts() + opts.Unset = &ExternalOauthIntegrationUnset{ + Enabled: Pointer(true), + ExternalOauthAudienceList: Pointer(true), + } + assertOptsValidAndSQLEquals(t, opts, "ALTER SECURITY INTEGRATION %s UNSET ENABLED, EXTERNAL_OAUTH_AUDIENCE_LIST", id.FullyQualifiedName()) + }) + + t.Run("set tags", func(t *testing.T) { + opts := defaultOpts() + opts.SetTags = []TagAssociation{ + { + Name: NewAccountObjectIdentifier("name"), + Value: "value", + }, + { + Name: NewAccountObjectIdentifier("second-name"), + Value: "second-value", + }, + } + assertOptsValidAndSQLEquals(t, opts, `ALTER SECURITY INTEGRATION %s SET TAG "name" = 'value', "second-name" = 'second-value'`, id.FullyQualifiedName()) + }) + + t.Run("unset tags", func(t *testing.T) { + opts := defaultOpts() + opts.UnsetTags = []ObjectIdentifier{ + NewAccountObjectIdentifier("name"), + NewAccountObjectIdentifier("second-name"), + } + assertOptsValidAndSQLEquals(t, opts, `ALTER SECURITY INTEGRATION %s UNSET TAG "name", "second-name"`, id.FullyQualifiedName()) + }) +} + func TestSecurityIntegrations_AlterOauthPartner(t *testing.T) { id := randomAccountObjectIdentifier() diff --git a/pkg/sdk/security_integrations_impl_gen.go b/pkg/sdk/security_integrations_impl_gen.go index ac29b7722c..480b62ee35 100644 --- a/pkg/sdk/security_integrations_impl_gen.go +++ b/pkg/sdk/security_integrations_impl_gen.go @@ -12,6 +12,11 @@ type securityIntegrations struct { client *Client } +func (v *securityIntegrations) CreateExternalOauth(ctx context.Context, request *CreateExternalOauthSecurityIntegrationRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + func (v *securityIntegrations) CreateOauthForPartnerApplications(ctx context.Context, request *CreateOauthForPartnerApplicationsSecurityIntegrationRequest) error { opts := request.toOpts() return validateAndExec(v.client, ctx, opts) @@ -32,6 +37,11 @@ func (v *securityIntegrations) CreateScim(ctx context.Context, request *CreateSc return validateAndExec(v.client, ctx, opts) } +func (v *securityIntegrations) AlterExternalOauth(ctx context.Context, request *AlterExternalOauthSecurityIntegrationRequest) error { + opts := request.toOpts() + return validateAndExec(v.client, ctx, opts) +} + func (v *securityIntegrations) AlterOauthForPartnerApplications(ctx context.Context, request *AlterOauthForPartnerApplicationsSecurityIntegrationRequest) error { opts := request.toOpts() return validateAndExec(v.client, ctx, opts) @@ -88,6 +98,44 @@ func (v *securityIntegrations) ShowByID(ctx context.Context, id AccountObjectIde return collections.FindOne(securityIntegrations, func(r SecurityIntegration) bool { return r.Name == id.Name() }) } +func (r *CreateExternalOauthSecurityIntegrationRequest) toOpts() *CreateExternalOauthSecurityIntegrationOptions { + opts := &CreateExternalOauthSecurityIntegrationOptions{ + OrReplace: r.OrReplace, + IfNotExists: r.IfNotExists, + name: r.name, + Enabled: r.Enabled, + ExternalOauthType: r.ExternalOauthType, + ExternalOauthIssuer: r.ExternalOauthIssuer, + ExternalOauthTokenUserMappingClaim: r.ExternalOauthTokenUserMappingClaim, + ExternalOauthSnowflakeUserMappingAttribute: r.ExternalOauthSnowflakeUserMappingAttribute, + ExternalOauthJwsKeysUrl: r.ExternalOauthJwsKeysUrl, + + ExternalOauthRsaPublicKey: r.ExternalOauthRsaPublicKey, + ExternalOauthRsaPublicKey2: r.ExternalOauthRsaPublicKey2, + + ExternalOauthAnyRoleMode: r.ExternalOauthAnyRoleMode, + ExternalOauthScopeDelimiter: r.ExternalOauthScopeDelimiter, + ExternalOauthScopeMappingAttribute: r.ExternalOauthScopeMappingAttribute, + Comment: r.Comment, + } + if r.ExternalOauthBlockedRolesList != nil { + opts.ExternalOauthBlockedRolesList = &BlockedRolesList{ + BlockedRolesList: r.ExternalOauthBlockedRolesList.BlockedRolesList, + } + } + if r.ExternalOauthAllowedRolesList != nil { + opts.ExternalOauthAllowedRolesList = &AllowedRolesList{ + AllowedRolesList: r.ExternalOauthAllowedRolesList.AllowedRolesList, + } + } + if r.ExternalOauthAudienceList != nil { + opts.ExternalOauthAudienceList = &AudienceList{ + AudienceList: r.ExternalOauthAudienceList.AudienceList, + } + } + return opts +} + func (r *CreateOauthForPartnerApplicationsSecurityIntegrationRequest) toOpts() *CreateOauthForPartnerApplicationsSecurityIntegrationOptions { opts := &CreateOauthForPartnerApplicationsSecurityIntegrationOptions{ OrReplace: r.OrReplace, @@ -183,6 +231,54 @@ func (r *CreateScimSecurityIntegrationRequest) toOpts() *CreateScimSecurityInteg return opts } +func (r *AlterExternalOauthSecurityIntegrationRequest) toOpts() *AlterExternalOauthSecurityIntegrationOptions { + opts := &AlterExternalOauthSecurityIntegrationOptions{ + IfExists: r.IfExists, + name: r.name, + SetTags: r.SetTags, + UnsetTags: r.UnsetTags, + } + if r.Set != nil { + opts.Set = &ExternalOauthIntegrationSet{ + Enabled: r.Set.Enabled, + ExternalOauthType: r.Set.ExternalOauthType, + ExternalOauthIssuer: r.Set.ExternalOauthIssuer, + ExternalOauthTokenUserMappingClaim: r.Set.ExternalOauthTokenUserMappingClaim, + ExternalOauthSnowflakeUserMappingAttribute: r.Set.ExternalOauthSnowflakeUserMappingAttribute, + ExternalOauthJwsKeysUrl: r.Set.ExternalOauthJwsKeysUrl, + + ExternalOauthRsaPublicKey: r.Set.ExternalOauthRsaPublicKey, + ExternalOauthRsaPublicKey2: r.Set.ExternalOauthRsaPublicKey2, + + ExternalOauthAnyRoleMode: r.Set.ExternalOauthAnyRoleMode, + ExternalOauthScopeDelimiter: r.Set.ExternalOauthScopeDelimiter, + Comment: r.Set.Comment, + } + if r.Set.ExternalOauthBlockedRolesList != nil { + opts.Set.ExternalOauthBlockedRolesList = &BlockedRolesList{ + BlockedRolesList: r.Set.ExternalOauthBlockedRolesList.BlockedRolesList, + } + } + if r.Set.ExternalOauthAllowedRolesList != nil { + opts.Set.ExternalOauthAllowedRolesList = &AllowedRolesList{ + AllowedRolesList: r.Set.ExternalOauthAllowedRolesList.AllowedRolesList, + } + } + if r.Set.ExternalOauthAudienceList != nil { + opts.Set.ExternalOauthAudienceList = &AudienceList{ + AudienceList: r.Set.ExternalOauthAudienceList.AudienceList, + } + } + } + if r.Unset != nil { + opts.Unset = &ExternalOauthIntegrationUnset{ + Enabled: r.Unset.Enabled, + ExternalOauthAudienceList: r.Unset.ExternalOauthAudienceList, + } + } + return opts +} + func (r *AlterOauthForPartnerApplicationsSecurityIntegrationRequest) toOpts() *AlterOauthForPartnerApplicationsSecurityIntegrationOptions { opts := &AlterOauthForPartnerApplicationsSecurityIntegrationOptions{ IfExists: r.IfExists, diff --git a/pkg/sdk/security_integrations_validations_gen.go b/pkg/sdk/security_integrations_validations_gen.go index b7b4d37d2d..6cfdeddaa9 100644 --- a/pkg/sdk/security_integrations_validations_gen.go +++ b/pkg/sdk/security_integrations_validations_gen.go @@ -1,10 +1,12 @@ package sdk var ( + _ validatable = new(CreateExternalOauthSecurityIntegrationOptions) _ validatable = new(CreateOauthForPartnerApplicationsSecurityIntegrationOptions) _ validatable = new(CreateOauthForCustomClientsSecurityIntegrationOptions) _ validatable = new(CreateSaml2SecurityIntegrationOptions) _ validatable = new(CreateScimSecurityIntegrationOptions) + _ validatable = new(AlterExternalOauthSecurityIntegrationOptions) _ validatable = new(AlterOauthForPartnerApplicationsSecurityIntegrationOptions) _ validatable = new(AlterOauthForCustomClientsSecurityIntegrationOptions) _ validatable = new(AlterSaml2SecurityIntegrationOptions) @@ -14,6 +16,29 @@ var ( _ validatable = new(ShowSecurityIntegrationOptions) ) +func (opts *CreateExternalOauthSecurityIntegrationOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if everyValueSet(opts.ExternalOauthBlockedRolesList, opts.ExternalOauthAllowedRolesList) { + errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList")) + } + if everyValueSet(opts.ExternalOauthJwsKeysUrl, opts.ExternalOauthRsaPublicKey) { + errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + } + if everyValueSet(opts.ExternalOauthJwsKeysUrl, opts.ExternalOauthRsaPublicKey2) { + errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2")) + } + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if everyValueSet(opts.OrReplace, opts.IfNotExists) { + errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "OrReplace", "IfNotExists")) + } + return JoinErrors(errs...) +} + func (opts *CreateOauthForPartnerApplicationsSecurityIntegrationOptions) validate() error { if opts == nil { return ErrNilOptions @@ -73,6 +98,39 @@ func (opts *CreateScimSecurityIntegrationOptions) validate() error { return JoinErrors(errs...) } +func (opts *AlterExternalOauthSecurityIntegrationOptions) validate() error { + if opts == nil { + return ErrNilOptions + } + var errs []error + if !ValidObjectIdentifier(opts.name) { + errs = append(errs, ErrInvalidObjectIdentifier) + } + if !exactlyOneValueSet(opts.Set, opts.Unset, opts.SetTags, opts.UnsetTags) { + errs = append(errs, errExactlyOneOf("AlterExternalOauthSecurityIntegrationOptions", "Set", "Unset", "SetTags", "UnsetTags")) + } + if valueSet(opts.Set) { + if everyValueSet(opts.Set.ExternalOauthBlockedRolesList, opts.Set.ExternalOauthAllowedRolesList) { + errs = append(errs, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList")) + } + if everyValueSet(opts.Set.ExternalOauthJwsKeysUrl, opts.Set.ExternalOauthRsaPublicKey) { + errs = append(errs, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + } + if everyValueSet(opts.Set.ExternalOauthJwsKeysUrl, opts.Set.ExternalOauthRsaPublicKey2) { + errs = append(errs, errOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2")) + } + if !anyValueSet(opts.Set.Enabled, opts.Set.ExternalOauthType, opts.Set.ExternalOauthIssuer, opts.Set.ExternalOauthTokenUserMappingClaim, opts.Set.ExternalOauthSnowflakeUserMappingAttribute, opts.Set.ExternalOauthJwsKeysUrl, opts.Set.ExternalOauthBlockedRolesList, opts.Set.ExternalOauthAllowedRolesList, opts.Set.ExternalOauthRsaPublicKey, opts.Set.ExternalOauthRsaPublicKey2, opts.Set.ExternalOauthAudienceList, opts.Set.ExternalOauthAnyRoleMode, opts.Set.ExternalOauthScopeDelimiter, opts.Set.Comment) { + errs = append(errs, errAtLeastOneOf("AlterExternalOauthSecurityIntegrationOptions.Set", "Enabled", "ExternalOauthType", "ExternalOauthIssuer", "ExternalOauthTokenUserMappingClaim", "ExternalOauthSnowflakeUserMappingAttribute", "ExternalOauthJwsKeysUrl", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList", "ExternalOauthRsaPublicKey", "ExternalOauthRsaPublicKey2", "ExternalOauthAudienceList", "ExternalOauthAnyRoleMode", "ExternalOauthScopeDelimiter", "Comment")) + } + } + if valueSet(opts.Unset) { + if !anyValueSet(opts.Unset.Enabled, opts.Unset.ExternalOauthAudienceList) { + errs = append(errs, errAtLeastOneOf("AlterExternalOauthSecurityIntegrationOptions.Unset", "Enabled", "ExternalOauthAudienceList")) + } + } + return JoinErrors(errs...) +} + func (opts *AlterOauthForPartnerApplicationsSecurityIntegrationOptions) validate() error { if opts == nil { return ErrNilOptions diff --git a/pkg/sdk/testint/security_integrations_gen_integration_test.go b/pkg/sdk/testint/security_integrations_gen_integration_test.go index 1971bded6a..1605985ce1 100644 --- a/pkg/sdk/testint/security_integrations_gen_integration_test.go +++ b/pkg/sdk/testint/security_integrations_gen_integration_test.go @@ -31,6 +31,24 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.NoError(t, err) }) } + createExternalOauth := func(t *testing.T, with func(*sdk.CreateExternalOauthSecurityIntegrationRequest)) (*sdk.SecurityIntegration, sdk.AccountObjectIdentifier, string) { + t.Helper() + id := testClientHelper().Ids.RandomAccountObjectIdentifier() + issuer := testClientHelper().Ids.Alpha() + req := sdk.NewCreateExternalOauthSecurityIntegrationRequest(id, false, sdk.ExternalOauthSecurityIntegrationTypeCustom, + issuer, []sdk.TokenUserMappingClaim{{Claim: "foo"}}, sdk.ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeLoginName, + ) + if with != nil { + with(req) + } + err := client.SecurityIntegrations.CreateExternalOauth(ctx, req) + require.NoError(t, err) + cleanupSecurityIntegration(t, id) + integration, err := client.SecurityIntegrations.ShowByID(ctx, id) + require.NoError(t, err) + + return integration, id, issuer + } createOauthCustom := func(t *testing.T, with func(*sdk.CreateOauthForCustomClientsSecurityIntegrationRequest)) (*sdk.SecurityIntegration, sdk.AccountObjectIdentifier) { t.Helper() id := testClientHelper().Ids.RandomAccountObjectIdentifier() @@ -109,6 +127,49 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Equal(t, "SECURITY", si.Category) } + assertFieldContainsList := func(details []sdk.SecurityIntegrationProperty, field, value string) { + found, err := collections.FindOne(details, func(d sdk.SecurityIntegrationProperty) bool { return d.Name == field }) + assert.NoError(t, err) + roles := strings.Split(found.Value, ",") + for _, exp := range strings.Split(value, ",") { + assert.Contains(t, roles, exp) + } + } + + type externalOauthDetails struct { + enabled string + externalOauthIssuer string + externalOauthJwsKeysUrl string + externalOauthAnyRoleMode string + externalOauthScopeMappingAttribute string + externalOauthRsaPublicKey string + externalOauthRsaPublicKey2 string + externalOauthBlockedRolesList string + externalOauthAllowedRolesList string + externalOauthAudienceList string + externalOauthTokenUserMappingClaim string + externalOauthSnowflakeUserMappingAttribute string + externalOauthScopeDelimiter string + comment string + } + + assertExternalOauth := func(details []sdk.SecurityIntegrationProperty, d externalOauthDetails) { + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "ENABLED", Type: "Boolean", Value: d.enabled, Default: "false"}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ISSUER", Type: "String", Value: d.externalOauthIssuer, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_JWS_KEYS_URL", Type: "Object", Value: d.externalOauthJwsKeysUrl, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ANY_ROLE_MODE", Type: "String", Value: d.externalOauthAnyRoleMode, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE", Type: "String", Value: d.externalOauthScopeMappingAttribute, Default: "scp"}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_RSA_PUBLIC_KEY", Type: "String", Value: d.externalOauthRsaPublicKey, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_RSA_PUBLIC_KEY_2", Type: "String", Value: d.externalOauthRsaPublicKey2, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ALLOWED_ROLES_LIST", Type: "List", Value: d.externalOauthAllowedRolesList, Default: "[]"}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_AUDIENCE_LIST", Type: "List", Value: d.externalOauthAudienceList, Default: "[]"}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM", Type: "Object", Value: d.externalOauthTokenUserMappingClaim, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE", Type: "String", Value: d.externalOauthSnowflakeUserMappingAttribute, Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_SCOPE_DELIMITER", Type: "String", Value: d.externalOauthScopeDelimiter, Default: ","}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "COMMENT", Type: "String", Value: d.comment, Default: ""}) + assertFieldContainsList(details, "EXTERNAL_OAUTH_BLOCKED_ROLES_LIST", d.externalOauthBlockedRolesList) + } + type oauthPartnerDetails struct { enabled string oauthIssueRefreshTokens string @@ -128,13 +189,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "PRE_AUTHORIZED_ROLES_LIST", Type: "List", Value: d.preAuthorizedRolesList, Default: "[]"}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "NETWORK_POLICY", Type: "String", Value: d.networkPolicy, Default: ""}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "COMMENT", Type: "String", Value: d.comment, Default: ""}) - // Check one-by-one because snowflake returns a few extra roles - found, err := collections.FindOne(details, func(d sdk.SecurityIntegrationProperty) bool { return d.Name == "BLOCKED_ROLES_LIST" }) - assert.NoError(t, err) - roles := strings.Split(found.Value, ",") - for _, exp := range strings.Split(d.blockedRolesList, ",") { - assert.Contains(t, roles, exp) - } + assertFieldContainsList(details, "BLOCKED_ROLES_LIST", d.blockedRolesList) } assertOauthCustom := func(details []sdk.SecurityIntegrationProperty, d oauthPartnerDetails, allowNonTlsRedirectUri, clientType, enforcePkce string) { @@ -196,6 +251,58 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "ALLOWED_EMAIL_PATTERNS", Type: "List", Value: d.allowedEmailPatterns, Default: "[]"}) } + t.Run("CreateExternalOauth with allowed list and jws keys url", func(t *testing.T) { + role1, role1Cleanup := testClientHelper().Role.CreateRole(t) + t.Cleanup(role1Cleanup) + + integration, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthAllowedRolesList(sdk.AllowedRolesListRequest{AllowedRolesList: []sdk.AccountObjectIdentifier{role1.ID()}}). + WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example.com"}}) + }) + details, err := client.SecurityIntegrations.Describe(ctx, id) + require.NoError(t, err) + + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_JWS_KEYS_URL", Type: "Object", Value: "http://example.com", Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ALLOWED_ROLES_LIST", Type: "List", Value: role1.Name, Default: "[]"}) + + assertSecurityIntegration(t, integration, id, "EXTERNAL_OAUTH - CUSTOM", false, "") + }) + + t.Run("CreateExternalOauth with other options", func(t *testing.T) { + role1, role1Cleanup := testClientHelper().Role.CreateRole(t) + t.Cleanup(role1Cleanup) + + integration, id, issuer := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthBlockedRolesList(sdk.BlockedRolesListRequest{BlockedRolesList: []sdk.AccountObjectIdentifier{role1.ID()}}). + WithExternalOauthRsaPublicKey(rsaKey). + WithExternalOauthRsaPublicKey2(rsaKey). + WithExternalOauthAudienceList(sdk.AudienceListRequest{AudienceList: []sdk.AudienceListItem{{Item: "foo"}}}). + WithExternalOauthAnyRoleMode(sdk.ExternalOauthSecurityIntegrationAnyRoleModeEnable). + WithExternalOauthScopeDelimiter(" "). + WithExternalOauthScopeMappingAttribute("scp"). + WithComment("foo") + }) + details, err := client.SecurityIntegrations.Describe(ctx, id) + require.NoError(t, err) + + assertExternalOauth(details, externalOauthDetails{ + enabled: "false", + externalOauthIssuer: issuer, + externalOauthAnyRoleMode: string(sdk.ExternalOauthSecurityIntegrationAnyRoleModeEnable), + externalOauthScopeMappingAttribute: "scp", + externalOauthRsaPublicKey: rsaKey, + externalOauthRsaPublicKey2: rsaKey, + externalOauthBlockedRolesList: role1.Name, + externalOauthAudienceList: "foo", + externalOauthTokenUserMappingClaim: "['foo']", + externalOauthSnowflakeUserMappingAttribute: string(sdk.ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeLoginName), + externalOauthScopeDelimiter: " ", + comment: "foo", + }) + + assertSecurityIntegration(t, integration, id, "EXTERNAL_OAUTH - CUSTOM", false, "foo") + }) + t.Run("CreateOauthPartner", func(t *testing.T) { role1, role1Cleanup := testClientHelper().Role.CreateRole(t) t.Cleanup(role1Cleanup) @@ -321,6 +428,120 @@ func TestInt_SecurityIntegrations(t *testing.T) { require.NoError(t, err) assertSecurityIntegration(t, si, id, "SCIM - GENERIC", false, "a") }) + t.Run("AlterExternalOauth", func(t *testing.T) { + _, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example.com"}}) + }) + role1, role1Cleanup := testClientHelper().Role.CreateRole(t) + t.Cleanup(role1Cleanup) + setRequest := sdk.NewAlterExternalOauthSecurityIntegrationRequest(id). + WithSet( + *sdk.NewExternalOauthIntegrationSetRequest(). + WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://test.com"}}). + WithExternalOauthAllowedRolesList(sdk.AllowedRolesListRequest{AllowedRolesList: []sdk.AccountObjectIdentifier{role1.ID()}}), + ) + err := client.SecurityIntegrations.AlterExternalOauth(ctx, setRequest) + require.NoError(t, err) + + details, err := client.SecurityIntegrations.Describe(ctx, id) + require.NoError(t, err) + + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_JWS_KEYS_URL", Type: "Object", Value: "http://test.com", Default: ""}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ALLOWED_ROLES_LIST", Type: "List", Value: role1.Name, Default: "[]"}) + }) + t.Run("AlterExternalOauth", func(t *testing.T) { + _, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthRsaPublicKey(rsaKey). + WithExternalOauthRsaPublicKey2(rsaKey) + }) + role1, role1Cleanup := testClientHelper().Role.CreateRole(t) + t.Cleanup(role1Cleanup) + newIssuer := testClientHelper().Ids.Alpha() + setRequest := sdk.NewAlterExternalOauthSecurityIntegrationRequest(id). + WithSet( + *sdk.NewExternalOauthIntegrationSetRequest(). + WithEnabled(true). + WithExternalOauthIssuer(newIssuer). + WithExternalOauthTokenUserMappingClaim([]sdk.TokenUserMappingClaim{{Claim: "bar"}}). + WithExternalOauthSnowflakeUserMappingAttribute(sdk.ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeEmailAddress). + WithExternalOauthBlockedRolesList(sdk.BlockedRolesListRequest{BlockedRolesList: []sdk.AccountObjectIdentifier{role1.ID()}}). + WithExternalOauthRsaPublicKey(rsaKey). + WithExternalOauthRsaPublicKey2(rsaKey). + WithExternalOauthAudienceList(sdk.AudienceListRequest{AudienceList: []sdk.AudienceListItem{{Item: "foo"}}}). + WithExternalOauthAnyRoleMode(sdk.ExternalOauthSecurityIntegrationAnyRoleModeDisable). + WithExternalOauthScopeDelimiter(" "). + WithComment("foo"), + ) + err := client.SecurityIntegrations.AlterExternalOauth(ctx, setRequest) + require.NoError(t, err) + + details, err := client.SecurityIntegrations.Describe(ctx, id) + require.NoError(t, err) + + assertExternalOauth(details, externalOauthDetails{ + enabled: "true", + externalOauthIssuer: newIssuer, + externalOauthAnyRoleMode: string(sdk.ExternalOauthSecurityIntegrationAnyRoleModeDisable), + externalOauthRsaPublicKey: rsaKey, + externalOauthRsaPublicKey2: rsaKey, + externalOauthBlockedRolesList: role1.Name, + externalOauthAudienceList: "foo", + externalOauthTokenUserMappingClaim: "['bar']", + externalOauthSnowflakeUserMappingAttribute: string(sdk.ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeEmailAddress), + externalOauthScopeDelimiter: " ", + comment: "foo", + }) + + unsetRequest := sdk.NewAlterExternalOauthSecurityIntegrationRequest(id). + WithUnset( + *sdk.NewExternalOauthIntegrationUnsetRequest(). + WithEnabled(true). + WithExternalOauthAudienceList(true), + ) + err = client.SecurityIntegrations.AlterExternalOauth(ctx, unsetRequest) + require.NoError(t, err) + + details, err = client.SecurityIntegrations.Describe(ctx, id) + require.NoError(t, err) + + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "ENABLED", Type: "Boolean", Value: "false", Default: "false"}) + assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_AUDIENCE_LIST", Type: "List", Value: "", Default: "[]"}) + }) + + t.Run("AlterExternalOauth - set and unset tags", func(t *testing.T) { + tag, tagCleanup := testClientHelper().Tag.CreateTag(t) + t.Cleanup(tagCleanup) + + _, id, _ := createExternalOauth(t, nil) + + tagValue := "abc" + tags := []sdk.TagAssociation{ + { + Name: tag.ID(), + Value: tagValue, + }, + } + alterRequestSetTags := sdk.NewAlterExternalOauthSecurityIntegrationRequest(id).WithSetTags(tags) + + err := client.SecurityIntegrations.AlterExternalOauth(ctx, alterRequestSetTags) + require.NoError(t, err) + + returnedTagValue, err := client.SystemFunctions.GetTag(ctx, tag.ID(), id, sdk.ObjectTypeIntegration) + require.NoError(t, err) + + assert.Equal(t, tagValue, returnedTagValue) + + unsetTags := []sdk.ObjectIdentifier{ + tag.ID(), + } + alterRequestUnsetTags := sdk.NewAlterExternalOauthSecurityIntegrationRequest(id).WithUnsetTags(unsetTags) + + err = client.SecurityIntegrations.AlterExternalOauth(ctx, alterRequestUnsetTags) + require.NoError(t, err) + + _, err = client.SystemFunctions.GetTag(ctx, tag.ID(), id, sdk.ObjectTypeIntegration) + require.Error(t, err) + }) t.Run("AlterOauthPartner", func(t *testing.T) { _, id := createOauthPartner(t, func(r *sdk.CreateOauthForPartnerApplicationsSecurityIntegrationRequest) { From 742ec894f59815f0a2547e29458e47feddac873b Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Fri, 24 May 2024 13:07:47 +0200 Subject: [PATCH 2/5] Rename tests --- pkg/sdk/testint/security_integrations_gen_integration_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/sdk/testint/security_integrations_gen_integration_test.go b/pkg/sdk/testint/security_integrations_gen_integration_test.go index 1605985ce1..1a8660399f 100644 --- a/pkg/sdk/testint/security_integrations_gen_integration_test.go +++ b/pkg/sdk/testint/security_integrations_gen_integration_test.go @@ -428,7 +428,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { require.NoError(t, err) assertSecurityIntegration(t, si, id, "SCIM - GENERIC", false, "a") }) - t.Run("AlterExternalOauth", func(t *testing.T) { + t.Run("AlterExternalOauth with allowed list and jws keys url", func(t *testing.T) { _, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { r.WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example.com"}}) }) @@ -449,7 +449,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_JWS_KEYS_URL", Type: "Object", Value: "http://test.com", Default: ""}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_ALLOWED_ROLES_LIST", Type: "List", Value: role1.Name, Default: "[]"}) }) - t.Run("AlterExternalOauth", func(t *testing.T) { + t.Run("AlterExternalOauth with other options", func(t *testing.T) { _, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { r.WithExternalOauthRsaPublicKey(rsaKey). WithExternalOauthRsaPublicKey2(rsaKey) From ada8109db1d168fb69073808bbdd5499e2d616eb Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Fri, 24 May 2024 14:12:34 +0200 Subject: [PATCH 3/5] Fix tests and validation --- pkg/sdk/security_integrations_def.go | 2 +- pkg/sdk/security_integrations_gen_test.go | 5 +++-- .../security_integrations_validations_gen.go | 4 ++-- ...urity_integrations_gen_integration_test.go | 20 ++++++++++++++++++- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/pkg/sdk/security_integrations_def.go b/pkg/sdk/security_integrations_def.go index 80fef045c7..95e16a82c0 100644 --- a/pkg/sdk/security_integrations_def.go +++ b/pkg/sdk/security_integrations_def.go @@ -279,7 +279,7 @@ var SecurityIntegrationsDef = g.NewInterface( OptionalTextAssignment("EXTERNAL_OAUTH_SCOPE_DELIMITER", g.ParameterOptions().SingleQuotes()). OptionalTextAssignment("EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE", g.ParameterOptions().SingleQuotes()). WithValidation(g.ConflictingFields, "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList"). - WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey"). + WithValidation(g.ExactlyOneValueSet, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey"). WithValidation(g.ConflictingFields, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2") }), allowedRolesListDef, diff --git a/pkg/sdk/security_integrations_gen_test.go b/pkg/sdk/security_integrations_gen_test.go index 9580b043d2..7579968dd8 100644 --- a/pkg/sdk/security_integrations_gen_test.go +++ b/pkg/sdk/security_integrations_gen_test.go @@ -31,11 +31,12 @@ func TestSecurityIntegrations_CreateExternalOauth(t *testing.T) { assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "OrReplace", "IfNotExists")) }) - t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey]", func(t *testing.T) { + t.Run("validation: exactly one fields in [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey]", func(t *testing.T) { opts := defaultOpts() + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) opts.ExternalOauthJwsKeysUrl = []JwsKeysUrl{{JwsKeyUrl: "foo"}} opts.ExternalOauthRsaPublicKey = Pointer("key") - assertOptsInvalidJoinedErrors(t, opts, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + assertOptsInvalidJoinedErrors(t, opts, errExactlyOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) }) t.Run("validation: conflicting fields for [opts.ExternalOauthJwsKeysUrl opts.ExternalOauthRsaPublicKey2]", func(t *testing.T) { opts := defaultOpts() diff --git a/pkg/sdk/security_integrations_validations_gen.go b/pkg/sdk/security_integrations_validations_gen.go index 6cfdeddaa9..57a9a37e20 100644 --- a/pkg/sdk/security_integrations_validations_gen.go +++ b/pkg/sdk/security_integrations_validations_gen.go @@ -24,8 +24,8 @@ func (opts *CreateExternalOauthSecurityIntegrationOptions) validate() error { if everyValueSet(opts.ExternalOauthBlockedRolesList, opts.ExternalOauthAllowedRolesList) { errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthBlockedRolesList", "ExternalOauthAllowedRolesList")) } - if everyValueSet(opts.ExternalOauthJwsKeysUrl, opts.ExternalOauthRsaPublicKey) { - errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) + if !exactlyOneValueSet(opts.ExternalOauthJwsKeysUrl, opts.ExternalOauthRsaPublicKey) { + errs = append(errs, errExactlyOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey")) } if everyValueSet(opts.ExternalOauthJwsKeysUrl, opts.ExternalOauthRsaPublicKey2) { errs = append(errs, errOneOf("CreateExternalOauthSecurityIntegrationOptions", "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey2")) diff --git a/pkg/sdk/testint/security_integrations_gen_integration_test.go b/pkg/sdk/testint/security_integrations_gen_integration_test.go index 1a8660399f..cc9fd000f7 100644 --- a/pkg/sdk/testint/security_integrations_gen_integration_test.go +++ b/pkg/sdk/testint/security_integrations_gen_integration_test.go @@ -512,7 +512,9 @@ func TestInt_SecurityIntegrations(t *testing.T) { tag, tagCleanup := testClientHelper().Tag.CreateTag(t) t.Cleanup(tagCleanup) - _, id, _ := createExternalOauth(t, nil) + _, id, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example.com"}}) + }) tagValue := "abc" tags := []sdk.TagAssociation{ @@ -950,6 +952,22 @@ func TestInt_SecurityIntegrations(t *testing.T) { assertSecurityIntegration(t, si, id, "SCIM - GENERIC", false, "") }) + t.Run("Show ExternalOauth", func(t *testing.T) { + si1, id1, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example.com"}}) + }) + si2, _, _ := createExternalOauth(t, func(r *sdk.CreateExternalOauthSecurityIntegrationRequest) { + r.WithExternalOauthJwsKeysUrl([]sdk.JwsKeysUrl{{JwsKeyUrl: "http://example2.com"}}) + }) + + returnedIntegrations, err := client.SecurityIntegrations.Show(ctx, sdk.NewShowSecurityIntegrationRequest().WithLike(sdk.Like{ + Pattern: sdk.Pointer(id1.Name()), + })) + require.NoError(t, err) + assert.Contains(t, returnedIntegrations, *si1) + assert.NotContains(t, returnedIntegrations, *si2) + }) + t.Run("Show OauthPartner", func(t *testing.T) { si1, id1 := createOauthPartner(t, nil) // more than one oauth partner integration is not allowed, create a custom one From b1c689804f6ed97d8d5730c2a43db3f4aec8a640 Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Mon, 27 May 2024 15:35:03 +0200 Subject: [PATCH 4/5] Fixes --- pkg/acceptance/helpers/random/url.go | 12 ------- pkg/sdk/poc/README.md | 11 ++++--- pkg/sdk/security_integrations_def.go | 6 ++-- .../security_integrations_dto_builders_gen.go | 33 +++++++++---------- pkg/sdk/security_integrations_dto_gen.go | 6 ++-- ...urity_integrations_gen_integration_test.go | 17 +++++----- 6 files changed, 37 insertions(+), 48 deletions(-) delete mode 100644 pkg/acceptance/helpers/random/url.go diff --git a/pkg/acceptance/helpers/random/url.go b/pkg/acceptance/helpers/random/url.go deleted file mode 100644 index 9fdb114dbf..0000000000 --- a/pkg/acceptance/helpers/random/url.go +++ /dev/null @@ -1,12 +0,0 @@ -package random - -import ( - "fmt" - "testing" -) - -// GenerateURL generates a random valid URL -func GenerateURL(t *testing.T) string { - t.Helper() - return fmt.Sprintf("https://%s.com", AlphaN(6)) -} diff --git a/pkg/sdk/poc/README.md b/pkg/sdk/poc/README.md index 69be9bcbdd..ac4c624de3 100644 --- a/pkg/sdk/poc/README.md +++ b/pkg/sdk/poc/README.md @@ -55,7 +55,7 @@ but if we add one case, or modify more cases this becomes more challenging) - in some cases we could need more filters -> see alerts.go (but we can implement it later) - handle arrays - handle more validation types -- write new `valueSet` function (see validations.go) that will have better defaults or more parameters that will determine +- write new `valueSet` function (see validations.go) that will have better defaults or more parameters that will determine checking behaviour which should get rid of edge cases that may cause bugs in the future - right now, we have `valueSet` function that doesn't take into consideration edge cases, e.g. with slice where sometimes we would like to do something like `alter x set y = ()` (set empty array to unset `y`). Those edge cases have cause on our @@ -66,7 +66,7 @@ checking behaviour which should get rid of edge cases that may cause bugs in the - example implementation - https://go.dev/play/p/Cgt0sISlzwK - divide implementation templates for Show, Describe and others - check if SelfIdentifier implementation is correct (mostly type, because it's derived from interface obj) by checking -if there's a resource with different types of identifiers across queries (e.g. Create , Alter ) +if there's a resource with different types of identifiers across queries (e.g. Create , Alter ) - we should specify prefix / postfix standard for top-level items in _def.go files to avoid any conflicts in the package - remove name argument from QueryStruct in the Operation, because Opt structs in the Operation will have name from op name + interface field and not query struct itself - Derive field name from QueryStruct, e.g. see network_policies_def where we can remove "Set" field, but we have to make a convention of creating nested struct with @@ -101,10 +101,13 @@ find a better solution to solve the issue (add more logic to the templates ?) - struct_to_builder is not supporting templated-like values. See stages_def.go where in SQL there could be value, where 'n' can be replaced with any number - `SKIP_FILE_n` - this looks more like keyword without a space between SQL prefix and int - `SKIP_FILE_n%` (e.g. `SKIP_FILE_123%`) - this is more template-like behaviour, notice that 'n' is inside the value (we cannot reproduce that right now with struct_to_builder capabilities) -- fix builder generation +- fix builder generation - we can add `flatten` option in cases where some sql structs had to be nested to create correct sql representation - for example encryption options in `stages_def.go` (instead of calling `.WithEncryption(NewEncryptionRequest(encryption))` we could call `.WithEncryption(encryption)`) - operation names (or their sql struct names) should dictate more how constructors are made +- better handling of list of strings/identifiers + - there should be no need to define custom types every time + - more clear definition of lists that can be empty vs cannot be empty ##### Known issues - generating two converts when Show and Desc use the same data structure @@ -130,4 +133,4 @@ type SomeReq struct { ##### Known limitations - automatic array conversion is not recursive, so we're only supporting one level mapping - - []Request1{ foo Request2, bar int } won't be converted, but []Request1{ foo string, bar int } will \ No newline at end of file + - []Request1{ foo Request2, bar int } won't be converted, but []Request1{ foo string, bar int } will diff --git a/pkg/sdk/security_integrations_def.go b/pkg/sdk/security_integrations_def.go index 95e16a82c0..e8c3e5f902 100644 --- a/pkg/sdk/security_integrations_def.go +++ b/pkg/sdk/security_integrations_def.go @@ -72,13 +72,13 @@ var ( preAuthorizedRolesListDef = g.NewQueryStruct("PreAuthorizedRolesList"). List("PreAuthorizedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) blockedRolesListDef = g.NewQueryStruct("BlockedRolesList"). - List("BlockedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) + List("BlockedRolesList", "AccountObjectIdentifier", g.ListOptions().Required().MustParentheses()) allowedRolesListDef = g.NewQueryStruct("AllowedRolesList"). - List("AllowedRolesList", "AccountObjectIdentifier", g.ListOptions().MustParentheses()) + List("AllowedRolesList", "AccountObjectIdentifier", g.ListOptions().Required().MustParentheses()) jwsKeysUrlDef = g.NewQueryStruct("JwsKeysUrl").Text("JwsKeyUrl", g.KeywordOptions().SingleQuotes().Required()) audienceListItemDef = g.NewQueryStruct("AudienceListItem").Text("Item", g.KeywordOptions().SingleQuotes().Required()) audienceListDef = g.NewQueryStruct("AudienceList"). - List("AudienceList", "AudienceListItem", g.ListOptions().MustParentheses()) + List("AudienceList", "AudienceListItem", g.ListOptions().Required().MustParentheses()) tokenUserMappingClaimDef = g.NewQueryStruct("TokenUserMappingClaim").Text("Claim", g.KeywordOptions().SingleQuotes().Required()) ) diff --git a/pkg/sdk/security_integrations_dto_builders_gen.go b/pkg/sdk/security_integrations_dto_builders_gen.go index f6e0a3342e..d075a351c7 100644 --- a/pkg/sdk/security_integrations_dto_builders_gen.go +++ b/pkg/sdk/security_integrations_dto_builders_gen.go @@ -82,31 +82,28 @@ func (s *CreateExternalOauthSecurityIntegrationRequest) WithComment(Comment stri return s } -func NewBlockedRolesListRequest() *BlockedRolesListRequest { - return &BlockedRolesListRequest{} -} - -func (s *BlockedRolesListRequest) WithBlockedRolesList(BlockedRolesList []AccountObjectIdentifier) *BlockedRolesListRequest { +func NewBlockedRolesListRequest( + BlockedRolesList []AccountObjectIdentifier, +) *BlockedRolesListRequest { + s := BlockedRolesListRequest{} s.BlockedRolesList = BlockedRolesList - return s -} - -func NewAllowedRolesListRequest() *AllowedRolesListRequest { - return &AllowedRolesListRequest{} + return &s } -func (s *AllowedRolesListRequest) WithAllowedRolesList(AllowedRolesList []AccountObjectIdentifier) *AllowedRolesListRequest { +func NewAllowedRolesListRequest( + AllowedRolesList []AccountObjectIdentifier, +) *AllowedRolesListRequest { + s := AllowedRolesListRequest{} s.AllowedRolesList = AllowedRolesList - return s -} - -func NewAudienceListRequest() *AudienceListRequest { - return &AudienceListRequest{} + return &s } -func (s *AudienceListRequest) WithAudienceList(AudienceList []AudienceListItem) *AudienceListRequest { +func NewAudienceListRequest( + AudienceList []AudienceListItem, +) *AudienceListRequest { + s := AudienceListRequest{} s.AudienceList = AudienceList - return s + return &s } func NewCreateOauthForPartnerApplicationsSecurityIntegrationRequest( diff --git a/pkg/sdk/security_integrations_dto_gen.go b/pkg/sdk/security_integrations_dto_gen.go index 5c9a39383c..0a887be3e0 100644 --- a/pkg/sdk/security_integrations_dto_gen.go +++ b/pkg/sdk/security_integrations_dto_gen.go @@ -40,15 +40,15 @@ type CreateExternalOauthSecurityIntegrationRequest struct { } type BlockedRolesListRequest struct { - BlockedRolesList []AccountObjectIdentifier + BlockedRolesList []AccountObjectIdentifier // required } type AllowedRolesListRequest struct { - AllowedRolesList []AccountObjectIdentifier + AllowedRolesList []AccountObjectIdentifier // required } type AudienceListRequest struct { - AudienceList []AudienceListItem + AudienceList []AudienceListItem // required } type CreateOauthForPartnerApplicationsSecurityIntegrationRequest struct { diff --git a/pkg/sdk/testint/security_integrations_gen_integration_test.go b/pkg/sdk/testint/security_integrations_gen_integration_test.go index cc9fd000f7..899d6dd403 100644 --- a/pkg/sdk/testint/security_integrations_gen_integration_test.go +++ b/pkg/sdk/testint/security_integrations_gen_integration_test.go @@ -34,7 +34,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { createExternalOauth := func(t *testing.T, with func(*sdk.CreateExternalOauthSecurityIntegrationRequest)) (*sdk.SecurityIntegration, sdk.AccountObjectIdentifier, string) { t.Helper() id := testClientHelper().Ids.RandomAccountObjectIdentifier() - issuer := testClientHelper().Ids.Alpha() + issuer := random.String() req := sdk.NewCreateExternalOauthSecurityIntegrationRequest(id, false, sdk.ExternalOauthSecurityIntegrationTypeCustom, issuer, []sdk.TokenUserMappingClaim{{Claim: "foo"}}, sdk.ExternalOauthSecurityIntegrationSnowflakeUserMappingAttributeLoginName, ) @@ -127,12 +127,13 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Equal(t, "SECURITY", si.Category) } - assertFieldContainsList := func(details []sdk.SecurityIntegrationProperty, field, value string) { + // TODO(SNOW-1449579): move to helpers + assertFieldContainsList := func(details []sdk.SecurityIntegrationProperty, field, value, sep string) { found, err := collections.FindOne(details, func(d sdk.SecurityIntegrationProperty) bool { return d.Name == field }) assert.NoError(t, err) - roles := strings.Split(found.Value, ",") - for _, exp := range strings.Split(value, ",") { - assert.Contains(t, roles, exp) + values := strings.Split(found.Value, sep) + for _, exp := range strings.Split(value, sep) { + assert.Contains(t, values, exp) } } @@ -167,7 +168,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE", Type: "String", Value: d.externalOauthSnowflakeUserMappingAttribute, Default: ""}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "EXTERNAL_OAUTH_SCOPE_DELIMITER", Type: "String", Value: d.externalOauthScopeDelimiter, Default: ","}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "COMMENT", Type: "String", Value: d.comment, Default: ""}) - assertFieldContainsList(details, "EXTERNAL_OAUTH_BLOCKED_ROLES_LIST", d.externalOauthBlockedRolesList) + assertFieldContainsList(details, "EXTERNAL_OAUTH_BLOCKED_ROLES_LIST", d.externalOauthBlockedRolesList, ",") } type oauthPartnerDetails struct { @@ -189,7 +190,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "PRE_AUTHORIZED_ROLES_LIST", Type: "List", Value: d.preAuthorizedRolesList, Default: "[]"}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "NETWORK_POLICY", Type: "String", Value: d.networkPolicy, Default: ""}) assert.Contains(t, details, sdk.SecurityIntegrationProperty{Name: "COMMENT", Type: "String", Value: d.comment, Default: ""}) - assertFieldContainsList(details, "BLOCKED_ROLES_LIST", d.blockedRolesList) + assertFieldContainsList(details, "BLOCKED_ROLES_LIST", d.blockedRolesList, ",") } assertOauthCustom := func(details []sdk.SecurityIntegrationProperty, d oauthPartnerDetails, allowNonTlsRedirectUri, clientType, enforcePkce string) { @@ -555,7 +556,7 @@ func TestInt_SecurityIntegrations(t *testing.T) { setRequest := sdk.NewAlterOauthForPartnerApplicationsSecurityIntegrationRequest(id). WithSet( *sdk.NewOauthForPartnerApplicationsIntegrationSetRequest(). - WithBlockedRolesList(*sdk.NewBlockedRolesListRequest().WithBlockedRolesList([]sdk.AccountObjectIdentifier{role1.ID()})). + WithBlockedRolesList(sdk.BlockedRolesListRequest{BlockedRolesList: []sdk.AccountObjectIdentifier{role1.ID()}}). WithComment("a"). WithEnabled(true). WithOauthIssueRefreshTokens(true). From c44dc90088284d7ebe5fda5731ff541b565eb3c9 Mon Sep 17 00:00:00 2001 From: Jakub Michalak Date: Tue, 28 May 2024 09:43:19 +0200 Subject: [PATCH 5/5] Fix tests --- pkg/sdk/testint/session_policies_gen_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sdk/testint/session_policies_gen_integration_test.go b/pkg/sdk/testint/session_policies_gen_integration_test.go index 130c2aa747..063304edc7 100644 --- a/pkg/sdk/testint/session_policies_gen_integration_test.go +++ b/pkg/sdk/testint/session_policies_gen_integration_test.go @@ -215,7 +215,7 @@ func TestInt_SessionPolicies(t *testing.T) { returnedSessionPolicies, err := client.SessionPolicies.Show(ctx, showRequest) require.NoError(t, err) - assert.Equal(t, 2, len(returnedSessionPolicies)) + assert.LessOrEqual(t, 2, len(returnedSessionPolicies)) assert.Contains(t, returnedSessionPolicies, *sessionPolicy1) assert.Contains(t, returnedSessionPolicies, *sessionPolicy2) })