diff --git a/pom.xml b/pom.xml
index 2efa036a0..1d8535af6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -496,17 +496,6 @@
**/*IT
-
- -Duser.timezone=UTC
@@ -519,7 +508,6 @@
**/*Test*
- -Duser.timezone=UTC
@@ -594,4 +582,4 @@
-
\ No newline at end of file
+
diff --git a/src/it/java/dbProcs/GetterAuthIT.java b/src/it/java/dbProcs/GetterAuthIT.java
index 470defdb0..2dde01b4c 100644
--- a/src/it/java/dbProcs/GetterAuthIT.java
+++ b/src/it/java/dbProcs/GetterAuthIT.java
@@ -7,6 +7,7 @@
import java.io.IOException;
import java.sql.SQLException;
+import java.util.TimeZone;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.AfterAll;
@@ -75,6 +76,30 @@ public void suspendedUserIsRejected() throws SQLException {
"User should be able to authenticate after unsuspension");
}
+ @Test
+ public void suspendedUserIsRejectedWhenJvmTimezoneIsNonUtc() throws SQLException {
+ requireDatabase();
+ TimeZone originalTimeZone = TimeZone.getDefault();
+ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Kolkata"));
+ try {
+ String userName = "authSuspendedNonUtcUser";
+
+ Setter.userCreate(
+ applicationRoot, null, userName, userName, "player", userName + "@test.com", false);
+ String[] user = Getter.authUser(applicationRoot, userName, userName);
+ assertNotNull(user, "User should be able to authenticate before suspension");
+
+ String userId = user[0];
+
+ assertTrue(Setter.suspendUser(applicationRoot, userId, 10), "Could not suspend user");
+ assertNull(
+ Getter.authUser(applicationRoot, userName, userName),
+ "Suspended user should not be able to authenticate under a non-UTC JVM timezone");
+ } finally {
+ TimeZone.setDefault(originalTimeZone);
+ }
+ }
+
@Test
public void ssoUserIsRejectedFromPasswordLogin() {
requireDatabase();
diff --git a/src/it/java/dbProcs/GetterIT.java b/src/it/java/dbProcs/GetterIT.java
index 3aac6a7e9..74e3b87c5 100644
--- a/src/it/java/dbProcs/GetterIT.java
+++ b/src/it/java/dbProcs/GetterIT.java
@@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -14,6 +15,7 @@
import java.util.ArrayList;
import java.util.Locale;
import java.util.ResourceBundle;
+import java.util.TimeZone;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
@@ -3194,6 +3196,29 @@ public void testSSOAuthSuspended() {
}
}
+ @Test
+ public void testSSOAuthSuspendedWithNonUtcJvmTimeZone() {
+ TimeZone originalTimeZone = TimeZone.getDefault();
+ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Kolkata"));
+ try {
+ String userName = "SSOSuspendedNonUtcUser Lastname";
+ String ssoName = "ssosuspendednonutcuser@example.com";
+
+ String[] user = Getter.authUserSSO(applicationRoot, null, userName, ssoName, "player");
+ assertNotNull(user, "Initial SSO auth should succeed");
+ assertFalse(user[0].isEmpty(), "Initial SSO auth should return a userId");
+
+ String userID = user[0];
+
+ assertTrue(Setter.suspendUser(applicationRoot, userID, 10), "Could not suspend user");
+ assertNull(
+ Getter.authUserSSO(applicationRoot, null, userName, ssoName, "player"),
+ "Suspended SSO user should not authenticate under a non-UTC JVM timezone");
+ } finally {
+ TimeZone.setDefault(originalTimeZone);
+ }
+ }
+
/**
* Exercises the existing-user SSO re-login path: the first call creates the user, the second call
* finds the existing (non-suspended) user. This drives Phase 1 (found) -> skip create -> Phase 3
diff --git a/src/main/java/dbProcs/Getter.java b/src/main/java/dbProcs/Getter.java
index 33f88ef18..2650b1a5f 100644
--- a/src/main/java/dbProcs/Getter.java
+++ b/src/main/java/dbProcs/Getter.java
@@ -21,6 +21,7 @@
import org.json.JSONObject;
import org.owasp.encoder.Encode;
import servlets.Register;
+import utils.DbTime;
import utils.ModulePlan;
import utils.ScoreboardStatus;
@@ -112,7 +113,7 @@ public static String[] authUser(String ApplicationRoot, String userName, String
badLoginCount = userResult.getInt(5);
tempPassword = userResult.getBoolean(6);
classId = userResult.getString(7);
- suspendedUntil = userResult.getTimestamp(8);
+ suspendedUntil = userResult.getTimestamp(8, DbTime.utcCalendar());
loginType = userResult.getString(9);
tempUsername = userResult.getBoolean(10);
} else {
@@ -237,7 +238,7 @@ public static String[] authUserSSO(
// User found if a row is in the database
userFound = true;
log.debug("User Found");
- suspendedUntil = userResult.getTimestamp(1);
+ suspendedUntil = userResult.getTimestamp(1, DbTime.utcCalendar());
} else {
userFound = false;
}
diff --git a/src/main/java/utils/DbTime.java b/src/main/java/utils/DbTime.java
new file mode 100644
index 000000000..588449695
--- /dev/null
+++ b/src/main/java/utils/DbTime.java
@@ -0,0 +1,15 @@
+package utils;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+public final class DbTime {
+
+ private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
+
+ private DbTime() {}
+
+ public static Calendar utcCalendar() {
+ return Calendar.getInstance(UTC);
+ }
+}
diff --git a/src/test/java/utils/DbTimeTest.java b/src/test/java/utils/DbTimeTest.java
new file mode 100644
index 000000000..e81d815da
--- /dev/null
+++ b/src/test/java/utils/DbTimeTest.java
@@ -0,0 +1,23 @@
+package utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+
+import java.util.Calendar;
+import org.junit.jupiter.api.Test;
+
+class DbTimeTest {
+
+ @Test
+ void utcCalendarUsesUtc() {
+ assertEquals("UTC", DbTime.utcCalendar().getTimeZone().getID());
+ }
+
+ @Test
+ void utcCalendarReturnsIndependentInstances() {
+ Calendar first = DbTime.utcCalendar();
+ Calendar second = DbTime.utcCalendar();
+
+ assertNotSame(first, second);
+ }
+}