You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2020/10/26 19:59:21 UTC

[guacamole-client] branch master updated (0091bb1 -> 4374362)

This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git.


    from 0091bb1  GUACAMOLE-1149: Merge correct regression in TOTP support if user accounts are not automatically created.
     new 0ec9bec  GUACAMOLE-760: Add support for configuring server timezone.
     new 3630e78  GUACAMOLE-760: Add validation and tests for the TimeZoneGuacamoleProperty
     new 6d7456e  GUACAMOLE-760: Add JUnit tests for TimeZone getAvailableIDs.
     new 23eaaa9  GUACAMOLE-760: Merge support for configuring MySQL / MariaDB server timezone.
     new 4374362  Merge 1.3.0 changes back to master.

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../mysql/MySQLAuthenticationProviderModule.java   |   6 +
 .../auth/mysql/conf/MySQLEnvironment.java          |  15 ++
 .../auth/mysql/conf/MySQLGuacamoleProperties.java  |  11 +
 ...roperty.java => TimeZoneGuacamoleProperty.java} |  46 ++--
 .../properties/TimeZoneGuacamolePropertyTest.java  | 258 +++++++++++++++++++++
 5 files changed, 320 insertions(+), 16 deletions(-)
 copy guacamole-ext/src/main/java/org/apache/guacamole/properties/{IntegerGuacamoleProperty.java => TimeZoneGuacamoleProperty.java} (50%)
 create mode 100644 guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java


[guacamole-client] 03/05: GUACAMOLE-760: Add JUnit tests for TimeZone getAvailableIDs.

Posted by mj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git

commit 6d7456ec3130ecfa4d563a09c3353aab025523d8
Author: Virtually Nick <vn...@apache.org>
AuthorDate: Mon Oct 26 11:09:49 2020 -0400

    GUACAMOLE-760: Add JUnit tests for TimeZone getAvailableIDs.
---
 .../properties/TimeZoneGuacamolePropertyTest.java  | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java b/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java
index 48535a1..4c4ced1 100644
--- a/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java
+++ b/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.properties;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.TimeZone;
 import org.apache.guacamole.GuacamoleException;
 import static org.junit.Assert.*;
 import org.junit.Test;
@@ -104,6 +105,12 @@ public class TimeZoneGuacamolePropertyTest {
     );
     
     /**
+     * The list of all available timezones that are known to the TimeZone class.
+     */
+    private static final List<String> TZ_AVAIL_IDS =
+            Arrays.asList(TimeZone.getAvailableIDs());
+    
+    /**
      * An example TimeZoneGuacamoleProperty for testing how various possible
      * TimeZone values will be parsed.
      */
@@ -218,6 +225,23 @@ public class TimeZoneGuacamolePropertyTest {
     }
     
     /**
+     * Tests the list of available identifiers provided by the TimeZone class
+     * to make sure that all identifiers provided pass through successfully and
+     * do not yield unexpected results.
+     * 
+     * @throws GuacamoleException 
+     *     If the test fails unexpectedly because the timezone is not recognized
+     *     and is converted to GMT.
+     */
+    public void availTzCheck() throws GuacamoleException {
+        for (String tzStr : TZ_AVAIL_IDS) {
+            String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+            assertNotNull(tzId);
+            assertTrue(tzId.equals(tzStr));
+        }
+    }
+    
+    /**
      * Tests parse of null input values to make sure the resuling parsed value
      * is also null.
      * 


[guacamole-client] 01/05: GUACAMOLE-760: Add support for configuring server timezone.

Posted by mj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git

commit 0ec9bec4c898e51ba3f170e311f37775a608d5c5
Author: Virtually Nick <vn...@apache.org>
AuthorDate: Thu Dec 26 22:35:34 2019 -0500

    GUACAMOLE-760: Add support for configuring server timezone.
---
 .../mysql/MySQLAuthenticationProviderModule.java   |  6 +++
 .../auth/mysql/conf/MySQLEnvironment.java          | 15 ++++++++
 .../auth/mysql/conf/MySQLGuacamoleProperties.java  | 11 ++++++
 .../properties/TimeZoneGuacamoleProperty.java      | 43 ++++++++++++++++++++++
 4 files changed, 75 insertions(+)

diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java
index 92bc541..d1fc93d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java
@@ -24,6 +24,7 @@ import com.google.inject.Module;
 import com.google.inject.name.Names;
 import java.io.File;
 import java.util.Properties;
+import java.util.TimeZone;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.mysql.conf.MySQLDriver;
 import org.apache.guacamole.auth.mysql.conf.MySQLEnvironment;
@@ -115,6 +116,11 @@ public class MySQLAuthenticationProviderModule implements Module {
         // Get the MySQL-compatible driver to use.
         mysqlDriver = environment.getMySQLDriver();
 
+        // If timezone is present, set it.
+        TimeZone serverTz = environment.getServerTimeZone();
+        if (serverTz != null)
+            driverProperties.setProperty("serverTimezone", serverTz.getID());
+
     }
 
     @Override
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java
index f452319..31f04e5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java
@@ -23,6 +23,7 @@ import java.io.File;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import java.util.TimeZone;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
 import org.slf4j.Logger;
@@ -393,4 +394,18 @@ public class MySQLEnvironment extends JDBCEnvironment {
                 false);
     }
 
+    /**
+     * Return the server timezone if configured in guacamole.properties, or
+     * null if the configuration option is not present.
+     * 
+     * @return
+     *     The server timezone as configured in guacamole.properties.
+     * 
+     * @throws GuacamoleException 
+     *     If an error occurs retrieving the configuration value.
+     */
+    public TimeZone getServerTimeZone() throws GuacamoleException {
+        return getProperty(MySQLGuacamoleProperties.SERVER_TIMEZONE);
+    }
+
 }
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java
index 8318b89..925f82a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java
@@ -24,6 +24,7 @@ import org.apache.guacamole.properties.EnumGuacamoleProperty;
 import org.apache.guacamole.properties.FileGuacamoleProperty;
 import org.apache.guacamole.properties.IntegerGuacamoleProperty;
 import org.apache.guacamole.properties.StringGuacamoleProperty;
