From 1db926a52401e890201696bce46aad356fa81ee6 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 28 Feb 2025 13:04:31 -0800 Subject: [PATCH 1/6] Remove scheme from URI before fetching path for CRL path check --- .../sqlserver/jdbc/ConfigurableRetryLogic.java | 13 +++++++++++-- .../microsoft/sqlserver/jdbc/SQLServerResource.java | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java index da8facdd8..d5ef6f1d9 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java @@ -13,6 +13,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Collections; @@ -284,13 +285,17 @@ private static void createConnectionRules(LinkedList listOfRules) throws private static String getCurrentClassPath() throws SQLServerException { String location = ""; String className = ""; + String schemeSpecificPart = ""; try { className = new Object() {}.getClass().getEnclosingClass().getName(); location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); - if (Files.isDirectory(Paths - .get(ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) { + schemeSpecificPart = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() + .toURI().getSchemeSpecificPart(); + schemeSpecificPart = schemeSpecificPart.substring(1, schemeSpecificPart.length() - 1); // Remove leading / + + if (Files.isDirectory(Paths.get(schemeSpecificPart))) { // We check if the Path we get from the CodeSource location is a directory. If so, we are running // from class files and should remove a suffix (i.e. the props file is in a different location from the // location returned) @@ -298,6 +303,10 @@ private static String getCurrentClassPath() throws SQLServerException { } return new URI(location).getPath() + DEFAULT_PROPS_FILE; // TODO: Allow custom paths + } catch (InvalidPathException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_PathInvalid")); + Object[] msgArgs = {schemeSpecificPart}; + throw new SQLServerException(form.format(msgArgs), null, 0, e); } catch (URISyntaxException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_URLInvalid")); Object[] msgArgs = {location}; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 942bfdc26..b92c9fdab 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -369,7 +369,8 @@ protected Object[][] getContents() { {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn", "Cannot execute statement or procedure {0} because Force Encryption was set as true for parameter {1} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, {"R_ForceEncryptionTrue_HonorAEFalseRS", "Cannot set Force Encryption to true for parameter {0} because encryption is not enabled for the statement or procedure."}, {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS", "Cannot execute update because Force Encryption was set as true for parameter {0} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, - {"R_NullValue", "{0} cannot be null."}, + {"R_NullValue", "{0} cannot be null."}, + {"R_PathInvalid", "Invalid path specified: {0}"}, {"R_URLInvalid", "Invalid URL specified: {0}."}, {"R_AKVPathNull", "Azure Key Vault key path cannot be null."}, {"R_AKVMasterKeyPathInvalid", "Invalid Azure Key Vault key path specified: {0}."}, From eca1e053acc3ea1b4b00f6370ccc3d67a8f5eb87 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 28 Feb 2025 13:09:00 -0800 Subject: [PATCH 2/6] Update src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java index d5ef6f1d9..4a76f9535 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java @@ -293,8 +293,7 @@ private static String getCurrentClassPath() throws SQLServerException { schemeSpecificPart = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() .toURI().getSchemeSpecificPart(); - schemeSpecificPart = schemeSpecificPart.substring(1, schemeSpecificPart.length() - 1); // Remove leading / - + schemeSpecificPart = schemeSpecificPart.substring(1); // Remove leading / if (Files.isDirectory(Paths.get(schemeSpecificPart))) { // We check if the Path we get from the CodeSource location is a directory. If so, we are running // from class files and should remove a suffix (i.e. the props file is in a different location from the From 9aa4eb6e0c4fb25cd1c3aa395b959c13746f7ebf Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 28 Feb 2025 13:10:20 -0800 Subject: [PATCH 3/6] Committed nitpick mentioned by copilot --- .../java/com/microsoft/sqlserver/jdbc/SQLServerResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index b92c9fdab..435dd286b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -370,7 +370,7 @@ protected Object[][] getContents() { {"R_ForceEncryptionTrue_HonorAEFalseRS", "Cannot set Force Encryption to true for parameter {0} because encryption is not enabled for the statement or procedure."}, {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS", "Cannot execute update because Force Encryption was set as true for parameter {0} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, {"R_NullValue", "{0} cannot be null."}, - {"R_PathInvalid", "Invalid path specified: {0}"}, + {"R_PathInvalid", "Invalid path specified: {0}."}, {"R_URLInvalid", "Invalid URL specified: {0}."}, {"R_AKVPathNull", "Azure Key Vault key path cannot be null."}, {"R_AKVMasterKeyPathInvalid", "Invalid Azure Key Vault key path specified: {0}."}, From 72f15af9c94ced7a1ad548bbdc058cddad831fff Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Fri, 28 Feb 2025 13:17:22 -0800 Subject: [PATCH 4/6] Added additional check + greater clarity --- .../sqlserver/jdbc/ConfigurableRetryLogic.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java index 4a76f9535..d9abb87d4 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java @@ -40,9 +40,11 @@ public class ConfigurableRetryLogic { private static final String SEMI_COLON = ";"; private static final String COMMA = ","; private static final String EQUALS_SIGN = "="; + private static final String FORWARD_SLASH = "/"; private static final String RETRY_EXEC = "retryExec"; private static final String RETRY_CONN = "retryConn"; private static final String STATEMENT = "statement"; + private static final String CLASS_FILES_SUFFIX = "target/classes/"; private static boolean replaceFlag = false; // Are we replacing the list of transient errors? /** * The time the properties file was last modified. @@ -290,15 +292,17 @@ private static String getCurrentClassPath() throws SQLServerException { try { className = new Object() {}.getClass().getEnclosingClass().getName(); location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); - schemeSpecificPart = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() .toURI().getSchemeSpecificPart(); - schemeSpecificPart = schemeSpecificPart.substring(1); // Remove leading / + if (schemeSpecificPart.startsWith(FORWARD_SLASH)) { + schemeSpecificPart = schemeSpecificPart.substring(1); // Remove leading / + } + if (Files.isDirectory(Paths.get(schemeSpecificPart))) { // We check if the Path we get from the CodeSource location is a directory. If so, we are running // from class files and should remove a suffix (i.e. the props file is in a different location from the // location returned) - location = location.substring(0, location.length() - ("target/classes/").length()); + location = location.substring(0, location.length() - CLASS_FILES_SUFFIX.length()); } return new URI(location).getPath() + DEFAULT_PROPS_FILE; // TODO: Allow custom paths From 611bfd9ff91a08ad7733487ff82d187498ededc5 Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Mon, 3 Mar 2025 09:30:08 -0800 Subject: [PATCH 5/6] The issue was with jar:file:/ NOT jar:/, corrected. --- .../sqlserver/jdbc/ConfigurableRetryLogic.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java index d9abb87d4..47a8f6097 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java @@ -287,18 +287,20 @@ private static void createConnectionRules(LinkedList listOfRules) throws private static String getCurrentClassPath() throws SQLServerException { String location = ""; String className = ""; - String schemeSpecificPart = ""; + String uriToString = ""; try { className = new Object() {}.getClass().getEnclosingClass().getName(); location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); - schemeSpecificPart = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() - .toURI().getSchemeSpecificPart(); - if (schemeSpecificPart.startsWith(FORWARD_SLASH)) { - schemeSpecificPart = schemeSpecificPart.substring(1); // Remove leading / + URI uri = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() + .toURI(); + uriToString = uri.toString(); + int initialIndexOfForwardSlash = uriToString.indexOf(FORWARD_SLASH); + if (initialIndexOfForwardSlash > 0) { + uriToString = uriToString.substring(initialIndexOfForwardSlash + 1); } - if (Files.isDirectory(Paths.get(schemeSpecificPart))) { + if (Files.isDirectory(Paths.get(uriToString))) { // We check if the Path we get from the CodeSource location is a directory. If so, we are running // from class files and should remove a suffix (i.e. the props file is in a different location from the // location returned) @@ -308,7 +310,7 @@ private static String getCurrentClassPath() throws SQLServerException { return new URI(location).getPath() + DEFAULT_PROPS_FILE; // TODO: Allow custom paths } catch (InvalidPathException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_PathInvalid")); - Object[] msgArgs = {schemeSpecificPart}; + Object[] msgArgs = {uriToString}; throw new SQLServerException(form.format(msgArgs), null, 0, e); } catch (URISyntaxException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_URLInvalid")); From ade238fd7e56b1faf535b369df83a924c10135fe Mon Sep 17 00:00:00 2001 From: Jeff Wasty Date: Mon, 3 Mar 2025 09:39:50 -0800 Subject: [PATCH 6/6] Forgot a case where there would be no scheme --- .../microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java index 47a8f6097..0a1bd4e44 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ConfigurableRetryLogic.java @@ -294,9 +294,14 @@ private static String getCurrentClassPath() throws SQLServerException { location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); URI uri = ConfigurableRetryLogic.class.getProtectionDomain().getCodeSource().getLocation() .toURI(); + uriToString = uri.toString(); + int initialIndexOfForwardSlash = uriToString.indexOf(FORWARD_SLASH); - if (initialIndexOfForwardSlash > 0) { + + if (!uri.getScheme().isEmpty() && initialIndexOfForwardSlash > 0) { + // If the URI has a scheme, i.e. jar:file:, jar:, or file: then we create a substring from the + // forward slash onwards. uriToString = uriToString.substring(initialIndexOfForwardSlash + 1); }