defined keychain access interfaces

This commit is contained in:
Sebastian Stenzel
2016-08-29 17:16:56 +02:00
parent 21d70b5ae4
commit 34af306309
11 changed files with 256 additions and 0 deletions

39
main/keychain/pom.xml Normal file
View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

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