The Gnome and KDE
desktop environments have designed a shared service API to allow
applications to protect, retrieve and manage their secret data
such as passwords and private keys. The Secret Service API defines
the mechanisms and operations that can be used by
applications to use the service.

The libsecret is the
C library that gives access to the Secret Service API.
The Ada Libsecret is an
Ada binding for the C library. The Ada binding does not allow to access
and use all of the functionalities implemented by the C library but it
implements the most useful operations allowing to store, retrieve
and delete some application secret data.

Understanding the Secret Service API

At first glance, the
Secret Service API
is not easy to use. Each secret is stored together with lookup
attributes and a label. Lookup attributes are formed of key/value pairs.
The label is the user friendly name that desktop key manager will use
to display some information to the end user.

The Secret Service API
is implemented by a keyring manager such as
gnome-keyring-daemon
or kwalletd. This is a daemon that
is started when a user opens a desktop session. It manages the application
secrets and protects their access. The secret database can be locked
in which case the access to secrets is forbidden. Unlocking is possible
but requires authentication by the user (in most cases a dialog popup
window opens and asks to unlock the keyring).

When a client application wishes to retrieve one of its secret, it
builds the lookup attributes that correspond to the secret to retrieve.
The lookup attributes are not encrypted and they are not part of the
secret. The client application uses the
D-Bus
IPC mechanism to ask the keyring manager for the secret.
The keyring manager will manage for unlocking the database by asking
the user to confirm the access. The keyring manager will then look
in its database for the secret associated with the lookup attributes.

Note that the label cannot be used as a key to retrieve the secret
since the same label can be associated with different lookup attributes.

Using the Ada Secret Service API

Setting up the project

After building and installing the
Ada Libsecret
library you will add the following line to your GNAT project file:

with "secret";

This definition will give you access to the Secret package
and will handle the build and link support to use the libsecret C library.

Setting the lookup attributes

Attributes are defined by the Secret.Attributes package which provides
the Map type that represents the lookup attributes. First, you will
add the following with clause:

with Secret.Attributes;

to make available the operations and types provided by the package.
Then, you will declare the attributes instance by using:

List : Secret.Attributes.Map;

At this stage, the lookup attributes are empty and you can check that
by using the Is_Null function that will return True in that case.
You must now add at least one key/value pair in the attributes by using
the Insert procedure:

Applications are free about what attributes they use. The attributes have
to be unique so that the application can identify and retrieve them.
For example, the svn command uses two attributes to store the password
to authenticate to svn remote repositories: domain and user. The domain represents the server URL and the user represents the
user name to use for the connection. By using these two attributes,
it is possible to store several passwords for different svn accounts.

Storing a secret

To store a secret, we will use the operations and types from the
Secret.Services and Secret.Values packages. The following
definitions:

with Secret.Services;
with Secret.Values;

will bring such definitions to the program. The secret service is
represented by the Service_Type type and we will declare an instance
of it as follows:

Service : Secret.Services.Service_Type;

This service instance is a proxy to the
Secret Service API
and it communicates to the gnome-keyring-daemon by using the
D-Bus protocol.

The secret value itself is represented by the Secret_Type and we can
define and create such secret by using the Create function as follows:

Storing the secret is done by the Store operation which associates
the secret value to the lookup attributes and a label. As explained
before, the lookup attributes represent the unique key to identify the
secret. The label is used to give a user friendly name to the association.
This label is used by the desktop password and key manager to give
information to the user.

Service.Store (List, "Secret tool password", Value);

Retreiving a secret

Retreiving a secret follows the same steps but involves using the
Lookup function that returns the secret value from the lookup
attributes. Care must be made to provide the same lookup attributes
that were used during the store phase.

Value : Secret.Values.Secret_Type := Service.Lookup (List);

The secret value should be checked by using the Is_Null function
to verify that the value was found. The secret value itself is
accessed by using the Get_Value function.

if not Value.Is_Null then
Ada.Text_IO.Put_Line (Value.Get_Value);
end if;

Conclusion

By using the
Ada Secret Service API,
Ada applications can now securely store private information and protect
resources for their users. The API is fairly simple and can be used
to store OAuth access tokens, database passwords, and more...