Giter Site home page Giter Site logo

swiesend / secret-service Goto Github PK

View Code? Open in Web Editor NEW
28.0 4.0 8.0 592 KB

A Java library for storing secrets under linux in the gnome-keyring over D-Bus. Like libsecret, but for Java.

License: MIT License

Java 100.00%
secrets password password-store password-vault keyring gnome-keyring libsecret dbus dbus-java java

secret-service's Introduction

Secret Service

Maven Central

A Java library for storing secrets in a keyring over the D-Bus.

The library is conforming to the freedesktop.org Secret Service API 0.2 and thus compatible with Gnome linux systems.

The Secret Service itself is implemented by the gnome-keyring and provided by the gnome-keyring-daemon.

This library can be seen as the functional equivalent to the libsecret C client library.

Related

For KDE systems there is the kdewallet client library, kindly provided by @purejava.

Security Issues

CVE-2018-19358 (Vulnerability)

There is a current investigation on the behaviour of the Secret Service API, as other applications can easily read any secret, if the keyring is unlocked (if a user is logged in, then the login/default collection is unlocked). Available D-Bus protection mechanisms (involving the busconfig and policy XML elements) are not used by default. The Secret Service API was never designed with a secure retrieval mechanism.

Usage

The library provides a simplified high-level API, which sends only transport encrypted secrets over the D-Bus.

Dependency

Add the secret-service as dependency to your project. You may want to exclude the slf4j-api if you use an incompatible version. The current version requires at least JDK 17.

<dependency>
    <groupId>de.swiesend</groupId>
    <artifactId>secret-service</artifactId>
    <version>2.0.1-alpha</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

High-Level API

public class Example {

    @Test
    @DisplayName("Create a password in the user's default collection (/org/freedesktop/secrets/aliases/default).")
    public void createPasswordInDefaultCollection() throws IOException, AccessControlException, IllegalArgumentException {
        try (SimpleCollection collection = new SimpleCollection()) {
            String item = collection.createItem("My Item", "secret");

            char[] actual = collection.getSecret(item);
            assertEquals("secret", new String(actual));
            assertEquals("My Item", collection.getLabel(item));

            collection.deleteItem(item);
        } // clears automatically all session secrets in memory, but does not close the D-Bus connection.
    }

    @Test
    @DisplayName("Create a password in a non-default collection (/org/freedesktop/secrets/collection/xxx).")
    public void createPasswordInNonDefaultCollection() throws IOException, AccessControlException, IllegalArgumentException {
        try (SimpleCollection collection = new SimpleCollection("My Collection", "super secret")) {
            String item = collection.createItem("My Item", "secret");

            char[] actual = collection.getSecret(item);
            assertEquals("secret", new String(actual));
            assertEquals("My Item", collection.getLabel(item));

            collection.deleteItem(item);
            collection.delete();
        } // clears automatically all session secrets in memory, but does not close the D-Bus connection.
    }

    @Test
    @DisplayName("Create a password with additional attributes.")
    public void createPasswordWithAttributes() throws IOException, AccessControlException, IllegalArgumentException {
        try (SimpleCollection collection = new SimpleCollection("My Collection", "super secret")) {
            // define unique attributes
            Map<String, String> attributes = new HashMap();
            attributes.put("uuid", "42");

            // create and forget
            collection.createItem("My Item", "secret", attributes);

            // find by attributes
            List<String> items = collection.getItems(attributes);
            assertEquals(1, items.size());
            String item = items.get(0);

            char[] actual = collection.getSecret(item);
            assertEquals("secret", new String(actual));
            assertEquals("My Item", collection.getLabel(item));
            assertEquals("42", collection.getAttributes(item).get("uuid"));

            collection.deleteItem(item);
            collection.delete();
        } // clears automatically all session secrets in memory, but does not close the D-Bus connection.
    }

    // The D-Bus connection gets closed at the end of the static lifetime of `SimpleCollection` by a shutdown hook.

}

Closing the D-Bus connection:

