From a6e4cda0e324d22972442cb3ebf0746e86f5fbc2 Mon Sep 17 00:00:00 2001 From: Pascal Bleser Date: Wed, 8 Oct 2025 19:20:31 +0200 Subject: [PATCH] groupware: make everything also work with the built-in LDAP and IDP --- .../config/stalwart/config.toml | 4 +- devtools/deployments/opencloud_full/ldap.yml | 1 + .../deployments/opencloud_full/opencloud.yml | 3 + .../deployments/opencloud_full/stalwart.yml | 2 + services/groupware/DEVELOPER.md | 361 ++++++++++++++---- 5 files changed, 302 insertions(+), 69 deletions(-) diff --git a/devtools/deployments/opencloud_full/config/stalwart/config.toml b/devtools/deployments/opencloud_full/config/stalwart/config.toml index 4fec2d941c..e7599a6655 100644 --- a/devtools/deployments/opencloud_full/config/stalwart/config.toml +++ b/devtools/deployments/opencloud_full/config/stalwart/config.toml @@ -3,7 +3,7 @@ authentication.fallback-admin.user = "mailadmin" authentication.master.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj." authentication.master.user = "master" directory.idmldap.attributes.class = "objectClass" -directory.idmldap.attributes.description = "description" +directory.idmldap.attributes.description = "displayName" directory.idmldap.attributes.email = "mail" directory.idmldap.attributes.groups = "memberOf" directory.idmldap.attributes.name = "uid" @@ -95,7 +95,7 @@ server.socket.reuse-addr = true server.socket.reuse-port = true storage.blob = "rocksdb" storage.data = "rocksdb" -storage.directory = "ldap" +storage.directory = "%{env:STALWART_AUTH_DIRECTORY}%" storage.fts = "rocksdb" storage.lookup = "rocksdb" store.rocksdb.compression = "lz4" diff --git a/devtools/deployments/opencloud_full/ldap.yml b/devtools/deployments/opencloud_full/ldap.yml index 52b3f83e06..a874e0df95 100644 --- a/devtools/deployments/opencloud_full/ldap.yml +++ b/devtools/deployments/opencloud_full/ldap.yml @@ -24,6 +24,7 @@ services: OC_LDAP_SERVER_WRITE_ENABLED: "false" # assuming the external ldap is not writable # OC_RUN_SERVICES specifies to start all services except glauth, idm and accounts. These are replaced by external services OC_EXCLUDE_RUN_SERVICES: idm + STALWART_AUTH_DIRECTORY: "ldap" ldap-server: image: bitnamilegacy/openldap:2.6 diff --git a/devtools/deployments/opencloud_full/opencloud.yml b/devtools/deployments/opencloud_full/opencloud.yml index 1c8790dcf2..56859c2e8a 100644 --- a/devtools/deployments/opencloud_full/opencloud.yml +++ b/devtools/deployments/opencloud_full/opencloud.yml @@ -58,6 +58,9 @@ services: COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.opencloud.test} # enable to allow using the banned passwords list OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt + IDM_REVASVC_PASSWORD: "admin" + OC_LDAP_BIND_PASSWORD: "admin" + IDM_LDAPS_ADDR: 0.0.0.0:9235 volumes: - ./config/opencloud/app-registry.yaml:/etc/opencloud/app-registry.yaml - ./config/opencloud/csp.yaml:/etc/opencloud/csp.yaml diff --git a/devtools/deployments/opencloud_full/stalwart.yml b/devtools/deployments/opencloud_full/stalwart.yml index 6f6ed50664..e2e5ccd336 100644 --- a/devtools/deployments/opencloud_full/stalwart.yml +++ b/devtools/deployments/opencloud_full/stalwart.yml @@ -19,6 +19,8 @@ services: - /etc/localtime:/etc/localtime:ro - ./config/stalwart:/opt/stalwart/etc - stalwart-data:/opt/stalwart/data + environment: + STALWART_AUTH_DIRECTORY: "${STALWART_AUTH_DIRECTORY:-idmldap}" labels: - "traefik.enable=true" - "traefik.http.routers.stalwart.entrypoints=https" diff --git a/services/groupware/DEVELOPER.md b/services/groupware/DEVELOPER.md index d0dee5e1d4..be4b53b23a 100644 --- a/services/groupware/DEVELOPER.md +++ b/services/groupware/DEVELOPER.md @@ -1,18 +1,21 @@ -# Introduction +# Groupware Developer Guide -The Groupware component of OpenCloud + -* is implemented as yet another microservice within the OpenCloud framework (see `./services/groupware/`) -* is essentially providing a REST API to the OpenCloud UI clients (web, mobile) that is high-level and adapted to the needs of the UIs -* the implementation of that REST API turns those high-level APIs into lower-level [JMAP](https://jmap.io/) API calls to [Stalwart, the JMAP mail server](https://stalw.art/), using our own JMAP client library in `./pkg/jmap/` with a couple of additional RFCs used by JMAP in `./pkg/jscalendar` and `./pkg/jscontact` +## Introduction -# Repository +The Groupware component of OpenCloud is implemented as a (micro)service within the OpenCloud framework (see `./services/groupware/`). -The code lives in the same tree as the other OpenCloud backend services, albeit in the `groupware` branch, that gets rebased on `main` on a regular basis (at least once per week.) +It is essentially providing a REST API to the OpenCloud UI clients (web, mobile) that is high-level and adapted to the needs of the UIs. + +The implementation of that REST API turns those high-level APIs into lower-level [JMAP](https://jmap.io/) API calls to [Stalwart, the JMAP mail server](https://stalw.art/), using our own JMAP client library in `./pkg/jmap/` with a couple of additional RFCs used by JMAP in `./pkg/jscalendar` and `./pkg/jscontact`. + +## Repository + +The code lives in the same tree as the other OpenCloud backend services, albeit currently in the `groupware` branch, that gets rebased on `main` on a regular basis (at least once per week.) Use [the `groupware` branch](https://github.com/opencloud-eu/opencloud/tree/groupware) - ```bash cd ~/src/opencloud/ OCDIR="$PWD" @@ -21,6 +24,8 @@ git clone --branch groupware git@github.com:opencloud-eu/opencloud.git Note that setting the variable `OCDIR` is merely going to help us with keeping the instructions below as generic as possible, it is not an environment variable that is used by OpenCloud. +### Tools Repository + Also, you might want to check out these [helper scripts in opencloud-tools](https://github.com/pbleser-oc/opencloud-tools) somewhere and put that directory into your `PATH`, as it contains scripts to test and build the OpenCloud Groupware: ```bash @@ -29,24 +34,27 @@ git clone git@github.com:pbleser-oc/opencloud-tools.git ./bin echo "export PATH=\"\$PATH:$OCDIR/bin\"" >> ~/.bashrc ``` +#### Tools Prerequisites + Those scripts have the following prerequisites: + * the [`jq`](https://github.com/jqlang/jq) JSON query command-line tool to extract access tokens, * either the [httpie](https://httpie.io/cli) (`pipx install httpie`) or [`xh`](https://github.com/ducaale/xh) (`cargo install xh --locked`) command-line HTTP clients, just out of convenience as their output is much nicer than curl's * `curl` as well, to retrieve the access tokens from Keycloak (no need for nice output there) -# Running - -Since we require having a Stalwart container running at the very least, the preferred way of running OpenCloud and its adjacent services for developing the Groupware component is by using the `opencloud_full` Docker Compose setup in `$OCDIR/devtools/deployments/opencloud_full`. - ## Configuration -The default hostname domain for the containers is `.opencloud.test` +Since we require having a Stalwart container running at the very least, the preferred way of running OpenCloud and its adjacent services for developing the Groupware component is by using the `opencloud_full` Docker Compose setup in `$OCDIR/opencloud/devtools/deployments/opencloud_full/`. + +This section will explain how to configure that Docker Compose setup for the needs of the Groupware backend. ### Hosts +The default hostname domain for the containers is `.opencloud.test` + Make sure to have the following entries in your `/etc/hosts`: -```text +```ruby 127.0.0.1 cloud.opencloud.test 127.0.0.1 keycloak.opencloud.test 127.0.0.1 wopiserver.opencloud.test @@ -71,9 +79,21 @@ done \ ### Compose -It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtools/deployments/opencloud_full/.env`, making the following changes (make sure to check out [the shell command-line that automates all of that, below](#automate-env-setup)): +There are two options, either + +1. running the Groupware backend with OpenLDAP and Keycloak containers, more akin to a production setup; +2. running the Groupware backend using the built-in LDAP and OIDC services, for a minimalistic setup that uses less resources and is more likely to be found in a home lab setup. + +In either case, the Docker Compose configuration in `$OCDIR/opencloud/devtools/deployments/opencloud_full/` needs to be modified. + +#### Production Setup + + + +Edit `$OCDIR/opencloud/devtools/deployments/opencloud_full/.env`, making the following changes (make sure to check out [the shell command-line that automates all of that, below](#automate-env-setup-prod)): * change the container image to `opencloudeu/opencloud:dev`: + ```diff -OC_DOCKER_IMAGE=opencloudeu/opencloud-rolling +OC_DOCKER_IMAGE=opencloudeu/opencloud @@ -82,36 +102,42 @@ It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtoo ``` * add the `groupware` service to `START_ADDITIONAL_SERVICES`: + ```diff -START_ADDITIONAL_SERVICES="notifications" +START_ADDITIONAL_SERVICES="notifications,groupware" ``` * enable the OpenLDAP container: + ```diff -#LDAP=:ldap.yml +LDAP=:ldap.yml ``` * enable the Keycloak container: + ```diff -#KEYCLOAK=:keycloak.yml +KEYCLOAK=:keycloak.yml ``` * enable the Stalwart container: + ```diff -#STALWART=:stalwart.yml +STALWART=:stalwart.yml ``` * optionally disable the Collabora container + ```diff -COLLABORA=:collabora.yml +#COLLABORA=:collabora.yml ``` * optionally disable UI containers + ```diff -UNZIP=:web_extensions/unzip.yml -DRAWIO=:web_extensions/drawio.yml @@ -125,7 +151,7 @@ It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtoo +#EXTERNALSITES=:web_extensions/externalsites.yml ``` - + All those changes above can be automated with the following script: ```bash @@ -133,14 +159,122 @@ cd "$OCDIR/opencloud/devtools/deployments/opencloud_full/" perl -pi -e ' s|^(OC_DOCKER_IMAGE)=.*$|$1=opencloudeu/opencloud|; s|^(OC_DOCKER_TAG)=.*$|$1=dev|; - s|^(START_ADDITIONAL_SERVICES=".*)"|$1,groupware"|; - s|^([A-Z]+=:web_extensions/.*yml)$|#$1|; - s,^(COLLABORA)=(.+)$,#$1=$2,; + s|^(START_ADDITIONAL_SERVICES=".*(? + +Edit `$OCDIR/opencloud/devtools/deployments/opencloud_full/.env`, making the following changes (make sure to check out [the shell command-line that automates all of that, below](#automate-env-setup-homelab)): + +* change the container image to `opencloudeu/opencloud:dev`: + +```diff +-OC_DOCKER_IMAGE=opencloudeu/opencloud-rolling ++OC_DOCKER_IMAGE=opencloudeu/opencloud +-OC_DOCKER_TAG= ++OC_DOCKER_TAG=dev +``` + +* enable the creation of demo users: + +```diff +-DEMO_USERS= ++DEMO_USERS=true +``` + +* add the `groupware` service to `START_ADDITIONAL_SERVICES`: + +```diff +-START_ADDITIONAL_SERVICES="notifications" ++START_ADDITIONAL_SERVICES="notifications,groupware" +``` + +* enable the Stalwart container: + +```diff +-#STALWART=:stalwart.yml ++STALWART=:stalwart.yml +``` + +* while not required, it is recommended to enable basic authentication support which, while less secure, allows for easier tooling when developing and testing HTTP APIs, by adding `PROXY_ENABLE_BASIC_AUTH=true` somewhere before the last line of the `.env` file: + +```diff + # Domain of Stalwart + # Defaults to "stalwart.opencloud.test" + STALWART_DOMAIN= + ++# Enable basic authentication to facilitate HTTP API testing ++# Do not do this in production. ++PROXY_ENABLE_BASIC_AUTH=true ++ + ## IMPORTANT ## +``` + +* optionally disable the Collabora container + +```diff +-COLLABORA=:collabora.yml ++#COLLABORA=:collabora.yml +``` + +* optionally disable UI containers + +```diff +-UNZIP=:web_extensions/unzip.yml +-DRAWIO=:web_extensions/drawio.yml +-JSONVIEWER=:web_extensions/jsonviewer.yml +-PROGRESSBARS=:web_extensions/progressbars.yml +-EXTERNALSITES=:web_extensions/externalsites.yml ++#UNZIP=:web_extensions/unzip.yml ++#DRAWIO=:web_extensions/drawio.yml ++#JSONVIEWER=:web_extensions/jsonviewer.yml ++#PROGRESSBARS=:web_extensions/progressbars.yml ++#EXTERNALSITES=:web_extensions/externalsites.yml +``` + + +All those changes above can be automated with the following script: + +```bash +cd "$OCDIR/opencloud/devtools/deployments/opencloud_full/" +perl -pi -e ' + BEGIN{$basic_auth=0} + s|^(OC_DOCKER_IMAGE)=.*$|$1=opencloudeu/opencloud|; + s|^(OC_DOCKER_TAG)=.*$|$1=dev|; + s|^(START_ADDITIONAL_SERVICES=".*(?Bind DN: `cn=admin,dc=opencloud,dc=eu` +* Bind Password: `admin` +* Base DN: `ou=users,dc=opencloud,dc=eu` +* Host: `localhost` +* LDAP Port: `389` +* LDAPS Port: `636` + Run the following command on your host (requires the `ldap-tools` package with the `ldapsearch` CLI tool), which should output a list of DNs of demo users: + ```bash -ldapsearch -h localhost -D 'cn=admin,dc=opencloud,dc=eu' -x -w 'admin' -b 'ou=users,dc=opencloud,dc=eu' -LLL '(objectClass=person)' dn +ldapsearch -h localhost -D 'cn=admin,dc=opencloud,dc=eu' \ +-x -w 'admin' -b 'ou=users,dc=opencloud,dc=eu' -LLL \ +'(objectClass=person)' dn ``` Sample output: -```text + +```ldif dn: uid=alan,ou=users,dc=opencloud,dc=eu dn: uid=lynn,ou=users,dc=opencloud,dc=eu @@ -198,20 +353,82 @@ dn: uid=margaret,ou=users,dc=opencloud,dc=eu ``` -### Keycloak +#### Homelab Setup LDAP + +Instead, when using the “homelab” setup (as depicted in section [Homelab Setup](#homelab-setup) above), queries cannot be performed directly from the host \ +but, instead, require spinning up another container in the same Docker network and do so from there. + +The necessary LDAP parameters are as follows: + +* Bind DN: `uid=libregraph,ou=sysusers,o=libregraph-idm` +* Bind Password: `admin` (or whichever password is set in the `IDM_REVASVC_PASSWORD` environment variable in `opencloud.yml`) +* Base DN: `o=libregraph-idm` or `` +* Host: `localhost` +* LDAP Port: none, only supports LDAPS +* LDAPS Port: `9235` + +To access the LDAP tree, spawn a new container in the same network, e.g. like this for a Debian 12 container: -To check whether it works correctly: ```bash -curl -ks -D- -X POST "https://keycloak.opencloud.test/realms/openCloud/protocol/openid-connect/token" -d username=alan -d password=demo -d grant_type=password -d client_id=groupware -d scope=openid +docker run --network 'opencloud_full_opencloud-net' --rm \ +--name "debian-${RANDOM}" -ti 'debian:12' ``` -should provide you with a JSON response that contains an `access_token`. + +In that container, install the necessary packages to have the LDAP command-line tools: + +```bash +apt-get update -y && apt-get install -y ca-certificates ldap-utils +``` + +Run the following command in that container, which should output a list of DNs of demo users: + +```bash +LDAPTLS_REQCERT=never ldapsearch -H ldaps://opencloud:9235 \ +-D 'uid=reva,ou=sysusers,o=libregraph-idm' -x -w 'admin' \ +-b 'o=libregraph-idm' -LLL \ +'(objectClass=person)' dn +``` + +Sample output: + +```ldif +dn: uid=admin,ou=users,o=libregraph-idm + +dn: uid=alan,ou=users,o=libregraph-idm + +dn: uid=lynn,ou=users,o=libregraph-idm + +dn: uid=mary,ou=users,o=libregraph-idm + +dn: uid=margaret,ou=users,o=libregraph-idm + +dn: uid=dennis,ou=users,o=libregraph-idm + +``` + +### Testing Keycloak + +> [!NOTE] +> Only available in the [“production” setup](#prod-setup) + +To check whether it works correctly, the following `curl` command: + +```bash +curl -ks -D- -X POST \ +"https://keycloak.opencloud.test/realms/openCloud/protocol/openid-connect/token" \ +-d username=alan -d password=demo -d grant_type=password \ +-d client_id=groupware -d scope=openid +``` + +should provide you with a JSON response that contains an `access_token` property. If it is not set up correctly, it should give you this instead: + ```json {"error":"invalid_client","error_description":"Invalid client or Invalid client credentials"} ``` -### Stalwart +### Testing Stalwart To then test the IMAP authentication with Stalwart, run the following command on your host (requires the `openssl` CLI tool): @@ -220,17 +437,20 @@ openssl s_client -crlf -connect localhost:993 ``` When then greeted with the following prompt: -```text + +```java * OK [CAPABILITY ...] Stalwart IMAP4rev2 at your service. ``` enter the following command: -```text + +```bash A LOGIN alan demo ``` to which one should receive the following response: -```text + +```java A OK [CAPABILITY IMAP4rev2 ...] Authentication successful ``` @@ -241,17 +461,25 @@ Once a [Stalwart](https://stalw.art/) container is running (using the Docker Com ```bash cd "$OCDIR/" git clone git@github.com:opencloud-eu/imap-filler.git -cd ./imap-filler -go run . --empty=true --username=alan --password=demo \ ---url=localhost:993 --folder=Inbox --senders=3 --count=20 +cd ./imap-filler/ +go run . --username=alan --password=demo \ + --url=localhost:993 \ + --empty=true \ + --folder=Inbox \ + --senders=6 \ + --count=50 ``` +> [!NOTE] +> Note that this operation does not use the Groupware APIs or any other OpenCloud backend services either, +> as it directly communicates with Stalwart via IMAPS on port `993` which is mapped on the host. + For more details on the usage of that little helper tool, consult its [`README.md`](https://github.com/opencloud-eu/imap-filler/blob/main/README.md), although it is quite self-explanatory. > [!NOTE] > This only needs to be done once, since the emails are stored in a volume used by the Stalwart container. -# Building +## Building after Changes If you run the `opencloud` service as a container, use the following script to update the container image and restart it: @@ -270,7 +498,7 @@ docker compose up -d opencloud If you run it from your IDE, there is obviously no need to do that. -# API Docs +## API Docs The REST API documentation is extracted from the source code structure and documentation using [`go-swagger`](https://goswagger.io/go-swagger/), which needs to be installed locally as a prerequisite: @@ -293,7 +521,7 @@ firefox ./api.html Note that `redocly-cli` does not need to be installed, it will be pulled locally by the `Makefile`, provided that you have [pnpm](https://pnpm.io/) installed as a pre-requisite, which is already necessary for other OpenCloud components. -# Testing +## Testing This section assumes that you are using the [helper scripts in opencloud-tools](https://github.com/pbleser-oc/opencloud-tools) as instructed above. @@ -304,12 +532,17 @@ export baseurl=https://localhost:9200 ``` The scripts default to using the user `alan` (with the password `demo`), which can be changed by setting the following environment variables: + * `username` * `password` Your main swiss army knife tool will be `oc-gw` (mnemonic for "OpenCloud Groupware"), which -* always retrieves an access token from Keycloak, using the credentials defined in the environment variables `username` and `password` (defaulting to `adam`/`demo`), using the "Direct Access Grant" OIDC or "Resource Owner Password Credentials Grant" OAuth2 flow -* and then use that JWT for Bearer authentication against the OpenCloud Groupware REST API + +* checks whether a container named `opencloud_full-opencloud-1` is running locally + * if so, whether it has basic auth enabled or not + * if yes, uses basic auth directly to authenticate against the OpenCloud Proxy service that ingresses for the OpenCloud Groupware backend, using the credentials defined in the environment variables `username` and `password` (defaulting to `alan`/`demo`) + * if not, always retrieves a fresh access token from Keycloak, using the credentials defined in the environment variables `username` and `password` (defaulting to `alan`/`demo`), using the "Direct Access Grant" OIDC API of Keycloak and then use that JWT for Bearer authentication against the OpenCloud Groupware REST API + * if no such container is running locally, it assumes that the `opencloud` process is running from within an IDE, with its OpenCloud Proxy service listening on `https://localhost:9200` It will also save you some typing as whenever you use `//` for the URL, it will replace that by the Groupware REST API base URL, e.g. @@ -333,10 +566,14 @@ Obviously, you may use whichever HTTP client you are most comfortable with. Here is how to do it without the `oc-gw` script, using [`curl`](https://curl.se/): -First, make sure to retrieve a JWT for authentication from Keycloak: +When using the “production” setup, first make sure to retrieve a JWT for authentication from Keycloak: ```bash -token=$(curl --silent --insecure --fail -X POST "https://keycloak.opencloud.test/realms/openCloud/protocol/openid-connect/token" -d username="alan" -d password="demo" -d grant_type=password -d client_id="groupware" -d scope=openid | jq -r '.access_token') +token=$(curl --silent --insecure --fail -X POST \ +"https://keycloak.opencloud.test/realms/openCloud/protocol/openid-connect/token" \ +-d username="alan" -d password="demo" \ +-d grant_type=password -d client_id="groupware" -d scope=openid \ +| jq -r '.access_token') ``` Then use that token to authenticate the Groupware API request: @@ -345,61 +582,51 @@ Then use that token to authenticate the Groupware API request: curl --insecure -s -H "Authorization: Bearer ${token}" "https://cloud.opencloud.test/groupware/" ``` +When using the “homelab” setup, authenticate directly using basic auth: + +```bash +curl --insecure -s -u "alan:demo" "https://cloud.opencloud.test/groupware/" +``` + > [!TIP] -> Until everything is documented, the complete list of URI routes can be found in `$OCDIR/opencloud/services/groupware/pkg/groupware/groupware_route.go` +> Until everything is documented, the complete list of URI routes can be found in \ +[`$OCDIR/opencloud/services/groupware/pkg/groupware/groupware_route.go`](./pkg/groupware/groupware_route.go) -# Services +## Services -## Stalwart +### Stalwart -### Web UI +#### Web UI To access the Stalwart admin UI, open and use the following credentials to log in: + * username: `mailadmin` * password: `admin` The usual admin username `admin` had to be changed into `mailadmin` because there is already an `admin` user that ships with the default users in OpenCloud, and Stalwart always checks the LDAP directory before its internal usernames. Those credentials are configured in `devtools/deployments/opencloud_full/config/stalwart/config.toml`: + ```ruby authentication.fallback-admin.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj." authentication.fallback-admin.user = "mailadmin" ``` -### Restart from Scratch +#### Restart from Scratch To start with a Stalwart container from scratch, removing all the data (including emails): ```bash cd "$OCDIR/opencloud/devtools/deployments/opencloud_full" -docker compose stop stalwart -docker compose rm stalwart +docker compose rm stalwart --stop docker volume rm opencloud_full_stalwart-data docker compose up -d stalwart ``` -### Diagnostics +#### Diagnostics If anything goes wrong, the first thing to check is Stalwart's logs, that are configured on the most verbose level (trace) and should thus provide a lot of insight: ```bash docker logs -f opencloud_full-stalwart-1 ``` - -## OpenLDAP - -The `opencloud_full-ldap-server-1` container exports the ports 389 (LDAP) and 636 (LDAPS) on the host. - -To access the LDAP tree: -* Host: `localhost` -* Port: `389` -* Bind DN: `cn=admin,dc=opencloud,dc=eu` -* Password: `admin` -* Base DN: `dc=opencloud,dc=eu` - -As an example, to list all the users, using the `ldap-tools` on your host: - -```bash -ldapsearch -h localhost -D 'cn=admin,dc=opencloud,dc=eu' -x -w 'admin' -b 'ou=users,dc=opencloud,dc=eu' -LLL '(objectClass=person)' -``` -