+import org.apache.guacamole.properties.TimeZoneGuacamoleProperty;
 
 /**
  * Properties used by the MySQL Authentication plugin.
@@ -251,6 +252,16 @@ public class MySQLGuacamoleProperties {
     
         @Override
         public String getName() { return "mysql-auto-create-accounts"; }
+    };
+
+    /**
+     * The time zone of the MySQL database server.
+     */
+    public static final TimeZoneGuacamoleProperty SERVER_TIMEZONE =
+            new TimeZoneGuacamoleProperty() {
+                
+        @Override
+        public String getName() { return "mysql-server-timezone"; }
                 
     };
 
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java
new file mode 100644
index 0000000..7877021
--- /dev/null
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.properties;
+
+import java.util.TimeZone;
+import org.apache.guacamole.GuacamoleException;
+
+/**
+ * A GuacamoleProperty whose value is a TimeZone.
+ */
+public abstract class TimeZoneGuacamoleProperty
+        implements GuacamoleProperty<TimeZone> {
+    
+    @Override
+    public TimeZone parseValue(String value) throws GuacamoleException {
+        
+        // Nothing in, nothing out
+        if (value == null || value.isEmpty())
+            return null;
+        
+        // Attempt to return the TimeZone of the provided string value.
+        return TimeZone.getTimeZone(value);
+        
+    }
+    
+}


[guacamole-client] 04/05: GUACAMOLE-760: Merge support for configuring MySQL / MariaDB server timezone.

Posted by mj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git

commit 23eaaa9132b693f3b25c3c11e873b75df2797d57
Merge: 0091bb1 6d7456e
Author: Mike Jumper <mj...@apache.org>
AuthorDate: Mon Oct 26 12:54:23 2020 -0700

    GUACAMOLE-760: Merge support for configuring MySQL / MariaDB server timezone.

 .../mysql/MySQLAuthenticationProviderModule.java   |   6 +
 .../auth/mysql/conf/MySQLEnvironment.java          |  15 ++
 .../auth/mysql/conf/MySQLGuacamoleProperties.java  |  11 +
 .../properties/TimeZoneGuacamoleProperty.java      |  60 +++++
 .../properties/TimeZoneGuacamolePropertyTest.java  | 258 +++++++++++++++++++++
 5 files changed, 350 insertions(+)


[guacamole-client] 05/05: Merge 1.3.0 changes back to master.

Posted by mj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git

commit 4374362163e8b5abeba377e30a31a370f8546da9
Merge: 0091bb1 23eaaa9
Author: Michael Jumper <mj...@apache.org>
AuthorDate: Mon Oct 26 12:59:01 2020 -0700

    Merge 1.3.0 changes back to master.

 .../mysql/MySQLAuthenticationProviderModule.java   |   6 +
 .../auth/mysql/conf/MySQLEnvironment.java          |  15 ++
 .../auth/mysql/conf/MySQLGuacamoleProperties.java  |  11 +
 .../properties/TimeZoneGuacamoleProperty.java      |  60 +++++
 .../properties/TimeZoneGuacamolePropertyTest.java  | 258 +++++++++++++++++++++
 5 files changed, 350 insertions(+)


