From 155fc248b0adf3b933835f039b77e9da1de4320a Mon Sep 17 00:00:00 2001 From: Markus Spann Date: Tue, 8 Sep 2026 11:27:17 +0200 Subject: [PATCH 1/3] Fix jackcess-encrypt/UCanAccess groupId mismatch and bump to latest version UCanAccess (io.github.spannm) now depends on io.github.spannm:jackcess instead of com.healthmarketscience.jackcess:jackcess, so the module's com.healthmarketscience.jackcess:jackcess-encrypt dependency pulled in a second, incompatible jackcess jar on the classpath. Switched to the matching io.github.spannm:jackcess-encrypt artifact and bumped both dependencies to their latest compatible releases (ucanaccess 5.1.7, jackcess-encrypt 5.1.5, both built against jackcess 5.1.5). --- dbptk-modules/dbptk-module-ms-access/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbptk-modules/dbptk-module-ms-access/pom.xml b/dbptk-modules/dbptk-module-ms-access/pom.xml index 83f4cba8..65c701b3 100644 --- a/dbptk-modules/dbptk-module-ms-access/pom.xml +++ b/dbptk-modules/dbptk-module-ms-access/pom.xml @@ -29,12 +29,12 @@ io.github.spannm ucanaccess - 5.1.3 + 5.1.7 - com.healthmarketscience.jackcess + io.github.spannm jackcess-encrypt - 4.0.3 + 5.1.5 org.bouncycastle From 97e3907104a8cc655508338d68c5062c51c5e9b6 Mon Sep 17 00:00:00 2001 From: Markus Spann Date: Tue, 8 Sep 2026 11:58:44 +0200 Subject: [PATCH 2/3] Actually decrypt password-protected Access databases via jackcess-encrypt UCanAccess forwards the password given to withPassword() only to the active IJackcessOpenerInterface implementation; it never registers a CodecProvider itself. Since the module relied on UCanAccess's DefaultJackcessOpener, the password was accepted but silently dropped for AES-encrypted (Access 2007+) databases - jackcess-encrypt was a dependency but never actually invoked. Added MsAccessCryptCodecJackcessOpener, a small IJackcessOpenerInterface implementation that wires the password into a jackcess-encrypt CryptCodecProvider, and register it via the jackcessOpener connection property whenever a password is supplied. --- .../MsAccessUCanAccessModuleFactory.java | 3 +- .../in/MsAccessCryptCodecJackcessOpener.java | 58 +++++++++++++++++++ .../in/MsAccessUCanAccessImportModule.java | 14 +++-- 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessCryptCodecJackcessOpener.java diff --git a/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/MsAccessUCanAccessModuleFactory.java b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/MsAccessUCanAccessModuleFactory.java index c87028a7..e8f267e2 100644 --- a/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/MsAccessUCanAccessModuleFactory.java +++ b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/MsAccessUCanAccessModuleFactory.java @@ -85,7 +85,8 @@ public Parameters getExportModuleParameters() throws UnsupportedModuleException } @Override - public DatabaseImportModule buildImportModule(Map parameters, Reporter reporter) throws ModuleException { + public DatabaseImportModule buildImportModule(Map parameters, Reporter reporter) + throws ModuleException { String pAccessFilePath = parameters.get(accessFilePath); String pAccessPassword = null; diff --git a/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessCryptCodecJackcessOpener.java b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessCryptCodecJackcessOpener.java new file mode 100644 index 00000000..0b867711 --- /dev/null +++ b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessCryptCodecJackcessOpener.java @@ -0,0 +1,58 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE file at the root of the source + * tree and available online at + * + * https://github.com/keeps/db-preservation-toolkit + */ +package com.databasepreservation.modules.msAccess.in; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; + +import org.apache.commons.lang3.StringUtils; + +import io.github.spannm.jackcess.Database; +import io.github.spannm.jackcess.DatabaseBuilder; +import io.github.spannm.jackcess.DateTimeType; +import io.github.spannm.jackcess.encrypt.CryptCodecProvider; +import net.ucanaccess.jdbc.IJackcessOpenerInterface; + +/** + * {@link IJackcessOpenerInterface} implementation that registers a + * {@link CryptCodecProvider} so that password-protected Microsoft Access + * databases (including the AES-encrypted format used by Access 2007+ + * {@code .accdb} files) can actually be decoded. UCanAccess itself never wires + * up {@code jackcess-encrypt}, so without a custom opener like this one, any + * password passed to UCanAccess is silently ignored. + */ +public class MsAccessCryptCodecJackcessOpener implements IJackcessOpenerInterface { + + @Override + public Database open(File fl, String pwd) throws IOException { + return open(fl, pwd, null); + } + + @Override + public Database open(File fl, String pwd, Charset charset) throws IOException { + DatabaseBuilder dbd = new DatabaseBuilder() + .withFile(fl) + .withAutoSync(false) + .withCharset(charset); + + if (StringUtils.isNotEmpty(pwd)) { + dbd.withCodecProvider(new CryptCodecProvider(pwd)); + } + + Database db; + try { + db = dbd.withReadOnly(false).open(); + } catch (Exception ex) { + db = dbd.withReadOnly(true).open(); + } + db.setDateTimeType(DateTimeType.LOCAL_DATE_TIME); + return db; + } + +} diff --git a/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessUCanAccessImportModule.java b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessUCanAccessImportModule.java index 8ba98469..35942755 100644 --- a/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessUCanAccessImportModule.java +++ b/dbptk-modules/dbptk-module-ms-access/src/main/java/com/databasepreservation/modules/msAccess/in/MsAccessUCanAccessImportModule.java @@ -63,13 +63,13 @@ public MsAccessUCanAccessImportModule(String moduleName, File msAccessFile, Map< super("net.ucanaccess.jdbc.UcanaccessDriver", "jdbc:ucanaccess://" + msAccessFile.getAbsolutePath() + ";showSchema=true;", new MsAccessHelper(), new MsAccessUCanAccessDatatypeImporter(), moduleName, properties); - this.msAccessFile = msAccessFile; + this.msAccessFile = msAccessFile; } public MsAccessUCanAccessImportModule(String moduleName, File msAccessFile, String password) throws ModuleException { this(moduleName, msAccessFile, MapUtils.buildMapFromObjects(MsAccessUCanAccessModuleFactory.PARAMETER_FILE, msAccessFile, MsAccessUCanAccessModuleFactory.PARAMETER_PASSWORD, password)); - this.password = password; + this.password = password; } public MsAccessUCanAccessImportModule(String moduleName, String accessFilePath) throws ModuleException { @@ -84,10 +84,12 @@ public MsAccessUCanAccessImportModule(String moduleName, String accessFilePath, @Override protected Connection createConnection() throws ModuleException { - UcanaccessConnectionBuilder builder = new UcanaccessConnectionBuilder().withDbPath(msAccessFile).withProp(Property.showSchema, true); - if (StringUtils.isNotEmpty(password)) { - builder.withPassword(password); - } + UcanaccessConnectionBuilder builder = new UcanaccessConnectionBuilder().withDbPath(msAccessFile).withProp( + Property.showSchema, true); + if (StringUtils.isNotEmpty(password)) { + builder.withPassword(password); + builder.withProp(Property.jackcessOpener, MsAccessCryptCodecJackcessOpener.class.getName()); + } return builder.build(); } From d7a0effd45cbdee1b20f439b2c3176c1ac780e5d Mon Sep 17 00:00:00 2001 From: Markus Spann Date: Sun, 13 Sep 2026 13:00:00 +0200 Subject: [PATCH 3/3] build: bump ucanaccess to 5.1.8, jackcess-encrypt to 5.1.6 --- dbptk-modules/dbptk-module-ms-access/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbptk-modules/dbptk-module-ms-access/pom.xml b/dbptk-modules/dbptk-module-ms-access/pom.xml index 65c701b3..e874d3ca 100644 --- a/dbptk-modules/dbptk-module-ms-access/pom.xml +++ b/dbptk-modules/dbptk-module-ms-access/pom.xml @@ -29,12 +29,12 @@ io.github.spannm ucanaccess - 5.1.7 + 5.1.8 io.github.spannm jackcess-encrypt - 5.1.5 + 5.1.6 org.bouncycastle