Skip to content

Commit

Permalink
chore: Test more authentication methods (#3178)
Browse files Browse the repository at this point in the history
<!-- Feel free to delete comments as you fill this in -->
- add a test for JWT authentication (skipped for now; it needs a
configuration adjustment and this will be done in [the next
PR](#3180))
- add a test for Okta
- add a test for session parameters
- move driver log level to sdk
- add tests for Mfa with and without passcode
- fix conflicting fields in view resource
- bring back configuring logging level for internal client tests
- describe all of the manual test steps in a readme
<!-- summary of changes -->

## Test Plan
<!-- detail ways in which this PR has been tested or needs to be tested
-->
* [x] acceptance tests
<!-- add more below if you think they are relevant -->
* [ ] …

## TODO
<!-- issues documentation links, etc  -->
- [(next
pr)](#3180)
read a compatible config file for older versions in acc tests, adjust
the configurations in Github secrets and our secret storage, and unskip
the relevant tests
- Other authentication methods will be done in SNOW-1791729.
  • Loading branch information
sfc-gh-jmichalak authored Nov 8, 2024
1 parent 4127b3f commit d345cd2
Show file tree
Hide file tree
Showing 16 changed files with 368 additions and 102 deletions.
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

0 comments on commit d345cd2

Please sign in to comment.