GUACAMOLE-919: Merge implement PostgreSQL defaultStatementTimeout and socketTimeout

diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java
index 331707c..280cead 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java
@@ -70,6 +70,15 @@
         myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true");
         myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1");
 
+        // Only set if > 0. Underlying backend does not take 0 as not-set.
+        int defaultStatementTimeout = environment.getPostgreSQLDefaultStatementTimeout();
+        if (defaultStatementTimeout > 0) {
+            myBatisProperties.setProperty(
+                "mybatis.configuration.defaultStatementTimeout",
+                String.valueOf(defaultStatementTimeout)
+            );
+        }
+
         // Use UTF-8 in database
         driverProperties.setProperty("characterEncoding", "UTF-8");
         
@@ -110,6 +119,12 @@
             
         }
 
+        // Handle case where TCP connection to database is silently dropped
+        driverProperties.setProperty(
+            "socketTimeout",
+            String.valueOf(environment.getPostgreSQLSocketTimeout())
+        );
+
     }
 
     @Override
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java
index e81e694..012877c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java
@@ -49,6 +49,19 @@
     private static final int DEFAULT_PORT = 5432;
 
     /**
+     * The default number of seconds the driver will wait for a response from
+     * the database, before aborting the query.
+     * A value of 0 (the default) means the timeout is disabled.
+     */
+    private static final int DEFAULT_STATEMENT_TIMEOUT = 0;
+
+    /**
+     * The default number of seconds to wait for socket read operations.
+     * A value of 0 (the default) means the timeout is disabled.
+     */
+    private static final int DEFAULT_SOCKET_TIMEOUT = 0;
+
+    /**
      * Whether a database user account is required by default for authentication
      * to succeed.
      */
@@ -249,6 +262,41 @@
     public String getPostgreSQLPassword() throws GuacamoleException {
         return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD);
     }
+    
+    /**
+     * Returns the defaultStatementTimeout set for PostgreSQL connections.
+     * If unspecified, this will default to 0,
+     * and should not be passed through to the backend.
+     * 
+     * @return
+     *     The statement timeout (in seconds)
+     *
+     * @throws GuacamoleException 
+     *     If an error occurs while retrieving the property value.
+     */
+    public int getPostgreSQLDefaultStatementTimeout() throws GuacamoleException {
+        return getProperty(
+            PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_STATEMENT_TIMEOUT,
+            DEFAULT_STATEMENT_TIMEOUT
+        );
+    }
+    
+    /**
+     * Returns the socketTimeout property to set on PostgreSQL connections.
+     * If unspecified, this will default to 0 (no timeout)
+     * 
+     * @return
+     *     The socketTimeout to use when waiting on read operations (in seconds)
+     *
+     * @throws GuacamoleException 
+     *     If an error occurs while retrieving the property value.
+     */
+    public int getPostgreSQLSocketTimeout() throws GuacamoleException {
+        return getProperty(
+            PostgreSQLGuacamoleProperties.POSTGRESQL_SOCKET_TIMEOUT,
+            DEFAULT_SOCKET_TIMEOUT
+        );
+    }
 
     @Override
     public boolean isRecursiveQuerySupported(SqlSession session) {
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java
index d2ae253..271d9c0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java
@@ -95,6 +95,36 @@
     };
 
     /**
+     * The number of seconds the driver will wait for a response from
+     * the database, before aborting the query.
+     * A value of 0 (the default) means the timeout is disabled.
+     */
+    public static final IntegerGuacamoleProperty
+            POSTGRESQL_DEFAULT_STATEMENT_TIMEOUT = new IntegerGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "postgresql-default-statement-timeout"; }
+
+    };
+
+    /**
+     * The number of seconds to wait for socket read operations.
+     * If reading from the server takes longer than this value, the
+     * connection will be closed. This can be used to handle network problems
+     * such as a dropped connection to the database. Similar to 
+     * postgresql-default-statement-timeout, it will have the effect of
+     * aborting queries that take too long.
+     * A value of 0 (the default) means the timeout is disabled.
+     */
+    public static final IntegerGuacamoleProperty
+            POSTGRESQL_SOCKET_TIMEOUT = new IntegerGuacamoleProperty() {
+
+        @Override
+        public String getName() { return "postgresql-socket-timeout"; }
+
+    };
+
+    /**
      * Whether a user account within the database is required for authentication
      * to succeed, even if the user has been authenticated via another
      * authentication provider.
diff --git a/guacamole-docker/bin/start.sh b/guacamole-docker/bin/start.sh
index 0d3b461..95b8763 100755
--- a/guacamole-docker/bin/start.sh
+++ b/guacamole-docker/bin/start.sh
@@ -354,10 +354,18 @@
         "postgresql-default-max-group-connections-per-user" \
         "$POSTGRES_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER"
 
+    set_optional_property                      \
+        "postgresql-default-statement-timeout" \
+        "$POSTGRES_DEFAULT_STATEMENT_TIMEOUT"
+
     set_optional_property          \
         "postgresql-user-required" \
         "$POSTGRES_USER_REQUIRED"
 
+    set_optional_property           \
+        "postgresql-socket-timeout" \
+        "$POSTGRES_SOCKET_TIMEOUT"
+
     set_optional_property      \
         "postgresql-ssl-mode"  \
         "$POSTGRESQL_SSL_MODE"