The D-Bus connection is closed eventually at end of the static lifetime of SimpleCollection with a shutdown hook and not by auto-close. One can also close the D-Bus connection manually by calling SimpleCollection.disconnect(), but once disconnected it is not possible to reconnect.

SimpleCollection-Interface:

For Further methods and attributes checkout the SimpleCollection-Interface.

Transport Encryption:

For the details of the transport encryption see: Transfer of Secrets, Transport Encryption Example

Low-Level API

The low-level API gives access to all defined D-Bus Methods, Properties and Signals of the Secret Service interface:

For the usage of the low-level API see the tests:

D-Bus Interfaces

The underlying introspected XML D-Bus interfaces are available as resources.

Contributing

You are welcome to point out issues, file PRs and comment on the project.

Please keep in mind that this is a non-profit effort in my spare time and thus it may take some time until issues are addressed.

Thank You

Special thanks goes out to

secret-service's People

Contributors

infeo avatar invidian avatar koppor avatar purejava avatar shocklateboy92 avatar swiesend avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

secret-service's Issues

Messaging opens several SignalHandlers for the same signal type

I think there should be only a singleton SingnalHandler for all signals to avoid registering duplicate handlers, which maybe won't get unregistered at shutdown.

A distinct event-store for each signal type would also enable better tracking of incoming signals of different kinds. This would allow a more reliable prompting process and ensuring, that the user has interacted with a prompt.

Enable full support for JDK8

The example source code fails to execute on JDK8 due to the following error:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer;
at org.freedesktop.secret.Secret.clear(Secret.java:166)
at org.freedesktop.secret.Secret.toBytes(Secret.java:128)
at org.freedesktop.secret.TransportEncryption.encrypt(TransportEncryption.java:109)
at org.freedesktop.secret.simple.SimpleCollection.createItem(SimpleCollection.java:258)
at org.freedesktop.secret.simple.SimpleCollection.createItem(SimpleCollection.java:291)

This is because maven has been setup using JDK9 or later and is using the source and target options instead of the newer 'release' flag. https://www.baeldung.com/maven-java-version

In JDK8 the ByteBuffer inherits a rewind method from Buffer:
https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html

In JDK9 a covariant return was added to ByteBuffer:
https://docs.oracle.com/javase/9/docs/api/java/nio/ByteBuffer.html#rewind--

Sometimes unit testing does not remove all signal handlers

When terminating a test, the "Closing Message Writer" Thread can't unregister a signal anymore.

Exception in thread "Thread-1" [Thread-2] INFO org.freedesktop.dbus.MessageWriter - Closing Message Writer
java.util.concurrent.RejectedExecutionException: Task org.freedesktop.dbus.connections.AbstractConnection$1@6002cb94 rejected from java.util.concurrent.ThreadPoolExecutor@29c1d7a6[Terminated, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 21]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2080)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:832)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)
	at org.freedesktop.dbus.connections.AbstractConnection.sendMessage(AbstractConnection.java:308)
	at org.freedesktop.dbus.RemoteInvocationHandler.executeRemoteMethod(RemoteInvocationHandler.java:147)
	at org.freedesktop.dbus.RemoteInvocationHandler.invoke(RemoteInvocationHandler.java:226)
	at com.sun.proxy.$Proxy11.RemoveMatch(Unknown Source)
	at org.freedesktop.dbus.connections.impl.DBusConnection.removeSigHandler(DBusConnection.java:752)
	at org.freedesktop.dbus.connections.AbstractConnection.removeSigHandler(AbstractConnection.java:330)
	at org.freedesktop.secret.handlers.SignalHandler.disconnect(SignalHandler.java:69)
	at org.freedesktop.secret.handlers.SignalHandler.lambda$new$0(SignalHandler.java:32)
	at java.base/java.lang.Thread.run(Thread.java:844)

Secret Service not found in Docker Container

Distro: AlmaLinux 8 container on top of Ubuntu 20.04 with privilege
secret-service version: 1.6.2
Error shows that

Exception in thread "main" java.lang.RuntimeException: java.io.IOException: The secret service is not available.

