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

fix: Apply patch from Issue #2683 to fix hanging ssl connections #2687

Merged
merged 3 commits into from
Nov 30, 2022
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ In addition to the standard connection parameters the driver supports a number o
| loginTimeout | Integer | 0 | Specify how long in seconds max(2147484) to wait for establishment of a database connection. |
| connectTimeout | Integer | 10 | The timeout value in seconds max(2147484) used for socket connect operations. |
| socketTimeout | Integer | 0 | The timeout value in seconds max(2147484) used for socket read operations. |
| sslResponseTimeout | Integer | 5000 | Socket timeout waiting for a response from a request for SSL upgrade from the server. |
| sslResponseTimeout | Integer | 5000 | Socket timeout in milliseconds waiting for a response from a request for SSL upgrade from the server. |
| tcpKeepAlive | Boolean | false | Enable or disable TCP keep-alive. |
| tcpNoDelay | Boolean | true | Enable or disable TCP no delay. |
| ApplicationName | String | PostgreSQL JDBC Driver | The application name (require server version >= 9.0). If assumeMinServerVersion is set to >= 9.0 this will be sent in the startup packets, otherwise after the connection is made |
| ApplicationName | String | PostgreSQL JDBC Driver | The application name (require server version >= 9.0). If assumeMinServerVersion is set to >= 9.0 this will be sent in the startup packets, otherwise after the connection is made |
| readOnly | Boolean | false | Puts this connection in read-only mode |
| disableColumnSanitiser | Boolean | false | Enable optimization that disables column name sanitiser |
| assumeMinServerVersion | String | null | Assume the server is at least that version |
Expand All @@ -137,6 +137,7 @@ In addition to the standard connection parameters the driver supports a number o
| reWriteBatchedInserts | Boolean | false | Enable optimization to rewrite and collapse compatible INSERT statements that are batched. |
| escapeSyntaxCallMode | String | select | Specifies how JDBC escape call syntax is transformed into underlying SQL (CALL/SELECT), for invoking procedures or functions (requires server version >= 11), possible values: select, callIfNoReturn, call |
| maxResultBuffer | String | null | Specifies size of result buffer in bytes, which can't be exceeded during reading result set. Can be specified as particular size (i.e. "100", "200M" "2G") or as percent of max heap memory (i.e. "10p", "20pct", "50percent") |
| gssResponseTimeout | Integer | 5000 | Socket timeout in milliseconds waiting for a response from a request for GSS encrypted connection from the server. |
| gssEncMode | String | allow | Controls the preference for using GSSAPI encryption for the connection, values are disable, allow, prefer, and require |
| adaptiveFetch | Boolean | false | Specifies if number of rows fetched in ResultSet by each fetch iteration should be dynamic. Number of rows will be calculated by dividing maxResultBuffer size into max row size observed so far. Requires declaring maxResultBuffer and defaultRowFetchSize for first iteration. |
| adaptiveFetchMinimum | Integer | 0 | Specifies minimum number of rows, which can be calculated by adaptiveFetch. Number of rows used by adaptiveFetch cannot go below this value. |
Expand All @@ -145,6 +146,7 @@ In addition to the standard connection parameters the driver supports a number o
| quoteReturningIdentifiers | Boolean | true | By default we double quote returning identifiers. Some ORM's already quote them. Switch allows them to turn this off |
| authenticationPluginClassName | String | null | Fully qualified class name of the class implementing the AuthenticationPlugin interface. If this is null, the password value in the connection properties will be used. |


## Contributing
For information on how to contribute to the project see the [Contributing Guidelines](CONTRIBUTING.md)

