Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add External Oauth security integration to sdk #2835

Merged
merged 6 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions pkg/sdk/poc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <AccountObjectIdentifier>, Alter <SchemaObjectIdentifier>)
if there's a resource with different types of identifiers across queries (e.g. Create <AccountObjectIdentifier>, Alter <SchemaObjectIdentifier>)
- 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
Expand Down Expand Up @@ -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
Expand All @@ -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
- []Request1{ foo Request2, bar int } won't be converted, but []Request1{ foo string, bar int } will
130 changes: 129 additions & 1 deletion pkg/sdk/security_integrations_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -48,7 +72,14 @@ 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").
sfc-gh-jcieslak marked this conversation as resolved.
Show resolved Hide resolved
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().Required().MustParentheses())
tokenUserMappingClaimDef = g.NewQueryStruct("TokenUserMappingClaim").Text("Claim", g.KeywordOptions().SingleQuotes().Required())
)

func createSecurityIntegrationOperation(structName string, opts func(qs *g.QueryStruct) *g.QueryStruct) *g.QueryStruct {
Expand Down Expand Up @@ -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")
sfc-gh-jcieslak marked this conversation as resolved.
Show resolved Hide resolved

var oauthForPartnerApplicationsIntegrationSetDef = g.NewQueryStruct("OauthForPartnerApplicationsIntegrationSet").
OptionalBooleanAssignment("ENABLED", g.ParameterOptions()).
OptionalBooleanAssignment("OAUTH_ISSUE_REFRESH_TOKENS", g.ParameterOptions()).
Expand Down Expand Up @@ -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.ExactlyOneValueSet, "ExternalOauthJwsKeysUrl", "ExternalOauthRsaPublicKey").
sfc-gh-asawicki marked this conversation as resolved.
Show resolved Hide resolved
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",
Expand Down Expand Up @@ -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",
Expand Down
Loading
Loading