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 SCIM and SAML2 security integrations to sdk #2799

Merged
merged 18 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
47 changes: 47 additions & 0 deletions pkg/acceptance/helpers/random/certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package random

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"strings"
"testing"
"time"

"github.com/stretchr/testify/require"
)

// Generate X509 returns base64 encoded certificate on a single line without the leading -----BEGIN CERTIFICATE----- and ending -----END CERTIFICATE----- markers.
func GenerateX509(t *testing.T) string {
t.Helper()
ca := &x509.Certificate{
SerialNumber: big.NewInt(1658),
Subject: pkix.Name{
Organization: []string{"Company, INC."},
},
NotAfter: time.Now().AddDate(10, 0, 0),
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}

caPrivKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)

caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
require.NoError(t, err)

certPEM := new(bytes.Buffer)
err = pem.Encode(certPEM, &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
})
require.NoError(t, err)

cert := strings.TrimPrefix(certPEM.String(), "-----BEGIN CERTIFICATE-----\n")
cert = strings.TrimSuffix(cert, "-----END CERTIFICATE-----\n")
return cert
}
13 changes: 13 additions & 0 deletions pkg/acceptance/helpers/role_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ func (c *RoleClient) GrantRoleToUser(t *testing.T, id sdk.AccountObjectIdentifie
require.NoError(t, err)
}

func (c *RoleClient) GrantRoleToCurrentRole(t *testing.T, id sdk.AccountObjectIdentifier) {
t.Helper()
ctx := context.Background()

currentRole, err := c.context.client.ContextFunctions.CurrentRole(ctx)
require.NoError(t, err)

err = c.client().Grant(ctx, sdk.NewGrantRoleRequest(id, sdk.GrantRole{
Role: sdk.Pointer(currentRole),
}))
require.NoError(t, err)
}