Expand Down
15 changes: 12 additions & 3 deletions docs/content/documentation/use.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ Class name of the SSL password provider. Defaults to `org.postgresql.ssl.jdbc4.L
* **`sslpassword (`*String*`)`**\
If provided will be used by ConsoleCallbackHandler

* **`sslResponseTimeout (`*Integer*`)`**\
Time in milliseconds to wait for a response after requesting an SSL encrypted connection from the server. If this is greater than the current connectTimeout then connectTimeout will be used.
Default is 5000ms


* **`protocolVersion (`*int*`)`**\
The driver supports the V3 frontend/backend protocols. The V3 protocol was introduced in 7.4 and the driver will by default try to connect using the V3 protocol.

Expand Down Expand Up @@ -203,7 +208,7 @@ The default is extended

* **`defaultRowFetchSize (`*int*`)`**\
Determine the number of rows fetched in `ResultSet` by one fetch with trip to the database. Limiting the number of rows are fetch with each trip to the database allow avoids unnecessary memory consumption and as a consequence `OutOfMemoryError` .
The default is zero, meaning that in `ResultSet` will be fetch all rows at once. Negative number is not available.
The default is zero, meaning that `ResultSet` will fetch all rows at once. Must be > 0.

* **`loginTimeout (`*int*`)`**\
Specify how long to wait for establishment of a database connection. The timeout is specified in seconds max(2147484).
Expand All @@ -224,7 +229,7 @@ Enable or disable TCP keep-alive probe. The default is `false` .
Enable or disable TCP nodelay. The default is `true` .

* **`unknownLength (`*int*`)`**\
Certain postgresql types such as `TEXT` do not have a well defined length. When returning meta-data about these types through functions like `ResultSetMetaData.getColumnDisplaySize` and `ResultSetMetaData.getPrecision` we must provide a value and various client tools have different ideas about what they would like to see. This parameter specifies the length to return for types of unknown length.
Certain postgresql types such as `TEXT` do not have a well-defined length. When returning meta-data about these types through functions like `ResultSetMetaData.getColumnDisplaySize` and `ResultSetMetaData.getPrecision` we must provide a value and various client tools have different ideas about what they would like to see. This parameter specifies the length to return for types of unknown length.

* **`stringtype (`*String*`)`**\
Specify the type to use when binding `PreparedStatement` parameters set via `setString()` . If `stringtype` is set to `VARCHAR` (the default), such parameters will be sent to the server as varchar parameters. If `stringtype` is set to `unspecified` , parameters will be sent to the server as untyped values, and the server will attempt to infer an appropriate type. This is useful if you have an existing application that uses `setString()` to set parameters that are actually some other type, such as integers, and you are unable to change the application to use an appropriate method such as `setInt()` .
Expand All @@ -245,14 +250,18 @@ Specifies whether to perform a JAAS login before authenticating with GSSAPI. If
PostgreSQL® 12 and later now allow GSSAPI encrypted connections. This parameter controls whether to enforce using GSSAPI encryption or not. The options are `disable` , `allow` , `prefer` and `require`
* `disable` is obvious and disables any attempt to connect using GSS encrypted mode
* `allow` will connect in plain text then if the server requests it will switch to encrypted mode
* `prefer` will attempt connect in encrypted mode and fall back to plain text if it fails to acquire an encrypted connection
* `prefer` will attempt to connect in encrypted mode and fall back to plain text if it fails to acquire an encrypted connection
* `require` attempts to connect in encrypted mode and will fail to connect if that is not possible.
The default is `allow` .

* **`gsslib (`*String*`)`**\
Force either SSPI (Windows transparent single-sign-on) or GSSAPI (Kerberos, via JSSE) to be used when the server requests Kerberos or SSPI authentication. Permissible values are auto (default, see below), sspi (force SSPI) or gssapi (force GSSAPI-JSSE).
If this parameter is auto, SSPI is attempted if the server requests SSPI authentication, the JDBC client is running on Windows, and the Waffle libraries required for SSPI are on the CLASSPATH. Otherwise Kerberos/GSSAPI via JSSE is used.

* **`gssResponseTimeout (`*Integer*`)`**\
Time in milliseconds to wait for a response after requesting a GSS encrypted connection from the server. If this is greater than the current connectTimeout then connectTimeout will be used.
Default is 5000ms

> **Note**
>
> This behaviour does not exactly match that of libpq, which uses Windows' SSPI libraries for Kerberos (GSSAPI) requests by default when on Windows.
Expand Down
11 changes: 11 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/PGProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,17 @@ public enum PGProperty {
false,
new String[] {"auto", "sspi", "gssapi"}),

/**
* <p>After requesting an upgrade to SSL from the server there are reports of the server not responding due to a failover
* without a timeout here, the client can wait forever. The pattern for requesting a GSS encrypted connection is the same so we provide the same
* timeout mechanism This timeout will be set before the request and reset after </p>
*/
GSS_RESPONSE_TIMEOUT(
"gssResponseTimeout",
"5000",
"Time in milliseconds we wait for a response from the server after requesting a GSS upgrade"),


/**
* Enable mode to filter out the names of database objects for which the current user has no privileges
* granted from appearing in the DatabaseMetaData returned by the driver.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,26 @@ private PGStream enableGSSEncrypted(PGStream pgStream, GSSEncMode gssEncMode, St
// attempt to acquire a GSS encrypted connection
LOGGER.log(Level.FINEST, " FE=> GSSENCRequest");

int gssTimeout = PGProperty.SSL_RESPONSE_TIMEOUT.getInt(info);
int currentTimeout = pgStream.getNetworkTimeout();

// if the current timeout is less than sslTimeout then
// use the smaller timeout. We could do something tricky
// here to not set it in that case but this is pretty readable
if (currentTimeout > 0 && currentTimeout < gssTimeout) {
gssTimeout = currentTimeout;
}

pgStream.setNetworkTimeout(gssTimeout);

// Send GSSEncryption request packet
pgStream.sendInteger4(8);
pgStream.sendInteger2(1234);
pgStream.sendInteger2(5680);
pgStream.flush();
// Now get the response from the backend, one of N, E, S.
int beresp = pgStream.receiveChar();
pgStream.setNetworkTimeout(currentTimeout);
switch (beresp) {
case 'E':
LOGGER.log(Level.FINEST, " <=BE GSSEncrypted Error");
Expand Down Expand Up @@ -533,7 +546,7 @@ private PGStream enableSSL(PGStream pgStream, SslMode sslMode, Properties info,
LOGGER.log(Level.FINEST, " FE=> SSLRequest");

int sslTimeout = PGProperty.SSL_RESPONSE_TIMEOUT.getInt(info);
int currentTimeout = pgStream.getSocket().getSoTimeout();
int currentTimeout = pgStream.getNetworkTimeout();

// if the current timeout is less than sslTimeout then
// use the smaller timeout. We could do something tricky
Expand All @@ -542,7 +555,7 @@ private PGStream enableSSL(PGStream pgStream, SslMode sslMode, Properties info,
sslTimeout = currentTimeout;
}

pgStream.getSocket().setSoTimeout(sslTimeout);
pgStream.setNetworkTimeout(sslTimeout);
// Send SSL request packet
pgStream.sendInteger4(8);
pgStream.sendInteger2(1234);
Expand All @@ -551,7 +564,7 @@ private PGStream enableSSL(PGStream pgStream, SslMode sslMode, Properties info,

// Now get the response from the backend, one of N, E, S.
int beresp = pgStream.receiveChar();
pgStream.getSocket().setSoTimeout(currentTimeout);
pgStream.setNetworkTimeout(currentTimeout);

switch (beresp) {
case 'E':
Expand Down
18 changes: 18 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,24 @@ public void setConnectTimeout(int connectTimeout) {
PGProperty.CONNECT_TIMEOUT.set(properties, connectTimeout);
}

/**
*
* @return GSS ResponseTimeout
* @see PGProperty#GSS_RESPONSE_TIMEOUT
*/
public int getGssResponseTimeout() {
return PGProperty.GSS_RESPONSE_TIMEOUT.getIntNoCheck(properties);
}

/**
*
* @param gssResponseTimeout gss response timeout
* @see PGProperty#GSS_RESPONSE_TIMEOUT
*/
public void setGssResponseTimeout(int gssResponseTimeout) {
PGProperty.GSS_RESPONSE_TIMEOUT.set(properties,gssResponseTimeout);
}

/**
*
* @return SSL ResponseTimeout
Expand Down