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

chore: Test more authentication methods #3178

Merged
merged 4 commits into from
Nov 8, 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
2 changes: 1 addition & 1 deletion MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ We have added new fields to match the ones in [the driver](https://pkg.go.dev/gi
To be more consistent with other configuration options, we have decided to add `driver_tracing` to the configuration schema. This value can also be configured by `SNOWFLAKE_DRIVER_TRACING` environmental variable and by `drivertracing` field in the TOML file. The previous `SF_TF_GOSNOWFLAKE_LOG_LEVEL` environmental variable is not supported now, and was removed from the provider.

#### *(behavior change)* deprecated fields
Because of new fields `account_name` and `organization_name`, `account` is now deprecated. It will be removed before v1. Please adjust your configurations from
Because of new fields `account_name` and `organization_name`, `account` is now deprecated. It will be removed with the v1 release. Please adjust your configurations from
```terraform
provider "snowflake" {
account = "ORGANIZATION-ACCOUNT"
Expand Down
1 change: 1 addition & 0 deletions pkg/acceptance/testenvs/testing_environment_variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (

EnableAcceptance env = resource.EnvTfAcc
EnableSweep env = "TEST_SF_TF_ENABLE_SWEEP"
EnableManual env = "TEST_SF_TF_ENABLE_MANUAL_TESTS"
ConfigureClientOnce env = "SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE"
TestObjectsSuffix env = "TEST_SF_TF_TEST_OBJECT_SUFFIX"
RequireTestObjectsSuffix env = "TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX"
Expand Down
1 change: 1 addition & 0 deletions pkg/acceptance/testprofiles/testing_config_profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ const (
IncorrectUserAndPassword = "incorrect_test_profile"
CompleteFields = "complete_fields"
CompleteFieldsInvalid = "complete_fields_invalid"
DefaultWithPasscode = "default_with_passcode"
)
3 changes: 2 additions & 1 deletion pkg/manual_tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Every test should be placed in the subfolder representing a particular test (mos
and should contain a file describing the manual steps to perform the test.

Here's the list of cases we currently cannot reproduce and write acceptance tests for:
- `user_default_database_and_role`: Setting up a user with default_namespace and default_role, then logging into that user to see what happens with those values in various scenarios (e.g. insufficient privileges on the role).
- `user_default_database_and_role`: Setting up a user with default_namespace and default_role, then logging into that user to see what happens with those values in various scenarios (e.g. insufficient privileges on the role).
- `authentication_methods`: Some of the authentication methods require manual steps, like confirming MFA or setting more dependencies.
53 changes: 53 additions & 0 deletions pkg/manual_tests/authentication_methods/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Authentication methods manual tests

This directory is dedicated to hold steps for manual authentication methods tests in the provider that are not possible to re-recreate in automated tests (or very hard to set up). These tests are disabled by default and require `TEST_SF_TF_ENABLE_MANUAL_TESTS` environmental variable to be set.

## Okta authenticator test
This test checks `Okta` authenticator option. It requires manual steps because of additional setup on Okta side. It assumes that `default` profile uses a standard values of account name, user, password, etc.
1. Set up a developer Okta account [here](https://developer.okta.com/signup/).
2. Go to admin panel and select Applications -> Create App Integration.
3. Create a new application with SAML 2.0 type and give it a unique name
4. Fill SAML settings - paste the URLs for the testing accounts, like `https://example.snowflakecomputing.com/fed/login` for Single sign on URL, Recipient URL, Destination URL and Audience URI (SP Entity ID)
5. Click Next and Finish
6. After the app gets created, click View SAML setup instructions
7. Save the values provided: IDP SSO URL, IDP Issuer, and X509 certificate
8. Create a new security integration in Snowflake:
```
CREATE SECURITY INTEGRATION MyIDP
TYPE=SAML2
ENABLED=true
SAML2_ISSUER='http://www.okta.com/example'
SAML2_SSO_URL='https://dev-123456.oktapreview.com/app/dev-123456_test_1/example/sso/saml'
SAML2_PROVIDER='OKTA'
SAML2_SP_INITIATED_LOGIN_PAGE_LABEL='myidp - okta'
SAML2_ENABLE_SP_INITIATED=false
SAML2_X509_CERT='<x509 cert, without headers>';
```
9. Note that Snowflake and Okta login name must match, otherwise create a temporary user with a login name matching the one in Okta.
10. Prepare a TOML config like:
```
[okta]
organizationname='ORGANIZATION_NAME'
accountname='ACCOUNT_NAME'
user='LOGIN_NAME' # This is a value used to login in Okta
password='PASSWORD' # This is a password in Okta
oktaurl='https://dev-123456.okta.com' # URL of your Okta environment
```
11. Run the tests - you should be able to authenticate with Okta.


## UsernamePasswordMFA authenticator test
This test checks `UsernamePasswordMFA` authenticator option. It requires manual steps because of additional verification via MFA device. It assumes that `default` profile uses a standard values of account name, user, password, etc.
1. Make sure the user you're testing with has enabled MFA (see [docs](https://docs.snowflake.com/en/user-guide/ui-snowsight-profile#enroll-in-multi-factor-authentication-mfa)) and an MFA bypass is not set (check `mins_to_bypass_mfa` in `SHOW USERS` output for the given user).
1. After running the test, you should get pinged 3 times in MFA app:
- The first two notifiactions are just test setups, also present in other acceptance tests.
- The third notification verifies that MFA is used for the first test step.
- For the second test step we are caching MFA token, so there is not any notification.

## UsernamePasswordMFA authenticator with passcode test
This test checks `UsernamePasswordMFA` authenticator option with using `passcode`. It requires manual steps because of additional verification via MFA device. It assumes that `default_with_passcode` profile uses a standard values of account name, user, password, etc. with `passcode` set to a value in your MFA app.
1. Make sure the user you're testing with has enabled MFA (see [docs](https://docs.snowflake.com/en/user-guide/ui-snowsight-profile#enroll-in-multi-factor-authentication-mfa)) and an MFA bypass is not set (check `mins_to_bypass_mfa` in `SHOW USERS` output for the given user).
1. After running the test, you should get pinged 2 times in MFA app:
- The first two notifiactions are just test setups, also present in other acceptance tests.
- The first step asks for permition to access your device keychain.
- For the second test step we are caching MFA token, so there is not any notification.
102 changes: 102 additions & 0 deletions pkg/manual_tests/authentication_methods/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package manual

import (
"fmt"
"testing"

acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testprofiles"
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/snowflakeenvs"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

// This is a manual test for authenticating with Okta.
func TestAcc_Provider_OktaAuth(t *testing.T) {
_ = testenvs.GetOrSkipTest(t, testenvs.EnableManual)
t.Setenv(string(testenvs.ConfigureClientOnce), "")

resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
PreCheck: func() {
acc.TestAccPreCheck(t)
testenvs.AssertEnvNotSet(t, snowflakeenvs.User)
testenvs.AssertEnvNotSet(t, snowflakeenvs.Password)
},
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.RequireAbove(tfversion.Version1_5_0),
},
Steps: []resource.TestStep{
{
Config: providerConfigWithAuthenticator("okta", sdk.AuthenticationTypeOkta),
},
},
})
}