// TODO: move later to grants client
func (c *RoleClient) GrantOwnershipOnAccountObject(t *testing.T, roleId sdk.AccountObjectIdentifier, objectId sdk.AccountObjectIdentifier, objectType sdk.ObjectType) {
t.Helper()
Expand Down
72 changes: 72 additions & 0 deletions pkg/acceptance/helpers/security_integration_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package helpers

import (
"context"
"testing"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
"github.com/stretchr/testify/require"
)

type SecurityIntegrationClient struct {
context *TestClientContext
ids *IdsGenerator
}

func NewSecurityIntegrationClient(context *TestClientContext, idsGenerator *IdsGenerator) *SecurityIntegrationClient {
return &SecurityIntegrationClient{
context: context,
ids: idsGenerator,
}
}

func (c *SecurityIntegrationClient) client() sdk.SecurityIntegrations {
return c.context.client.SecurityIntegrations
}

func (c *SecurityIntegrationClient) CreateSaml2(t *testing.T, id sdk.AccountObjectIdentifier) (*sdk.SecurityIntegration, func()) {
t.Helper()
return c.CreateSaml2WithRequest(t, sdk.NewCreateSaml2SecurityIntegrationRequest(id, false, c.ids.Alpha(), "https://example.com", "Custom", random.GenerateX509(t)))
}

func (c *SecurityIntegrationClient) CreateSaml2WithRequest(t *testing.T, request *sdk.CreateSaml2SecurityIntegrationRequest) (*sdk.SecurityIntegration, func()) {
t.Helper()
ctx := context.Background()

err := c.client().CreateSaml2(ctx, request)
require.NoError(t, err)

si, err := c.client().ShowByID(ctx, request.GetName())
require.NoError(t, err)

return si, c.DropSecurityIntegrationFunc(t, request.GetName())
}

func (c *SecurityIntegrationClient) CreateScim(t *testing.T) (*sdk.SecurityIntegration, func()) {
t.Helper()
return c.CreateScimWithRequest(t, sdk.NewCreateScimSecurityIntegrationRequest(c.ids.RandomAccountObjectIdentifier(), false, sdk.ScimSecurityIntegrationScimClientGeneric, sdk.ScimSecurityIntegrationRunAsRoleGenericScimProvisioner))
}

func (c *SecurityIntegrationClient) CreateScimWithRequest(t *testing.T, request *sdk.CreateScimSecurityIntegrationRequest) (*sdk.SecurityIntegration, func()) {
t.Helper()
ctx := context.Background()

err := c.client().CreateScim(ctx, request)
require.NoError(t, err)

si, err := c.client().ShowByID(ctx, request.GetName())
require.NoError(t, err)

return si, c.DropSecurityIntegrationFunc(t, request.GetName())
}

func (c *SecurityIntegrationClient) DropSecurityIntegrationFunc(t *testing.T, id sdk.AccountObjectIdentifier) func() {
t.Helper()
ctx := context.Background()

return func() {
err := c.client().Drop(ctx, sdk.NewDropSecurityIntegrationRequest(id).WithIfExists(sdk.Bool(true)))
require.NoError(t, err)
}
}
122 changes: 62 additions & 60 deletions pkg/acceptance/helpers/test_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,37 @@ type TestClient struct {

Ids *IdsGenerator

Account *AccountClient
Alert *AlertClient
ApiIntegration *ApiIntegrationClient
Application *ApplicationClient
ApplicationPackage *ApplicationPackageClient
Context *ContextClient
Database *DatabaseClient
DatabaseRole *DatabaseRoleClient
DynamicTable *DynamicTableClient
FailoverGroup *FailoverGroupClient
FileFormat *FileFormatClient
MaskingPolicy *MaskingPolicyClient
MaterializedView *MaterializedViewClient
NetworkPolicy *NetworkPolicyClient
Parameter *ParameterClient
PasswordPolicy *PasswordPolicyClient
Pipe *PipeClient
ResourceMonitor *ResourceMonitorClient
Role *RoleClient
RowAccessPolicy *RowAccessPolicyClient
Schema *SchemaClient
SessionPolicy *SessionPolicyClient
Share *ShareClient
Stage *StageClient
Table *TableClient
Tag *TagClient
Task *TaskClient
User *UserClient
View *ViewClient
Warehouse *WarehouseClient
Account *AccountClient
Alert *AlertClient
ApiIntegration *ApiIntegrationClient
Application *ApplicationClient
ApplicationPackage *ApplicationPackageClient
Context *ContextClient
Database *DatabaseClient
DatabaseRole *DatabaseRoleClient
DynamicTable *DynamicTableClient
FailoverGroup *FailoverGroupClient
FileFormat *FileFormatClient
MaskingPolicy *MaskingPolicyClient
MaterializedView *MaterializedViewClient
NetworkPolicy *NetworkPolicyClient
Parameter *ParameterClient
PasswordPolicy *PasswordPolicyClient
Pipe *PipeClient
ResourceMonitor *ResourceMonitorClient
Role *RoleClient
RowAccessPolicy *RowAccessPolicyClient
Schema *SchemaClient
SecurityIntegration *SecurityIntegrationClient
SessionPolicy *SessionPolicyClient
Share *ShareClient
Stage *StageClient
Table *TableClient
Tag *TagClient
Task *TaskClient
User *UserClient
View *ViewClient
Warehouse *WarehouseClient
}

func NewTestClient(c *sdk.Client, database string, schema string, warehouse string, testObjectSuffix string) *TestClient {
Expand All @@ -55,36 +56,37 @@ func NewTestClient(c *sdk.Client, database string, schema string, warehouse stri

Ids: idsGenerator,

Account: NewAccountClient(context),
Alert: NewAlertClient(context, idsGenerator),
ApiIntegration: NewApiIntegrationClient(context, idsGenerator),
Application: NewApplicationClient(context, idsGenerator),
ApplicationPackage: NewApplicationPackageClient(context, idsGenerator),
Context: NewContextClient(context),
Database: NewDatabaseClient(context, idsGenerator),
DatabaseRole: NewDatabaseRoleClient(context, idsGenerator),
DynamicTable: NewDynamicTableClient(context, idsGenerator),
FailoverGroup: NewFailoverGroupClient(context, idsGenerator),
FileFormat: NewFileFormatClient(context, idsGenerator),
MaskingPolicy: NewMaskingPolicyClient(context, idsGenerator),
MaterializedView: NewMaterializedViewClient(context, idsGenerator),
NetworkPolicy: NewNetworkPolicyClient(context, idsGenerator),
Parameter: NewParameterClient(context),
PasswordPolicy: NewPasswordPolicyClient(context, idsGenerator),
Pipe: NewPipeClient(context, idsGenerator),
ResourceMonitor: NewResourceMonitorClient(context, idsGenerator),
Role: NewRoleClient(context, idsGenerator),
RowAccessPolicy: NewRowAccessPolicyClient(context, idsGenerator),
Schema: NewSchemaClient(context, idsGenerator),
SessionPolicy: NewSessionPolicyClient(context, idsGenerator),
Share: NewShareClient(context, idsGenerator),
Stage: NewStageClient(context, idsGenerator),
Table: NewTableClient(context, idsGenerator),
Tag: NewTagClient(context, idsGenerator),
Task: NewTaskClient(context, idsGenerator),
User: NewUserClient(context, idsGenerator),
View: NewViewClient(context, idsGenerator),
Warehouse: NewWarehouseClient(context, idsGenerator),
Account: NewAccountClient(context),
Alert: NewAlertClient(context, idsGenerator),
ApiIntegration: NewApiIntegrationClient(context, idsGenerator),
Application: NewApplicationClient(context, idsGenerator),
ApplicationPackage: NewApplicationPackageClient(context, idsGenerator),
Context: NewContextClient(context),
Database: NewDatabaseClient(context, idsGenerator),
DatabaseRole: NewDatabaseRoleClient(context, idsGenerator),
DynamicTable: NewDynamicTableClient(context, idsGenerator),
FailoverGroup: NewFailoverGroupClient(context, idsGenerator),
FileFormat: NewFileFormatClient(context, idsGenerator),
MaskingPolicy: NewMaskingPolicyClient(context, idsGenerator),
MaterializedView: NewMaterializedViewClient(context, idsGenerator),
NetworkPolicy: NewNetworkPolicyClient(context, idsGenerator),
Parameter: NewParameterClient(context),
PasswordPolicy: NewPasswordPolicyClient(context, idsGenerator),
Pipe: NewPipeClient(context, idsGenerator),
ResourceMonitor: NewResourceMonitorClient(context, idsGenerator),
Role: NewRoleClient(context, idsGenerator),
RowAccessPolicy: NewRowAccessPolicyClient(context, idsGenerator),
Schema: NewSchemaClient(context, idsGenerator),
SecurityIntegration: NewSecurityIntegrationClient(context, idsGenerator),
SessionPolicy: NewSessionPolicyClient(context, idsGenerator),
Share: NewShareClient(context, idsGenerator),
Stage: NewStageClient(context, idsGenerator),
Table: NewTableClient(context, idsGenerator),
Tag: NewTagClient(context, idsGenerator),
Task: NewTaskClient(context, idsGenerator),
User: NewUserClient(context, idsGenerator),
View: NewViewClient(context, idsGenerator),
Warehouse: NewWarehouseClient(context, idsGenerator),
}
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/internal/snowflakeroles/snowflake_predefined_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package snowflakeroles
import "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"

var (
Orgadmin = sdk.NewAccountObjectIdentifier("ORGADMIN")
Accountadmin = sdk.NewAccountObjectIdentifier("ACCOUNTADMIN")
Orgadmin = sdk.NewAccountObjectIdentifier("ORGADMIN")
Accountadmin = sdk.NewAccountObjectIdentifier("ACCOUNTADMIN")
GenericScimProvisioner = sdk.NewAccountObjectIdentifier("GENERIC_SCIM_PROVISIONER")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not add also others (there were three in the docs, right?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I didn't need this atm, as the remaining roles are present in defs file. I can add them here in follow ups tho

)
2 changes: 2 additions & 0 deletions pkg/sdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type Client struct {
Roles Roles
RowAccessPolicies RowAccessPolicies
Schemas Schemas
SecurityIntegrations SecurityIntegrations
Sequences Sequences
SessionPolicies SessionPolicies
Sessions Sessions
Expand Down Expand Up @@ -226,6 +227,7 @@ func (c *Client) initialize() {
c.Roles = &roles{client: c}
c.RowAccessPolicies = &rowAccessPolicies{client: c}
c.Schemas = &schemas{client: c}
c.SecurityIntegrations = &securityIntegrations{client: c}
c.Sequences = &sequences{client: c}
c.SessionPolicies = &sessionPolicies{client: c}
c.Sessions = &sessions{client: c}
Expand Down
9 changes: 9 additions & 0 deletions pkg/sdk/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ func (parameters *parameters) SetAccountParameter(ctx context.Context, parameter
return fmt.Errorf("CLIENT_ENCRYPTION_KEY_SIZE session parameter is an integer, got %v", value)
}
opts.Set.Parameters.AccountParameters.ClientEncryptionKeySize = Pointer(v)
case AccountParameterEnableIdentifierFirstLogin:
b, err := parseBooleanParameter(string(parameter), value)
if err != nil {
return err
}
opts.Set.Parameters.AccountParameters.EnableIdentifierFirstLogin = b
case AccountParameterEnableInternalStagesPrivatelink:
b, err := parseBooleanParameter(string(parameter), value)
if err != nil {
Expand Down Expand Up @@ -328,6 +334,7 @@ const (
AccountParameterAllowClientMFACaching AccountParameter = "ALLOW_CLIENT_MFA_CACHING"
AccountParameterAllowIDToken AccountParameter = "ALLOW_ID_TOKEN" // #nosec G101
AccountParameterClientEncryptionKeySize AccountParameter = "CLIENT_ENCRYPTION_KEY_SIZE"
AccountParameterEnableIdentifierFirstLogin AccountParameter = "ENABLE_IDENTIFIER_FIRST_LOGIN"
AccountParameterEnableInternalStagesPrivatelink AccountParameter = "ENABLE_INTERNAL_STAGES_PRIVATELINK"
AccountParameterEnableTriSecretAndRekeyOptOutForImageRepository AccountParameter = "ENABLE_TRI_SECRET_AND_REKEY_OPT_OUT_FOR_IMAGE_REPOSITORY" // #nosec G101
AccountParameterEnableTriSecretAndRekeyOptOutForSpcsBlockStorage AccountParameter = "ENABLE_TRI_SECRET_AND_REKEY_OPT_OUT_FOR_SPCS_BLOCK_STORAGE" // #nosec G101
Expand Down Expand Up @@ -524,6 +531,7 @@ type AccountParameters struct {
AllowClientMFACaching *bool `ddl:"parameter" sql:"ALLOW_CLIENT_MFA_CACHING"`
AllowIDToken *bool `ddl:"parameter" sql:"ALLOW_ID_TOKEN"`
ClientEncryptionKeySize *int `ddl:"parameter" sql:"CLIENT_ENCRYPTION_KEY_SIZE"`
EnableIdentifierFirstLogin *bool `ddl:"parameter" sql:"ENABLE_IDENTIFIER_FIRST_LOGIN"`
EnableInternalStagesPrivatelink *bool `ddl:"parameter" sql:"ENABLE_INTERNAL_STAGES_PRIVATELINK"`
EnableUnredactedQuerySyntaxError *bool `ddl:"parameter" sql:"ENABLE_UNREDACTED_QUERY_SYNTAX_ERROR"`
EnableTriSecretAndRekeyOptOutForImageRepository *bool `ddl:"parameter" sql:"ENABLE_TRI_SECRET_AND_REKEY_OPT_OUT_FOR_IMAGE_REPOSITORY"`
Expand Down Expand Up @@ -567,6 +575,7 @@ type AccountParametersUnset struct {
AllowClientMFACaching *bool `ddl:"keyword" sql:"ALLOW_CLIENT_MFA_CACHING"`
AllowIDToken *bool `ddl:"keyword" sql:"ALLOW_ID_TOKEN"`
ClientEncryptionKeySize *bool `ddl:"keyword" sql:"CLIENT_ENCRYPTION_KEY_SIZE"`
EnableIdentifierFirstLogin *bool `ddl:"keyword" sql:"ENABLE_IDENTIFIER_FIRST_LOGIN"`
EnableInternalStagesPrivatelink *bool `ddl:"keyword" sql:"ENABLE_INTERNAL_STAGES_PRIVATELINK"`
EnableTriSecretAndRekeyOptOutForImageRepository *bool `ddl:"keyword" sql:"ENABLE_TRI_SECRET_AND_REKEY_OPT_OUT_FOR_IMAGE_REPOSITORY"`
EnableTriSecretAndRekeyOptOutForSpcsBlockStorage *bool `ddl:"keyword" sql:"ENABLE_TRI_SECRET_AND_REKEY_OPT_OUT_FOR_SPCS_BLOCK_STORAGE"`
Expand Down
4 changes: 2 additions & 2 deletions pkg/sdk/poc/generator/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,6 @@ func (i *Interface) DescribeOperation(describeKind DescriptionMappingKind, doc s
return i
}

func (i *Interface) CustomOperation(kind string, doc string, queryStruct *QueryStruct) *Interface {
return i.newSimpleOperation(kind, doc, queryStruct)
func (i *Interface) CustomOperation(kind string, doc string, queryStruct *QueryStruct, helperStructs ...IntoField) *Interface {
return i.newSimpleOperation(kind, doc, queryStruct, helperStructs...)
}
1 change: 1 addition & 0 deletions pkg/sdk/poc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var definitionMapping = map[string]*generator.Interface{
"external_functions_def.go": sdk.ExternalFunctionsDef,
"streamlits_def.go": sdk.StreamlitsDef,
"network_rule_def.go": sdk.NetworkRuleDef,
"security_integrations_def.go": sdk.SecurityIntegrationsDef,
}

func main() {
Expand Down
Loading
Loading