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

[SNOW-1346233] Tests for authentication methods (external browser, oauth, okta, keypair) #1264

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ba5a0c3
Additional external browser tests
sfc-gh-pcyrek Dec 4, 2024
efc3ecc
add err handling, docker container change
sfc-gh-pcyrek Dec 4, 2024
7f31099
skip github actions check
sfc-gh-pcyrek Dec 5, 2024
65e7cdd
docker repo setup2
sfc-gh-pcyrek Dec 5, 2024
719f724
test default configuration
sfc-gh-pcyrek Dec 5, 2024
298a08a
test default configuration, only IPADDR
sfc-gh-pcyrek Dec 5, 2024
9d63c1d
test default configuration, only IPADDR2
sfc-gh-pcyrek Dec 5, 2024
29b8f2b
test default configuration3
sfc-gh-pcyrek Dec 5, 2024
5540296
adding okta tests, solution refactor
sfc-gh-pcyrek Dec 5, 2024
707c64b
adding oauth tests, small refactor
sfc-gh-pcyrek Dec 6, 2024
c77b081
linter fix
sfc-gh-pcyrek Dec 6, 2024
3053d2d
linter fix2
sfc-gh-pcyrek Dec 10, 2024
0c6d4b9
review 1
sfc-gh-pcyrek Dec 13, 2024
26d3ff2
fix usernames
sfc-gh-pcyrek Dec 13, 2024
ff49f15
logging for flaky tc
sfc-gh-pcyrek Dec 16, 2024
245ade2
after review session
sfc-gh-pcyrek Dec 17, 2024
bf866bf
after review session2
sfc-gh-pcyrek Dec 17, 2024
ca5c1d7
linters fix
sfc-gh-pcyrek Dec 17, 2024
833a75f
Merge branch 'master' into pcyrek-golang-external-browser-tests
sfc-gh-pcyrek Dec 17, 2024
e78d18f
review - round 2
sfc-gh-pcyrek Dec 18, 2024
361984d
Merge remote-tracking branch 'origin/pcyrek-golang-external-browser-t…
sfc-gh-pcyrek Dec 18, 2024
fd3dc3c
Merge branch 'master' into pcyrek-golang-external-browser-tests
sfc-gh-pcyrek Dec 18, 2024
a26313a
linters fix
sfc-gh-pcyrek Dec 18, 2024
03adfa1
linters fix2
sfc-gh-pcyrek Dec 18, 2024
b6ac5ba
Merge remote-tracking branch 'origin/pcyrek-golang-external-browser-t…
sfc-gh-pcyrek Dec 18, 2024
4959876
linters fix3
sfc-gh-pcyrek Dec 18, 2024
b1073b1
linterfix4
sfc-gh-pcyrek Dec 18, 2024
d2f480b
linterfix5
sfc-gh-pcyrek Dec 18, 2024
a52cb60
errorhandling
sfc-gh-pcyrek Dec 18, 2024
c3ef9e5
review - round 3
sfc-gh-pcyrek Dec 19, 2024
cf0a112
lintersfix1
sfc-gh-pcyrek Dec 19, 2024
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
Binary file not shown.
23 changes: 20 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,26 @@ timestamps {
string(name: 'parent_job', value: env.JOB_NAME),
string(name: 'parent_build_number', value: env.BUILD_NUMBER)
]
stage('Test') {
build job: 'RT-LanguageGo-PC',parameters: params
}
parallel(
'Test': {
stage('Test') {
build job: 'RT-LanguageGo-PC', parameters: params
}
},
'Test Authentication': {
stage('Test Authentication') {
withCredentials([
string(credentialsId: 'a791118f-a1ea-46cd-b876-56da1b9bc71c', variable: 'NEXUS_PASSWORD'),
string(credentialsId: 'sfctest0-parameters-secret', variable: 'PARAMETERS_SECRET')
]) {
sh '''\
|#!/bin/bash -e
|$WORKSPACE/ci/test_authentication.sh
'''.stripMargin()
}
}
}
)
}
}