[guacamole-client] 02/05: GUACAMOLE-760: Add validation and tests for the TimeZoneGuacamoleProperty

Posted by mj...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mjumper pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/guacamole-client.git

commit 3630e7800c57c08c5d7e6445ce2777468d7b66ac
Author: Virtually Nick <vn...@apache.org>
AuthorDate: Sat Oct 24 14:53:17 2020 -0400

    GUACAMOLE-760: Add validation and tests for the TimeZoneGuacamoleProperty
---
 .../properties/TimeZoneGuacamoleProperty.java      |  19 +-
 .../properties/TimeZoneGuacamolePropertyTest.java  | 234 +++++++++++++++++++++
 2 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java
index 7877021..a294bda 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java
@@ -20,7 +20,9 @@
 package org.apache.guacamole.properties;
 
 import java.util.TimeZone;
+import java.util.regex.Pattern;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
 
 /**
  * A GuacamoleProperty whose value is a TimeZone.
@@ -28,6 +30,12 @@ import org.apache.guacamole.GuacamoleException;
 public abstract class TimeZoneGuacamoleProperty
         implements GuacamoleProperty<TimeZone> {
     
+    /**
+     * A regex that matches valid variants of GMT timezones.
+     */
+    public static final Pattern GMT_REGEX =
+            Pattern.compile("^GMT([+-](0|00)((:)?00)?)?$");
+    
     @Override
     public TimeZone parseValue(String value) throws GuacamoleException {
         
@@ -36,7 +44,16 @@ public abstract class TimeZoneGuacamoleProperty
             return null;
         
         // Attempt to return the TimeZone of the provided string value.
-        return TimeZone.getTimeZone(value);
+        TimeZone tz = TimeZone.getTimeZone(value);
+        
+        // If the input is not GMT, but the output is GMT, the TimeZone is not
+        // valid and we throw an exception.
+        if (!GMT_REGEX.matcher(value).matches()
+                && GMT_REGEX.matcher(tz.getID()).matches())
+            throw new GuacamoleServerException("Property \"" + getName()
+                + "\" does not specify a valid time zone.");
+
+        return tz;
         
     }
     
