Become Part of our Team and Push Digital Sovereignty
- Teamleader IT / Project Manager (m/f/x)
- IT Consultant (m/f/x)
- Outbound Sales Represantative (m/f/x)
- a.m.m.

Listener modules support you in your administrative work by synchronizing and controlling all changes in the UCS’ OpenLDAP Einacross all connected services – Learn how to build and use them!
You are surely using a variety of (cloud) services in your organization and, if required, these services will make changes to your directory service, either Active Directory or OpenLDAP. In heterogeneous environments, where UCS is typically used, the question is, how can service A notice the changes that service B has made to certain objects in the directory, and that are relevant to both services? For example, when a new printer has been added to the network, and has joined the UCS domain, the list of printers is updated in the configuration file of the printer service (CUPS) and the service reloaded.
I can also ask the above question in a simpler way as UCS is based on OpenLDAP, which is processing and storing all important information:
“How can service A notice any changes in OpenLDAP?”
A very common tool is the direct query (ldapsearch) in OpenLDAP, already described by my colleague Timo Denissen in How to Integrate with LDAP: “Generic LDAP Connection.
The advantage here is that this kind of query is widely used and thus has been implemented by a great deal of open source libraries in all kinds of possible programming languages. For simple queries, such as authentication, a service provider here is almost never forced to program something.
The disadvantage, however, is that direct queries in OpenLDAP are relatively rigid to handle:
Exactly these drawbacks are solved by listener modules. In a UCS domain, they are used as a powerful tool to monitor changes and events in the LDAP in all details and, if required, to query the state of objects.
The advantages of listener modules are evident:
Listener modules can be written, registered and used by anyone in a UCS domain. They are Python scripts – some of them very simple – that follow the UCS API. They are designed in such a way that the information about changes in the directory service will be communicated to the listener modules in an easy way. A detailed description can be found in our developer manual.
The UCS system itself often uses listener modules as it acts as a powerful interface. For example, the complete replication of the [OpenLDAP directory from UCS] master to backups or slaves takes place via listener/notifier mechanism.
In addition, many other services such as the following:
The information itself comes from the LDAP. A UCS-specific overlay module (TransLog) logs the [LDAP] transactions in the directory and transmits them to the notifier service [running on the UCS master and Backup roles]. The listener establishes a connection with the notifier and is therefore informed if relevant changes have occurred. Listeners can also be located on different systems. The most important feature is a connection between notifier and listener. The listener itself, in turn, passes the information on to those listener modules registered with it.
root@ucsma01:~# univention-directory-listener-ctrl modules
univention-directory-listener-ctrl resync modulname
root@ucsma01:~# univention-directory-listener-ctrl resync ucs-school-user-logonscript
root@ucsma01:~# univention-directory-listener-ctrl resync univention-printer-assignment root@ucsma01:~# univention-directory-listener-ctrl resync opsilistener
“univention-directory-listener-ctrl resync ucs-school-user-logonscript” regenerates all logon scripts at /var/lib/samba/netlogon/user/.
“univention-directory-listener-ctrl resync univention-printer-assignment” regenerates all VBS scripts at /var/lib/samba/netlogon/printerassignment/.
“univention-directory-listener-ctrl resync opsilistener” resynchronizes all computers from the LDAP to the opsi database.
Further possibilities can be found in the administrator manual.
root@ucsma01:~# service univention-directory-listener restart
root@ucsma01:~# ucr set listener/debug/level=XY
To demonstrate the whole process better, I would like to give you a practical example by writing a small listener module that queries a Web API in order to create teachers in a web service that previously had been created in the LDAP. A valuable source of further information here is the developer manual. I call the listener module “Web-Connector”.
1. Generally it is sufficient to start by putting a file into /usr/lib/univention-directory-listener/system/:
root@ucsma01:~# vim /usr/lib/univention-directory-listener/system/web_connector.py
2. Each listener module requires a few definitions.
name = "web_connector" description = "the Web-Connector refers to a Web-API." filter = "(objectClass=ucsschoolTeacher)" attribute = ["ucsschoolSchool", "departmentNumber:"]
3. In addition, at least one method (handler) must be implemented:
def handler(dn, new, old): pass
This already would be a “Hello World!” example and will work without problems.
1. With the following command (see also above “Helpful commands for listener modules”) you can load the listener module:
root@ucsma01:~# service univention-directory-listener restart
2. You can check this with the following command:
root@ucsma01:~# univention-directory-listener-ctrl modules [...] 0 web_connector /usr/lib/univention-directory-listener/system/web_connector.py [...]
If the listener module does not appear in the list of the modules, you should first look in the listener.log at /var/log/univention/listener.log, to find out what could be the cause.
1. In the next step I want to extend the listener module a little bit as shown in the following complete example:
__package__ = "" # workaround for PEP 366
import univention.debug as ud
import requests
name = "web_connector"
description = "Der Web-Connector spricht eine Web-API an."
filter = "(objectClass=ucsschoolTeacher)"
attribute = ["ucsschoolSchool", "departmentNumber:"]
def handler(dn, new, old):
ud.debug(ud.LISTENER, ud.ERROR, 'New teacher "%s"' % new)
ud.debug(ud.LISTENER, ud.ERROR, 'Old teacher "%s"' % old)
if new and not old:
r = requests.post("https://call.webservice.org", data={'name': new['uid'], 'type': 'teacher', 'action': 'create'})
else:
pass
For further examples, you may also look in the developer manual.
Additional links we recommend:
1. Univention Directory Listener
2. Listener/notifier domain replication
We hope that we have given you a good overview about the function of listener modules and tips on how to build them by yourself. If you have any further questions, please do not hesitate to contact us via our forum or
Michel joined Univention in January 2014, initially working in the Professional Services team as an education project manager. Here he was involved in various projects in the school administration environment. Currently, as Product Manager Education, he is responsible for the entire education sector at Univention and is working on sustainably advancing digital education in Germany. When he finds time next to family and work, his personal interests are running, football and cooking.