Expand Down
67 changes: 67 additions & 0 deletions auth_generic_test_methods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package gosnowflake
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"
"database/sql"
"flag"
"log"
)

func getConfigFromEnv() (*Config, error) {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
return GetConfigFromEnv([]*ConfigParam{
{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
{Name: "User", EnvName: "SNOWFLAKE_AUTH_TEST_OKTA_USER", FailOnMissing: true},
{Name: "Password", EnvName: "SNOWFLAKE_AUTH_TEST_OKTA_PASS", FailOnMissing: true},
{Name: "Host", EnvName: "SNOWFLAKE_TEST_HOST", FailOnMissing: false},
{Name: "Port", EnvName: "SNOWFLAKE_TEST_PORT", FailOnMissing: false},
{Name: "Protocol", EnvName: "SNOWFLAKE_AUTH_TEST_PROTOCOL", FailOnMissing: false},
{Name: "Role", EnvName: "SNOWFLAKE_TEST_ROLE", FailOnMissing: false},
})
}

func getConfig(authMethod AuthType) (*Config, error) {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
cfg, err := getConfigFromEnv()
if err != nil {
return nil, err
}

cfg.Authenticator = authMethod
cfg.DisableQueryContextCache = true

return cfg, nil
}

func parseFlags() {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
if !flag.Parsed() {
flag.Parse()
}
}

func executeQuery(query string, dsn string) (rows *sql.Rows, err error) {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
db, err := sql.Open("snowflake", dsn)
if err != nil {
log.Fatalf("failed to connect. %v, err: %v", dsn, err)
}
defer db.Close()

rows, err = db.Query(query)
return rows, err
}

func getDbHandler(cfg *Config) *sql.DB {
dsn, err := DSN(cfg)
if err != nil {
log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
}

db, err := sql.Open("snowflake", dsn)
if err != nil {
log.Fatalf("failed to open database. %v, err: %v", dsn, err)
}
return db
}

func createConnection(db *sql.DB) (*sql.Conn, error) {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
conn, err := db.Conn(context.Background())
return conn, err
}
205 changes: 205 additions & 0 deletions auth_with_external_browser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package gosnowflake

import (
"context"
"database/sql"
"fmt"
"log"
"os/exec"
"sync"
"testing"
"time"
)

func TestExternalBrowserSuccessful(t *testing.T) {
cfg := setupExternalBrowserTest(t)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
provideCredentials(externalBrowserType.Success, cfg.User, cfg.Password)
}()
go func() {
defer wg.Done()
_, err := connectToSnowflake(cfg, "SELECT 1", true)
if err != nil {
t.Errorf("Connection failed: err %v", err)
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
}
}()
wg.Wait()
}

func TestExternalBrowserFailed(t *testing.T) {
cfg := setupExternalBrowserTest(t)
cfg.ExternalBrowserTimeout = time.Duration(10000) * time.Millisecond
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
provideCredentials(externalBrowserType.Fail, "FakeAccount", "NotARealPassword")
}()
go func() {
defer wg.Done()
tOut := "authentication timed out"
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
_, err := connectToSnowflake(cfg, "SELECT 1", false)
if err.Error() != tOut {
t.Errorf("Expected %v, but got %v", tOut, err)
}
}()
wg.Wait()
}

func TestExternalBrowserTimeout(t *testing.T) {
cfg := setupExternalBrowserTest(t)
cfg.ExternalBrowserTimeout = time.Duration(1000) * time.Millisecond
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
provideCredentials(externalBrowserType.Timeout, cfg.User, cfg.Password)
}()
go func() {
defer wg.Done()
tOut := "authentication timed out"
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
_, err := connectToSnowflake(cfg, "SELECT 1", false)
if err.Error() != tOut {
t.Errorf("Expected %v, but got %v", tOut, err)
}
}()
wg.Wait()
}

