diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92fb2c6..9d47798 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,7 +76,7 @@ were args are one of the following: | Query Argument | Description | Values | |----------------|-------------|--------| | use_prepared_statements | whether to use client-side query interpolation or server-side argument binding |
  • true = (default) use server-side bindings
  • false = user client side interpolation
  • | -| tlsmode | the ssl policy for this connection |
  • none (default) = don't use SSL for this connection
  • server = server must support SSL, but skip verification (INSECURE!)
  • server-strict = server must support SSL
  • custom = use custom TLS config (Need to generate certs with `resources/tests/genCerts.sh` in advance)
  • | +| tlsmode | the ssl policy for this connection |
  • none = don't use SSL for this connection
  • prefer (default) = checks for SSL/TLS server support; if unsupported, SSL/TLS is not used for this connection.
  • server = server must support SSL, but skip verification (INSECURE!)
  • server-strict = server must support SSL
  • custom = use custom TLS config (Need to generate certs with `resources/tests/genCerts.sh` in advance)
  • | | locator | host and port of the Vertica connection | (default) localhost:5433 | | user | Vertica user name | (default) dbadmin | | password | Vertica password for the connecting user | (default) (empty) | diff --git a/README.md b/README.md index eb338ea..530c501 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Currently supported query arguments are: |----------------|-------------|--------| | use_prepared_statements | Whether to use client-side query interpolation or server-side argument binding. | 1 = (default) use server-side bindings
    0 = user client side interpolation **(LESS SECURE)** | | connection_load_balance | Whether to enable connection load balancing on the client side. | 0 = (default) disable load balancing
    1 = enable load balancing | -| tlsmode | The ssl/tls policy for this connection. |
  • 'none' (default) = don't use SSL/TLS for this connection
  • 'server' = server must support SSL/TLS, but skip verification **(INSECURE!)**
  • 'server-strict' = server must support SSL/TLS
  • {customName} = use custom registered `tls.Config` (see "Using custom TLS config" section below)
  • | +| tlsmode | The ssl/tls policy for this connection. |
  • 'none' = don't use SSL/TLS for this connection
  • 'prefer' (default) = checks for SSL/TLS server support; if unsupported, SSL/TLS is not used for this connection.
  • 'server' = server must support SSL/TLS, but skip verification **(INSECURE!)**
  • 'server-strict' = server must support SSL/TLS
  • {customName} = use custom registered `tls.Config` (see "Using custom TLS config" section below)
  • | | backup_server_node | A list of backup hosts for the client to try to connect if the primary host is unreachable. | a comma-seperated list of backup host-port pairs. E.g.
    'host1:port1,host2:port2,host3:port3' | | client_label | Sets a label for the connection on the server. This value appears in the `client_label` column of the SESSIONS system table. | (default) vertica-sql-go-{version}-{pid}-{timestamp} | | autocommit | Controls whether the connection automatically commits transactions. | 1 = (default) on
    0 = off| diff --git a/connection.go b/connection.go index 60b711f..ea1823f 100644 --- a/connection.go +++ b/connection.go @@ -58,6 +58,7 @@ var ( ) const ( + tlsModePrefer = "prefer" tlsModeServer = "server" tlsModeServerStrict = "server-strict" tlsModeNone = "none" @@ -85,9 +86,9 @@ func (t *_tlsConfigs) get(name string) (*tls.Config, bool) { var tlsConfigs = &_tlsConfigs{m: make(map[string]*tls.Config)} // db, err := sql.Open("vertica", "user@tcp(localhost:3306)/test?tlsmode=custom") -// reserved modes: 'server', 'server-strict' or 'none' +// reserved modes: 'prefer', 'server', 'server-strict' or 'none' func RegisterTLSConfig(name string, config *tls.Config) error { - if name == tlsModeServer || name == tlsModeServerStrict || name == tlsModeNone { + if name == tlsModePrefer || name == tlsModeServer || name == tlsModeServerStrict || name == tlsModeNone { return fmt.Errorf("config name '%s' is reserved therefore cannot be used", name) } return tlsConfigs.add(name, config) @@ -665,6 +666,10 @@ func (v *connection) initializeSSL(sslFlag string) error { } if buf[0] == 'N' { + if sslFlag == tlsModePrefer { + connectionLogger.Info("SSL/TLS is not supported, proceeding with non-SSL connection in prefer mode") + return nil + } return fmt.Errorf("SSL/TLS is not enabled on this server") } @@ -673,6 +678,9 @@ func (v *connection) initializeSSL(sslFlag string) error { } switch sslFlag { + case tlsModePrefer: + connectionLogger.Info("enabling SSL/TLS prefer mode") + v.conn = tls.Client(v.conn, &tls.Config{InsecureSkipVerify: true}) case tlsModeServer: connectionLogger.Info("enabling SSL/TLS server mode") v.conn = tls.Client(v.conn, &tls.Config{InsecureSkipVerify: true}) diff --git a/driver_test.go b/driver_test.go index 4c77981..6cb544b 100644 --- a/driver_test.go +++ b/driver_test.go @@ -201,6 +201,10 @@ func TestTLSConfiguration(t *testing.T) { switch *tlsMode { case "none": assertEqual(t, sslState, "None") + case "prefer": + if sslState != "None" && sslState != "Server" { + t.Fatalf("Expected ssl_state to be 'None' or 'Server', but got '%s'", sslState) + } case "server", "server-strict": assertEqual(t, sslState, "Server") case "custom": @@ -1227,7 +1231,7 @@ func TestClientOSHostnameProperty(t *testing.T) { var verticaUserName = flag.String("user", "dbadmin", "the user name to connect to Vertica") var verticaPassword = flag.String("password", os.Getenv("VERTICA_TEST_PASSWORD"), "Vertica password for this user") var verticaHostPort = flag.String("locator", "localhost:5433", "Vertica's host and port") -var tlsMode = flag.String("tlsmode", "none", "SSL/TLS mode (none, server, server-strict, custom)") +var tlsMode = flag.String("tlsmode", "none", "SSL/TLS mode (none, prefer, server, server-strict, custom)") var usePreparedStmts = flag.Bool("use_prepared_statements", true, "whether to use prepared statements for all queries/executes") var oauthAccessToken = flag.String("oauth_access_token", os.Getenv("VERTICA_TEST_OAUTH_ACCESS_TOKEN"), "the OAuth Access Token to connect to Vertica")