Using the Secret Service API in Your Code
Once you have set appropriate classpaths in your project, you will have access to dbus-java-2.7.jar classes and secret-service-api-java-0.1.jar classes.
Do not forget to set the java.library.path property to use the libmatthew native java-unix.so library.
A Simple (Useless?) Use-case
Let's build a class that connects to the Gnome 'login' keyring and get the password for indentifier='21' (use an existing ID in your 'login' keyring). If you want to test on KDE, change 'login' for an existing folder (probably 'passwords').
First we have to open a connection to the DBus daemon:
DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
A Dbus connection can be opened at the System level or at the Session level. Here we want to get access to our personal keyrings so use the Session level.
Then we have to open a session, which will give us a Session object that will be used to exchange secrets (passwords):
String objectPath = "/org/freedesktop/secrets";
String busName = "org.freedesktop.secrets";
// get a proxy remote object that implements the Service interface
Service serv = (Service) conn.getRemoteObject(busName, objectPath, Service.class);
// call remote OpenSession on it (no encryption)
Pair<Variant,DBusInterface> osr = serv.OpenSession("plain", new org.freedesktop.dbus.Variant(""));
// get the session in the return object
DBusInterface dbusSession = osr.b;
The next step will provide the password:
// build the object path to the Item '21' in collection 'login'
objectPath = "/org/freedesktop/secrets/collection/login/21";
// get the remote object that implements the Item interface
Item item = (Item) conn.getRemoteObject(busName, objectPath, Item.class);
// call the remote method GetSecret and get a Secret object as the result
Secret secret = item.GetSecret(dbusSession);
// Access the password (stored in the 'value' member
Byte[] passwordAsByteArray = secret.value;
You will likely also get the name of the Item (called Label in the Secret Service API). The label is part of the information that you can get
using the standard DBus 'Properties' interface:
// get the remote object that implements the Properties interface
prop = (Properties) conn.getRemoteObject(busName, objectPath, Properties.class);
// call the remote method 'Get' to get the 'Label' property
String label = (String) prop.Get("org.freedesktop.Secret.Item", "Label");
You can get each property ('Get') or all properties ('GetAll'). To know which property is available on an interface, use the introspection:
// get the remote object that implements the Introspectable interface
Introspectable in = (Introspectable) conn.getRemoteObject(busName, objectPath, Introspectable.class);
// call the remote method Introspect and get the XML definition as a String
String xmlDef = in.Introspect();
Right, I know, you have recognized the content of the XML files described in page 3.
A More Realistic Use-case
OK, I see. What you really want to do is to find a password from its name (user,service...). Let's try to get the password of your XMPP account ("XMPP myaccount@myjabber.mydomain.org"):
The first step is the same as above. Once you have the dbusSession object, you get the list of passwords stored in the 'login' collection and iterate in this list, to get what you are looking for.
// build the object path for the 'login' collection
objectPath = "/org/freedesktop/secrets/collection/login";
// get the remote object that implements the Collection interface
Collection collection = (Collection) conn.getRemoteObject(busName, objectPath, Collection.class);
// call the remote method with an empty Map as search attributes and get all the items in the collection
// as a pair of List: one for unlocked items, one for locked items
Pair<List<DBusInterface>,List<DBusInterface>> itemList = collection.SearchItems(new HashMap());
List<DBusInterface> unlockedItems = itemList.a;
List<DBusInterface> lockedItems = itemList.b;
// scan the unlocked list to find the item with Label="XMPP myaccount@myjabber.mydomain.org"
for (int i=0; i<unlockedItems.size(); i++) {
// get the label of the item
prop = (Properties)unlockedItems.get(i);
String foundLabel = (String) prop.Get("org.freedesktop.Secret.Item", "Label");
if (foundLabel.equals("XMPP myaccount@myjabber.mydomain.org")) {
// This is a bit tricky here:
// proxy objects sent by SearchItems do not implement Item, but Properties and Introspectable only
// so we cannot use directly the GetSecret method
// instead we get the objectPath as String and get the remote object that implements Item
// get the Object path from toString() !!! because there is not getObjectPath() method...
// toString = ":busadress+":"+objectpath+":"+iface"
objectPath = prop.toString().split(":")[2];
Item item = (Item) conn.getRemoteObject(busName, objectPath, Item.class);
secret = item.GetSecret(dbusSession);
// Access the password (stored in the 'value' member
Byte[] passwordAsByteArray = secret.value;
break;
}
}
Of course, you can also scan the locked list, but if you find your item in this list, you will not be able to get the corresponding secret. The item has to be unlocked first.
Unlocking an item can be done by this API (org.freedesktop.Secret.Service.Unlock) or using your desktop environment.
Note that a more elegant way to get your chat password would have been to use the attributes instead of the hard-coded Label "XMPP myaccount@myjabber.mydomain.org":
// call the remote method with a Map of attributes and get all matching items in the collection
// as a pair of List: one for unlocked items, one for locked items
Map attrs = new HashMap();
attrs.put("user", "myaccount");
attrs.put("protocol", "xmpp");
attrs.put("server", "myjabber.mydomain.org");
Pair<List<DBusInterface>,List<DBusInterface>> itemList = collection.SearchItems(attrs);
Other Use-cases
Using the Secret Service API, your application will be able to store passwords, create collections, lock and unlock items...
Comments
There are no comments yet. Be the first to comment!