func TestExternalBrowserMismatchUser(t *testing.T) {
cfg := setupExternalBrowserTest(t)
correctUsername := cfg.User
cfg.User = "fakeAccount"
var wg sync.WaitGroup

wg.Add(2)
go func() {
defer wg.Done()
provideCredentials(externalBrowserType.Success, correctUsername, cfg.Password)
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
}()
go func() {
defer wg.Done()
expectedErrorMsg := "390191 (08004): The user you were trying to authenticate " +
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
"as differs from the user currently logged in at the IDP."

_, err := connectToSnowflake(cfg, "SELECT 1", false)
if err.Error() != expectedErrorMsg {
t.Errorf("Expected %v, but got %v", expectedErrorMsg, err)
}
}()
wg.Wait()
}

func TestClientStoreCredentials(t *testing.T) {
cfg := setupExternalBrowserTest(t)
cfg.ClientStoreTemporaryCredential = 1
cfg.ExternalBrowserTimeout = time.Duration(10000) * time.Millisecond

t.Run("Obtains the ID token from the server and saves it on the local storage", func(t *testing.T) {
cleanupBrowserProcesses()
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
provideCredentials(externalBrowserType.Success, cfg.User, cfg.Password)
}()
go func() {
defer wg.Done()
conn, err := connectToSnowflake(cfg, "SELECT 1", true)
if err != nil {
t.Errorf("Connection failed: err %v", err)
}
defer conn.Close()
}()
wg.Wait()
})

t.Run("Verify validation of ID token if option enabled", func(t *testing.T) {
cleanupBrowserProcesses()
cfg.ClientStoreTemporaryCredential = 1
conn, _ := createConnection(getDbHandler(cfg))
_, err := conn.QueryContext(context.Background(), "SELECT 1")
if err != nil {
log.Fatalf("failed to run a query. err: %v", err)
}
})

t.Run("Verify validation of IDToken if option disabled", func(t *testing.T) {
cleanupBrowserProcesses()
cfg.ClientStoreTemporaryCredential = 0
tOut := "authentication timed out"
_, err := createConnection(getDbHandler(cfg))
if err.Error() != tOut {
t.Errorf("Expected %v, but got %v", tOut, err)
}
})
}

type Mode struct {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
Success string
Fail string
Timeout string
}

var externalBrowserType = Mode{
Success: "success",
Fail: "fail",
Timeout: "timeout",
}

func cleanupBrowserProcesses() {
const cleanBrowserProcessesPath = "/externalbrowser/cleanBrowserProcesses.js"
_, err := exec.Command("node", cleanBrowserProcessesPath).Output()
if err != nil {
log.Fatalf("failed to execute command: %v", err)
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
}
}

func provideCredentials(mode string, user string, password string) {
const provideBrowserCredentialsPath = "/externalbrowser/provideBrowserCredentials.js"
_, err := exec.Command("node", provideBrowserCredentialsPath, mode, user, password).Output()
if err != nil {
log.Fatalf("failed to execute command: %v", err)
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
}
}

func connectToSnowflake(cfg *Config, query string, exceptionHandler bool) (rows *sql.Rows, err error) {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
parseFlags()
dsn, err := DSN(cfg)
if err != nil {
log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
}
rows, err = executeQuery(query, dsn)
if exceptionHandler && err != nil {
log.Fatalf("failed to run a query. %v, err: %v", rows, err)
} else if err != nil {
return rows, err
}
defer rows.Close()
var v int
for rows.Next() {
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
err := rows.Scan(&v)
if exceptionHandler && err != nil {
log.Fatalf("failed to get result. err: %v", err)
} else if exceptionHandler {
fmt.Printf("Congrats! You have successfully run '%v' with Snowflake DB! \n", query)
}
}
return rows, err
}

func setupExternalBrowserTest(t *testing.T) *Config {
skipOnJenkins(t, "Running only on Docker container")
sfc-gh-pcyrek marked this conversation as resolved.
Show resolved Hide resolved
if runningOnGithubAction() {
t.Skip("Running only on Docker container")
}
cleanupBrowserProcesses()
cfg, err := getConfig(AuthTypeExternalBrowser)
if err != nil {
t.Fatalf("failed to get config: %v", err)
}
return cfg
}
Loading
Loading