Client library to interact with the Univention Directory Manager (UDM) REST API.
Project description
UDM REST API Client
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: installsaiohttpsync: installsrequestscli: installspython-ldapandrequests
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eaf4266116f50574ce5768c86b12717b9e430bf4955954c0cba666735f301823
|
|
| MD5 |
911db9bf037ed41e3337ea770ac47f1a
|
|
| BLAKE2b-256 |
bed41cfd2e94db151c072720d35670b1cea1bc9d601ee3292472451aed804bd9
|
File details
Details for the file udm_rest_api_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: udm_rest_api_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc4a06a11afaa8231a7bdf81923460468130f97e8d17bd6d3806decd866ef666
|
|
| MD5 |
3a51784da1d9d55d9093709acf45fc80
|
|
| BLAKE2b-256 |
1519f8e97e62a42ef68f94b9bd96f45a53f5c29ef7da6d990adb9c4cbb98ab53
|