From 63383866ea7c26168285ec64104e315f9d34fb42 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sat, 29 Jun 2019 15:28:26 +0200 Subject: [PATCH 1/4] Add access functionality for Gnome login keyring --- main/keychain/pom.xml | 9 ++- .../cryptomator/keychain/KeychainModule.java | 4 +- .../keychain/LinuxSecretServiceAccess.java | 67 +++++++++++++++++++ .../keychain/TestKeychainModule.java | 2 +- 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 29471ed1d..01e276cc9 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -39,7 +39,14 @@ com.google.dagger dagger - + + + + de.swiesend + secret-service + 1.0.0-RC.3 + + org.slf4j diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java index 5db7bc372..f05a90f1f 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java @@ -31,8 +31,8 @@ public class KeychainModule { @Provides @ElementsIntoSet - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain) { - return Sets.newHashSet(macKeychain, winKeychain); + Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceAccess linKeychain) { + return Sets.newHashSet(macKeychain, winKeychain, linKeychain); } @Provides diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java new file mode 100644 index 000000000..70781fd39 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java @@ -0,0 +1,67 @@ +package org.cryptomator.keychain; + +import com.google.common.base.Preconditions; +import org.apache.commons.lang3.SystemUtils; +import org.freedesktop.secret.simple.SimpleCollection; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LinuxSecretServiceAccess implements KeychainAccessStrategy { + private final Optional gnomeLoginKeyring; + + @Inject + public LinuxSecretServiceAccess() { + SimpleCollection keyring = null; + try { + keyring = new SimpleCollection(); + } catch (Exception e) { + // Accessing secret-service DBus API failed + } finally { + gnomeLoginKeyring = Optional.ofNullable(keyring); + } + } + + @Override + public boolean isSupported() { + return SystemUtils.IS_OS_LINUX && gnomeLoginKeyring.isPresent(); + } + + @Override + public void storePassphrase(String key, CharSequence passphrase) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); + if (list == null) { + gnomeLoginKeyring.get().createItem("Cryptomator", passphrase, createAttributes(key)); + } + } + + @Override + public char[] loadPassphrase(String key) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); + if (list != null) { + return gnomeLoginKeyring.get().getSecret(list.get(0)); + } else { + return null; + } + } + + @Override + public void deletePassphrase(String key) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); + if (list != null) { + gnomeLoginKeyring.get().deleteItem(list.get(0)); + } + } + + private Map createAttributes(String key) { + Map attributes = new HashMap(); + attributes.put("Vault", key); + return attributes; + } +} diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java index 66addc62a..bafc81a97 100644 --- a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java +++ b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java @@ -12,7 +12,7 @@ import com.google.common.collect.Sets; public class TestKeychainModule extends KeychainModule { @Override - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain) { + Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceAccess linKeychain) { return Sets.newHashSet(new MapKeychainAccess()); } From 5217546f73c865582bed66e804974f78cb71ade3 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sat, 29 Jun 2019 15:31:22 +0200 Subject: [PATCH 2/4] Isolate SimpleCollection via an interface and avoid imports for it This is needed on other platforms than Linux to avoid class loading problems on runtime in case secret-service.jar is missing --- .../keychain/GnomeKeyringAccess.java | 9 ++++ .../keychain/GnomeKeyringAccessImpl.java | 52 +++++++++++++++++++ .../keychain/LinuxKeychainTester.java | 25 +++++++++ .../keychain/LinuxSecretServiceAccess.java | 40 +++----------- 4 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java new file mode 100644 index 000000000..998fdfab7 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java @@ -0,0 +1,9 @@ +package org.cryptomator.keychain; + +public interface GnomeKeyringAccess { + public void storePassword(String key, CharSequence passphrase); + + public char[] loadPassword(String key); + + public void deletePassword(String key); +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java new file mode 100644 index 000000000..34dcdb5fa --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java @@ -0,0 +1,52 @@ +package org.cryptomator.keychain; + +import org.freedesktop.secret.simple.SimpleCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GnomeKeyringAccessImpl implements GnomeKeyringAccess { + private static final Logger LOG = LoggerFactory.getLogger(GnomeKeyringAccessImpl.class); + private SimpleCollection keyring; + + public GnomeKeyringAccessImpl() { + try { + keyring = new SimpleCollection(); + } catch (IOException e) { + LOG.error("D-Bus reports a problem.", e); + } + } + + public void storePassword(String key, CharSequence passphrase) { + List list = keyring.getItems(createAttributes(key)); + if (list == null) { + keyring.createItem("Cryptomator", passphrase, createAttributes(key)); + } + } + + public char[] loadPassword(String key) { + List list = keyring.getItems(createAttributes(key)); + if (list != null) { + return keyring.getSecret(list.get(0)); + } else { + return null; + } + } + + public void deletePassword(String key) { + List list = keyring.getItems(createAttributes(key)); + if (list != null) { + keyring.deleteItem(list.get(0)); + } + } + + private Map createAttributes(String key) { + Map attributes = new HashMap(); + attributes.put("Vault", key); + return attributes; + } +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java new file mode 100644 index 000000000..1466e895c --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java @@ -0,0 +1,25 @@ +package org.cryptomator.keychain; + +import java.util.Optional; + +public class LinuxKeychainTester { + public static boolean secretServiceIsAvailable() { + try { + Class.forName("org.freedesktop.secret.simple.SimpleCollection"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + public static Optional getSecretService() { + if (!secretServiceIsAvailable()) return Optional.empty(); + try { + Class clazz = Class.forName("org.cryptomator.keychain.GnomeKeyringAccessImpl"); + GnomeKeyringAccess keyring = (GnomeKeyringAccess) clazz.getDeclaredConstructor().newInstance(); + return Optional.of(keyring); + } catch (Exception e) { + return Optional.empty(); + } + } +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java index 70781fd39..ef8dcb092 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java @@ -2,66 +2,38 @@ package org.cryptomator.keychain; import com.google.common.base.Preconditions; import org.apache.commons.lang3.SystemUtils; -import org.freedesktop.secret.simple.SimpleCollection; import javax.inject.Inject; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Optional; public class LinuxSecretServiceAccess implements KeychainAccessStrategy { - private final Optional gnomeLoginKeyring; + private final Optional gnomeLoginKeyring; @Inject public LinuxSecretServiceAccess() { - SimpleCollection keyring = null; - try { - keyring = new SimpleCollection(); - } catch (Exception e) { - // Accessing secret-service DBus API failed - } finally { - gnomeLoginKeyring = Optional.ofNullable(keyring); - } + gnomeLoginKeyring = LinuxKeychainTester.getSecretService(); } @Override public boolean isSupported() { - return SystemUtils.IS_OS_LINUX && gnomeLoginKeyring.isPresent(); + return SystemUtils.IS_OS_LINUX && LinuxKeychainTester.getSecretService().isPresent(); } @Override public void storePassphrase(String key, CharSequence passphrase) { Preconditions.checkState(gnomeLoginKeyring.isPresent()); - List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); - if (list == null) { - gnomeLoginKeyring.get().createItem("Cryptomator", passphrase, createAttributes(key)); - } + gnomeLoginKeyring.get().storePassword(key, passphrase); } @Override public char[] loadPassphrase(String key) { Preconditions.checkState(gnomeLoginKeyring.isPresent()); - List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); - if (list != null) { - return gnomeLoginKeyring.get().getSecret(list.get(0)); - } else { - return null; - } + return gnomeLoginKeyring.get().loadPassword(key); } @Override public void deletePassphrase(String key) { Preconditions.checkState(gnomeLoginKeyring.isPresent()); - List list = gnomeLoginKeyring.get().getItems(createAttributes(key)); - if (list != null) { - gnomeLoginKeyring.get().deleteItem(list.get(0)); - } - } - - private Map createAttributes(String key) { - Map attributes = new HashMap(); - attributes.put("Vault", key); - return attributes; + gnomeLoginKeyring.get().deletePassword(key); } } From 1aec6ef877f146008961d11c6d58973f39b2d864 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sat, 29 Jun 2019 15:34:15 +0200 Subject: [PATCH 3/4] Include required jar files for secret-service in Linux build --- main/buildkit/assembly-linux.xml | 7 +++++++ main/buildkit/pom.xml | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/main/buildkit/assembly-linux.xml b/main/buildkit/assembly-linux.xml index 9784212b5..35eb98c9e 100644 --- a/main/buildkit/assembly-linux.xml +++ b/main/buildkit/assembly-linux.xml @@ -28,5 +28,12 @@ libs + + target/linux-secret-service + + *.jar + + libs + \ No newline at end of file diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml index 32fa59d67..00344c9a8 100644 --- a/main/buildkit/pom.xml +++ b/main/buildkit/pom.xml @@ -62,6 +62,7 @@ ${project.build.directory}/libs linux,mac,win + dbus-java,secret-service,hkdf,java-utils @@ -76,6 +77,17 @@ linux + + copy-linux-secret-service + prepare-package + + copy-dependencies + + + ${project.build.directory}/linux-secret-service + dbus-java,secret-service,hkdf,java-utils + + copy-mac-libs prepare-package From 7fcaded720173111be42aa075603a2e29937fdcf Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 2 Jul 2019 16:09:48 +0200 Subject: [PATCH 4/4] minor amendment to #905 [ci skip] --- main/buildkit/assembly-linux.xml | 7 ------- main/buildkit/pom.xml | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/main/buildkit/assembly-linux.xml b/main/buildkit/assembly-linux.xml index 35eb98c9e..9784212b5 100644 --- a/main/buildkit/assembly-linux.xml +++ b/main/buildkit/assembly-linux.xml @@ -28,12 +28,5 @@ libs - - target/linux-secret-service - - *.jar - - libs - \ No newline at end of file diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml index 00344c9a8..4c9dac1ce 100644 --- a/main/buildkit/pom.xml +++ b/main/buildkit/pom.xml @@ -84,7 +84,7 @@ copy-dependencies - ${project.build.directory}/linux-secret-service + ${project.build.directory}/linux-libs dbus-java,secret-service,hkdf,java-utils