Caused by: java.io.IOException: The secret service is not available.
	at org.freedesktop.secret.simple.SimpleCollection.init(SimpleCollection.java:277)
	at org.freedesktop.secret.simple.SimpleCollection.<init>(SimpleCollection.java:57)

The org.freedesktop.secrets.service and org.gnome.keyring.service exist.

ls /usr/share/dbus-1/services/
ca.desrt.dconf.service                  org.freedesktop.secrets.service            org.gnome.keyring.SystemPrompter.service
org.freedesktop.systemd1.service           org.gnome.keyring.service
org.a11y.Bus.service                    org.gnome.keyring.PrivatePrompter.service  org.gtk.GLib.PACRunner.service

gnome-keyring is also running

ps aux | grep gnome-keyring
user    1217  0.0  0.0 154656  4864 ?        Sl   01:12   0:00 gnome-keyring-daemon --daemonize --login
user    1222  0.0  0.1 302364  9232 ?        Sl   01:12   0:00 gnome-keyring-daemon --unlock
user    1227  0.0  0.0      0     0 ?        Z    01:12   0:00 [gnome-keyring-d] <defunct>
user    1517  0.0  0.0   9220  1204 ?        S    01:13   0:00 grep gnome-keyring

We also have some keyring related tests running successfully in the container.

Why is it complaining about the secret service is not available?
Is there any general advice about how to run this in container?

Thank you very much.

DBusConnection - broken pipe

There are problems with the 1.2.0 version on shutting down.

[DBus Sender Thread-1] INFO org.freedesktop.dbus.connections.impl.DBusConnection - Setting reply to MethodCall(0,42) { Path=>/org/freedesktop/DBus, Interface=>org.freedesktop.DBus, Member=>RemoveMatch, Destination=>org.freedesktop.DBus, Signature=>s } { type='signal',member='CollectionChanged',interface='org.freedesktop.Secret.Service' } as an error
[Thread-2] ERROR org.freedesktop.secret.handlers.SignalHandler - org.freedesktop.dbus.exceptions.DBusException: org.freedesktop.dbus.exceptions.DBusExecutionException: Message Failed to Send: Datenübergabe unterbrochen (broken pipe)
org.freedesktop.dbus.exceptions.DBusExecutionException: Message Failed to Send: Datenübergabe unterbrochen (broken pipe)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at org.freedesktop.dbus.errors.Error.getException(Error.java:157)
	at org.freedesktop.dbus.errors.Error.throwException(Error.java:187)
	at org.freedesktop.dbus.RemoteInvocationHandler.executeRemoteMethod(RemoteInvocationHandler.java:164)
	at org.freedesktop.dbus.RemoteInvocationHandler.invoke(RemoteInvocationHandler.java:228)
	at com.sun.proxy.$Proxy26.RemoveMatch(Unknown Source)
	at org.freedesktop.dbus.connections.impl.DBusConnection.removeSigHandler(DBusConnection.java:818)
	at org.freedesktop.dbus.connections.AbstractConnection.removeSigHandler(AbstractConnection.java:400)
	at org.freedesktop.secret.handlers.SignalHandler.disconnect(SignalHandler.java:63)
	at org.freedesktop.secret.handlers.SignalHandler.lambda$new$0(SignalHandler.java:31)
	at java.base/java.lang.Thread.run(Thread.java:834)
[Thread-2] ERROR org.freedesktop.secret.handlers.SignalHandler - Could not remove all signal handlers from the D-Bus.

Log thrown exceptions instead of exception cause

The SimpleCollection uses exception catch pattern of:
log.error(e.toString(), e.getCause()); throw new IOException(e.toString(), e.getCause());

This pattern drops the important cause frames which are needed for troubleshooting. Currently the logging code produces the following output:
[02 Nov 2020 18:45:33,310] [ERROR] SimpleCollection.<init>() - java.lang.NullPointerException

This is because e.getCause() is null therefore, no throwable was passed to the logger.

However, if I change the catch pattern to the following:
log.error(e.toString(), e); throw new IOException(e.toString(), e);

