Skip to content

Commit 0ccd2ce

Browse files
authored
Merge pull request #94 from BenCodez/codex/simpleapi-postgres-tls-mode-20260926
Add verified PostgreSQL TLS mode
2 parents 2a899b8 + 8158465 commit 0ccd2ce

12 files changed

Lines changed: 259 additions & 5 deletions

File tree

‎SimpleAPI/pom.xml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<include>com/bencodez/simpleapi/sql/mysql/AbstractSqlTable*.class</include>
9090
<include>com/bencodez/simpleapi/sql/mysql/ConnectionManager*.class</include>
9191
<include>com/bencodez/simpleapi/sql/mysql/DbType.class</include>
92+
<include>com/bencodez/simpleapi/sql/mysql/PostgreSqlTlsMode.class</include>
9293
<include>com/bencodez/simpleapi/sql/mysql/MySQL*.class</include>
9394
<include>com/bencodez/simpleapi/sql/mysql/config/MysqlConfig.class</include>
9495
<include>com/bencodez/simpleapi/sql/mysql/config/MysqlConfigView.class</include>
@@ -117,6 +118,7 @@
117118
<include>com/bencodez/simpleapi/sql/mysql/AbstractSqlTable.java</include>
118119
<include>com/bencodez/simpleapi/sql/mysql/ConnectionManager.java</include>
119120
<include>com/bencodez/simpleapi/sql/mysql/DbType.java</include>
121+
<include>com/bencodez/simpleapi/sql/mysql/PostgreSqlTlsMode.java</include>
120122
<include>com/bencodez/simpleapi/sql/mysql/MySQL.java</include>
121123
<include>com/bencodez/simpleapi/sql/mysql/config/MysqlConfig.java</include>
122124
<include>com/bencodez/simpleapi/sql/mysql/config/MysqlConfigView.java</include>

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/core/sql/MysqlConfigView.java‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package com.bencodez.simpleapi.core.sql;
22

3-
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfig;
4-
53
import java.util.Objects;
4+
65
import com.bencodez.simpleapi.file.config.ConfigView;
76
import com.bencodez.simpleapi.sql.mysql.DbType;
7+
import com.bencodez.simpleapi.sql.mysql.PostgreSqlTlsMode;
8+
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfig;
89

