diff --git a/dbptk-modules/dbptk-module-ms-access/pom.xml b/dbptk-modules/dbptk-module-ms-access/pom.xml index 83f4cba80..e874d3cad 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.8 - com.healthmarketscience.jackcess + io.github.spannm jackcess-encrypt - 4.0.3 + 5.1.6 org.bouncycastle 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 c87028a72..e8f267e2d 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 000000000..0b867711a --- /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 8ba98469c..359427553 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(); }