// This test requires manual action due to MFA. Make sure the user does not have a positive `mins_to_bypass_mfa` in `SHOW USERS`.
func TestAcc_Provider_UsernamePasswordMfaAuth(t *testing.T) {
_ = testenvs.GetOrSkipTest(t, testenvs.EnableManual)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
PreCheck: func() {
acc.TestAccPreCheck(t)
},
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.RequireAbove(tfversion.Version1_5_0),
},
Steps: []resource.TestStep{
// ensure MFA is checked here - accept login on your MFA device
{
Config: providerConfigWithAuthenticator(testprofiles.Default, sdk.AuthenticationTypeUsernamePasswordMfa),
},
// check that MFA login is cached - this step should not require manual action
{
Config: providerConfigWithAuthenticator(testprofiles.Default, sdk.AuthenticationTypeUsernamePasswordMfa),
},
},
})
}

// This test requires manual action due to MFA. Make sure the user does not have a positive `mins_to_bypass_mfa` in `SHOW USERS`.
func TestAcc_Provider_UsernamePasswordMfaAuthWithPasscode(t *testing.T) {
_ = testenvs.GetOrSkipTest(t, testenvs.EnableManual)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
PreCheck: func() {
acc.TestAccPreCheck(t)
},
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.RequireAbove(tfversion.Version1_5_0),
},
Steps: []resource.TestStep{
// ensure MFA is checked here - accept access to keychain on your device
{
Config: providerConfigWithAuthenticator(testprofiles.DefaultWithPasscode, sdk.AuthenticationTypeUsernamePasswordMfa),
},
// check that MFA login is cached - this step should not require manual action
{
Config: providerConfigWithAuthenticator(testprofiles.DefaultWithPasscode, sdk.AuthenticationTypeUsernamePasswordMfa),
},
},
})
}

func providerConfigWithAuthenticator(profile string, authenticator sdk.AuthenticationType) string {
return fmt.Sprintf(`
provider "snowflake" {
profile = "%[1]s"
authenticator = "%[2]s"
}
`, profile, authenticator) + datasourceConfig()
}

func datasourceConfig() string {
return `
data snowflake_database "t" {
name = "SNOWFLAKE"
}`
}
6 changes: 3 additions & 3 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,10 @@ func Provider() *schema.Provider {
},
"driver_tracing": {
Type: schema.TypeString,
Description: envNameFieldDescription(fmt.Sprintf("Specifies the logging level to be used by the driver. Valid options are: %v.", docs.PossibleValuesListed(allDriverLogLevels)), snowflakeenvs.DriverTracing),
Description: envNameFieldDescription(fmt.Sprintf("Specifies the logging level to be used by the driver. Valid options are: %v.", docs.PossibleValuesListed(sdk.AllDriverLogLevels)), snowflakeenvs.DriverTracing),
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(snowflakeenvs.DriverTracing, nil),
ValidateDiagFunc: validators.NormalizeValidation(toDriverLogLevel),
ValidateDiagFunc: validators.NormalizeValidation(sdk.ToDriverLogLevel),
},
"tmp_directory_path": {
Type: schema.TypeString,
Expand Down Expand Up @@ -781,7 +781,7 @@ func getDriverConfigFromTerraform(s *schema.ResourceData) (*gosnowflake.Config,
// driver tracing
func() error {
if v, ok := s.GetOk("driver_tracing"); ok {
driverLogLevel, err := toDriverLogLevel(v.(string))
driverLogLevel, err := sdk.ToDriverLogLevel(v.(string))
if err != nil {
return err
}
Expand Down
Loading
Loading