/secret-service

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

Primary LanguageJavaMIT LicenseMIT

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