diff --git a/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java b/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java
new file mode 100644
index 0000000..48535a1
--- /dev/null
+++ b/guacamole-ext/src/test/java/org/apache/guacamole/properties/TimeZoneGuacamolePropertyTest.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.properties;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.guacamole.GuacamoleException;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ * Tests that validate Time Zone property input.
+ */
+public class TimeZoneGuacamolePropertyTest {
+    
+    /**
+     * An array of valid TimeZones that should be correct parsed by the TimeZone
+     * property, returning either the same or synonymous zone.
+     */
+    private static final List<String> TZ_TEST_VALID = Arrays.asList(
+            "America/Los_Angeles",
+            "America/New_York",
+            "Australia/Sydney",
+            "Africa/Johannesburg",
+            "Asia/Shanghai"
+    );
+    
+    /**
+     * An array of invalid timezone names that should be parsed to GMT, which
+     * should cause an exception to be thrown by the TimeZone property.
+     */
+    private static final List<String> TZ_TEST_INVALID = Arrays.asList(
+            "Chips/Guacamole",
+            "Chips/Queso",
+            "Chips/Salsa",
+            "Mashed/Avacado",
+            "Pico/De_Guayo"
+    );
+    
+    /**
+     * An array of valid GMT specifications that should be correctly parsed
+     * by the TimeZone property as GMT.
+     */
+    private static final List<String> TZ_GMT_VALID = Arrays.asList(
+            "GMT",
+            "GMT-0000",
+            "GMT+000",
+            "GMT+00:00",
+            "GMT-0:00",
+            "GMT+0"
+    );
+    
+    /**
+     * An array of invalid GMT specifications that should cause an exception to
+     * be thrown for the TimeZone property.
+     */
+    private static final List<String> TZ_GMT_INVALID = Arrays.asList(
+            "GMTx0000",
+            "GMT=00:00",
+            "GMT0:00",
+            "GMT+000000",
+            "GMT-000:000",
+            "GMT100"
+    );
+    
+    /**
+     * An array of custom GMT offsets that should evaluate correctly for
+     * the TimeZone property.
+     */
+    private static final List<String> TZ_CUSTOM_VALID = Arrays.asList(
+            "GMT-23:59",
+            "GMT+01:30",
+            "GMT-00:30",
+            "GMT-11:25"
+    );
+    
+    /**
+     * An array of invalid custom GMT offsets that should cause an exception
+     * to be thrown by the TimeZone property.
+     */
+    private static final List<String> TZ_CUSTOM_INVALID = Arrays.asList(
+            "GMT-9999",
+            "GMT+2500",
+            "GMT+29:30",
+            "GMT-1:99",
+            "GMT+10:65"
+    );
+    
+    /**
+     * An example TimeZoneGuacamoleProperty for testing how various possible
+     * TimeZone values will be parsed.
+     */
+    private static final TimeZoneGuacamoleProperty WHERE_IN_WORLD =
+            new TimeZoneGuacamoleProperty() {
+            
+        @Override
+        public String getName() {
+            return "carmen-sandiego";
+        }
+        
+    };
+    
+    /**
+     * Tests to verify that each of the items in this list returns a valid,
+     * non-GMT timezone.
+     * 
+     * @throws GuacamoleException 
+     *     If a test value fails to parse correctly as a non-GMT timezone.
+     */
+    @Test
+    public void testValidTZs() throws GuacamoleException {
+        for (String tzStr : TZ_TEST_VALID) {
+            String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+            assertFalse(TimeZoneGuacamoleProperty.GMT_REGEX.matcher(tzId).matches());
+        }
+    }
+    
+    /**
+     * Tests invalid time zones to make sure that they produce the desired
+     * result, which is an exception thrown failing to parse the value.
+     */
+    @Test
+    public void testInvalidTZs() {
+        TZ_TEST_INVALID.forEach((tzStr) -> {
+            try {
+                String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+                fail("Invalid TimeZoneGuacamoleProperty should fail to parse with an exception.");
+            }
+            catch (GuacamoleException e) {
+                String msg = e.getMessage();
+                assertTrue(msg.contains("does not specify a valid time zone"));
+            }
+        });
+    }
+    
+    /**
+     * Tests a list of strings that should be valid representations of the GMT
+     * time zone, throwing an exception if an invalid String is found.
+     * 
+     * @throws GuacamoleException 
+     *     If the test value incorrectly fails to parse as a valid GMT string.
+     */
+    @Test
+    public void testValidGMT() throws GuacamoleException {
+        for (String tzStr : TZ_GMT_VALID) {
+            String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+            assertNotNull(tzId);
+        }
+    }
+    
+    /**
+     * Tests various invalid GMT representations to insure that parsing of these
+     * values fails and the expected GuacamoleException is thrown.
+     */
+    @Test
+    public void testInvalidGMT() {
+        TZ_GMT_INVALID.forEach((tzStr) -> {
+            try {
+                String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+                fail("Invalid GMT value \"" + tzStr + "\" for TimeZoneGuacamoleProperty should fail to parse with an exception.");
+            }
+            catch (GuacamoleException e) {
+                String msg = e.getMessage();
+                assertTrue(msg.contains("does not specify a valid time zone"));
+            }
+        });
+    }
+    
+    /**
+     * Tests several custom offsets from GMT to make sure that they are returned
+     * as valid TimeZone objects.
+     * 
+     * @throws GuacamoleException 
+     *     If the test unexpectedly fails because a custom offset throws an
+     *     exception as an invalid TimeZone.
+     */
+    @Test
+    public void testValidCustomTz() throws GuacamoleException {
+        for (String tzStr : TZ_CUSTOM_VALID) {
+            String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+            assertNotNull(tzId);
+        }
+    }
+    
+    /**
+     * Tests several invalid custom timezone offsets to make sure that they are
+     * not accepted as valid timezones.
+     */
+    @Test
+    public void testInvalidCustomTz() {
+        TZ_CUSTOM_INVALID.forEach((tzStr) -> {
+            try {
+                String tzId = WHERE_IN_WORLD.parseValue(tzStr).getID();
+                fail("Invalid custom time zone value \"" + tzStr + "\" for TimeZoneGuacamoleProperty should fail to parse with an exception.");
+            }
+            catch (GuacamoleException e) {
+                String msg = e.getMessage();
+                assertTrue(msg.contains("does not specify a valid time zone"));
+            }
+        });
+    }
+    
+    /**
+     * Tests parse of null input values to make sure the resuling parsed value
+     * is also null.
+     * 
+     * @throws GuacamoleException
+     *     If the test unexpectedly fails parsing a null value instead
+     *     recognizing it as an invalid value.
+     */
+    @Test
+    public void nullTzCheck() throws GuacamoleException {
+        assertNull(WHERE_IN_WORLD.parseValue(null));
+    }
+    
+    
+}