The following is output is shown:
[03 Nov 2020 16:34:08,347] [ERROR] SimpleCollection.<init>() - java.lang.NullPointerException java.lang.NullPointerException: null at org.freedesktop.secret.handlers.MessageHandler.send(MessageHandler.java:50) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.handlers.Messaging.send(Messaging.java:37) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.Service.openSession(Service.java:29) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.TransportEncryption.openSession(TransportEncryption.java:80) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.simple.SimpleCollection.init(SimpleCollection.java:174) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.simple.SimpleCollection.<init>(SimpleCollection.java:92) [secret-service-1.2.1.jar:?]

Recommendation would be to:

  1. Change the logging throwable arguments (right hand side) to log the root exception and not the cause.
  2. Change the wrapping exception to wrap the caught exception instead of wrapping a cause that may not be present.
  3. Update the logging message (left hand side) to include context about the operation that failed and avoid logging e.toString() as the message.

Please update to dbus-java 3.2.3

dbus-java 3.2.3 will be released shortly.
It contains a fix (dbus-java #110), that is essential for kdewallet to work correctly.

As Cryptomator includes secret-service and probably will include kdewallet as well, they need to depend on the same dbus-java version.

Thanks.

API-Design: Don't expose classes from dependencies

In my opinion we shouldn't consume or return any instaces of classes from dependencies, such as DBusPath. This makes it hard to migrate to a different library or library version without breaking the API.

Therefore I suggest to only return "normal" (i.e. java.lang.*) or classes from this library.

NullPointerException on systems without `gnome-keyring` installed or `login` as default collection

On systems without gnome-keyring installed the secret-service can't find any default collection /org/freedesktop/secrets/collection/login.

This problem relates to Cryptomator #950.

cryptomator0.log

18:31:24.707 [JavaFX Application Thread] ERROR o.f.secret.handlers.MessageHandler - org.freedesktop.dbus.exceptions.DBusException: org.freedesktop.DBus.Error.UnknownMethod: Keine derartige Schnittstelle »org.freedesktop.DBus.Properties« des Objekts im Pfad /org/freedesktop/secrets/collection/login
....
Caused by: java.lang.NullPointerException: null
	at org.freedesktop.secret.handlers.MessageHandler.getProperty(MessageHandler.java:72)
	at org.freedesktop.secret.handlers.Messaging.getProperty(Messaging.java:41)
	at org.freedesktop.secret.Collection.isLocked(Collection.java:86)
	at org.freedesktop.secret.simple.SimpleCollection.unlock(SimpleCollection.java:174)
	at org.freedesktop.secret.simple.SimpleCollection.<init>(SimpleCollection.java:47)

Suggested solution

MessageHandler.send() should not return null, but preferably raise an Exception. The high low and level API should be adapted to handle this, where the high level API may return Optionals where returning a type or pass through any Exception as IOException when not returning anything.

public Object[] send(String service, String path, String iface, String method, String signature, Object... args) {
try {
org.freedesktop.dbus.messages.Message message = new MethodCall(
service,
path,
iface,
method, (byte) 0, signature, args);
connection.sendMessage(message);
org.freedesktop.dbus.messages.Message response = ((MethodCall) message).getReply(2000L);
log.trace(response.toString());
if (response instanceof org.freedesktop.dbus.errors.Error) {
switch (response.getName()) {
case "org.freedesktop.Secret.Error.NoSession":
throw new NoSession((String) response.getParameters()[0]);
case "org.freedesktop.Secret.Error.NoSuchObject":
throw new NoSuchObject((String) response.getParameters()[0]);
case "org.freedesktop.Secret.Error.IsLocked":
throw new IsLocked((String) response.getParameters()[0]);
default:
throw new DBusException(response.getName() + ": " + response.getParameters()[0]);
}
}
Object[] parameters = response.getParameters();
log.debug(Arrays.deepToString(parameters));
return parameters;
} catch (NoSession | NoSuchObject | IsLocked | DBusException e) {
log.error(e.toString(), e.getCause());
}
return null;
}

DBusConnection - RejectedExecutionException

There are problems with versions 1.2.0-1.2.3 on shutting down the static initial connection to check whether there is a secret-service or not.

Exception in thread "DBusConnection" java.util.concurrent.RejectedExecutionException: Task org.freedesktop.dbus.connections.AbstractConnection$3@6f96a320 rejected from java.util.concurrent.ThreadPoolExecutor@231c97bd[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at org.freedesktop.dbus.connections.AbstractConnection.executeInWorkerThreadPool(AbstractConnection.java:946)
	at org.freedesktop.dbus.connections.AbstractConnection.handleMessage(AbstractConnection.java:920)
	at org.freedesktop.dbus.connections.AbstractConnection.handleMessage(AbstractConnection.java:709)
	at org.freedesktop.dbus.connections.IncomingMessageThread.run(IncomingMessageThread.java:43)

SimpleCollection.isAvailable checks for wrong service

The SimpleCollection has the static isAvailable()method, to check wether the running OS has the gnome keyring service installed. But looking into the method, it actually only checks if the DBUS service is available.

if (!Arrays.asList(bus.ListActivatableNames()).contains(Static.DBus.Service.DBUS)) {

The string to check should be org.gnome.keyring.

Do we have some benchmarks available for this library?

Using an unlocked default collection...I'm seeing a single write take about 32 milliseconds on average and a single read take about 6.5 milliseconds on average.

Comparing this with KDE Wallet using the JAVA KDE Wallet library, I see the following on KDE Wallet:

With KWallet, I see a single write take about 0.675 milliseconds on average and a single read take about 0.489 seconds on average.

I initially thought it was due to DBus, however, KWallet also operates over DBus...so not sure why this library takes so much time.

Working with other secret service implementations

The Secret Service API 0.2 as been a published standard for quite some time and is now implemented by other services including:

However, if something tries to use SimpleCollection with one of those instead of gnome-keyring, it just crashes with:

IOException(""The secret service is not available.")

because the org.gnome.keyring dbus service is not available.

Is it possible to defer that check?
To only crash if someone tries to use a gnome-specific feature?

slf4j-simple is in compile-scope

... which leads to conflicts when using this library in any project using a different logger. Use slf4j-api instead and add slf4j-simple to test-scope.

RejectedExecutionException at program termination

I'm using your library. It works great, but upon program termination, I always encounter the following error:

Exception in thread "DBusConnection" java.util.concurrent.RejectedExecutionException: Task org.freedesktop.dbus.connections.AbstractConnection$1@7682e526 rejected from java.util.concurrent.ThreadPoolExecutor@710fe758[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 32]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at org.freedesktop.dbus.connections.AbstractConnection.sendMessage(AbstractConnection.java:317)
	at org.freedesktop.dbus.connections.AbstractConnection.handleMessage(AbstractConnection.java:959)
	at org.freedesktop.dbus.connections.AbstractConnection.handleMessage(AbstractConnection.java:619)
	at org.freedesktop.dbus.connections.IncomingMessageThread.run(IncomingMessageThread.java:43)

I looked into this a bit and suspect that it is caused by the following refence chain: SimpleCollection -> TransportEncryption -> DBusConnection. If SimpleCollection.close() is called, DBusConnection.close() is not called.

Code like the following for SimpleCollection.close() would fix the problem:

    @Override
    public void close() {
        clear();
        if (encryption != null) {
            encryption.close();
        }
        if (encrypted != null) {
            encrypted.close();
        }
        if (session != null) {
            session.close();
        }
    }

Does Lock / Unlock method do anything for a non-default SimpleCollection?

I'm creating an instance of a SimpleCollection object for a non-default collection as follows:

SimpleCollection collection = new SimpleCollection("My Collection", "<my-secret>")

It seems that calling the lock and unlock methods on this instance don't do anything and the collection is effectively always unlocked as I am always able to create items and get items from this collection. Is this expected? What should be the expected behavior after calling lock on such a collection?

[feature-request] interface re-design to get more flexibility

Dear Sebastian,

I would like to suggest a little re-design of the interfaces that are part of secret-service.

Right now, the interfaces in org.freedesktop.secret.interfaces are all public abstract classes. While this is no problem in having working D-Bus interfaces (and serecret-service is working very well), this has a flaw: sending these over D-Bus throws an exception.

Why is this a problem?

Generally, checking on D-Bus, if an interface is available, e.g. check for the corresponding daemon being installed and configured, is done via connection.getRemoteObject, which requires a "real" D-Bus interface instead of a public abstract class.

The advantage of having the change would be, that it would easily be possible to create a method to check whether gnome-keyring is installed and running, not more, without creating an instance of the SimpleCollectionand using the default-collection in one flush like it is now. This would make secret-service more flexible.

So, what do you think about a change like this one: purejava@ea272ba

The change passes all maven tests you have created. 😃

Store passwords in char[]

At the moment passwords in parameters, variables, fields and returned from methods are plain Strings.

Storing Passwords as char[]

Whenever we store passwords, we should do it in a char[], as it can be nilled at the end of the lifecycle of the instance referencing it. A String, however, can not be changed via public APIs and potentially stays in memory after being GC'ed.

Consuming Passwords as CharSequences

When we consume a password, it should be passed as a CharSequence (which can be a String but also allows the char[]-backed and therefore more secure CharBuffer:

public DBusPath createPassword(String label, String password) throws IllegalArgumentException {

Returning passwords as char[]

When we return a password, it should be a char[]. This allows library users to destroy the password after using it but doesn't restrict them if they still want to construct a String.

public String getPassword(DBusPath object) {

Can't reuse SimpleCollection returned by SimpleService

SimpleCollection is AutoCloseable i.e. it should either be used in a try-with-resource statement or wrapped in a class that is itself AutoCloseable.

SimpleService returns a single instance of SimpleCollection here:

/**
* Connect to the default collection.
*/
public Optional<SimpleCollection> connect() {
try {
SimpleCollection keyring = new SimpleCollection();
return Optional.of(keyring);
} catch (Exception e) {
log.error(e.toString(), e.getCause());
return Optional.empty();
}
}

During your unit tests you only use such instances once and dispose them afterwards, thus they work. But the API suggests reusability, which is not provided.

I.e. the following code does close() the SimpleCollection twice:

Optional<SimpleCollection> connection = new SimpleService().connect();
assert connection.isPresent();

try (SimpleCollection collection = connection.get()) {
    ...
} catch (IOException e) { ... }

// at this point the collection is already closed:
try (SimpleCollection collection = connection.get()) {
    ...
} catch (IOException e) { ... }

I suggest to design the API that can be used like this:

try (SimpleService service = SimpleService.create()) { // factory method instead of constructor, as public constructors should ideally not throw any exceptions. attempt to initialize basic dbus connection here.
    try (SimpleServiceSession session = service.createSession()) {
        session.doStuffOnKeyring();
    } catch (IOException e) { ... }

    try (SimpleServiceSession session = service.createSession()) {
        session.doOtherStuffOnKeyring();
    } catch (IOException e) { ... }
} catch (SimpleServiceUnavailableException e) { ... }

AutoClose disconnects from the DBus

Related to cryptomator/integrations-linux#13 and #26

The behavior to auto-close the D-Bus connection was introduced to fix #26 with c386feb. This would be fine if one does not want to reuse the DBus connection for another instances of SimpleCollection, but it is a common use case to create multiple instances of SimpleCollection which use all the same DBus connection.

One way to fix this would be to use different DBus connections for the static lifetime (which only exist due to bad interface design in 1.x.x) and the instances. Another is to give manual control over the disconnect from global DBus connection and remove the disconnect() from the auto-close of the SimpleCollection instances.

GNOME keyring is not triggered to show an unlock prompt on application autostart

On a retrieve password request with a locked keyring, a pop up to unlock the keyring should be shown to either unlock the keyring or dismiss the pop up and keep the keyring locked.

On configuring Cryptomator with the "Unlock vault when starting Cryptomator" setting in conjunction with autologin to your system on booting, Cryptomator should launch and a pop up to unlock the keyring should appear.

secret-service instead logs

19:49:19.049 [JavaFX Application Thread] DEBUG o.c.u.k.m.PassphraseEntryController - Unlock canceled by user.
19:49:19.058 [JavaFX Application Thread] DEBUG o.c.ui.unlock.UnlockWorkflow - Unlock of 'Test2' canceled.

but there was no pop up that got dismissed.

This issue goes back to cryptomator/cryptomator#2769.

Update to `dbus-java` 4.x

This is a feature request that will not be downwards compatible and may require a new major version:

Could you please update dbus-java to version 4? It got modularized and offers a variety of transport implementations, including dbus-java-transport-native-unixsocket, which relies on Java's native unix sockets, so we could get rid of the dependency to the whole JNR ecosystem.

This requires to bump the JDK to 17 (technically 16, but I guess LTS makes more sense). On the long run, this is the most important step to make this library work with Java's module system.

Logger NPE in MessageHandler.send

MessageHandler logging fails to check for a null response when logging a trace message at line 50:
https://github.com/swiesend/secret-service/blob/master/src/main/java/org/freedesktop/secret/handlers/MessageHandler.java#L50

Error message with fixed logging is:
[03 Nov 2020 16:34:08,347] [ERROR] SimpleCollection.<init>() - java.lang.NullPointerException java.lang.NullPointerException: null at org.freedesktop.secret.handlers.MessageHandler.send(MessageHandler.java:50) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.handlers.Messaging.send(Messaging.java:37) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.Service.openSession(Service.java:29) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.TransportEncryption.openSession(TransportEncryption.java:80) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.simple.SimpleCollection.init(SimpleCollection.java:174) ~[secret-service-1.2.1.jar:?] at org.freedesktop.secret.simple.SimpleCollection.<init>(SimpleCollection.java:92) [secret-service-1.2.1.jar:?]

The code is:
log.trace(response.toString());

It should be changed to:
log.trace(String.valueOf(response));

Perhaps a logging guard statement should be added.

Unlocking Secrets before retrieving them

If I understand the spec correctly here

The client application should act as if it must unlock each item individually
https://specifications.freedesktop.org/secret-service/latest/ch08.html

The client must ask the application to unlock the specific item before using get to retrieve the secret. For example, Keepassxc has a configuration, that asks with a prompt if I want to provide access to a secret to the specified application. Because of this, I cannot retrieve secrets. There should be a check, if the secret is locked, before trying to get it.

`ExceptionInInitializerError` thrown when calling SimpleCollection.isAvailable()

When calling SimpleCollections::isAvailable, there still can be an ExceptionInInitailzerError thrown.

Exception org.freedesktop.dbus.exceptions.AddressResolvingException: Cannot Resolve Session Bus Address: MachineId file can not be found [in thread "JavaFX Application Thread"]

This is related to the static init of the DBusConnection with the getConnection()method:

/**
* Try to get a new DBus connection.
*
* @return a new DBusConnection or null
*/
private static DBusConnection getConnection() {
try {
return DBusConnectionBuilder.forSessionBus().withShared(false).build();
} catch (DBusException e) {
if (e == null) {
log.warn("Could not communicate properly with the D-Bus.");
} else {
log.warn("Could not communicate properly with the D-Bus: " + e.getMessage() + " (" + e.getClass().getSimpleName() + ")");
}
}
return null;
}

The thrown exceptions AddressResolvingException extends not DBusException, but the DBusExecutionException. Unfortunately, I don't know Linux systems good enough to evaluate if the machine-id file must always be readable (see above), but a defensive programming is always benefical.

See also cryptomator/cryptomator#3279.

[question] Can I connect to kwallet as well?

Hello, on my fedora system gnome-keyring is installed by default and secret-service uses it without any problem (fine!). But is it possible to talk to kwallet as well? And if yes, how to archive this?

avoid split packages

As already discussed in the context of #9 and #31:

[...] Please consider using a package namespace that you have sole control over, as org.gnome.* and org.freedesktop.* etc will lead to split packages in the post-Java-8 modular world.

Convention would be for Maven group/artifact, Java module name and root package name to match.

I would suggest to move those packages to de.swiesend.secretservice.gnome.* and de.swiesend.secretservice.freedesktop.* respectively.

Since this is a breaking change, it should be considered before releasing 2.0.0.

Together with #37 and #31 you would then be ready to add a module-info.java (I would volunteer to create a PR).

what to pass to SimpleCollection constructor?

I was shocked to have been prompted for a password when I had clearly passed a password as an argument to the SimpleCollection constructor. When I look at the source code, it appears that there is some encryption occurring under the covers. How can I know what to pass to SimpleCollection so that no password prompt appears at runtime?

private static final String COLLECTION_NAME = Main.class.getName();
private static final String PASSWORD = "super-secret";

public static void main(final String [] args) throws IOException {
    final String key = args[0];

    try (SimpleCollection collection = new SimpleCollection(COLLECTION_NAME, PASSWORD)) {
        collection.unlockWithUserPermission();

        try {
            Map<String, String> attributes = new HashMap<>();
            attributes.put(key, String.valueOf(key.hashCode()));
            List<String> items = collection.getItems(attributes);
            if (items != null && !items.isEmpty()) {
                System.out.println("result: " + collection.getSecret(items.get(0)));
            }
        } finally {
            collection.lock();
        }
    }

    System.out.println("no result");
    System.exit(0);
}

java 11 module problem with secret-service-1.0.0-RC.3.jar

There are some unwanted directory entries in the jar:

$ unzip -l lib/secret-service-1.0.0-RC.3.jar 
Archive:  lib/secret-service-1.0.0-RC.3.jar
  Length      Date    Time    Name
---------  ---------- -----   ----
       97  05-07-2019 02:20   META-INF/MANIFEST.MF
        0  05-07-2019 02:20   META-INF/
        0  05-07-2019 02:19   org/
        0  05-07-2019 02:19   org/gnome/
        0  05-07-2019 02:19   org/gnome/keyring/
        0  05-07-2019 02:19   org/gnome/keyring/interfaces/
        0  05-07-2019 02:19   org/freedesktop/
        0  05-07-2019 02:19   org/freedesktop/secret/
        0  05-07-2019 02:19   org/freedesktop/secret/interfaces/
        0  05-07-2019 02:19   org/freedesktop/secret/simple/
        0  05-07-2019 02:19   org/freedesktop/secret/handlers/
        0  05-07-2019 02:19   org/freedesktop/secret/errors/
        0  05-07-2019 02:19   org/freedesktop/dbus/
...

This is bad when using the java 11 module system because it leads to the 'split jar' problem:

error: module secret.service reads package org.freedesktop.dbus from both secret.service and dbus.java

Closing `SimpleCollection` does not stop `DBusConnection`

Consider the following application:

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.freedesktop.secret.simple.SimpleCollection;

import static java.util.Optional.*;

public class Application {
  public static void main(String[] args) throws IOException {
    var collection = new SimpleCollection("My Collection", null);

    var attributes = Map.of("example", "secret");

    ofNullable(collection.getItems(attributes))
      .flatMap(matchingPaths -> matchingPaths.stream().findFirst())
      .flatMap(pathToSecret -> ofNullable(collection.getSecret(pathToSecret)))
      .ifPresentOrElse(
        secret -> System.out.println(new String(secret)),
        () -> System.out.println("Not found")
      );

    collection.lock();
    collection.close();
    System.out.println("-- Locked & closed the collection");
  }
}

I expect this application to exit after printing the last line "-- Locked & closed the collection" to the console.

The program doesn't stop, however. The Debugger shows that the DBusConnection thread is still running.

Screenshot from 2021-04-11 21-33-03

I'm writing a CLI program in which I would like to make use of this library to connect to the Gnome Keyring. I'd like to prevent having to explicitly call a System.exit(0) since I use a library to manage the lifecycle of parsing options and calling the appropriate functions after parsing the options.

It does work, however, to explicitly call System.exit(0).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.