Last week I worked with the Azure Storage Explorer team to create a snap. The storage-explorer snap requires the password-manager-service, all the storage objects are kept in the keyring.
I’d like to request (on behalf of the Storage Explorer team) that the password-manager-service is auto-connected to the storage-explorer snap. Without connecting this interface all previously connected storage object are absent each time the application is started.
-1 to auto-connect. Please keep in mind that GNOME Software in Ubuntu, the snap-store snap and possibly other snap installers allow setting this up on install. Also, the snap can quickly determine if the interface is connected on first launch and tell the user that the manual connection is needed to use the interface.
I agree with @jdstrand’s rationale: given how sensitive the information unlocked by this interface is, I think connecting it should be a conscious user choice (so -1 to auto-connect).
That said - are there alternatives we can suggest in order to ensure a friendly user experience? Other than installers allowing the user to make this choice at install time, the usual pattern is for the snap to contain a wrapper which checks for the interface and asks/guides the user to connect it at that time, while making the implications clear. Would this work for Storage Explorer?
Yes… though it might not have the properties they want. It depends on how they set up things. Usually secret-service/kwallet is only useful for protecting data at rest, after the user logs out/shuts off the machine and usually software stores keys in the ‘default’ or ‘login’ keyring so it is automatically opened on login. It in no way isolates applications from each other. Implementing some keyring service in the snap would not have this unlock upon login integration.
snapd could grow a secret-service/kwallet proxy so snaps only have access to their own credentials, but in the meantime I maintain that the snap should on first launch determine if the interface is connected and provide useful information to the user on why the interface is not connected and how to perform the connection. Auto-connection in some ways hinders the user’s choice since the user must seek out the auto-connected interfaces. Storage Explorer’s security-conscious users likely don’t want password-manager-service connected (or wouldn’t if they knew that other applications had access to the objects).
I certainly understand the implications here, and some alternatives might be possible. I’m a little new to Linux and Snapcraft; how might I go about creating a wrapper?
The major concern here is user experience. In the non-snap case, Storage Explorer throws a fatal error, because a libgnome-keyring0 package is missing. That, at least, gave you an idea of what was wrong. Currently, for the snap, not connecting the password manager results in a functional app that doesn’t “remember” any credentials. It’s not clear from the user’s perspective what’s wrong (not sure if that’s because we include libgnome-keyring0 as a stage-package for one of our Snapcraft parts).
I’ll also note that chromium has a concept of using different password backends including basic (I think that is the name), gnome-keyring and kwallet. The application can be started with any of these via command line option, and basic defaults to an disk storage. Firefox has on disk storage which can also be protected via a master password to protect against offline attacks.
I don’t know if Storage Explorer has other storage options like the above, but thought I’d mention it since if it did, it could pick one or another based on interface connection, etc.
I’m not too familiar with what Azure Storage Explorer does and the extent to which it interacts with other applications on the system, is there ever an instance where the Storage Explorer would need to “share” it’s objects that are stored in the keyring with other applications on the same system?
I seem to recall some work being done in user session services (inside snaps that is) that are autostarted as that user when the user logs in, would that work here? Maybe @jamesh could comment on that…
No, Storage Explorer doesn’t interact with any other applications. The password manager service is really just a means of storing sign-in credentials we use to authenticate Azure requests. We use the keytar npm package to interface with the system’s password manager.
It looks like keytar uses libsecret, so the dbus-send command I gave above would be a way to see if the interface is connected or not. It doesn’t seem to implement other backends for Linux and does work with the default keyring (ie, the one that auto-unlocks upon login) afaics.
The storage-explorer app runs the command desktop-launch $SNAP/StorageExplorer. I’ve tried switching to a bin/start or a $SNAP/bin/start, but I keep getting “does not exist or is not executable” errors. Am I supposed to add a part or something?
What’s the correct way for including yad? Most of the chatter is for zenity, but my understanding is yad has less overhead.
That said, it might be possible to have the application ship secret service, then on application start, create a private session bus, then fork off secret service on it (DBUS_SESSION_BUS_ADDRESS), then have keytar talk to it (it would use the same DBUS_SESSION_BUS_ADDRESS). This has an interesting property that on first launch after session start, the user enters the password to unlock the (private) keyring but thereafter storage explorer just uses the unlocked (private) keyring. In principle this should all work, but secret service might need some massaging to start in this manner and you might need to make adjustments in your code to only use your private DBUS_SESSION_BUS_ADDRESS for keytar functions.
This would be an interesting thing to explore (perhaps by the community), but the zenity/yad approach I outlined could be done quickly and immediately.
This is purely to workaround the fact that snaps can’t use snapctl to ask if an interface is connected at this time. The dbus-send tries to introspect org.freedesktop.secrets. If it can, it returns 0, if it cannot, it returns non-zero. So, if apparmor is blocking it, we expect to get the ‘1’ and then run tell_user().
You can ship $SNAP/StorageExplorer.wrap in your snap. Eg via the dump plugin:
then put your wrapper in files/StorageExplorer.wrap and when you build it should end up in $SNAP. Then adjust your snap.yaml to use desktop-launch $SNAP/StorageExplorer.wrap and StorageExplorer.wrap to use as its last line exec $SNAP/StorageExplorer "$@".
@lucyllewy or @sergiusens may be able to help there, but I also recall seeing something like this where $SNAP could be used as the argument to something but not in the command itself. Ie, command: foo, command: bin/foo, command: desktop-launch $SNAP/foo and command: desktop-launch $SNAP/bin/foo are all ok, but command: $SNAP/foo and command: $SNAP/bin/foo are not.
I don’t think there is any way to get the same user experience with a snapped user service. A big part of what makes the keyring work is pam_gnome_keyring.so, which unlocks the keyring using the user’s password on login, and reencrypts the keyring on password change.
Unless we also want to let snaps install PAM modules (which would be great for writing a password logger…), you won’t match that experience.