github.com/snowflakedb/gosnowflake@v1.9.0/dsn_test.go (about) 1 // Copyright (c) 2017-2022 Snowflake Computing Inc. All rights reserved. 2 3 package gosnowflake 4 5 import ( 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 cr "crypto/rand" 9 "crypto/rsa" 10 "crypto/x509" 11 "encoding/pem" 12 "fmt" 13 "net/url" 14 "os" 15 "reflect" 16 "strconv" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/aws/smithy-go/rand" 22 ) 23 24 type tcParseDSN struct { 25 dsn string 26 config *Config 27 ocspMode string 28 err error 29 } 30 31 func TestParseDSN(t *testing.T) { 32 privKeyPKCS8 := generatePKCS8StringSupress(testPrivKey) 33 privKeyPKCS1 := generatePKCS1String(testPrivKey) 34 testcases := []tcParseDSN{ 35 { 36 dsn: "user:pass@ac-1-laksdnflaf.global/db/schema", 37 config: &Config{ 38 Account: "ac-1", User: "user", Password: "pass", Region: "global", 39 Protocol: "https", Host: "ac-1-laksdnflaf.global.snowflakecomputing.com", Port: 443, 40 Database: "db", Schema: "schema", 41 OCSPFailOpen: OCSPFailOpenTrue, 42 ValidateDefaultParameters: ConfigBoolTrue, 43 ClientTimeout: defaultClientTimeout, 44 JWTClientTimeout: defaultJWTClientTimeout, 45 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 46 IncludeRetryReason: ConfigBoolTrue, 47 }, 48 ocspMode: ocspModeFailOpen, 49 err: nil, 50 }, 51 { 52 dsn: "user:pass@ac-laksdnflaf.global/db/schema", 53 config: &Config{ 54 Account: "ac", User: "user", Password: "pass", Region: "global", 55 Protocol: "https", Host: "ac-laksdnflaf.global.snowflakecomputing.com", Port: 443, 56 Database: "db", Schema: "schema", 57 OCSPFailOpen: OCSPFailOpenTrue, 58 ValidateDefaultParameters: ConfigBoolTrue, 59 ClientTimeout: defaultClientTimeout, 60 JWTClientTimeout: defaultJWTClientTimeout, 61 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 62 IncludeRetryReason: ConfigBoolTrue, 63 }, 64 ocspMode: ocspModeFailOpen, 65 err: nil, 66 }, 67 { 68 dsn: "u:p@asnowflakecomputing.com/db/pa?account=a&protocol=https&role=r&timezone=UTC&aehouse=w", 69 config: &Config{Account: "a", User: "u", Password: "p", Database: "db", Schema: "pa", 70 Protocol: "https", Role: "r", Host: "asnowflakecomputing.com.snowflakecomputing.com", Port: 443, Region: "com", 71 OCSPFailOpen: OCSPFailOpenTrue, 72 ValidateDefaultParameters: ConfigBoolTrue, 73 ClientTimeout: defaultClientTimeout, 74 JWTClientTimeout: defaultJWTClientTimeout, 75 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 76 IncludeRetryReason: ConfigBoolTrue, 77 }, 78 ocspMode: ocspModeFailOpen, 79 err: nil, 80 }, 81 { 82 dsn: "u:p@/db?account=ac", 83 config: &Config{ 84 Account: "ac", User: "u", Password: "p", Database: "db", 85 Protocol: "https", Host: "ac.snowflakecomputing.com", Port: 443, 86 OCSPFailOpen: OCSPFailOpenTrue, 87 ValidateDefaultParameters: ConfigBoolTrue, 88 ClientTimeout: defaultClientTimeout, 89 JWTClientTimeout: defaultJWTClientTimeout, 90 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 91 IncludeRetryReason: ConfigBoolTrue, 92 }, 93 ocspMode: ocspModeFailOpen, 94 err: nil, 95 }, 96 { 97 dsn: "user:pass@account-hfdw89q748ew9gqf48w9qgf.global/db/s", 98 config: &Config{ 99 Account: "account", User: "user", Password: "pass", Region: "global", 100 Protocol: "https", Host: "account-hfdw89q748ew9gqf48w9qgf.global.snowflakecomputing.com", Port: 443, 101 Database: "db", Schema: "s", 102 ValidateDefaultParameters: ConfigBoolTrue, 103 OCSPFailOpen: OCSPFailOpenTrue, 104 ClientTimeout: defaultClientTimeout, 105 JWTClientTimeout: defaultJWTClientTimeout, 106 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 107 IncludeRetryReason: ConfigBoolTrue, 108 }, 109 ocspMode: ocspModeFailOpen, 110 err: nil, 111 }, 112 { 113 dsn: "user:pass@account-hfdw89q748ew9gqf48w9qgf/db/s", 114 config: &Config{ 115 Account: "account-hfdw89q748ew9gqf48w9qgf", User: "user", Password: "pass", Region: "", 116 Protocol: "https", Host: "account-hfdw89q748ew9gqf48w9qgf.snowflakecomputing.com", Port: 443, 117 Database: "db", Schema: "s", 118 ValidateDefaultParameters: ConfigBoolTrue, 119 OCSPFailOpen: OCSPFailOpenTrue, 120 ClientTimeout: defaultClientTimeout, 121 JWTClientTimeout: defaultJWTClientTimeout, 122 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 123 IncludeRetryReason: ConfigBoolTrue, 124 }, 125 ocspMode: ocspModeFailOpen, 126 err: nil, 127 }, 128 { 129 dsn: "user:pass@account", 130 config: &Config{ 131 Account: "account", User: "user", Password: "pass", Region: "", 132 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 133 OCSPFailOpen: OCSPFailOpenTrue, 134 ValidateDefaultParameters: ConfigBoolTrue, 135 ClientTimeout: defaultClientTimeout, 136 JWTClientTimeout: defaultJWTClientTimeout, 137 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 138 IncludeRetryReason: ConfigBoolTrue, 139 }, 140 ocspMode: ocspModeFailOpen, 141 err: nil, 142 }, 143 { 144 dsn: "user:pass@account.eu-faraway", 145 config: &Config{ 146 Account: "account", User: "user", Password: "pass", Region: "eu-faraway", 147 Protocol: "https", Host: "account.eu-faraway.snowflakecomputing.com", Port: 443, 148 OCSPFailOpen: OCSPFailOpenTrue, 149 ValidateDefaultParameters: ConfigBoolTrue, 150 ClientTimeout: defaultClientTimeout, 151 JWTClientTimeout: defaultJWTClientTimeout, 152 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 153 IncludeRetryReason: ConfigBoolTrue, 154 }, 155 ocspMode: ocspModeFailOpen, 156 err: nil, 157 }, 158 { 159 dsn: "user:pass@account?region=eu-faraway", 160 config: &Config{ 161 Account: "account", User: "user", Password: "pass", Region: "eu-faraway", 162 Protocol: "https", Host: "account.eu-faraway.snowflakecomputing.com", Port: 443, 163 OCSPFailOpen: OCSPFailOpenTrue, 164 ValidateDefaultParameters: ConfigBoolTrue, 165 ClientTimeout: defaultClientTimeout, 166 JWTClientTimeout: defaultJWTClientTimeout, 167 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 168 IncludeRetryReason: ConfigBoolTrue, 169 }, 170 ocspMode: ocspModeFailOpen, 171 err: nil, 172 }, 173 { 174 dsn: "user:pass@account/db", 175 config: &Config{ 176 Account: "account", User: "user", Password: "pass", 177 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 178 Database: "db", 179 OCSPFailOpen: OCSPFailOpenTrue, 180 ValidateDefaultParameters: ConfigBoolTrue, 181 ClientTimeout: defaultClientTimeout, 182 JWTClientTimeout: defaultJWTClientTimeout, 183 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 184 IncludeRetryReason: ConfigBoolTrue, 185 }, 186 ocspMode: ocspModeFailOpen, 187 err: nil, 188 }, 189 { 190 dsn: "user:pass@host:123/db/schema?account=ac&protocol=http", 191 config: &Config{ 192 Account: "ac", User: "user", Password: "pass", 193 Protocol: "http", Host: "host", Port: 123, 194 Database: "db", Schema: "schema", 195 OCSPFailOpen: OCSPFailOpenTrue, 196 ValidateDefaultParameters: ConfigBoolTrue, 197 ClientTimeout: defaultClientTimeout, 198 JWTClientTimeout: defaultJWTClientTimeout, 199 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 200 IncludeRetryReason: ConfigBoolTrue, 201 }, 202 ocspMode: ocspModeFailOpen, 203 err: nil, 204 }, 205 { 206 dsn: "user@host:123/db/schema?account=ac&protocol=http", 207 config: &Config{ 208 Account: "ac", User: "user", Password: "pass", 209 Protocol: "http", Host: "host", Port: 123, 210 Database: "db", Schema: "schema", 211 OCSPFailOpen: OCSPFailOpenTrue, 212 ValidateDefaultParameters: ConfigBoolTrue, 213 ClientTimeout: defaultClientTimeout, 214 JWTClientTimeout: defaultJWTClientTimeout, 215 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 216 IncludeRetryReason: ConfigBoolTrue, 217 }, 218 ocspMode: ocspModeFailOpen, 219 err: errEmptyPassword(), 220 }, 221 { 222 dsn: "@host:123/db/schema?account=ac&protocol=http", 223 config: &Config{ 224 Account: "ac", User: "user", Password: "pass", 225 Protocol: "http", Host: "host", Port: 123, 226 Database: "db", Schema: "schema", 227 OCSPFailOpen: OCSPFailOpenTrue, 228 ValidateDefaultParameters: ConfigBoolTrue, 229 ClientTimeout: defaultClientTimeout, 230 JWTClientTimeout: defaultJWTClientTimeout, 231 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 232 IncludeRetryReason: ConfigBoolTrue, 233 }, 234 ocspMode: ocspModeFailOpen, 235 err: errEmptyUsername(), 236 }, 237 { 238 dsn: "user:p@host:123/db/schema?protocol=http", 239 config: &Config{ 240 Account: "ac", User: "user", Password: "pass", 241 Protocol: "http", Host: "host", Port: 123, 242 Database: "db", Schema: "schema", 243 OCSPFailOpen: OCSPFailOpenTrue, 244 ValidateDefaultParameters: ConfigBoolTrue, 245 ClientTimeout: defaultClientTimeout, 246 JWTClientTimeout: defaultJWTClientTimeout, 247 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 248 IncludeRetryReason: ConfigBoolTrue, 249 }, 250 ocspMode: ocspModeFailOpen, 251 err: errEmptyAccount(), 252 }, 253 { 254 dsn: "u:p@a.snowflakecomputing.com/db/pa?account=a&protocol=https&role=r&timezone=UTC&warehouse=w", 255 config: &Config{ 256 Account: "a", User: "u", Password: "p", 257 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 258 Database: "db", Schema: "pa", Role: "r", Warehouse: "w", 259 OCSPFailOpen: OCSPFailOpenTrue, 260 ValidateDefaultParameters: ConfigBoolTrue, 261 ClientTimeout: defaultClientTimeout, 262 JWTClientTimeout: defaultJWTClientTimeout, 263 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 264 IncludeRetryReason: ConfigBoolTrue, 265 }, 266 ocspMode: ocspModeFailOpen, 267 err: nil, 268 }, 269 { 270 dsn: "u:p@snowflake.local:9876?account=a&protocol=http", 271 config: &Config{ 272 Account: "a", User: "u", Password: "p", 273 Protocol: "http", Host: "snowflake.local", Port: 9876, 274 OCSPFailOpen: OCSPFailOpenTrue, 275 ValidateDefaultParameters: ConfigBoolTrue, 276 ClientTimeout: defaultClientTimeout, 277 JWTClientTimeout: defaultJWTClientTimeout, 278 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 279 IncludeRetryReason: ConfigBoolTrue, 280 }, 281 ocspMode: ocspModeFailOpen, 282 err: nil, 283 }, 284 { 285 dsn: "snowflake.local:9876?account=a&protocol=http&authenticator=OAUTH", 286 config: &Config{ 287 Account: "a", Authenticator: AuthTypeOAuth, 288 Protocol: "http", Host: "snowflake.local", Port: 9876, 289 OCSPFailOpen: OCSPFailOpenTrue, 290 ValidateDefaultParameters: ConfigBoolTrue, 291 ClientTimeout: defaultClientTimeout, 292 JWTClientTimeout: defaultJWTClientTimeout, 293 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 294 IncludeRetryReason: ConfigBoolTrue, 295 }, 296 ocspMode: ocspModeFailOpen, 297 err: nil, 298 }, 299 { 300 dsn: "u:@a.snowflake.local:9876?account=a&protocol=http&authenticator=SNOWFLAKE_JWT", 301 config: &Config{ 302 Account: "a", User: "u", Authenticator: AuthTypeJwt, 303 Protocol: "http", Host: "a.snowflake.local", Port: 9876, 304 OCSPFailOpen: OCSPFailOpenTrue, 305 ValidateDefaultParameters: ConfigBoolTrue, 306 ClientTimeout: defaultClientTimeout, 307 JWTClientTimeout: defaultJWTClientTimeout, 308 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 309 IncludeRetryReason: ConfigBoolTrue, 310 }, 311 ocspMode: ocspModeFailOpen, 312 err: nil, 313 }, 314 315 { 316 dsn: "u:p@a?database=d&jwtTimeout=20", 317 config: &Config{ 318 Account: "a", User: "u", Password: "p", 319 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 320 Database: "d", Schema: "", 321 JWTExpireTimeout: 20 * time.Second, 322 OCSPFailOpen: OCSPFailOpenTrue, 323 ValidateDefaultParameters: ConfigBoolTrue, 324 ClientTimeout: defaultClientTimeout, 325 JWTClientTimeout: defaultJWTClientTimeout, 326 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 327 IncludeRetryReason: ConfigBoolTrue, 328 }, 329 ocspMode: ocspModeFailOpen, 330 }, 331 { 332 dsn: "u:p@a?database=d&externalBrowserTimeout=20", 333 config: &Config{ 334 Account: "a", User: "u", Password: "p", 335 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 336 Database: "d", Schema: "", 337 ExternalBrowserTimeout: 20 * time.Second, 338 OCSPFailOpen: OCSPFailOpenTrue, 339 ValidateDefaultParameters: ConfigBoolTrue, 340 ClientTimeout: defaultClientTimeout, 341 JWTClientTimeout: defaultJWTClientTimeout, 342 IncludeRetryReason: ConfigBoolTrue, 343 MaxRetryCount: defaultMaxRetryCount, 344 }, 345 ocspMode: ocspModeFailOpen, 346 }, 347 { 348 dsn: "u:p@a?database=d&maxRetryCount=20", 349 config: &Config{ 350 Account: "a", User: "u", Password: "p", 351 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 352 Database: "d", Schema: "", 353 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 354 OCSPFailOpen: OCSPFailOpenTrue, 355 ValidateDefaultParameters: ConfigBoolTrue, 356 ClientTimeout: defaultClientTimeout, 357 JWTClientTimeout: defaultJWTClientTimeout, 358 IncludeRetryReason: ConfigBoolTrue, 359 MaxRetryCount: 20, 360 }, 361 ocspMode: ocspModeFailOpen, 362 }, 363 { 364 dsn: "u:p@a?database=d", 365 config: &Config{ 366 Account: "a", User: "u", Password: "p", 367 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 368 Database: "d", Schema: "", 369 JWTExpireTimeout: defaultJWTTimeout, 370 OCSPFailOpen: OCSPFailOpenTrue, 371 ValidateDefaultParameters: ConfigBoolTrue, 372 ClientTimeout: defaultClientTimeout, 373 JWTClientTimeout: defaultJWTClientTimeout, 374 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 375 IncludeRetryReason: ConfigBoolTrue, 376 }, 377 ocspMode: ocspModeFailOpen, 378 }, 379 { 380 dsn: "u:p@snowflake.local:NNNN?account=a&protocol=http", 381 config: &Config{ 382 Account: "a", User: "u", Password: "p", 383 Protocol: "http", Host: "snowflake.local", Port: 9876, 384 OCSPFailOpen: OCSPFailOpenTrue, 385 ValidateDefaultParameters: ConfigBoolTrue, 386 ClientTimeout: defaultClientTimeout, 387 JWTClientTimeout: defaultJWTClientTimeout, 388 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 389 IncludeRetryReason: ConfigBoolTrue, 390 }, 391 ocspMode: ocspModeFailOpen, 392 err: &SnowflakeError{ 393 Message: errMsgFailedToParsePort, 394 MessageArgs: []interface{}{"NNNN"}, 395 Number: ErrCodeFailedToParsePort, 396 }, 397 }, 398 { 399 dsn: "u:p@a?database=d&schema=s&role=r&application=aa&authenticator=snowflake&insecureMode=true&passcode=pp&passcodeInPassword=true", 400 config: &Config{ 401 Account: "a", User: "u", Password: "p", 402 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 403 Database: "d", Schema: "s", Role: "r", Authenticator: AuthTypeSnowflake, Application: "aa", 404 InsecureMode: true, Passcode: "pp", PasscodeInPassword: true, 405 OCSPFailOpen: OCSPFailOpenTrue, 406 ValidateDefaultParameters: ConfigBoolTrue, 407 ClientTimeout: defaultClientTimeout, 408 JWTClientTimeout: defaultJWTClientTimeout, 409 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 410 IncludeRetryReason: ConfigBoolTrue, 411 }, 412 ocspMode: ocspModeInsecure, 413 err: nil, 414 }, 415 { 416 // schema should be ignored as no value is specified. 417 dsn: "u:p@a?database=d&schema", 418 config: &Config{ 419 Account: "a", User: "u", Password: "p", 420 Protocol: "https", Host: "a.snowflakecomputing.com", Port: 443, 421 Database: "d", Schema: "", 422 OCSPFailOpen: OCSPFailOpenTrue, 423 ValidateDefaultParameters: ConfigBoolTrue, 424 ClientTimeout: defaultClientTimeout, 425 JWTClientTimeout: defaultJWTClientTimeout, 426 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 427 IncludeRetryReason: ConfigBoolTrue, 428 }, 429 ocspMode: ocspModeFailOpen, 430 err: nil, 431 }, 432 { 433 dsn: "u:p@a?database= %Sd", 434 config: &Config{}, 435 err: url.EscapeError(`invalid URL escape`), 436 }, 437 { 438 dsn: "u:p@a?schema= %Sd", 439 config: &Config{}, 440 err: url.EscapeError(`invalid URL escape`), 441 }, 442 { 443 dsn: "u:p@a?warehouse= %Sd", 444 config: &Config{}, 445 err: url.EscapeError(`invalid URL escape`), 446 }, 447 { 448 dsn: "u:p@a?role= %Sd", 449 config: &Config{}, 450 err: url.EscapeError(`invalid URL escape`), 451 }, 452 { 453 dsn: ":/", 454 config: &Config{}, 455 err: &SnowflakeError{ 456 Number: ErrCodeFailedToParsePort, 457 }, 458 }, 459 { 460 dsn: "u:u@/+/+?account=+&=0", 461 config: &Config{}, 462 err: errEmptyAccount(), 463 }, 464 { 465 dsn: "u:u@/+/+?account=+&=+&=+", 466 config: &Config{}, 467 err: errEmptyAccount(), 468 }, 469 { 470 dsn: "user%40%2F1:p%3A%40s@/db%2F?account=ac", 471 config: &Config{ 472 Account: "ac", User: "user@/1", Password: "p:@s", Database: "db/", 473 Protocol: "https", Host: "ac.snowflakecomputing.com", Port: 443, 474 OCSPFailOpen: OCSPFailOpenTrue, 475 ValidateDefaultParameters: ConfigBoolTrue, 476 ClientTimeout: defaultClientTimeout, 477 JWTClientTimeout: defaultJWTClientTimeout, 478 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 479 IncludeRetryReason: ConfigBoolTrue, 480 }, 481 ocspMode: ocspModeFailOpen, 482 err: nil, 483 }, 484 { 485 dsn: fmt.Sprintf("u:p@ac.snowflake.local:9876?account=ac&protocol=http&authenticator=SNOWFLAKE_JWT&privateKey=%v", privKeyPKCS8), 486 config: &Config{ 487 Account: "ac", User: "u", Password: "p", 488 Authenticator: AuthTypeJwt, PrivateKey: testPrivKey, 489 Protocol: "http", Host: "ac.snowflake.local", Port: 9876, 490 OCSPFailOpen: OCSPFailOpenTrue, 491 ValidateDefaultParameters: ConfigBoolTrue, 492 ClientTimeout: defaultClientTimeout, 493 JWTClientTimeout: defaultJWTClientTimeout, 494 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 495 IncludeRetryReason: ConfigBoolTrue, 496 }, 497 ocspMode: ocspModeFailOpen, 498 err: nil, 499 }, 500 { 501 dsn: fmt.Sprintf("u:p@ac.snowflake.local:9876?account=ac&protocol=http&authenticator=%v", url.QueryEscape("https://ac.okta.com")), 502 config: &Config{ 503 Account: "ac", User: "u", Password: "p", 504 Authenticator: AuthTypeOkta, 505 OktaURL: &url.URL{ 506 Scheme: "https", 507 Host: "ac.okta.com", 508 }, 509 PrivateKey: testPrivKey, 510 Protocol: "http", Host: "ac.snowflake.local", Port: 9876, 511 OCSPFailOpen: OCSPFailOpenTrue, 512 ValidateDefaultParameters: ConfigBoolTrue, 513 ClientTimeout: defaultClientTimeout, 514 JWTClientTimeout: defaultJWTClientTimeout, 515 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 516 IncludeRetryReason: ConfigBoolTrue, 517 }, 518 ocspMode: ocspModeFailOpen, 519 err: nil, 520 }, 521 { 522 dsn: fmt.Sprintf("u:p@a.snowflake.local:9876?account=a&protocol=http&authenticator=SNOWFLAKE_JWT&privateKey=%v", privKeyPKCS1), 523 config: &Config{ 524 Account: "a", User: "u", Password: "p", 525 Authenticator: AuthTypeJwt, PrivateKey: testPrivKey, 526 Protocol: "http", Host: "a.snowflake.local", Port: 9876, 527 OCSPFailOpen: OCSPFailOpenTrue, 528 ValidateDefaultParameters: ConfigBoolTrue, 529 ClientTimeout: defaultClientTimeout, 530 JWTClientTimeout: defaultJWTClientTimeout, 531 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 532 IncludeRetryReason: ConfigBoolTrue, 533 }, 534 ocspMode: ocspModeFailOpen, 535 err: &SnowflakeError{Number: ErrCodePrivateKeyParseError}, 536 }, 537 { 538 dsn: "user:pass@account/db/s?ocspFailOpen=true", 539 config: &Config{ 540 Account: "account", User: "user", Password: "pass", 541 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 542 Database: "db", Schema: "s", OCSPFailOpen: OCSPFailOpenTrue, 543 ValidateDefaultParameters: ConfigBoolTrue, 544 ClientTimeout: defaultClientTimeout, 545 JWTClientTimeout: defaultJWTClientTimeout, 546 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 547 IncludeRetryReason: ConfigBoolTrue, 548 }, 549 ocspMode: ocspModeFailOpen, 550 err: nil, 551 }, 552 { 553 dsn: "user:pass@account/db/s?ocspFailOpen=false", 554 config: &Config{ 555 Account: "account", User: "user", Password: "pass", 556 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 557 Database: "db", Schema: "s", OCSPFailOpen: OCSPFailOpenFalse, 558 ValidateDefaultParameters: ConfigBoolTrue, 559 ClientTimeout: defaultClientTimeout, 560 JWTClientTimeout: defaultJWTClientTimeout, 561 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 562 IncludeRetryReason: ConfigBoolTrue, 563 }, 564 ocspMode: ocspModeFailClosed, 565 err: nil, 566 }, 567 { 568 dsn: "user:pass@account/db/s?insecureMode=true&ocspFailOpen=false", 569 config: &Config{ 570 Account: "account", User: "user", Password: "pass", 571 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 572 Database: "db", Schema: "s", OCSPFailOpen: OCSPFailOpenFalse, InsecureMode: true, 573 ValidateDefaultParameters: ConfigBoolTrue, 574 ClientTimeout: defaultClientTimeout, 575 JWTClientTimeout: defaultJWTClientTimeout, 576 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 577 IncludeRetryReason: ConfigBoolTrue, 578 }, 579 ocspMode: ocspModeInsecure, 580 err: nil, 581 }, 582 { 583 dsn: "user:pass@account/db/s?validateDefaultParameters=true", 584 config: &Config{ 585 Account: "account", User: "user", Password: "pass", 586 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 587 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 588 ClientTimeout: defaultClientTimeout, 589 JWTClientTimeout: defaultJWTClientTimeout, 590 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 591 IncludeRetryReason: ConfigBoolTrue, 592 }, 593 ocspMode: ocspModeFailOpen, 594 err: nil, 595 }, 596 { 597 dsn: "user:pass@account/db/s?validateDefaultParameters=false", 598 config: &Config{ 599 Account: "account", User: "user", Password: "pass", 600 Protocol: "https", Host: "account.snowflakecomputing.com", Port: 443, 601 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolFalse, OCSPFailOpen: OCSPFailOpenTrue, 602 ClientTimeout: defaultClientTimeout, 603 JWTClientTimeout: defaultJWTClientTimeout, 604 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 605 IncludeRetryReason: ConfigBoolTrue, 606 }, 607 ocspMode: ocspModeFailOpen, 608 err: nil, 609 }, 610 { 611 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&validateDefaultParameters=false", 612 config: &Config{ 613 Account: "a", User: "u", Password: "p", 614 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 615 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolFalse, OCSPFailOpen: OCSPFailOpenTrue, 616 ClientTimeout: defaultClientTimeout, 617 JWTClientTimeout: defaultJWTClientTimeout, 618 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 619 IncludeRetryReason: ConfigBoolTrue, 620 }, 621 ocspMode: ocspModeFailOpen, 622 err: nil, 623 }, 624 { 625 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&clientTimeout=300&jwtClientTimeout=45&includeRetryReason=false", 626 config: &Config{ 627 Account: "a", User: "u", Password: "p", 628 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 629 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 630 ClientTimeout: 300 * time.Second, 631 JWTClientTimeout: 45 * time.Second, 632 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 633 DisableQueryContextCache: false, 634 IncludeRetryReason: ConfigBoolFalse, 635 }, 636 ocspMode: ocspModeFailOpen, 637 err: nil, 638 }, 639 { 640 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&tmpDirPath=%2Ftmp", 641 config: &Config{ 642 Account: "a", User: "u", Password: "p", 643 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 644 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 645 ClientTimeout: defaultClientTimeout, 646 JWTClientTimeout: defaultJWTClientTimeout, 647 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 648 TmpDirPath: "/tmp", 649 IncludeRetryReason: ConfigBoolTrue, 650 }, 651 ocspMode: ocspModeFailOpen, 652 err: nil, 653 }, 654 { 655 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&disableQueryContextCache=true", 656 config: &Config{ 657 Account: "a", User: "u", Password: "p", 658 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 659 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 660 ClientTimeout: defaultClientTimeout, 661 JWTClientTimeout: defaultJWTClientTimeout, 662 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 663 DisableQueryContextCache: true, 664 IncludeRetryReason: ConfigBoolTrue, 665 }, 666 ocspMode: ocspModeFailOpen, 667 err: nil, 668 }, 669 { 670 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&includeRetryReason=true", 671 config: &Config{ 672 Account: "a", User: "u", Password: "p", 673 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 674 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 675 ClientTimeout: defaultClientTimeout, 676 JWTClientTimeout: defaultJWTClientTimeout, 677 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 678 IncludeRetryReason: ConfigBoolTrue, 679 }, 680 ocspMode: ocspModeFailOpen, 681 err: nil, 682 }, 683 { 684 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&includeRetryReason=true&clientConfigFile=%2FUsers%2Fuser%2Fconfig.json", 685 config: &Config{ 686 Account: "a", User: "u", Password: "p", 687 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 688 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 689 ClientTimeout: defaultClientTimeout, 690 JWTClientTimeout: defaultJWTClientTimeout, 691 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 692 IncludeRetryReason: ConfigBoolTrue, 693 ClientConfigFile: "/Users/user/config.json", 694 }, 695 ocspMode: ocspModeFailOpen, 696 err: nil, 697 }, 698 { 699 dsn: "u:p@a.r.c.snowflakecomputing.com/db/s?account=a.r.c&includeRetryReason=true&clientConfigFile=c%3A%5CUsers%5Cuser%5Cconfig.json", 700 config: &Config{ 701 Account: "a", User: "u", Password: "p", 702 Protocol: "https", Host: "a.r.c.snowflakecomputing.com", Port: 443, 703 Database: "db", Schema: "s", ValidateDefaultParameters: ConfigBoolTrue, OCSPFailOpen: OCSPFailOpenTrue, 704 ClientTimeout: defaultClientTimeout, 705 JWTClientTimeout: defaultJWTClientTimeout, 706 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 707 IncludeRetryReason: ConfigBoolTrue, 708 ClientConfigFile: "c:\\Users\\user\\config.json", 709 }, 710 ocspMode: ocspModeFailOpen, 711 err: nil, 712 }, 713 { 714 dsn: "u:p@a.snowflakecomputing.com:443?authenticator=http%3A%2F%2Fsc.okta.com&ocspFailOpen=true&validateDefaultParameters=true", 715 err: errFailedToParseAuthenticator(), 716 }, 717 { 718 dsn: "u:p@a.snowflake.local:9876?account=a&protocol=http&authenticator=EXTERNALBROWSER&disableConsoleLogin=true", 719 config: &Config{ 720 Account: "a", User: "u", Password: "p", 721 Authenticator: AuthTypeExternalBrowser, 722 Protocol: "http", Host: "a.snowflake.local", Port: 9876, 723 OCSPFailOpen: OCSPFailOpenTrue, 724 ValidateDefaultParameters: ConfigBoolTrue, 725 ClientTimeout: defaultClientTimeout, 726 JWTClientTimeout: defaultJWTClientTimeout, 727 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 728 IncludeRetryReason: ConfigBoolTrue, 729 DisableConsoleLogin: ConfigBoolTrue, 730 }, 731 ocspMode: ocspModeFailOpen, 732 err: nil, 733 }, 734 { 735 dsn: "u:p@a.snowflake.local:9876?account=a&protocol=http&authenticator=EXTERNALBROWSER&disableConsoleLogin=false", 736 config: &Config{ 737 Account: "a", User: "u", Password: "p", 738 Authenticator: AuthTypeExternalBrowser, 739 Protocol: "http", Host: "a.snowflake.local", Port: 9876, 740 OCSPFailOpen: OCSPFailOpenTrue, 741 ValidateDefaultParameters: ConfigBoolTrue, 742 ClientTimeout: defaultClientTimeout, 743 JWTClientTimeout: defaultJWTClientTimeout, 744 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 745 IncludeRetryReason: ConfigBoolTrue, 746 DisableConsoleLogin: ConfigBoolFalse, 747 }, 748 ocspMode: ocspModeFailOpen, 749 err: nil, 750 }, 751 } 752 753 for _, at := range []AuthType{AuthTypeExternalBrowser, AuthTypeOAuth} { 754 testcases = append(testcases, tcParseDSN{ 755 dsn: fmt.Sprintf("@host:777/db/schema?account=ac&protocol=http&authenticator=%v", strings.ToLower(at.String())), 756 config: &Config{ 757 Account: "ac", User: "", Password: "", 758 Protocol: "http", Host: "host", Port: 777, 759 Database: "db", Schema: "schema", 760 OCSPFailOpen: OCSPFailOpenTrue, 761 ValidateDefaultParameters: ConfigBoolTrue, 762 ClientTimeout: defaultClientTimeout, 763 JWTClientTimeout: defaultJWTClientTimeout, 764 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 765 IncludeRetryReason: ConfigBoolTrue, 766 Authenticator: at, 767 }, 768 ocspMode: ocspModeFailOpen, 769 err: nil, 770 }) 771 } 772 773 for _, at := range []AuthType{AuthTypeSnowflake, AuthTypeUsernamePasswordMFA, AuthTypeJwt} { 774 testcases = append(testcases, tcParseDSN{ 775 dsn: fmt.Sprintf("@host:888/db/schema?account=ac&protocol=http&authenticator=%v", strings.ToLower(at.String())), 776 config: &Config{ 777 Account: "ac", User: "", Password: "", 778 Protocol: "http", Host: "host", Port: 888, 779 Database: "db", Schema: "schema", 780 OCSPFailOpen: OCSPFailOpenTrue, 781 ValidateDefaultParameters: ConfigBoolTrue, 782 ClientTimeout: defaultClientTimeout, 783 JWTClientTimeout: defaultJWTClientTimeout, 784 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 785 IncludeRetryReason: ConfigBoolTrue, 786 Authenticator: at, 787 }, 788 ocspMode: ocspModeFailOpen, 789 err: errEmptyUsername(), 790 }) 791 } 792 793 for _, at := range []AuthType{AuthTypeSnowflake, AuthTypeUsernamePasswordMFA} { 794 testcases = append(testcases, tcParseDSN{ 795 dsn: fmt.Sprintf("user@host:888/db/schema?account=ac&protocol=http&authenticator=%v", strings.ToLower(at.String())), 796 config: &Config{ 797 Account: "ac", User: "user", Password: "", 798 Protocol: "http", Host: "host", Port: 888, 799 Database: "db", Schema: "schema", 800 OCSPFailOpen: OCSPFailOpenTrue, 801 ValidateDefaultParameters: ConfigBoolTrue, 802 ClientTimeout: defaultClientTimeout, 803 JWTClientTimeout: defaultJWTClientTimeout, 804 ExternalBrowserTimeout: defaultExternalBrowserTimeout, 805 IncludeRetryReason: ConfigBoolTrue, 806 Authenticator: at, 807 }, 808 ocspMode: ocspModeFailOpen, 809 err: errEmptyPassword(), 810 }) 811 } 812 813 for i, test := range testcases { 814 t.Run(test.dsn, func(t *testing.T) { 815 cfg, err := ParseDSN(test.dsn) 816 switch { 817 case test.err == nil: 818 if err != nil { 819 t.Fatalf("%d: Failed to parse the DSN. dsn: %v, err: %v", i, test.dsn, err) 820 } 821 if test.config.Host != cfg.Host { 822 t.Fatalf("%d: Failed to match host. expected: %v, got: %v", 823 i, test.config.Host, cfg.Host) 824 } 825 if test.config.Account != cfg.Account { 826 t.Fatalf("%d: Failed to match account. expected: %v, got: %v", 827 i, test.config.Account, cfg.Account) 828 } 829 if test.config.User != cfg.User { 830 t.Fatalf("%d: Failed to match user. expected: %v, got: %v", 831 i, test.config.User, cfg.User) 832 } 833 if test.config.Password != cfg.Password { 834 t.Fatalf("%d: Failed to match password. expected: %v, got: %v", 835 i, test.config.Password, cfg.Password) 836 } 837 if test.config.Database != cfg.Database { 838 t.Fatalf("%d: Failed to match database. expected: %v, got: %v", 839 i, test.config.Database, cfg.Database) 840 } 841 if test.config.Schema != cfg.Schema { 842 t.Fatalf("%d: Failed to match schema. expected: %v, got: %v", 843 i, test.config.Schema, cfg.Schema) 844 } 845 if test.config.Warehouse != cfg.Warehouse { 846 t.Fatalf("%d: Failed to match warehouse. expected: %v, got: %v", 847 i, test.config.Warehouse, cfg.Warehouse) 848 } 849 if test.config.Role != cfg.Role { 850 t.Fatalf("%d: Failed to match role. expected: %v, got: %v", 851 i, test.config.Role, cfg.Role) 852 } 853 if test.config.Region != cfg.Region { 854 t.Fatalf("%d: Failed to match region. expected: %v, got: %v", 855 i, test.config.Region, cfg.Region) 856 } 857 if test.config.Protocol != cfg.Protocol { 858 t.Fatalf("%d: Failed to match protocol. expected: %v, got: %v", 859 i, test.config.Protocol, cfg.Protocol) 860 } 861 if test.config.Passcode != cfg.Passcode { 862 t.Fatalf("%d: Failed to match passcode. expected: %v, got: %v", 863 i, test.config.Passcode, cfg.Passcode) 864 } 865 if test.config.PasscodeInPassword != cfg.PasscodeInPassword { 866 t.Fatalf("%d: Failed to match passcodeInPassword. expected: %v, got: %v", 867 i, test.config.PasscodeInPassword, cfg.PasscodeInPassword) 868 } 869 if test.config.Authenticator != cfg.Authenticator { 870 t.Fatalf("%d: Failed to match Authenticator. expected: %v, got: %v", 871 i, test.config.Authenticator.String(), cfg.Authenticator.String()) 872 } 873 if test.config.Authenticator == AuthTypeOkta && *test.config.OktaURL != *cfg.OktaURL { 874 t.Fatalf("%d: Failed to match okta URL. expected: %v, got: %v", 875 i, test.config.OktaURL, cfg.OktaURL) 876 } 877 if test.config.OCSPFailOpen != cfg.OCSPFailOpen { 878 t.Fatalf("%d: Failed to match OCSPFailOpen. expected: %v, got: %v", 879 i, test.config.OCSPFailOpen, cfg.OCSPFailOpen) 880 } 881 if test.ocspMode != cfg.ocspMode() { 882 t.Fatalf("%d: Failed to match OCSPMode. expected: %v, got: %v", 883 i, test.ocspMode, cfg.ocspMode()) 884 } 885 if test.config.ValidateDefaultParameters != cfg.ValidateDefaultParameters { 886 t.Fatalf("%d: Failed to match ValidateDefaultParameters. expected: %v, got: %v", 887 i, test.config.ValidateDefaultParameters, cfg.ValidateDefaultParameters) 888 } 889 if test.config.ClientTimeout != cfg.ClientTimeout { 890 t.Fatalf("%d: Failed to match ClientTimeout. expected: %v, got: %v", 891 i, test.config.ClientTimeout, cfg.ClientTimeout) 892 } 893 if test.config.JWTClientTimeout != cfg.JWTClientTimeout { 894 t.Fatalf("%d: Failed to match JWTClientTimeout. expected: %v, got: %v", 895 i, test.config.JWTClientTimeout, cfg.JWTClientTimeout) 896 } 897 if test.config.ExternalBrowserTimeout != cfg.ExternalBrowserTimeout { 898 t.Fatalf("%d: Failed to match ExternalBrowserTimeout. expected: %v, got: %v", 899 i, test.config.ExternalBrowserTimeout, cfg.ExternalBrowserTimeout) 900 } 901 if test.config.TmpDirPath != cfg.TmpDirPath { 902 t.Fatalf("%v: Failed to match TmpDirPatch. expected: %v, got: %v", i, test.config.TmpDirPath, cfg.TmpDirPath) 903 } 904 if test.config.DisableQueryContextCache != cfg.DisableQueryContextCache { 905 t.Fatalf("%v: Failed to match DisableQueryContextCache. expected: %v, got: %v", i, test.config.DisableQueryContextCache, cfg.DisableQueryContextCache) 906 } 907 if test.config.IncludeRetryReason != cfg.IncludeRetryReason { 908 t.Fatalf("%v: Failed to match IncludeRetryReason. expected: %v, got: %v", i, test.config.IncludeRetryReason, cfg.IncludeRetryReason) 909 } 910 if test.config.DisableConsoleLogin != cfg.DisableConsoleLogin { 911 t.Fatalf("%v: Failed to match DisableConsoleLogin. expected: %v, got: %v", i, test.config.DisableConsoleLogin, cfg.DisableConsoleLogin) 912 } 913 assertEqualF(t, cfg.ClientConfigFile, test.config.ClientConfigFile, "client config file") 914 case test.err != nil: 915 driverErrE, okE := test.err.(*SnowflakeError) 916 driverErrG, okG := err.(*SnowflakeError) 917 if okE && !okG || !okE && okG { 918 t.Fatalf("%d: Wrong error. expected: %v, got: %v", i, test.err, err) 919 } 920 if okE && okG { 921 if driverErrE.Number != driverErrG.Number { 922 t.Fatalf("%d: Wrong error number. expected: %v, got: %v", i, driverErrE.Number, driverErrG.Number) 923 } 924 } else { 925 t1 := reflect.TypeOf(err) 926 t2 := reflect.TypeOf(test.err) 927 if t1 != t2 { 928 t.Fatalf("%d: Wrong error. expected: %T:%v, got: %T:%v", i, test.err, test.err, err, err) 929 } 930 } 931 } 932 933 }) 934 } 935 } 936 937 type tcDSN struct { 938 cfg *Config 939 dsn string 940 err error 941 } 942 943 func TestDSN(t *testing.T) { 944 tmfmt := "MM-DD-YYYY" 945 testcases := []tcDSN{ 946 { 947 cfg: &Config{ 948 User: "u", 949 Password: "p", 950 Account: "a-aofnadsf.somewhere.azure", 951 }, 952 dsn: "u:p@a-aofnadsf.somewhere.azure.snowflakecomputing.com:443?ocspFailOpen=true®ion=somewhere.azure&validateDefaultParameters=true", 953 }, 954 { 955 cfg: &Config{ 956 User: "u", 957 Password: "p", 958 Account: "a-aofnadsf.global", 959 }, 960 dsn: "u:p@a-aofnadsf.global.snowflakecomputing.com:443?ocspFailOpen=true®ion=global&validateDefaultParameters=true", 961 }, 962 { 963 cfg: &Config{ 964 User: "u", 965 Password: "p", 966 Account: "a-aofnadsf.global", 967 Region: "us-west-2", 968 }, 969 dsn: "u:p@a-aofnadsf.global.snowflakecomputing.com:443?ocspFailOpen=true®ion=global&validateDefaultParameters=true", 970 }, 971 { 972 cfg: &Config{ 973 User: "u", 974 Password: "p", 975 Account: "a-aofnadsf.global", 976 Region: "r", 977 }, 978 err: errInvalidRegion(), 979 }, 980 { 981 cfg: &Config{ 982 User: "u", 983 Password: "p", 984 Account: "a", 985 }, 986 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=true&validateDefaultParameters=true", 987 }, 988 { 989 cfg: &Config{ 990 User: "u", 991 Password: "p", 992 Account: "a", 993 Region: "us-west-2", 994 }, 995 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=true&validateDefaultParameters=true", 996 }, 997 { 998 cfg: &Config{ 999 User: "u", 1000 Password: "p", 1001 Account: "a", 1002 Region: "r", 1003 }, 1004 dsn: "u:p@a.r.snowflakecomputing.com:443?ocspFailOpen=true®ion=r&validateDefaultParameters=true", 1005 }, 1006 { 1007 cfg: &Config{ 1008 User: "u", 1009 Password: "p", 1010 Account: "a", 1011 Region: "r", 1012 ExternalBrowserTimeout: 20 * time.Second, 1013 }, 1014 dsn: "u:p@a.r.snowflakecomputing.com:443?externalBrowserTimeout=20&ocspFailOpen=true®ion=r&validateDefaultParameters=true", 1015 }, 1016 { 1017 cfg: &Config{ 1018 User: "", 1019 Password: "p", 1020 Account: "a", 1021 }, 1022 err: errEmptyUsername(), 1023 }, 1024 { 1025 cfg: &Config{ 1026 User: "u", 1027 Password: "", 1028 Account: "a", 1029 }, 1030 err: errEmptyPassword(), 1031 }, 1032 { 1033 cfg: &Config{ 1034 User: "u", 1035 Password: "p", 1036 Account: "", 1037 }, 1038 err: errEmptyAccount(), 1039 }, 1040 { 1041 cfg: &Config{ 1042 User: "u", 1043 Password: "p", 1044 Account: "a.e", 1045 }, 1046 dsn: "u:p@a.e.snowflakecomputing.com:443?ocspFailOpen=true®ion=e&validateDefaultParameters=true", 1047 }, 1048 { 1049 cfg: &Config{ 1050 User: "u", 1051 Password: "p", 1052 Account: "a.e", 1053 Region: "us-west-2", 1054 }, 1055 dsn: "u:p@a.e.snowflakecomputing.com:443?ocspFailOpen=true®ion=e&validateDefaultParameters=true", 1056 }, 1057 { 1058 cfg: &Config{ 1059 User: "u", 1060 Password: "p", 1061 Account: "a.e", 1062 Region: "r", 1063 }, 1064 err: errInvalidRegion(), 1065 }, 1066 { 1067 cfg: &Config{ 1068 User: "u", 1069 Password: "p", 1070 Account: "a", 1071 Database: "db", 1072 Schema: "sc", 1073 Role: "ro", 1074 Region: "b", 1075 Authenticator: AuthTypeSnowflake, 1076 Passcode: "db", 1077 PasscodeInPassword: true, 1078 LoginTimeout: 10 * time.Second, 1079 RequestTimeout: 300 * time.Second, 1080 Application: "special go", 1081 }, 1082 dsn: "u:p@a.b.snowflakecomputing.com:443?application=special+go&database=db&loginTimeout=10&ocspFailOpen=true&passcode=db&passcodeInPassword=true®ion=b&requestTimeout=300&role=ro&schema=sc&validateDefaultParameters=true", 1083 }, 1084 { 1085 cfg: &Config{ 1086 User: "u", 1087 Password: "p", 1088 Account: "a", 1089 Authenticator: AuthTypeExternalBrowser, 1090 ClientStoreTemporaryCredential: ConfigBoolTrue, 1091 }, 1092 dsn: "u:p@a.snowflakecomputing.com:443?authenticator=externalbrowser&clientStoreTemporaryCredential=true&ocspFailOpen=true&validateDefaultParameters=true", 1093 }, 1094 { 1095 cfg: &Config{ 1096 User: "u", 1097 Password: "p", 1098 Account: "a", 1099 Authenticator: AuthTypeExternalBrowser, 1100 ClientStoreTemporaryCredential: ConfigBoolFalse, 1101 }, 1102 dsn: "u:p@a.snowflakecomputing.com:443?authenticator=externalbrowser&clientStoreTemporaryCredential=false&ocspFailOpen=true&validateDefaultParameters=true", 1103 }, 1104 { 1105 cfg: &Config{ 1106 User: "u", 1107 Password: "p", 1108 Account: "a", 1109 Authenticator: AuthTypeOkta, 1110 OktaURL: &url.URL{ 1111 Scheme: "https", 1112 Host: "sc.okta.com", 1113 }, 1114 }, 1115 dsn: "u:p@a.snowflakecomputing.com:443?authenticator=https%3A%2F%2Fsc.okta.com&ocspFailOpen=true&validateDefaultParameters=true", 1116 }, 1117 { 1118 cfg: &Config{ 1119 User: "u", 1120 Password: "p", 1121 Account: "a.e", 1122 Params: map[string]*string{ 1123 "TIMESTAMP_OUTPUT_FORMAT": &tmfmt, 1124 }, 1125 }, 1126 dsn: "u:p@a.e.snowflakecomputing.com:443?TIMESTAMP_OUTPUT_FORMAT=MM-DD-YYYY&ocspFailOpen=true®ion=e&validateDefaultParameters=true", 1127 }, 1128 { 1129 cfg: &Config{ 1130 User: "u", 1131 Password: ":@abc", 1132 Account: "a.e", 1133 Params: map[string]*string{ 1134 "TIMESTAMP_OUTPUT_FORMAT": &tmfmt, 1135 }, 1136 }, 1137 dsn: "u:%3A%40abc@a.e.snowflakecomputing.com:443?TIMESTAMP_OUTPUT_FORMAT=MM-DD-YYYY&ocspFailOpen=true®ion=e&validateDefaultParameters=true", 1138 }, 1139 { 1140 cfg: &Config{ 1141 User: "u", 1142 Password: "p", 1143 Account: "a", 1144 OCSPFailOpen: OCSPFailOpenTrue, 1145 }, 1146 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=true&validateDefaultParameters=true", 1147 }, 1148 { 1149 cfg: &Config{ 1150 User: "u", 1151 Password: "p", 1152 Account: "a", 1153 OCSPFailOpen: OCSPFailOpenFalse, 1154 }, 1155 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=false&validateDefaultParameters=true", 1156 }, 1157 { 1158 cfg: &Config{ 1159 User: "u", 1160 Password: "p", 1161 Account: "a", 1162 ValidateDefaultParameters: ConfigBoolFalse, 1163 }, 1164 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=true&validateDefaultParameters=false", 1165 }, 1166 { 1167 cfg: &Config{ 1168 User: "u", 1169 Password: "p", 1170 Account: "a", 1171 ValidateDefaultParameters: ConfigBoolTrue, 1172 }, 1173 dsn: "u:p@a.snowflakecomputing.com:443?ocspFailOpen=true&validateDefaultParameters=true", 1174 }, 1175 { 1176 cfg: &Config{ 1177 User: "u", 1178 Password: "p", 1179 Account: "a", 1180 InsecureMode: true, 1181 }, 1182 dsn: "u:p@a.snowflakecomputing.com:443?insecureMode=true&ocspFailOpen=true&validateDefaultParameters=true", 1183 }, 1184 { 1185 cfg: &Config{ 1186 User: "u", 1187 Password: "p", 1188 Account: "a.b.c", 1189 }, 1190 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1191 }, 1192 { 1193 cfg: &Config{ 1194 User: "u", 1195 Password: "p", 1196 Account: "a.b.c", 1197 Region: "us-west-2", 1198 }, 1199 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1200 }, 1201 { 1202 cfg: &Config{ 1203 User: "u", 1204 Password: "p", 1205 Account: "a.b.c", 1206 Region: "r", 1207 }, 1208 err: errInvalidRegion(), 1209 }, 1210 { 1211 cfg: &Config{ 1212 User: "u", 1213 Password: "p", 1214 Account: "a.b.c", 1215 ClientTimeout: 400 * time.Second, 1216 JWTClientTimeout: 60 * time.Second, 1217 }, 1218 dsn: "u:p@a.b.c.snowflakecomputing.com:443?clientTimeout=400&jwtClientTimeout=60&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1219 }, 1220 { 1221 cfg: &Config{ 1222 User: "u", 1223 Password: "p", 1224 Account: "a.b.c", 1225 ClientTimeout: 400 * time.Second, 1226 JWTExpireTimeout: 30 * time.Second, 1227 }, 1228 dsn: "u:p@a.b.c.snowflakecomputing.com:443?clientTimeout=400&jwtTimeout=30&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1229 }, 1230 { 1231 cfg: &Config{ 1232 User: "u", 1233 Password: "p", 1234 Account: "a.b.c", 1235 Protocol: "http", 1236 }, 1237 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true&protocol=http®ion=b.c&validateDefaultParameters=true", 1238 }, 1239 { 1240 cfg: &Config{ 1241 User: "u", 1242 Password: "p", 1243 Account: "a.b.c", 1244 Tracing: "debug", 1245 }, 1246 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&tracing=debug&validateDefaultParameters=true", 1247 }, 1248 { 1249 cfg: &Config{ 1250 User: "u", 1251 Password: "p", 1252 Account: "a.b.c", 1253 Authenticator: AuthTypeUsernamePasswordMFA, 1254 ClientRequestMfaToken: ConfigBoolTrue, 1255 }, 1256 dsn: "u:p@a.b.c.snowflakecomputing.com:443?authenticator=username_password_mfa&clientRequestMfaToken=true&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1257 }, 1258 { 1259 cfg: &Config{ 1260 User: "u", 1261 Password: "p", 1262 Account: "a.b.c", 1263 Authenticator: AuthTypeUsernamePasswordMFA, 1264 ClientRequestMfaToken: ConfigBoolFalse, 1265 }, 1266 dsn: "u:p@a.b.c.snowflakecomputing.com:443?authenticator=username_password_mfa&clientRequestMfaToken=false&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1267 }, 1268 { 1269 cfg: &Config{ 1270 User: "u", 1271 Password: "p", 1272 Account: "a.b.c", 1273 Warehouse: "wh", 1274 }, 1275 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&validateDefaultParameters=true&warehouse=wh", 1276 }, 1277 { 1278 cfg: &Config{ 1279 User: "u", 1280 Password: "p", 1281 Account: "a.b.c", 1282 Token: "t", 1283 }, 1284 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&token=t&validateDefaultParameters=true", 1285 }, 1286 { 1287 cfg: &Config{ 1288 User: "u", 1289 Password: "p", 1290 Account: "a.b.c", 1291 Authenticator: AuthTypeTokenAccessor, 1292 }, 1293 dsn: "u:p@a.b.c.snowflakecomputing.com:443?authenticator=tokenaccessor&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1294 }, 1295 { 1296 cfg: &Config{ 1297 User: "u", 1298 Password: "p", 1299 Account: "a.b.c", 1300 TmpDirPath: "/tmp", 1301 }, 1302 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&tmpDirPath=%2Ftmp&validateDefaultParameters=true", 1303 }, 1304 { 1305 cfg: &Config{ 1306 User: "u", 1307 Password: "p", 1308 Account: "a.b.c", 1309 IncludeRetryReason: ConfigBoolFalse, 1310 MaxRetryCount: 30, 1311 }, 1312 dsn: "u:p@a.b.c.snowflakecomputing.com:443?includeRetryReason=false&maxRetryCount=30&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1313 }, 1314 { 1315 cfg: &Config{ 1316 User: "u", 1317 Password: "p", 1318 Account: "a.b.c", 1319 DisableQueryContextCache: true, 1320 IncludeRetryReason: ConfigBoolTrue, 1321 }, 1322 dsn: "u:p@a.b.c.snowflakecomputing.com:443?disableQueryContextCache=true&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1323 }, 1324 { 1325 cfg: &Config{ 1326 User: "u", 1327 Password: "p", 1328 Account: "a.b.c", 1329 IncludeRetryReason: ConfigBoolFalse, 1330 }, 1331 dsn: "u:p@a.b.c.snowflakecomputing.com:443?includeRetryReason=false&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1332 }, 1333 { 1334 cfg: &Config{ 1335 User: "u", 1336 Password: "p", 1337 Account: "a.b.c", 1338 IncludeRetryReason: ConfigBoolTrue, 1339 }, 1340 dsn: "u:p@a.b.c.snowflakecomputing.com:443?ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1341 }, 1342 { 1343 cfg: &Config{ 1344 User: "u", 1345 Password: "p", 1346 Account: "a.b.c", 1347 IncludeRetryReason: ConfigBoolTrue, 1348 ClientConfigFile: "/Users/user/config.json", 1349 }, 1350 dsn: "u:p@a.b.c.snowflakecomputing.com:443?clientConfigFile=%2FUsers%2Fuser%2Fconfig.json&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1351 }, 1352 { 1353 cfg: &Config{ 1354 User: "u", 1355 Password: "p", 1356 Account: "a.b.c", 1357 IncludeRetryReason: ConfigBoolTrue, 1358 ClientConfigFile: "c:\\Users\\user\\config.json", 1359 }, 1360 dsn: "u:p@a.b.c.snowflakecomputing.com:443?clientConfigFile=c%3A%5CUsers%5Cuser%5Cconfig.json&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1361 }, 1362 { 1363 cfg: &Config{ 1364 User: "u", 1365 Password: "p", 1366 Account: "a.b.c", 1367 Authenticator: AuthTypeExternalBrowser, 1368 DisableConsoleLogin: ConfigBoolTrue, 1369 }, 1370 dsn: "u:p@a.b.c.snowflakecomputing.com:443?authenticator=externalbrowser&disableConsoleLogin=true&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1371 }, 1372 { 1373 cfg: &Config{ 1374 User: "u", 1375 Password: "p", 1376 Account: "a.b.c", 1377 Authenticator: AuthTypeExternalBrowser, 1378 DisableConsoleLogin: ConfigBoolFalse, 1379 }, 1380 dsn: "u:p@a.b.c.snowflakecomputing.com:443?authenticator=externalbrowser&disableConsoleLogin=false&ocspFailOpen=true®ion=b.c&validateDefaultParameters=true", 1381 }, 1382 } 1383 for _, test := range testcases { 1384 t.Run(test.dsn, func(t *testing.T) { 1385 dsn, err := DSN(test.cfg) 1386 if test.err == nil && err == nil { 1387 if dsn != test.dsn { 1388 t.Errorf("failed to get DSN. expected: %v, got:\n %v", test.dsn, dsn) 1389 } 1390 _, err := ParseDSN(dsn) 1391 if err != nil { 1392 t.Errorf("failed to parse DSN. dsn: %v, err: %v", dsn, err) 1393 } 1394 } 1395 if test.err != nil && err == nil { 1396 t.Errorf("expected error. dsn: %v, err: %v", test.dsn, test.err) 1397 } 1398 if err != nil && test.err == nil { 1399 t.Errorf("failed to match. err: %v", err) 1400 } 1401 }) 1402 } 1403 } 1404 1405 func TestParsePrivateKeyFromFileMissingFile(t *testing.T) { 1406 _, err := parsePrivateKeyFromFile("nonexistent") 1407 1408 if err == nil { 1409 t.Error("should report error for nonexistent file") 1410 } 1411 } 1412 1413 func TestParsePrivateKeyFromFileIncorrectData(t *testing.T) { 1414 pemFile := createTmpFile("exampleKey.pem", []byte("gibberish")) 1415 _, err := parsePrivateKeyFromFile(pemFile) 1416 1417 if err == nil { 1418 t.Error("should report error for wrong data in file") 1419 } 1420 } 1421 1422 func TestParsePrivateKeyFromFileNotRSAPrivateKey(t *testing.T) { 1423 // Generate an ECDSA private key for testing 1424 ecdsaPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 1425 if err != nil { 1426 t.Fatalf("failed to generate ECDSA private key: %v", err) 1427 } 1428 1429 ecdsaPrivateKeyBytes, err := x509.MarshalECPrivateKey(ecdsaPrivateKey) 1430 if err != nil { 1431 t.Fatalf("failed to marshal ECDSA private key: %v", err) 1432 } 1433 pemBlock := &pem.Block{ 1434 Type: "EC PRIVATE KEY", 1435 Bytes: ecdsaPrivateKeyBytes, 1436 } 1437 pemData := pem.EncodeToMemory(pemBlock) 1438 1439 // Write the PEM data to a temporary file 1440 pemFile := createTmpFile("ecdsaKey.pem", pemData) 1441 1442 // Attempt to parse the private key 1443 _, err = parsePrivateKeyFromFile(pemFile) 1444 if err == nil { 1445 t.Error("expected an error when trying to parse an ECDSA private key as RSA") 1446 } 1447 } 1448 1449 func TestParsePrivateKeyFromFile(t *testing.T) { 1450 generatedKey, _ := rsa.GenerateKey(cr.Reader, 1024) 1451 pemKey, _ := x509.MarshalPKCS8PrivateKey(generatedKey) 1452 pemData := pem.EncodeToMemory( 1453 &pem.Block{ 1454 Type: "RSA PRIVATE KEY", 1455 Bytes: pemKey, 1456 }, 1457 ) 1458 keyFile := createTmpFile("exampleKey.pem", pemData) 1459 defer os.Remove(keyFile) 1460 1461 parsedKey, err := parsePrivateKeyFromFile(keyFile) 1462 if err != nil { 1463 t.Errorf("unable to parse pam file from path: %v, err: %v", keyFile, err) 1464 } else if !parsedKey.Equal(generatedKey) { 1465 t.Errorf("generated key does not equal to parsed key from file\ngeneratedKey=%v\nparsedKey=%v", 1466 generatedKey, parsedKey) 1467 } 1468 } 1469 1470 func createTmpFile(fileName string, content []byte) string { 1471 tempFile, _ := os.CreateTemp("", fileName) 1472 tempFile.Write(content) 1473 absolutePath := tempFile.Name() 1474 return absolutePath 1475 } 1476 1477 type configParamToValue struct { 1478 configParam string 1479 value string 1480 } 1481 1482 func TestGetConfigFromEnv(t *testing.T) { 1483 envMap := map[string]configParamToValue{ 1484 "SF_TEST_ACCOUNT": {"Account", "account"}, 1485 "SF_TEST_USER": {"User", "user"}, 1486 "SF_TEST_PASSWORD": {"Password", "password"}, 1487 "SF_TEST_ROLE": {"Role", "role"}, 1488 "SF_TEST_HOST": {"Host", "host"}, 1489 "SF_TEST_PORT": {"Port", "8080"}, 1490 "SF_TEST_PROTOCOL": {"Protocol", "http"}, 1491 "SF_TEST_WAREHOUSE": {"Warehouse", "warehouse"}, 1492 "SF_TEST_DATABASE": {"Database", "database"}, 1493 "SF_TEST_REGION": {"Region", "region"}, 1494 "SF_TEST_PASSCODE": {"Passcode", "passcode"}, 1495 "SF_TEST_SCHEMA": {"Schema", "schema"}, 1496 "SF_TEST_APPLICATION": {"Application", "application"}, 1497 } 1498 var properties = make([]*ConfigParam, len(envMap)) 1499 i := 0 1500 for key, ctv := range envMap { 1501 os.Setenv(key, ctv.value) 1502 cfgParam := ConfigParam{ctv.configParam, key, true} 1503 properties[i] = &cfgParam 1504 i++ 1505 } 1506 defer func() { 1507 for key := range envMap { 1508 os.Unsetenv(key) 1509 } 1510 }() 1511 1512 cfg, err := GetConfigFromEnv(properties) 1513 if err != nil { 1514 t.Errorf("unable to parse env variables to Config, err: %v", err) 1515 } 1516 1517 err = checkConfig(*cfg, envMap) 1518 if err != nil { 1519 t.Error(err) 1520 } 1521 } 1522 1523 func checkConfig(cfg Config, envMap map[string]configParamToValue) error { 1524 appendError := func(errArray []string, envName string, expected string, received string) []string { 1525 errArray = append(errArray, fmt.Sprintf("field %v expected value: %v, received value: %v", envName, expected, received)) 1526 return errArray 1527 } 1528 1529 value := reflect.ValueOf(cfg) 1530 typeOfCfg := value.Type() 1531 cfgValues := make(map[string]interface{}, value.NumField()) 1532 for i := 0; i < value.NumField(); i++ { 1533 cfgValues[typeOfCfg.Field(i).Name] = value.Field(i).Interface() 1534 } 1535 1536 var errArray []string 1537 for key, ctv := range envMap { 1538 if ctv.configParam == "Port" { 1539 if portStr := strconv.Itoa(cfgValues[ctv.configParam].(int)); portStr != ctv.value { 1540 errArray = appendError(errArray, key, ctv.value, cfgValues[ctv.configParam].(string)) 1541 } 1542 } else if cfgValues[ctv.configParam] != ctv.value { 1543 errArray = appendError(errArray, key, ctv.value, cfgValues[ctv.configParam].(string)) 1544 } 1545 } 1546 1547 if errArray != nil { 1548 return fmt.Errorf(strings.Join(errArray, "\n")) 1549 } 1550 1551 return nil 1552 } 1553 1554 func TestConfigValidateTmpDirPath(t *testing.T) { 1555 cfg := &Config{ 1556 TmpDirPath: "/not/existing", 1557 } 1558 if err := cfg.Validate(); err == nil { 1559 t.Fatalf("Should fail on not existing TmpDirPath") 1560 } 1561 }