Skip to main content

UDM REST API Client

PyPI - Version PyPI - Python Version License - AGPLv3 linting - Ruff types - Mypy

Client library and CLI to interact with the Univention Directory Manager (UDM) REST API.

Features

  • Asynchronous and synchronous Python functions
  • Command line interface
  • Automatic handling of HTTP(S) sessions
  • Type annotations
  • Python 3.11+

Usage

Synchronous Python code

from univention.admin.rest.client import UDM

udm = UDM.http("https://10.20.30.40/univention/udm/", "Administrator", "s3cr3t")
module = udm.get("users/user")

# 1. create a user
obj = module.new()
obj.properties["username"] = "foo"
obj.properties["password"] = "univention"
obj.properties["lastname"] = "foo"
obj.save()

# 2. search for users
for result in module.search("uid=*"):
    obj = result.open()
    print(obj)
    print(obj.properties)
    print(obj.objects.groups)

# 3. get by dn
ldap_base = udm.get_ldap_base()
obj = module.get(f"uid=foo,cn=users,{ldap_base}")

# 4. get referenced objects e.g. groups
pg = obj.objects["primaryGroup"][0].open()
print(pg.dn, pg.properties)
print(obj.objects["groups"])

# 5. modify
obj.properties["description"] = "foo"
obj.save()

# 6. move to the ldap base
obj.move(ldap_base)

# 7. remove
obj.delete()

Asynchronous Python code

import asyncio
from univention.admin.rest.async_client import UDM

async def main():
    async with UDM.http("http://10.20.30.40./univention/udm/", "Administrator", "s3cr3t") as udm:
        module = await udm.get("users/user")

        # 1. create a user
        obj = await module.new()
        obj.properties["username"] = "foo"
        obj.properties["password"] = "univention"
        obj.properties["lastname"] = "foo"
        await obj.save()

        # 2. search for users
        async for result in module.search("uid=*"):
            obj = await result.open()
            print(obj)
            print(obj.properties)
            print(obj.objects.groups)

        # 3. get by dn
        ldap_base = await udm.get_ldap_base()
        obj = await module.get(f"uid=foo,cn=users,{ldap_base}")

        # 4. get referenced objects e.g. groups
        pg = await obj.objects["primaryGroup"][0].open()
        print(pg.dn, pg.properties)
        print(obj.objects["groups"])

        # 5. modify
        obj.properties["description"] = "foo"
        await obj.save()

        # 6. move to the ldap base
        await obj.move(ldap_base)

        # 7. remove
        await obj.delete()

asyncio.run(main())

Custom Request ID Generation

By default, the UDM client generates unique request IDs using uuid.uuid4().hex for each HTTP request. You can provide a custom request ID generator function to control how request IDs are created:

from univention.admin.rest.client import UDM
import time

# Custom request ID generator using timestamp and counter
counter = 0
def custom_request_id():
    global counter
    counter += 1
    return f"req-{int(time.time())}-{counter}"

# Use with synchronous client
udm = UDM.http(
    "https://10.20.30.40/univention/udm/",
    "Administrator",
    "s3cr3t",
    request_id_generator=custom_request_id
)

# Use with bearer token authentication
udm = UDM.bearer(
    "https://10.20.30.40/univention/udm/",
    "your-bearer-token",
    request_id_generator=custom_request_id
)

For asynchronous clients:

from univention.admin.rest.async_client import UDM

async def main():
    async with UDM.http(
        "http://10.20.30.40./univention/udm/",
        "Administrator",
        "s3cr3t",
        request_id_generator=lambda: f"async-{uuid.uuid4().hex[:8]}"
    ) as udm:
        # Your async code here
        pass

The request_id_generator function should return a string that will be used as the X-Request-Id header value. If the function returns None, no request ID will be added to that particular request.

Command line interface

PASS_FILE="$HOME/pw-$(date +%Y%m%d%H%M%S)"
echo "s3cr3t" > "$PASS_FILE"

udm \
  --username Administrator \
  --bindpwdfile "$PASS_FILE" \
  --uri http://10.20.30.40/univention/udm/ \
  users/user list \
  --filter uid=Administrator

rm -f "$PASS_FILE"

Instead of using udm, the CLI can also be called using python3 -m univention.admin.rest.client.

Error codes

Error codes and other details of the UDM REST API can be found in its documentation.

Installation

The dependencies for the CLI, synchronous and asynchronous clients differ. They are available separately as "extra" dependencies, to reduce your projects total dependencies. Without installing the "extra" requirements, only the common dependencies of the three interfaces will be installed, and none will be usable.

  • async: installs aiohttp
  • sync: installs requests
  • cli: installs python-ldap and requests

To install the library including the dependencies for the synchronous client via pip from PyPI run:

pip install udm-rest-api-client[sync]

To install the library including the dependencies for the asynchronous client via pip from PyPI run:

pip install udm-rest-api-client[async]

To install the CLI (incl. the required library and its dependencies):

pip install udm-rest-api-client[cli]

Multiple extras can be specified at the same time:

