Skip to main content

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

Project description

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

Using Docker Compose

docker compose -f tests/docker-compose.yml run --rm test
docker compose -f tests/docker-compose.yml down -v

Locally

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

docker compose -f tests/docker-compose.yml up -d ldap-server udm-rest-api

export UDM_URL=http://127.0.0.1:9979/udm/
pytest

docker compose -f tests/docker-compose.yml down -v

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/ .

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.1.0) unstable; urgency=low

  • Require Python 3.11, support PEP 585 type hints
  • Standardize linter configuration
  • update copyright to 2025
  • Replace %-formatting with format() and f-strings
  • Run mypy with strict=false.
  • Connect to new SonarQube server
  • Add tests for the example code in the README.
  • No code changes in UCS repo between 12.0.7 (initial import) and 12.2.0.

... see here for earlier changes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

udm_rest_api_client-0.1.0.tar.gz (59.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

udm_rest_api_client-0.1.0-py3-none-any.whl (37.8 kB view details)

Uploaded Python 3

File details

Details for the file udm_rest_api_client-0.1.0.tar.gz.

File metadata

  • Download URL: udm_rest_api_client-0.1.0.tar.gz
  • Upload date:
  • Size: 59.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for udm_rest_api_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 eaf4266116f50574ce5768c86b12717b9e430bf4955954c0cba666735f301823
MD5 911db9bf037ed41e3337ea770ac47f1a
BLAKE2b-256 bed41cfd2e94db151c072720d35670b1cea1bc9d601ee3292472451aed804bd9

See more details on using hashes here.

File details

Details for the file udm_rest_api_client-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for udm_rest_api_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cc4a06a11afaa8231a7bdf81923460468130f97e8d17bd6d3806decd866ef666
MD5 3a51784da1d9d55d9093709acf45fc80
BLAKE2b-256 1519f8e97e62a42ef68f94b9bd96f45a53f5c29ef7da6d990adb9c4cbb98ab53

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page