jaraco / keyring

MIT License
1.24k stars 152 forks source link

Use the keyring python module with gnome-keyring #609

Open rkouznetsov opened 1 year ago

rkouznetsov commented 1 year ago

Not exactly a bug, but a lack of documentation. Sorry if it is not the right use of keyring.

In a shell script I can get a needed password from gnome-keyring to a variable or feed it via pipe to some program:

passwd=$(secret-tool lookup user myname domain somehost.com)

If I got it right, keyring can be used for the same purpose in a python script. I could not find any minimal working example example to do that in python with keyring module. There probably must be a better way than using os.popen(cmd).read() with the above shell command...

The example from the README file

$ python
  >>> import keyring
  >>> keyring.get_keyring()
  <keyring.backends.SecretService.Keyring object at 0x7f9b9c971ba8>
  >>> keyring.set_password("system", "username", "password")
  >>> keyring.get_password("system", "username")

launces "KDE Wallet Service" configuration which is not relevant for me, since I use gnome-keyring...

Thank you!

Environment

$ dpkg -l |grep python3-keyring
ii  python3-keyring                               23.5.0-1                                all          store and access your passwords safely
$ keyring --list-backends
keyring.backends.kwallet.DBusKeyring (priority: 4.9)
keyring.backends.fail.Keyring (priority: 0)
keyring.backends.chainer.ChainerBackend (priority: 10)
keyring.backends.libsecret.Keyring (priority: 4.8)
jaraco commented 1 year ago

Keyring tries to use the most relevant backend available, and in your environment, it believes the kwallet.DBusKeyring is the best backend for your environment. You can see that preference in the debugging command (DBusKeyring has the highest priority at 4.9). My guess is you probably want to be using the SecretService backend, but for whatever reason, it's not viable on your system.

See the section in the readme on configuring for headless Linux systems, which gives some tips around making the SecretService backend work in constrained environments.

You can also manually construct that backend:

import keyring.backends.SecretService
kr = keyring.backends.SecretService.Keyring()
kr.priority

You'll get an exception when kr.priority runs indicating why it's not viable (probably "SecretStorage required" or similar).

You can configure keyring to manually use that keyring on your system, but that's not going to help you any if that keyring isn't viable, so I'm assuming you don't want that.

When it comes to coding for others to use, you'll want to simply use keyring.get_password/set_password, etc., and leave it to the library to resolve the best backend for each user.

Hope that helps.

rkouznetsov commented 1 year ago

Thank you! I have checked the manual about a headless setup. Looks like by default in Ubuntu Mate 22.04 the library fails to resolve the best backend.

keyring.get_password call triggers a dialog Untitled despite gnome-keyring-daemon is perfectly up and running.

kr.priority complains about

---> 3 kr.priority

/usr/lib/python3/dist-packages/keyring/util/properties.py in __get__(self, cls, owner)
     22 
     23     def __get__(self, cls, owner):
---> 24         return self.fget.__get__(None, owner)()
     25 
     26 

/usr/lib/python3/dist-packages/keyring/backends/SecretService.py in priority(cls)
     46                     )
     47         except exceptions.SecretStorageException as e:
---> 48             raise RuntimeError("Unable to initialize SecretService: %s" % e)
     49         return 5
     50 

RuntimeError: Unable to initialize SecretService: Environment variable DBUS_SESSION_BUS_ADDRESS is unset

secret-tool works just fine in the same environment. So there must be some other way secret-tool knows about DBUS (or works with gnome-keyring without it)...

takluyver commented 1 year ago

Is there anything odd about your terminal or shell session, which could cause an environment variable from your login not to show up there?

D-Bus is normally launched, and that environment variable set, when you log in. There is a fallback way to find the D-Bus session bus using X11, which might be how secret-tool is working. The pure-Python code behind the SecretService backend doesn't implement this fallback - I wrote the D-Bus layer for this, but I'd rather not delve into X APIs when that's clearly not the way the world is going.