910
/** Platform-neutral snapshot of the existing MySQL section keys and defaults. */
1011
public class MysqlConfigView extends MysqlConfig {
@@ -31,6 +32,7 @@ public MysqlConfigView(ConfigView section) {
3132
: section.getBoolean("UseMariaDB", false) ? DbType.MARIADB : DbType.MYSQL);
3233
setDriver(section.getString("Driver", ""));
3334
setUseSSL(section.getBoolean("UseSSL", false));
35+
setPostgreSqlTlsMode(PostgreSqlTlsMode.fromString(section.getString("PostgreSqlTlsMode", "LEGACY")));
3436
setPublicKeyRetrieval(section.getBoolean("PublicKeyRetrieval", false));
3537
setUseMariaDB(section.getBoolean("UseMariaDB", false));
3638
setLine(section.getString("Line", ""));

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/ConnectionManager.java‎

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.bencodez.simpleapi.sql.mysql;
22

3+
import java.net.URLDecoder;
4+
import java.nio.charset.StandardCharsets;
35
import java.sql.Connection;
46
import java.sql.SQLException;
7+
import java.util.Locale;
8+
import java.util.Objects;
59

610
import com.zaxxer.hikari.HikariConfig;
711
import com.zaxxer.hikari.HikariDataSource;
@@ -81,6 +85,13 @@ public class ConnectionManager {
8185
@Setter
8286
private boolean useSSL = false;
8387

88+
@Getter
89+
private PostgreSqlTlsMode postgreSqlTlsMode = PostgreSqlTlsMode.LEGACY;
90+
91+
public void setPostgreSqlTlsMode(PostgreSqlTlsMode mode) {
92+
postgreSqlTlsMode = Objects.requireNonNull(mode, "mode");
93+
}
94+
8495
/**
8596
* Legacy flag still supported; only used if dbType isn't explicitly set.
8697
*/
@@ -207,7 +218,7 @@ private String resolveMariaDbWithFallback() throws ClassNotFoundException {
207218
}
208219
}
209220

210-
private String buildJdbcUrl(String driverClassName) {
221+
String buildJdbcUrl(String driverClassName) {
211222
String extra = (str == null ? "" : str);
212223

213224
// Postgres
@@ -216,10 +227,17 @@ private String buildJdbcUrl(String driverClassName) {
216227

217228
// Defaults:
218229
// - reWriteBatchedInserts improves batch perf
219-
// - sslmode if useSSL
230+
// - absent explicit mode preserves the legacy UseSSL behavior
220231
String defaults = "reWriteBatchedInserts=true";
221-
if (useSSL) {
232+
if (postgreSqlTlsMode == PostgreSqlTlsMode.LEGACY && useSSL) {
222233
defaults += "&sslmode=require";
234+
} else if (postgreSqlTlsMode != PostgreSqlTlsMode.LEGACY) {
235+
rejectConflictingPostgreSqlTlsOptions(extra);
236+
defaults += "&sslmode=" + postgreSqlTlsMode.getJdbcValue();
237+
if (postgreSqlTlsMode == PostgreSqlTlsMode.REQUIRE
238+
|| postgreSqlTlsMode == PostgreSqlTlsMode.VERIFY_FULL) {
239+
defaults += "&gssEncMode=disable";
240+
}
223241
}
224242

225243
if (extra.isEmpty()) {
@@ -240,6 +258,9 @@ private String buildJdbcUrl(String driverClassName) {
240258
}
241259

242260
// MySQL / MariaDB
261+
if (postgreSqlTlsMode != PostgreSqlTlsMode.LEGACY) {
262+
throw new IllegalArgumentException("PostgreSqlTlsMode applies only to PostgreSQL connections");
263+
}
243264
boolean maria = (dbType == DbType.MARIADB) || "org.mariadb.jdbc.Driver".equals(driverClassName);
244265
String base = maria ? String.format("jdbc:mariadb://%s:%s/%s", host, port, database)
245266
: String.format("jdbc:mysql://%s:%s/%s", host, port, database);
@@ -250,6 +271,24 @@ private String buildJdbcUrl(String driverClassName) {
250271
+ extra;
251272
}
252273

274+
private void rejectConflictingPostgreSqlTlsOptions(String extra) {
275+
String options = extra.startsWith("?") || extra.startsWith("&") ? extra.substring(1) : extra;
276+
for (String parameter : options.split("&", -1)) {
277+
String rawKey = parameter.split("=", 2)[0];
278+
String key;
279+
try {
280+
key = URLDecoder.decode(rawKey, StandardCharsets.UTF_8).trim().toLowerCase(Locale.ROOT);
281+
} catch (IllegalArgumentException ex) {
282+
throw new IllegalArgumentException("Invalid encoded parameter name in PostgreSQL Line", ex);
283+
}
284+
if (key.equals("sslmode") || key.equals("ssl") || key.equals("sslfactory")
285+
|| key.equals("sslhostnameverifier")
286+
|| (postgreSqlTlsMode != PostgreSqlTlsMode.DISABLE && key.equals("gssencmode"))) {
287+
throw new IllegalArgumentException("PostgreSqlTlsMode conflicts with a TLS parameter in Line");
288+
}
289+
}
290+
}
291+
253292
// --- Pool Configuration ---
254293

255294
public boolean open() {

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/MySQL.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public boolean connect(MysqlConfig config) {
5454
} else {
5555
connectionManager.setDbType(config.isUseMariaDB() ? DbType.MARIADB : DbType.MYSQL);
5656
}
57+
connectionManager.setPostgreSqlTlsMode(config.getPostgreSqlTlsMode());
5758

5859
String driver = config.getDriver();
5960
if (driver != null && !driver.isEmpty()) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.bencodez.simpleapi.sql.mysql;
2+
3+
import java.util.Locale;
4+
5+
/** PostgreSQL JDBC TLS policy. LEGACY preserves the existing UseSSL setting. */
6+
public enum PostgreSqlTlsMode {
7+
LEGACY(null),
8+
DISABLE("disable"),
9+
REQUIRE("require"),
10+
VERIFY_FULL("verify-full");
11+
12+
private final String jdbcValue;
13+
14+
PostgreSqlTlsMode(String jdbcValue) {
15+
this.jdbcValue = jdbcValue;
16+
}
17+
18+
public String getJdbcValue() {
19+
return jdbcValue;
20+
}
21+
22+
public static PostgreSqlTlsMode fromString(String raw) {
23+
if (raw == null || raw.trim().isEmpty()) {
24+
return LEGACY;
25+
}
26+
String normalized = raw.trim().replace('-', '_').toUpperCase(Locale.ROOT);
27+
try {
28+
return valueOf(normalized);
29+
} catch (IllegalArgumentException ex) {
30+
throw new IllegalArgumentException("Invalid PostgreSqlTlsMode; expected LEGACY, DISABLE, REQUIRE, or VERIFY_FULL", ex);
31+
}
32+
}
33+
}

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/config/MysqlConfig.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.bencodez.simpleapi.sql.mysql.config;
22

3+
import java.util.Objects;
4+
35
import com.bencodez.simpleapi.sql.mysql.DbType;
6+
import com.bencodez.simpleapi.sql.mysql.PostgreSqlTlsMode;
47

58
import lombok.Getter;
69
import lombok.Setter;
@@ -82,6 +85,13 @@ public class MysqlConfig {
8285
@Setter
8386
private boolean useSSL;
8487

88+
@Getter
89+
private PostgreSqlTlsMode postgreSqlTlsMode = PostgreSqlTlsMode.LEGACY;
90+
91+
public void setPostgreSqlTlsMode(PostgreSqlTlsMode mode) {
92+
postgreSqlTlsMode = Objects.requireNonNull(mode, "mode");
93+
}
94+
8595
@Getter
8696
@Setter
8797
private boolean publicKeyRetrieval;

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/config/MysqlConfigBungee.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.bencodez.simpleapi.sql.mysql.config;
22

33
import com.bencodez.simpleapi.sql.mysql.DbType;
4+
import com.bencodez.simpleapi.sql.mysql.PostgreSqlTlsMode;
45

56
import net.md_5.bungee.config.Configuration;
67

@@ -50,6 +51,7 @@ public MysqlConfigBungee(Configuration section) {
5051

5152
// --- Driver / Behavior Options ---
5253
setUseSSL(section.getBoolean("UseSSL", false));
54+
setPostgreSqlTlsMode(PostgreSqlTlsMode.fromString(section.getString("PostgreSqlTlsMode", "LEGACY")));
5355
setPublicKeyRetrieval(section.getBoolean("PublicKeyRetrieval", false));
5456
setUseMariaDB(section.getBoolean("UseMariaDB", false));
5557

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/config/MysqlConfigSpigot.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.bukkit.configuration.ConfigurationSection;
44

55
import com.bencodez.simpleapi.sql.mysql.DbType;
6+
import com.bencodez.simpleapi.sql.mysql.PostgreSqlTlsMode;
67

78
public class MysqlConfigSpigot extends MysqlConfig {
89

@@ -49,6 +50,7 @@ public MysqlConfigSpigot(ConfigurationSection section) {
4950

5051
// --- Driver / Behavior Options ---
5152
setUseSSL(section.getBoolean("UseSSL", false));
53+
setPostgreSqlTlsMode(PostgreSqlTlsMode.fromString(section.getString("PostgreSqlTlsMode", "LEGACY")));
5254
setPublicKeyRetrieval(section.getBoolean("PublicKeyRetrieval", false));
5355
setUseMariaDB(section.getBoolean("UseMariaDB", false));
5456

‎SimpleAPI/src/main/java/com/bencodez/simpleapi/sql/mysql/config/MysqlConfigVelocity.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import com.bencodez.simpleapi.file.velocity.VelocityYMLFile;
66
import com.bencodez.simpleapi.sql.mysql.DbType;
7+
import com.bencodez.simpleapi.sql.mysql.PostgreSqlTlsMode;
78

89
public class MysqlConfigVelocity extends MysqlConfig {
910

@@ -59,6 +60,8 @@ private void load(String prePath, VelocityYMLFile config) {
5960

6061
// --- Driver / Behavior Options ---
6162
setUseSSL(config.getBoolean(node(config, prePath, "UseSSL"), false));
63+
setPostgreSqlTlsMode(PostgreSqlTlsMode.fromString(
64+
config.getString(node(config, prePath, "PostgreSqlTlsMode"), "LEGACY")));
6265
setPublicKeyRetrieval(config.getBoolean(node(config, prePath, "PublicKeyRetrieval"), false));
6366
setUseMariaDB(config.getBoolean(node(config, prePath, "UseMariaDB"), false));
6467

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.bencodez.simpleapi.sql.mysql;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
6+
import java.nio.file.Path;
7+
8+
import org.bukkit.configuration.MemoryConfiguration;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.io.TempDir;
11+
import org.spongepowered.configurate.BasicConfigurationNode;
12+
13+
import com.bencodez.simpleapi.file.config.configurate.ConfigurateConfigView;
14+
import com.bencodez.simpleapi.file.velocity.VelocityYMLFile;
15+
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfigBungee;
16+
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfigSpigot;
17+
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfigVelocity;
18+
import com.bencodez.simpleapi.sql.mysql.config.MysqlConfigView;
19+
20+
import net.md_5.bungee.config.Configuration;
21+
22+
class PostgreSqlTlsConfigTest {
23+
@TempDir Path tempDir;
24+
25+
@Test void allAdaptersReadExplicitModeAndPreserveLegacyDefault() {
26+
MemoryConfiguration spigot = new MemoryConfiguration();
27+
Configuration bungee = new Configuration();
28+
var shared = BasicConfigurationNode.root();
29+
VelocityYMLFile velocity = new VelocityYMLFile(tempDir.resolve("mysql.yml").toFile());
30+
assertEquals(PostgreSqlTlsMode.LEGACY, new MysqlConfigSpigot(spigot).getPostgreSqlTlsMode());
31+
assertEquals(PostgreSqlTlsMode.LEGACY, new MysqlConfigBungee(bungee).getPostgreSqlTlsMode());
32+
assertEquals(PostgreSqlTlsMode.LEGACY,
33+
new MysqlConfigView(new ConfigurateConfigView(shared)).getPostgreSqlTlsMode());
34+
assertEquals(PostgreSqlTlsMode.LEGACY, new MysqlConfigVelocity(velocity).getPostgreSqlTlsMode());
35+
36+
spigot.set("PostgreSqlTlsMode", "verify-full");
37+
bungee.set("PostgreSqlTlsMode", "verify-full");
38+
shared.node("PostgreSqlTlsMode").raw("verify-full");
39+
velocity.getNode("MySQL", "PostgreSqlTlsMode").raw("verify-full");
40+
assertEquals(PostgreSqlTlsMode.VERIFY_FULL, new MysqlConfigSpigot(spigot).getPostgreSqlTlsMode());
41+
assertEquals(PostgreSqlTlsMode.VERIFY_FULL, new MysqlConfigBungee(bungee).getPostgreSqlTlsMode());
42+
assertEquals(PostgreSqlTlsMode.VERIFY_FULL,
43+
new MysqlConfigView(new ConfigurateConfigView(shared)).getPostgreSqlTlsMode());
44+
assertEquals(PostgreSqlTlsMode.VERIFY_FULL,
45+
new MysqlConfigVelocity("MySQL", velocity).getPostgreSqlTlsMode());
46+
}
47+
48+
@Test void invalidModeFailsAtConfigLoad() {
49+
MemoryConfiguration spigot = new MemoryConfiguration();
50+
spigot.set("PostgreSqlTlsMode", "anything");
51+
assertThrows(IllegalArgumentException.class, () -> new MysqlConfigSpigot(spigot));
52+
}
53+
}

0 commit comments

Comments
 (0)