Browse Source

defined keychain access interfaces

Sebastian Stenzel 8 years ago
parent
commit
34af306309

+ 39 - 0
main/keychain/pom.xml

@@ -0,0 +1,39 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.cryptomator</groupId>
+		<artifactId>main</artifactId>
+		<version>1.2.0-SNAPSHOT</version>
+	</parent>
+	<artifactId>keychain</artifactId>
+	<name>System Keychain Access</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcprov-jdk15on</artifactId>
+			<version>1.54</version>
+		</dependency>
+
+		<!-- DI -->
+		<dependency>
+			<groupId>com.google.dagger</groupId>
+			<artifactId>dagger</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.google.dagger</groupId>
+			<artifactId>dagger-compiler</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		
+		<!-- Test -->
+		<dependency>
+			<groupId>org.cryptomator</groupId>
+			<artifactId>commons-test</artifactId>
+		</dependency>
+	</dependencies>
+</project>

+ 19 - 0
main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java

@@ -0,0 +1,19 @@
+package org.cryptomator.keychain;
+
+public interface KeychainAccess {
+
+	/**
+	 * Associates a passphrase with a given key.
+	 * 
+	 * @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}.
+	 * @param passphrase The secret to store in this keychain.
+	 */
+	void storePassphrase(String key, CharSequence passphrase);
+
+	/**
+	 * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
+	 * @return The stored passphrase for the given key or <code>null</code> if no value for the given key could be found.
+	 */
+	CharSequence loadPassphrase(String key);
+
+}

+ 10 - 0
main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java

@@ -0,0 +1,10 @@
+package org.cryptomator.keychain;
+
+interface KeychainAccessStrategy extends KeychainAccess {
+
+	/**
+	 * @return <code>true</code> if this KeychainAccessStrategy works on the current machine.
+	 */
+	boolean isSupported();
+
+}

+ 15 - 0
main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java

@@ -0,0 +1,15 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+@Singleton
+@Component(modules = KeychainModule.class)
+public interface KeychainComponent {
+
+	Optional<KeychainAccess> keychainAccess();
+
+}

+ 26 - 0
main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java

@@ -0,0 +1,26 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+
+@Module
+public class KeychainModule {
+
+	@Provides
+	@ElementsIntoSet
+	Set<KeychainAccessStrategy> provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsSystemKeychainAccess winKeychain) {
+		return Sets.newHashSet(macKeychain, winKeychain);
+	}
+
+	@Provides
+	public Optional<KeychainAccess> provideSupportedKeychain(Set<KeychainAccessStrategy> keychainAccessStrategies) {
+		return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).map(KeychainAccess.class::cast).findFirst();
+	}
+
+}

+ 45 - 0
main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java

@@ -0,0 +1,45 @@
+package org.cryptomator.keychain;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.commons.lang3.SystemUtils;
+
+@Singleton
+class MacSystemKeychainAccess implements KeychainAccessStrategy {
+
+	private final KeyStore keyStore;
+
+	@Inject
+	public MacSystemKeychainAccess() {
+		KeyStore ks;
+		try {
+			ks = KeyStore.getInstance("KeychainStore", "Apple");
+			ks.load(null);
+		} catch (GeneralSecurityException | IOException e) {
+			ks = null;
+		}
+		this.keyStore = ks;
+	}
+
+	@Override
+	public void storePassphrase(String key, CharSequence passphrase) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public CharSequence loadPassphrase(String key) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public boolean isSupported() {
+		return SystemUtils.IS_OS_MAC_OSX && keyStore != null;
+	}
+
+}

+ 45 - 0
main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java

@@ -0,0 +1,45 @@
+package org.cryptomator.keychain;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.commons.lang3.SystemUtils;
+
+@Singleton
+class WindowsSystemKeychainAccess implements KeychainAccessStrategy {
+
+	private final KeyStore keyStore;
+
+	@Inject
+	public WindowsSystemKeychainAccess() {
+		KeyStore ks;
+		try {
+			ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
+			ks.load(null);
+		} catch (GeneralSecurityException | IOException e) {
+			ks = null;
+		}
+		this.keyStore = ks;
+	}
+
+	@Override
+	public void storePassphrase(String key, CharSequence passphrase) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public CharSequence loadPassphrase(String key) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public boolean isSupported() {
+		return SystemUtils.IS_OS_WINDOWS && keyStore != null;
+	}
+
+}

+ 17 - 0
main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java

@@ -0,0 +1,17 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class KeychainModuleTest {
+
+	@Test
+	public void testGetKeychain() {
+		Optional<KeychainAccess> keychainAccess = DaggerKeychainComponent.builder().keychainModule(new KeychainTestModule()).build().keychainAccess();
+		Assert.assertTrue(keychainAccess.isPresent());
+		Assert.assertTrue(keychainAccess.get() instanceof MapKeychainAccess);
+	}
+
+}

+ 14 - 0
main/keychain/src/test/java/org/cryptomator/keychain/KeychainTestModule.java

@@ -0,0 +1,14 @@
+package org.cryptomator.keychain;
+
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+public class KeychainTestModule extends KeychainModule {
+
+	@Override
+	Set<KeychainAccessStrategy> provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsSystemKeychainAccess winKeychain) {
+		return Sets.newHashSet(new MapKeychainAccess());
+	}
+
+}

+ 25 - 0
main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java

@@ -0,0 +1,25 @@
+package org.cryptomator.keychain;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class MapKeychainAccess implements KeychainAccessStrategy {
+
+	private final Map<String, CharSequence> map = new HashMap<>();
+
+	@Override
+	public void storePassphrase(String key, CharSequence passphrase) {
+		map.put(key, passphrase);
+	}
+
+	@Override
+	public CharSequence loadPassphrase(String key) {
+		return map.get(key);
+	}
+
+	@Override
+	public boolean isSupported() {
+		return true;
+	}
+
+}

+ 1 - 0
main/pom.xml

@@ -273,6 +273,7 @@
 		<module>frontend-webdav</module>
 		<module>ui</module>
 		<module>filesystem-charsets</module>
+		<module>keychain</module>
 	</modules>
 
 	<profiles>