pip install udm-rest-api-client[async,cli,dev,sync]

CLI and pipx

If you wish to use the udm command line interface from anywhere in your system, without having to manually handle virtual environments, install it using pipx:

pipx install udm-rest-api-client[cli]
which udm
$HOME/.local/bin/udm

Testing

The tests need a UDM REST API. The CI pipeline deploys a minimal Nubus into a Kubernetes namespace with the nubus-k8s CI component and runs the tests against it.

To run them locally against any Nubus deployment:

pip install -e '.[async,sync,dev,cli]'

export UDM_URL=https://nubus.example.com/univention/udm/
export UDM_USERNAME=Administrator
export UDM_PASSWORD=s3cr3t
pytest

The tests create and delete users named foo_*. Do not run them against a production system.

Building and publishing

There is a Makefile that offers all required commands. A help text is available, when started without arguments:

$ make

clean                remove all build and Python artifacts
clean-build          remove build artifacts
clean-pyc            remove Python file artifacts
build                builds source and wheel package
publish              package and upload a release to pypi
publish-test         package and upload a release to the pypi test site
install-hatch        install 'hatch' using 'pipx'

The build system uses hatch. To install it, run make install-hatch. Then execute make publish-test to build and publish the client to https://test.pypi.org/project/udm-rest-api-client/ or make publish to publish to https://pypi.org/project/udm-rest-api-client/ .

Use prek to run pre-commit linters.

License

The UDM REST API Client is distributed under the terms of the GNU Affero General Public License v3.0 only (AGPLv3) license.

Changelog

udm-rest-api-client (0.2.0) unstable; urgency=low

  • Add methods for paginated search: Module.search_page() and Module.search_paginated()
  • Add Object.restore() to restore objects from the Recycle Bin
  • Add HTTPError.errors registry, the TooManyRequests (429) exception and Session.has_relation()
  • Return Self from UDM.http() and UDM.bearer()
  • Handle empty 204 responses in the async client
  • Increase the maximum number of response headers for aiohttp 3.13.4
  • Speed up resolving of relations
  • Deprecate the CLI option --bindpwd in favor of --bindpwdfile
  • Add docstrings to the client classes and exceptions
  • Update copyright to 2026, remove the vacancies link
  • Run the tests against a Nubus deployed into Kubernetes with the nubus-k8s CI component instead of Docker Compose
  • Switch pre-commit linting to prek
  • Build Debian packages for Debian 13 and Ubuntu 26.04, no longer for Debian 11 and Ubuntu 20.04 and 22.04

... see here for earlier changes.

Metadata

Release files for udm-rest-api-client 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for udm-rest-api-client 0.2.0
File Size Uploaded Provenance Actions
udm_rest_api_client-0.2.0.tar.gz 53.6 kB Without provenance Details for udm_rest_api_client-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for udm-rest-api-client 0.2.0
File Interpreter ABI Platform Actions
udm_rest_api_client-0.2.0-py3-none-any.whl Python 3 none any Details for udm_rest_api_client-0.2.0-py3-none-any.whl

Total release size: 93.3 kB

Release files / udm_rest_api_client-0.2.0.tar.gz

Download URL udm_rest_api_client-0.2.0.tar.gz
Size 53.6 kB
Tags Source
SHA-256 checksum
How to use checksums
59674f170ea31677c54bb66c1aa1723850cd8833ea894e8d8234dc715aaf6b52
BLAKE2b-256 checksum
How to use checksums
8dffdc219bdf2556215dc30e022fcafd05187da23a100e6ffb0d38d8a62282ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.2 {"ci":true,"cpu":"x86_64","distro":{"id":"trixie","libc":{"lib":"glibc","version":"2.41"},"name":"Debian GNU/Linux","version":"13"},"implementation":{"name":"CPython","version":"3.11.18"},"installer":{"name":"hatch","version":"1.18.2"},"openssl_version":"OpenSSL 3.5.7 9 Jun 2026","python":"3.11.18","system":{"name":"Linux","release":"6.12.100+deb13-cloud-amd64"}} HTTPX2/2.16.0

Release files / udm_rest_api_client-0.2.0-py3-none-any.whl

Download URL udm_rest_api_client-0.2.0-py3-none-any.whl
Size 39.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
106a35a78f7740e516b0c6e4ca9c9c9e5015cededd713e4c9da178f90f380dd1
BLAKE2b-256 checksum
How to use checksums
236a328405a950ed04d6e3c8518cc11c4bac382ad416d74250199ad2100cc601
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Hatch/1.18.2 {"ci":true,"cpu":"x86_64","distro":{"id":"trixie","libc":{"lib":"glibc","version":"2.41"},"name":"Debian GNU/Linux","version":"13"},"implementation":{"name":"CPython","version":"3.11.18"},"installer":{"name":"hatch","version":"1.18.2"},"openssl_version":"OpenSSL 3.5.7 9 Jun 2026","python":"3.11.18","system":{"name":"Linux","release":"6.12.100+deb13-cloud-amd64"}} HTTPX2/2.16.0

Security for udm-rest-api-client 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page