Skip to content

Commit d28783c

Browse files
committed
Add a SecretAgent class that makes it easy to write your own secret agents.
1 parent 94cbffb commit d28783c

2 files changed

Lines changed: 53 additions & 2 deletions

File tree

NetworkManager.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import copy
88
import dbus
9+
import dbus.service
910
import os
1011
import six
1112
import socket
@@ -413,11 +414,36 @@ class IP6Config(TransientNMDbusInterface): pass
413414
class DHCP4Config(TransientNMDbusInterface): pass
414415
class DHCP6Config(TransientNMDbusInterface): pass
415416

416-
# These three are interfaces that must be provided to NetworkManager. Keep them
417+
# Evil hack to work around not being able to specify a method name in the
418+
# dbus.service.method decorator.
419+
class SecretAgentType(type(dbus.service.Object)):
420+
def __new__(type_, name, bases, attrs):
421+
if bases != (dbus.service.Object,):
422+
attrs['GetSecretsImpl'] = attrs.pop('GetSecrets')
423+
return super(SecretAgentType, type_).__new__(type_, name, bases, attrs)
424+
425+
@six.add_metaclass(SecretAgentType)
426+
class SecretAgent(dbus.service.Object):
427+
object_path = '/org/freedesktop/NetworkManager/SecretAgent'
428+
interface_name = 'org.freedesktop.NetworkManager.SecretAgent'
429+
430+
def __init__(self, identifier):
431+
self.identifier = identifier
432+
dbus.service.Object.__init__(self, dbus.SystemBus(), self.object_path)
433+
AgentManager.Register(self.identifier)
434+
435+
@dbus.service.method(dbus_interface=interface_name, in_signature='a{sa{sv}}osasu', out_signature='a{sa{sv}}')
436+
def GetSecrets(self, connection, connection_path, setting_name, hints, flags):
437+
settings = fixups.to_python('SecretAgent', 'GetSecrets', 'connection', connection, 'a{sa{sv}}')
438+
connection = fixups.to_python('SecretAgent', 'GetSecrets', 'connection_path', connection_path, 'o')
439+
setting_name = fixups.to_python('SecretAgent', 'GetSecrets', 'setting_name', setting_name, 's')
440+
hints = fixups.to_python('SecretAgent', 'GetSecrets', 'hints', hints, 'as')
441+
return self.GetSecretsImpl(settings, connection, setting_name, hints, flags)
442+
443+
# These two are interfaces that must be provided to NetworkManager. Keep them
417444
# as comments for documentation purposes.
418445
#
419446
# class PPP(NMDbusInterface): pass
420-
# class SecretAgent(NMDbusInterface): pass
421447
# class VPNPlugin(NMDbusInterface):
422448
# interface_names = ['org.freedesktop.NetworkManager.VPN.Plugin']
423449

docs/index.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,5 +184,30 @@ interface, which gives you access to basic device properties. Note that you will
184184
`Wired <https://developer.gnome.org/NetworkManager/1.2/gdbus-org.freedesktop.NetworkManager.Device.Wired.html>`_ and
185185
`Wireless <https://developer.gnome.org/NetworkManager/1.2/gdbus-org.freedesktop.NetworkManager.Device.Wireless.html>`_
186186

187+
.. class:: SecretAgent
188+
189+
The NetworkManager daemon can ask separate programs, called agents, for secrets
190+
if it needs them. The NetworkManager applet and the `nmcli` command-line tool
191+
are examples of such agents. You can also write such agents by subclassing the
192+
`SecretAgent` class and providing a `GetSecrets` method as in the following
193+
example, which returns a static password for each secret::
194+
195+
import dbus.mainloop.glib
196+
import GObject
197+
import NetworkManager
198+
199+
class MyAgent(NetworkManager.SecretAgent):
200+
def GetSecrets(self, settings, connection, setting_name, hints, flags):
201+
return {setting_name: {'secrets': {'password': 'TopSecret!'}}}
202+
203+
agent = MyAgent()
204+
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
205+
Gobject.MainLoop().run()
206+
207+
Beware that NetworkManager will ask each agent in turn in what is in essence
208+
random order. Except it will prioritize the program that activated the
209+
connection. So if you want to make sure your agent is called first, activate
210+
the connection from the same application.
211+
187212
.. toctree::
188213
:maxdepth: 2

0 commit comments

Comments
 (0)