Repository: owncloud/ocis
Pull request #3223 (2022-02-23 06:21:05)

Bump github.com/owncloud/libre-graph-api-go from 0.10.0 to 0.11.0
Bumps [github.com/owncloud/libre-graph-api-go](https://github.com/owncloud/libre-graph-api-go) from 0.10.0 to 0.11.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/owncloud/libre-graph-api-go/releases">github.com/owncloud/libre-graph-api-go's releases</a>.</em></p>
<blockquote>
<h2>v0.11.0</h2>
<p><strong>Full Changelog</strong>: <a href="https://github.com/owncloud/libre-graph-api-go/compare/v0.10.0...v0.11.0">https://github.com/owncloud/libre-graph-api-go/compare/v0.10.0...v0.11.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/owncloud/libre-graph-api-go/commit/15fca8bd8753031d04ac089392b828c11f3685c6"><code>15fca8b</code></a> Bump version</li>
<li><a href="https://github.com/owncloud/libre-graph-api-go/commit/e47b801b8dcdfcc62fb6be17e4c48fbdc533d2e7"><code>e47b801</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/owncloud/libre-graph-api-go/issues/27">#27</a> from owncloud/fix/missing-comments</li>
<li><a href="https://github.com/owncloud/libre-graph-api-go/commit/a3b3ecf97fdc58bff4093c38b07ed0e12e63bbab"><code>a3b3ecf</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/owncloud/libre-graph-api-go/issues/31">#31</a> from owncloud/add-order-by</li>
<li>See full diff in <a href="https://github.com/owncloud/libre-graph-api-go/compare/v0.10.0...v0.11.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/owncloud/libre-graph-api-go&package-manager=go_modules&previous-version=0.10.0&new-version=0.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.drone.env b/.drone.env
index ef054361862..40dac482000 100644
--- a/.drone.env
+++ b/.drone.env
@@ -1,5 +1,5 @@
 # The test runner source for API tests
-CORE_COMMITID=a0a4064c77a3576763885f83d57ca4c558348b8c
+CORE_COMMITID=87e97eb1a9b4795a72c5dcc94515b5b86b947274
 CORE_BRANCH=master
 
 # The test runner source for UI tests
diff --git a/.drone.star b/.drone.star
index f0f0991d8ef..ee45183affc 100644
--- a/.drone.star
+++ b/.drone.star
@@ -1674,6 +1674,7 @@ def example_deploys(ctx):
         "ocis_hello/latest.yml",
         "ocis_s3/latest.yml",
         "oc10_ocis_parallel/latest.yml",
+        "ocis_individual_services/latest.yml",
     ]
     released_configs = [
         "ocis_ldap/released.yml",
diff --git a/.make/go.mk b/.make/go.mk
index 2ac312ceed0..b2af851fdca 100644
--- a/.make/go.mk
+++ b/.make/go.mk
@@ -74,7 +74,7 @@ ci-golangci-lint: $(GOLANGCI_LINT)
 
 .PHONY: test
 test:
-	@go test -v -coverprofile coverage.out ./...
+	@go test -v -tags '$(TAGS)' -coverprofile coverage.out ./...
 
 .PHONY: go-coverage
 go-coverage:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7521041455a..f8c6666488e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,15 +6,29 @@ The following sections list the changes for unreleased.
 
 ## Summary
 
+* Bugfix - Capabilities for password protected public links: [#3229](https://github.com/owncloud/ocis/pull/3229)
 * Bugfix - Make events settings configurable: [#3214](https://github.com/owncloud/ocis/pull/3214)
 * Bugfix - Align storage metadata GPRC bind port with other variable names: [#3169](https://github.com/owncloud/ocis/pull/3169)
 * Change - Unify file IDs: [#3185](https://github.com/owncloud/ocis/pull/3185)
 * Enhancement - Add sorting to list Spaces: [#3200](https://github.com/owncloud/ocis/issues/3200)
 * Enhancement - Change NATS port: [#3210](https://github.com/owncloud/ocis/pull/3210)
+* Enhancement - Re-Enabling web cache control: [#3109](https://github.com/owncloud/ocis/pull/3109)
+* Enhancement - Add SPA conform fileserver for web: [#3109](https://github.com/owncloud/ocis/pull/3109)
+* Enhancement - Implement notifications service: [#3217](https://github.com/owncloud/ocis/pull/3217)
+* Enhancement - Thumbnails in spaces: [#3219](https://github.com/owncloud/ocis/pull/3219)
+* Enhancement - Update reva to v1.16.1-0.20220224114254-d4ffaf323e70: [#3231](https://github.com/owncloud/ocis/pull/3231)
 * Enhancement - Update ownCloud Web to v5.1.0: [#3202](https://github.com/owncloud/ocis/pull/3202)
 
 ## Details
 
+* Bugfix - Capabilities for password protected public links: [#3229](https://github.com/owncloud/ocis/pull/3229)
+
+   Allow password protected public links to request capabilities.
+
+   https://github.com/owncloud/web/issues/5863
+   https://github.com/owncloud/ocis/pull/3229
+   https://github.com/owncloud/web/pull/6471
+
 * Bugfix - Make events settings configurable: [#3214](https://github.com/owncloud/ocis/pull/3214)
 
    We've fixed the hardcoded events settings to be configurable.
@@ -56,6 +70,41 @@ The following sections list the changes for unreleased.
 
    https://github.com/owncloud/ocis/pull/3210
 
+* Enhancement - Re-Enabling web cache control: [#3109](https://github.com/owncloud/ocis/pull/3109)
+
+   We've re-enable browser caching headers (`Expires` and `Last-Modified`) for the web
+   service, this was disabled due to a problem in the fileserver used before. Since we're now using
+   our own fileserver implementation this works again and is enabled by default.
+
+   https://github.com/owncloud/ocis/pull/3109
+
+* Enhancement - Add SPA conform fileserver for web: [#3109](https://github.com/owncloud/ocis/pull/3109)
+
+   We've added an SPA conform fileserver to the web service. It enables web to use vue's history
+   mode and behaves like nginx try_files.
+
+   https://github.com/owncloud/ocis/pull/3109
+
+* Enhancement - Implement notifications service: [#3217](https://github.com/owncloud/ocis/pull/3217)
+
+   Implemented the minimal version of the notifications service to be able to notify a user when
+   they received a share.
+
+   https://github.com/owncloud/ocis/pull/3217
+
+* Enhancement - Thumbnails in spaces: [#3219](https://github.com/owncloud/ocis/pull/3219)
+
+   Added support for thumbnails in spaces.
+
+   https://github.com/owncloud/ocis/pull/3219
+   https://github.com/owncloud/ocis/pull/3235
+
+* Enhancement - Update reva to v1.16.1-0.20220224114254-d4ffaf323e70: [#3231](https://github.com/owncloud/ocis/pull/3231)
+
+   We updated reva to the latest edge branch. Changelog will follow.
+
+   https://github.com/owncloud/ocis/pull/3231
+
 * Enhancement - Update ownCloud Web to v5.1.0: [#3202](https://github.com/owncloud/ocis/pull/3202)
 
    Tags: web
diff --git a/changelog/unreleased/enhancement-web-cache-control.md b/changelog/unreleased/enhancement-web-cache-control.md
new file mode 100644
index 00000000000..ff64ff0b9e7
--- /dev/null
+++ b/changelog/unreleased/enhancement-web-cache-control.md
@@ -0,0 +1,6 @@
+Enhancement: Re-Enabling web cache control
+
+We've re-enable browser caching headers (`Expires` and `Last-Modified`) for the web service, this was disabled due to a problem in the fileserver used before.
+Since we're now using our own fileserver implementation this works again and is enabled by default.
+
+https://github.com/owncloud/ocis/pull/3109
diff --git a/changelog/unreleased/enhancement-web-spa-fileserver.md b/changelog/unreleased/enhancement-web-spa-fileserver.md
new file mode 100644
index 00000000000..dad95f59eec
--- /dev/null
+++ b/changelog/unreleased/enhancement-web-spa-fileserver.md
@@ -0,0 +1,6 @@
+Enhancement: Add SPA conform fileserver for web
+
+We've added an SPA conform fileserver to the web service.
+It enables web to use vue's history mode and behaves like nginx try_files.
+
+https://github.com/owncloud/ocis/pull/3109
diff --git a/changelog/unreleased/fix-capabilities-for-public-links.md b/changelog/unreleased/fix-capabilities-for-public-links.md
new file mode 100644
index 00000000000..c1546a4376a
--- /dev/null
+++ b/changelog/unreleased/fix-capabilities-for-public-links.md
@@ -0,0 +1,7 @@
+Bugfix: Capabilities for password protected public links
+
+Allow password protected public links to request capabilities.
+
+https://github.com/owncloud/ocis/pull/3229
+https://github.com/owncloud/web/pull/6471
+https://github.com/owncloud/web/issues/5863
diff --git a/changelog/unreleased/notifications-service.md b/changelog/unreleased/notifications-service.md
new file mode 100644
index 00000000000..a6bc56932fa
--- /dev/null
+++ b/changelog/unreleased/notifications-service.md
@@ -0,0 +1,5 @@
+Enhancement: Implement notifications service
+
+Implemented the minimal version of the notifications service to be able to notify a user when they received a share.
+
+https://github.com/owncloud/ocis/pull/3217
diff --git a/changelog/unreleased/spaces-thumbnails.md b/changelog/unreleased/spaces-thumbnails.md
new file mode 100644
index 00000000000..d0aca360e53
--- /dev/null
+++ b/changelog/unreleased/spaces-thumbnails.md
@@ -0,0 +1,6 @@
+Enhancement: Thumbnails in spaces
+
+Added support for thumbnails in spaces.
+
+https://github.com/owncloud/ocis/pull/3219
+https://github.com/owncloud/ocis/pull/3235
diff --git a/changelog/unreleased/update-reva.md b/changelog/unreleased/update-reva.md
new file mode 100644
index 00000000000..2e5e87224f7
--- /dev/null
+++ b/changelog/unreleased/update-reva.md
@@ -0,0 +1,5 @@
+Enhancement: Update reva to v1.16.1-0.20220224114254-d4ffaf323e70
+
+We updated reva to the latest edge branch. Changelog will follow.
+
+https://github.com/owncloud/ocis/pull/3231
diff --git a/deployments/continuous-deployment-config/ocis_keycloak/released.yml b/deployments/continuous-deployment-config/ocis_keycloak/released.yml
index 173063e60a3..5c5f38e7997 100644
--- a/deployments/continuous-deployment-config/ocis_keycloak/released.yml
+++ b/deployments/continuous-deployment-config/ocis_keycloak/released.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_ldap/released.yml b/deployments/continuous-deployment-config/ocis_ldap/released.yml
index c59d000a942..06a6125ecc3 100644
--- a/deployments/continuous-deployment-config/ocis_ldap/released.yml
+++ b/deployments/continuous-deployment-config/ocis_ldap/released.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_traefik/released.yml b/deployments/continuous-deployment-config/ocis_traefik/released.yml
index 99998642445..93053a7c5b1 100644
--- a/deployments/continuous-deployment-config/ocis_traefik/released.yml
+++ b/deployments/continuous-deployment-config/ocis_traefik/released.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_wopi/released.yml b/deployments/continuous-deployment-config/ocis_wopi/released.yml
index 6dd9a23e509..701583d592f 100644
--- a/deployments/continuous-deployment-config/ocis_wopi/released.yml
+++ b/deployments/continuous-deployment-config/ocis_wopi/released.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/examples/ocis_individual_services/.env b/deployments/examples/ocis_individual_services/.env
new file mode 100644
index 00000000000..df4a4d90a45
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/.env
@@ -0,0 +1,36 @@
+# If you're on a internet facing server please comment out following line.
+# It skips certificate validation for various parts of oCIS and is needed if you use self signed certificates.
+INSECURE=true
+
+### Traefik settings ###
+# Serve Treafik dashboard. Defaults to "false".
+TRAEFIK_DASHBOARD=
+# Domain of Traefik, where you can find the dashboard. Defaults to "traefik.owncloud.test"
+TRAEFIK_DOMAIN=
+# Basic authentication for the dashboard. Defaults to user "admin" and password "admin"
+TRAEFIK_BASIC_AUTH_USERS=
+# Email address for obtaining LetsEncrypt certificates, needs only be changed if this is a public facing server
+TRAEFIK_ACME_MAIL=
+
+### oCIS settings ###
+# oCIS version. Defaults to "latest"
+OCIS_DOCKER_TAG=
+# Domain of oCIS, where you can find the frontend. Defaults to "ocis.owncloud.test"
+OCIS_DOMAIN=
+# IDP LDAP bind password. Must be changed in order to have a secure oCIS. Defaults to "idp".
+IDP_LDAP_BIND_PASSWORD=
+# Storage LDAP bind password. Must be changed in order to have a secure oCIS. Defaults to "reva".
+STORAGE_LDAP_BIND_PASSWORD=
+# JWT secret which is used for the storage provider. Must be changed in order to have a secure oCIS. Defaults to "Pive-Fumkiu4"
+OCIS_JWT_SECRET=
+# JWT secret which is used for uploads to create transfer tokens. Must be changed in order to have a secure oCIS. Defaults to "replace-me-with-a-transfer-secret"
+STORAGE_TRANSFER_SECRET=
+# Machine auth api key secret. Must be changed in order to have a secure oCIS. Defaults to "change-me-please"
+OCIS_MACHINE_AUTH_API_KEY=
+# Number of services to run for extensions, that currently can be easily scaled. Defaults to 1.
+OCIS_SCALE=
+
+# If you want to use debugging and tracing with this stack,
+# you need uncomment following line. Please see documentation at
+# https://owncloud.dev/ocis/deployment/monitoring-tracing/
+#COMPOSE_FILE=docker-compose.yml:monitoring_tracing/docker-compose-additions.yml
diff --git a/deployments/examples/ocis_individual_services/README.md b/deployments/examples/ocis_individual_services/README.md
new file mode 100644
index 00000000000..3f5f4047807
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/README.md
@@ -0,0 +1,6 @@
+---
+document this deployment example in: docs/ocis/deployment/ocis_individual_services.md
+---
+
+Please refer to [our documentation](https://owncloud.dev/ocis/deployment/ocis_individual_services/)
+for instructions on how to deploy this scenario.
diff --git a/deployments/examples/ocis_individual_services/config/accounts/entrypoint-override.sh b/deployments/examples/ocis_individual_services/config/accounts/entrypoint-override.sh
new file mode 100755
index 00000000000..4b890128c06
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/config/accounts/entrypoint-override.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+set -e
+
+ocis accounts server&
+sleep 10
+
+echo "##################################################"
+echo "change default secrets:"
+
+# IDP
+IDP_USER_UUID=$(ocis accounts list | grep "| Kopano IDP " | egrep '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}' -o)
+echo "  IDP user UUID: $IDP_USER_UUID"
+ocis accounts update --password $IDP_LDAP_BIND_PASSWORD $IDP_USER_UUID
+
+# REVA
+REVA_USER_UUID=$(ocis accounts list | grep " | Reva Inter " | egrep '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}' -o)
+echo "  Reva user UUID: $REVA_USER_UUID"
+ocis accounts update --password $STORAGE_LDAP_BIND_PASSWORD $REVA_USER_UUID
+
+echo "default secrets changed"
+echo "##################################################"
+
+wait # wait for accounts service to exit
diff --git a/deployments/examples/ocis_individual_services/config/proxy/proxy.json b/deployments/examples/ocis_individual_services/config/proxy/proxy.json
new file mode 100644
index 00000000000..3874ceff194
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/config/proxy/proxy.json
@@ -0,0 +1,103 @@
+{
+  "HTTP": {
+    "Namespace": "com.owncloud"
+  },
+  "policy_selector": {
+    "static": {
+      "policy": "ocis"
+    }
+  },
+  "policies": [
+    {
+      "name": "ocis",
+      "routes": [
+        {
+          "endpoint": "/",
+          "backend": "http://web:9100"
+        },
+        {
+          "endpoint": "/.well-known/",
+          "backend": "http://idp:9130"
+        },
+        {
+          "endpoint": "/konnect/",
+          "backend": "http://idp:9130"
+        },
+        {
+          "endpoint": "/signin/",
+          "backend": "http://idp:9130"
+        },
+        {
+          "type": "regex",
+          "endpoint": "/ocs/v[12].php/cloud/(users?|groups)",
+          "backend": "http://ocs:9110"
+        },
+        {
+          "endpoint": "/ocs/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "type": "query",
+          "endpoint": "/remote.php/?preview=1",
+          "backend": "http://webdav:9115"
+        },
+        {
+          "endpoint": "/remote.php/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/dav/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/webdav/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/status.php",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/index.php/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/data",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/app/",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/archiver",
+          "backend": "http://storage-frontend:9140"
+        },
+        {
+          "endpoint": "/graph/",
+          "backend": "http://graph:9120"
+        },
+        {
+          "endpoint": "/graph-explorer/",
+          "backend": "http://graph-explorer:9135"
+        },
+        {
+          "endpoint": "/api/v0/accounts",
+          "backend": "http://accounts:9181"
+        },
+        {
+          "endpoint": "/accounts.js",
+          "backend": "http://accounts:9181"
+        },
+        {
+          "endpoint": "/api/v0/settings",
+          "backend": "http://settings:9190"
+        },
+        {
+          "endpoint": "/settings.js",
+          "backend": "http://settings:9190"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/deployments/examples/ocis_individual_services/docker-compose.yml b/deployments/examples/ocis_individual_services/docker-compose.yml
new file mode 100644
index 00000000000..27ec4754325
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/docker-compose.yml
@@ -0,0 +1,734 @@
+---
+version: "3.7"
+
+services:
+  traefik:
+    image: traefik:v2.5
+    networks:
+      ocis-net:
+        aliases:
+          - ${OCIS_DOMAIN:-ocis.owncloud.test}
+    command:
+      - "--log.level=${TRAEFIK_LOG_LEVEL:-ERROR}"
+      # letsencrypt configuration
+      - "--certificatesResolvers.http.acme.email=${TRAEFIK_ACME_MAIL:-example@example.org}"
+      - "--certificatesResolvers.http.acme.storage=/certs/acme.json"
+      - "--certificatesResolvers.http.acme.httpChallenge.entryPoint=http"
+      # enable dashboard
+      - "--api.dashboard=true"
+      # define entrypoints
+      - "--entryPoints.http.address=:80"
+      - "--entryPoints.http.http.redirections.entryPoint.to=https"
+      - "--entryPoints.http.http.redirections.entryPoint.scheme=https"
+      - "--entryPoints.https.address=:443"
+      # docker provider (get configuration from container labels)
+      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
+      - "--providers.docker.exposedByDefault=false"
+    ports:
+      - "80:80"
+      - "443:443"
+    volumes:
+      - "/var/run/docker.sock:/var/run/docker.sock:ro"
+      - "traefik-certs:/certs"
+    labels:
+      - "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
+      - "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
+      - "traefik.http.routers.traefik.entrypoints=https"
+      - "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
+      - "traefik.http.routers.traefik.middlewares=traefik-auth"
+      - "traefik.http.routers.traefik.tls.certresolver=http"
+      - "traefik.http.routers.traefik.service=api@internal"
+    logging:
+      driver: "local"
+    restart: always
+
+  proxy:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - proxy
+      - server
+    environment:
+      PROXY_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      PROXY_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      PROXY_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      PROXY_TLS: "false" # do not use SSL between Traefik and oCIS
+
+      REVA_GATEWAY: storage-gateway:9142
+
+      PROXY_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      PROXY_MACHINE_AUTH_API_KEY: ${OCIS_MACHINE_AUTH_API_KEY:-change-me-please}
+      PROXY_INSECURE_BACKENDS: "false"
+
+      PROXY_OIDC_INSECURE: "${INSECURE:-false}"
+      PROXY_OIDC_ISSUER: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      PROXY_AUTOPROVISION_ACCOUNTS: "true"
+
+      PROXY_HTTP_ADDR: 0.0.0.0:9200
+    volumes:
+      - "./config/proxy/proxy.json:/etc/ocis/proxy.json"
+    labels:
+      - "traefik.enable=true"
+      - "traefik.http.routers.ocis.entrypoints=https"
+      - "traefik.http.routers.ocis.rule=Host(`${OCIS_DOMAIN:-ocis.owncloud.test\
+        }`)"
+      - "traefik.http.routers.ocis.tls.certresolver=http"
+      - "traefik.http.routers.ocis.service=ocis"
+      - "traefik.http.services.ocis.loadbalancer.server.port=9200"
+    logging:
+      driver: "local"
+    restart: always
+
+  nats:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - nats-server
+      - server
+    environment:
+      NATS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      NATS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      NATS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      NATS_NATS_HOST: 0.0.0.0
+      NATS_NATS_PORT: 9233
+    logging:
+      driver: "local"
+    restart: always
+
+  accounts:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - /bin/sh
+      - /entrypoint-override.sh
+    #entrypoint:
+    #  - ocis
+    #  - accounts
+    #  - server
+    environment:
+      ACCOUNTS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      ACCOUNTS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      ACCOUNTS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      ACCOUNTS_HTTP_ADDR: 0.0.0.0:9181
+      ACCOUNTS_GRPC_ADDR: 0.0.0.0:9180
+
+      ACCOUNTS_STORAGE_BACKEND: cs3
+      ACCOUNTS_STORAGE_CS3_PROVIDER_ADDR: storage-metadata:9215
+
+      IDP_LDAP_BIND_PASSWORD: ${IDP_LDAP_BIND_PASSWORD:-idp}
+      STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva}
+
+      ACCOUNTS_JWT_SECRET: ${OCIS_METADATA_JWT_SECRET:-Pive-Fumkiu4}
+    volumes:
+      - ./config/accounts/entrypoint-override.sh:/entrypoint-override.sh
+    logging:
+      driver: "local"
+    restart: always
+
+  glauth:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - glauth
+      - server
+    environment:
+      GLAUTH_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      GLAUTH_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      GLAUTH_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      GLAUTH_LDAP_ADDR: 0.0.0.0:9125
+      GLAUTH_LDAPS_ADDR: 0.0.0.0:9126
+
+      GLAUTH_BACKEND_INSECURE: "true"
+    logging:
+      driver: "local"
+    restart: always
+
+  idp:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - idp
+      - server
+    environment:
+      IDP_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      IDP_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      IDP_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      IDP_HTTP_ADDR: 0.0.0.0:9130
+
+      IDP_LDAP_URI: ldap://glauth:9125
+      IDP_LDAP_BIND_PASSWORD: ${IDP_LDAP_BIND_PASSWORD:-idp}
+
+      IDP_ISS: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+      IDP_INSECURE: "${INSECURE:-false}"
+    logging:
+      driver: "local"
+    restart: always
+
+  ocs:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - ocs
+      - server
+    environment:
+      OCS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      OCS_HTTP_ADDR: 0.0.0.0:9110
+
+      OCS_ACCOUNT_BACKEND_TYPE: accounts
+      OCS_IDM_ADDRESS: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      OCS_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      OCS_MACHINE_AUTH_API_KEY: ${OCIS_MACHINE_AUTH_API_KEY:-change-me-please}
+
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  settings:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - settings
+      - server
+    environment:
+      SETTINGS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      SETTINGS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      SETTINGS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      SETTINGS_HTTP_ADDR: 0.0.0.0:9190
+      SETTINGS_GRPC_ADDR: 0.0.0.0:9191
+
+      SETTINGS_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+    volumes:
+      - "ocis-settings:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  store:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - store
+      - server
+    environment:
+      STORE_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      STORE_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      STORE_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORE_GRPC_ADDR: 0.0.0.0:9460
+    volumes:
+      - "ocis-settings:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  thumbnails:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - thumbnails
+      - server
+    environment:
+      THUMBNAILS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      THUMBNAILS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      THUMBNAILS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      THUMBNAILS_GRPC_ADDR: 0.0.0.0:9185
+
+      THUMBNAILS_CS3SOURCE_INSECURE: "true"
+      REVA_GATEWAY: storage-gateway:9142
+
+    volumes:
+      # optional shared thumbnail cache between services
+      - "ocis-settings:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  web:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - web
+      - server
+    environment:
+      WEB_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      WEB_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      WEB_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      WEB_HTTP_ADDR: 0.0.0.0:9100
+
+      WEB_OIDC_AUTHORITY: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+      WEB_UI_THEME_SERVER: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+      WEB_UI_CONFIG_SERVER: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+    logging:
+      driver: "local"
+    restart: always
+
+  webdav:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - webdav
+      - server
+    environment:
+      WEBDAV_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      WEBDAV_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      WEBDAV_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      WEBDAV_HTTP_ADDR: 0.0.0.0:9115
+
+      OCIS_PUBLIC_URL: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  graph:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - graph
+      - server
+    environment:
+      GRAPH_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      GRAPH_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      GRAPH_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      GRAPH_HTTP_ADDR: 0.0.0.0:9120
+      GRAPH_SPACES_WEBDAV_BASE: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      REVA_GATEWAY: storage-gateway:9142
+      GRAPH_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+
+      GRAPH_LDAP_URI: ldap://glauth:9125
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-metadata:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-metadata
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_HOME_DATAPROVIDER_INSECURE: "${INSECURE:-false}"
+
+      STORAGE_METADATA_GRPC_ADDR: 0.0.0.0:9215
+      STORAGE_METADATA_HTTP_ADDR: 0.0.0.0:9216
+      STORAGE_METADATA_DATA_SERVER_URL: http://storage-metadata:9216/data
+
+      STORAGE_JWT_SECRET: ${OCIS_METADATA_JWT_SECRET:-Pive-Fumkiu4}
+      STORAGE_TRANSFER_SECRET: ${STORAGE_TRANSFER_SECRET:-replace-me-with-a-transfer-secret}
+
+      STORAGE_METADATA_DRIVER: ocis
+
+      REVA_GATEWAY: storage-gateway:9142
+    volumes:
+      - "ocis-storage-metadata:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-authbasic:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-auth-basic
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_AUTH_BASIC_GRPC_ADDR: 0.0.0.0:9146
+      STORAGE_AUTH_BASIC_ENDPOINT: storage-authbasic:9146
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-authmachine:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-auth-machine
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_AUTH_MACHINE_GRPC_ADDR: 0.0.0.0:9148
+      STORAGE_AUTH_MACHINE_ENDPOINT: storage-authmachine:9148
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-authbearer:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-auth-bearer
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_AUTH_BEARER_GRPC_ADDR: 0.0.0.0:9166
+      STORAGE_AUTH_BEARER_ENDPOINT: storage-authbearer:9166
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-shares:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-shares
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_SHARES_GRPC_ADDR: 0.0.0.0:9154
+      STORAGE_SHARES_ENDPOINT: storage-shares:9154
+
+      STORAGE_SHARING_ENDPOINT: storage-sharing:9150
+
+      STORAGE_TRANSFER_SECRET: ${STORAGE_TRANSFER_SECRET:-replace-me-with-a-transfer-secret}
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-users:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-users
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_USERS_DATAPROVIDER_INSECURE: "${INSECURE:-false}"
+
+      STORAGE_USERS_DRIVER: ocis
+
+      STORAGE_USERS_GRPC_ADDR: 0.0.0.0:9157
+      STORAGE_USERS_ENDPOINT: storage-users:9157
+
+      STORAGE_USERS_HTTP_ADDR: 0.0.0.0:9158
+      STORAGE_USERS_DATA_SERVER_URL: http://storage-users:9158/data
+
+      STORAGE_TRANSFER_SECRET: ${STORAGE_TRANSFER_SECRET:-replace-me-with-a-transfer-secret}
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    volumes:
+      - "ocis-storage-users:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-publiclink:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-public-link
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_PUBLIC_LINK_ENDPOINT: storage-publiclink:9178
+      STORAGE_PUBLIC_LINK_GRPC_ADDR: 0.0.0.0:9178
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-sharing:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: 1
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-sharing
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_SHARING_ENDPOINT: storage-sharing:9150
+      STORAGE_SHARING_GRPC_ADDR: 0.0.0.0:9150
+
+      STORAGE_SHARING_USER_DRIVER: json
+      STORAGE_SHARING_USER_JSON_FILE: /var/lib/ocis/storage/sharing/shares.json
+      STORAGE_SHARING_PUBLIC_DRIVER: json
+      STORAGE_SHARING_PUBLIC_JSON_FILE: /var/lib/ocis/storage/sharing/publicshares.json
+
+      STORAGE_SHARING_EVENTS_ADDRESS: nats:9233
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    volumes:
+      - "ocis-storage-sharing:/var/lib/ocis"
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-userprovider:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-userprovider
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_USERPROVIDER_ENDPOINT: storage-userprovider:9144
+      STORAGE_USERPROVIDER_ADDR: 0.0.0.0:9144
+
+      STORAGE_USERPROVIDER_DRIVER: ldap
+      STORAGE_LDAP_HOSTNAME: glauth
+      STORAGE_LDAP_PORT: 9126
+      STORAGE_LDAP_INSECURE: "true"
+      STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva}
+      STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-groupprovider:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-groupprovider
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_GROUPPROVIDER_ENDPOINT: storage-groupprovider:9160
+      STORAGE_GROUPPROVIDER_ADDR: 0.0.0.0:9160
+
+      STORAGE_GROUPPROVIDER_DRIVER: ldap
+      STORAGE_LDAP_HOSTNAME: glauth
+      STORAGE_LDAP_PORT: 9126
+      STORAGE_LDAP_INSECURE: "true"
+      STORAGE_LDAP_BIND_PASSWORD: ${STORAGE_LDAP_BIND_PASSWORD:-reva}
+      STORAGE_LDAP_IDP: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-frontend:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-frontend
+      - server
+    environment:
+      STORAGE_FRONTEND_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      STORAGE_FRONTEND_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      STORAGE_FRONTEND_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_FRONTEND_APPPROVIDER_INSECURE: "true"
+      STORAGE_FRONTEND_ARCHIVER_INSECURE: "true"
+      STORAGE_FRONTEND_OCDAV_INSECURE: "true"
+
+      STORAGE_FRONTEND_PUBLIC_URL: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+      STORAGE_FRONTEND_HTTP_ADDR: 0.0.0.0:9140
+
+      STORAGE_SHARING_ENDPOINT: storage-sharing:9150
+
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+      REVA_GATEWAY: storage-gateway:9142
+    logging:
+      driver: "local"
+    restart: always
+
+  storage-gateway:
+    image: owncloud/ocis:${OCIS_DOCKER_TAG:-latest}
+    deploy:
+      replicas: ${OCIS_SCALE:-1}
+    networks:
+      ocis-net: null
+    entrypoint:
+      - ocis
+      - storage-gateway
+      - server
+    environment:
+      OCIS_LOG_LEVEL: "${OCIS_LOG_LEVEL:-error}"
+      OCIS_LOG_COLOR: "${OCIS_LOG_COLOR:-false}"
+      OCIS_LOG_PRETTY: "${OCIS_LOG_PRETTY:-false}"
+
+      STORAGE_GATEWAY_GRPC_ADDR: 0.0.0.0:9142
+
+      REVA_GATEWAY: storage-gateway:9142
+
+      STORAGE_USERS_ENDPOINT: storage-users:9157
+
+      STORAGE_PUBLIC_LINK_ENDPOINT: storage-publiclink:9178
+
+      STORAGE_AUTH_BASIC_ENDPOINT: storage-authbasic:9146
+      STORAGE_AUTH_BEARER_ENDPOINT: storage-authbearer:9166
+      STORAGE_AUTH_MACHINE_ENDPOINT: storage-authmachine:9148
+
+      STORAGE_SHARES_ENDPOINT: storage-shares:9154
+      STORAGE_SHARING_ENDPOINT: storage-sharing:9150
+
+      STORAGE_GROUPPROVIDER_ENDPOINT: storage-groupprovider:9160
+      STORAGE_USERPROVIDER_ENDPOINT: storage-userprovider:9144
+      STORAGE_PERMISSIONS_ENDPOINT: settings:9191
+
+      STORAGE_FRONTEND_PUBLIC_URL: https://${OCIS_DOMAIN:-ocis.owncloud.test}
+
+      STORAGE_TRANSFER_SECRET: ${STORAGE_TRANSFER_SECRET:-replace-me-with-a-transfer-secret}
+      STORAGE_JWT_SECRET: ${OCIS_JWT_SECRET:-Pive-Fumkiu4}
+    logging:
+      driver: "local"
+    restart: always
+
+volumes:
+  traefik-certs: null
+  ocis-settings: null
+  ocis-store: null
+  ocis-storage-metadata: null
+  ocis-storage-users: null
+  ocis-storage-sharing: null
+
+networks:
+  ocis-net:
+    external: true
diff --git a/deployments/examples/ocis_individual_services/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_individual_services/monitoring_tracing/docker-compose-additions.yml
new file mode 100644
index 00000000000..21e2e23296a
--- /dev/null
+++ b/deployments/examples/ocis_individual_services/monitoring_tracing/docker-compose-additions.yml
@@ -0,0 +1,202 @@
+---
+version: "3.7"
+
+services:
+  proxy:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      PROXY_DEBUG_ADDR: 0.0.0.0:9205
+
+  accounts:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+
+  glauth:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      GLAUTH_DEBUG_ADDR: 0.0.0.0:9129
+  idp:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      IDP_DEBUG_ADDR: 0.0.0.0:9134
+  ocs:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      OCS_DEBUG_ADDR: 0.0.0.0:9114
+  settings:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      SETTINGS_DEBUG_ADDR: 0.0.0.0:9194
+  store:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORE_DEBUG_ADDR: 0.0.0.0:9464
+  thumbnails:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      THUMBNAILS_DEBUG_ADDR: 0.0.0.0:9189
+  web:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      WEB_DEBUG_ADDR: 0.0.0.0:9104
+  webdav:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      WEBDAV_DEBUG_ADDR: 0.0.0.0:9119
+  graph:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      GRAPH_DEBUG_ADDR: 0.0.0.0:9124
+  #graph-explorer:
+  #  environment:
+  #    # tracing
+  #    OCIS_TRACING_ENABLED: "true"
+  #    OCIS_TRACING_TYPE: jaeger
+  #    OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+  #    # metrics
+  #    GRAPH_EXPLORER_DEBUG_ADDR: 0.0.0.0:9136
+  storage-metadata:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217
+  storage-authbasic:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_AUTH_BASIC_DEBUG_ADDR: 0.0.0.0:9147
+  storage-authmachine:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_AUTH_MACHINE_DEBUG_ADDR: 0.0.0.0:9167
+  storage-authbearer:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_AUTH_BEARER_DEBUG_ADDR: 0.0.0.0:9149
+  storage-shares:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_SHARES_DEBUG_ADDR: 0.0.0.0:9156
+  storage-users:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_USERS_DEBUG_ADDR: 0.0.0.0:9159
+  storage-publiclink:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179
+  storage-sharing:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_SHARING_DEBUG_ADDR: 0.0.0.0:9151
+  storage-userprovider:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145
+  storage-groupprovider:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161
+  storage-frontend:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141
+  storage-gateway:
+    environment:
+      # tracing
+      OCIS_TRACING_ENABLED: "true"
+      OCIS_TRACING_TYPE: jaeger
+      OCIS_TRACING_ENDPOINT: jaeger-agent:6831
+      # metrics
+      STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143
+      APP_PROVIDER_DEBUG_ADDR: 0.0.0.0:9165
+
+networks:
+  ocis-net:
+    external: true
diff --git a/docs/extensions/graph/_index.md b/docs/extensions/graph/_index.md
index 3ad1e8d9b81..7ff7bc687c4 100644
--- a/docs/extensions/graph/_index.md
+++ b/docs/extensions/graph/_index.md
@@ -9,3 +9,5 @@ geekdocCollapseSection: true
 ---
 
 This service provides a simple graph world API which can be used by clients or other extensions.
+
+{{< toc-tree >}}
diff --git a/docs/extensions/graph/groups.md b/docs/extensions/graph/groups.md
new file mode 100644
index 00000000000..eef9e9f8d80
--- /dev/null
+++ b/docs/extensions/graph/groups.md
@@ -0,0 +1,199 @@
+---
+title: Groups
+weight: 40
+geekdocRepo: https://github.com/owncloud/ocis
+geekdocEditPath: edit/master/docs/extensions/graph
+geekdocFilePath: users.md
+---
+
+{{< toc >}}
+
+## Groups API
+
+The Groups API is implementing a subset of the functionality of the
+[MS Graph Group resource](https://docs.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0)
+The JSON representation of a Group as handled by the Groups API looks like this:
+
+```
+{
+    "displayName": "group",
+    "id": "f0d97060-da16-4b0d-9fa4-d1ec43afc5f1"
+}
+```
+
+Our implemenation currently support two Attributes for a Group:
+
+| Attribute	| Description |
+|---------------|-------------|
+| displayName	| The groups name|
+| id		| An unique, stable readonly identifier for the group that stays the same for the whole lifetime of the User, usually a UUID|
+
+
+### Reading groups
+
+#### `GET /groups`
+
+Returns a list of all groups 
+
+Example:
+
+```
+curl -k 'https://localhost:9200/graph/v1.0/groups' -u user:password
+
+```
+
+Response:
+
+```
+{
+    "value": [
+        {
+            "displayName": "group",
+            "id": "38580a2e-7018-42ed-aff6-b2af0b4e9790"
+        },
+        {
+            "displayName": "Example Users",
+            "id": "7a20f238-8a22-4458-902d-47674c317e5f"
+        }
+    ]
+}
+```
+
+#### `GET /groups/{groupid}`
+
+Example:
+
+```
+curl -k 'https://localhost:9200/graph/v1.0/groups/7a20f238-8a22-4458-902d-47674c317e5f' -u user:password
+```
+
+Response:
+
+```
+{
+    "displayName": "Example Users",
+    "id": "7a20f238-8a22-4458-902d-47674c317e5f"
+}
+```
+### Getting Group Members
+
+#### `GET /groups/{groupid}/members`
+
+Returns a list of User objects that are members of a group.
+
+Example:
+
+```
+curl -k 'https://localhost:9200/graph/v1.0/groups/7a20f238-8a22-4458-902d-47674c317e5f/members' -u user:password
+
+```
+
+Response:
+
+```
+[
+    {
+        "displayName": "Test User",
+        "id": "c54b0588-7157-4521-bb52-c1c8ca84ea71",
+        "mail": "example@example.org",
+        "onPremisesSamAccountName": "example"
+    },
+    {
+        "displayName": "Albert Einstein",
+        "id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
+        "mail": "einstein@example.org",
+        "onPremisesSamAccountName": "einstein"
+    }
+]
+```
+
+### Creating / Updating Groups
+
+#### `POST /groups`
+
+Use this to create a new group.
+h
+##### Request Body
+
+Note the missing `"id"` Attribute. It will be generated by the server:
+
+```
+{
+    "displayName": "Example Users"
+}
+```
+
+##### Response
+
+When successful, the Reponse will return the new group including the newly allocated `"id"`:
+
+```
+{
+    "displayName": "Example Users",
+    "id": "7a20f238-8a22-4458-902d-47674c317e5f"
+}
+```
+
+#### `DELETE /groups/{id}`
+
+Example:
+
+```
+curl -k --request DELETE 'https://localhost:9200/graph/v1.0/groups/7a20f238-8a22-4458-902d-47674c317e5f' -u user:password
+```
+
+When successful the API returns no response body and the HTTP status code 204 (No Content)
+
+#### `PATCH /groups/{id}`
+
+Updating attributes of a single group is supposed to be done with a patch request. This is however currently not fully 
+implemented for our write-enabled backends. The PATCH request can however be used to add multiple members to a group at once.
+See below.
+
+### Adding a single member to a group
+
+#### `POST /groups/{id}/members/$ref`
+
+The request body contains a single attribute "`@odata.id`" referencing the new member of the group by URI. Example:
+
+```
+curl -k --header "Content-Type: application/json" \
+        --request POST  --data \
+	'{ "@odata.id": "https://localhost:9200/graph/v1.0/users/4c510ada-c86b-4815-8820-42cdf82c3d51" }' \
+	'https://localhost:9200/graph/v1.0/groups/7a20f238-8a22-4458-902d-47674c317e5f/members/$ref' -u user:password
+
+```
+
+When successful the API returns no response body and the HTTP status code 204 (No Content)
+
+### Adding multiple members in a single request
+
+#### `PATCH /groups/{id}`
+
+The request body contains the attribute `members@odata.bind` holding a list of URI references for the new members.
+Example:
+
+```
+{
+    "members@odata.bind": [
+        "https://localhost:9200/graph/v1.0/users/4c510ada-c86b-4815-8820-42cdf82c3d51",
+	"https://localhost:9200/graph/v1.0/users/c54b0588-7157-4521-bb52-c1c8ca84ea71"
+    ]
+}
+```
+
+When successful the API returns no response body and the HTTP status code 204 (No Content)
+
+### Removing a member
+
+#### `DELETE /groups/{groupid}/members/{id}/$ref`
+
+Example
+
+```
+curl -k --request DELETE  \
+     'https://localhost:9200/graph/v1.0/groups/7a20f238-8a22-4458-902d-47674c317e5f/members/4c510ada-c86b-4815-8820-42cdf82c3d51/$ref' \
+     -u user:password
+```
+
+When successful the API returns no response body and the HTTP status code 204 (No Content)
diff --git a/docs/extensions/graph/users.md b/docs/extensions/graph/users.md
new file mode 100644
index 00000000000..e7172ea1215
--- /dev/null
+++ b/docs/extensions/graph/users.md
@@ -0,0 +1,165 @@
+---
+title: Users
+weight: 30
+geekdocRepo: https://github.com/owncloud/ocis
+geekdocEditPath: edit/master/docs/extensions/graph
+geekdocFilePath: users.md
+---
+
+{{< toc >}}
+
+## Users API
+
+The Users API is implementing a subset of the functionality of the
+[MS Graph User resource](https://docs.microsoft.com/en-us/graph/api/resources/user?view=graph-rest-1.0)
+The JSON representation of a User handled by the Users API looks like this:
+
+```
+{
+    "displayName": "Albert Einstein",
+    "id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
+    "mail": "einstein@example.org",
+    "onPremisesSamAccountName": "einstein"
+}
+```
+
+Our implemenation currently supports only a limited set of Attributes of Users:
+
+| Attribute	| Description |
+|---------------|-------------|
+| displayName	| The full name of the user, usually a combination for givenname and lastname|
+| mail		| The user's email address |
+| onPremisesSamAccountName | The loginname/account name of the user|
+| id		| An unique, stable readonly identifier for the user that stays the same for the whole lifetime of the User, usually a UUID|
+| passwordProfile | Contains the password of the users. This is only present when updating or creating users. It is never returned by the API|
+
+
+### Reading users
+
+#### `GET /me`
+
+Returns the user object of the currently signed-in user
+
+Example:
+```
+curl -k 'https://localhost:9200/graph/v1.0/me' -u user:password
+```
+
+Response:
+```
+{
+    "displayName": "Albert Einstein",
+    "id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
+    "mail": "einstein@example.org",
+    "onPremisesSamAccountName": "einstein"
+}
+```
+
+#### `GET /users`
+
+Returns a list of all users 
+
+Example:
+
+```
+curl -k 'https://localhost:9200/graph/v1.0/users' -u user:password
+
+```
+
+Response:
+
+```
+{
+    "value": [
+        {
+            "displayName": "Albert Einstein",
+            "id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
+            "mail": "einstein@example.org",
+            "onPremisesSamAccountName": "einstein"
+        },
+        {
+            "displayName": "Maurice Moss",
+            "id": "058bff95-6708-4fe5-91e4-9ea3d377588b",
+            "mail": "moss@example.org",
+            "onPremisesSamAccountName": "moss"
+        }
+    ]
+}
+```
+
+#### `GET /users/{userid or accountname}`
+
+Example:
+
+```
+curl -k 'https://localhost:9200/graph/v1.0/users/058bff95-6708-4fe5-91e4-9ea3d377588b' -u user:password
+```
+
+Response:
+
+```
+{
+    "displayName": "Maurice Moss",
+    "id": "058bff95-6708-4fe5-91e4-9ea3d377588b",
+    "mail": "moss@example.org",
+    "onPremisesSamAccountName": "moss"
+}
+```
+
+### Creating / Updating Users
+
+#### `POST /users`
+
+Use this to create a new user.
+
+##### Request Body
+
+Note the missing `"id"` Attribute. It will be generated by the server:
+
+```
+{
+    "displayName": "Example User",
+    "mail": "example@example.org",
+    "onPremisesSamAccountName": "example",
+    "passwordProfile": {
+    	"password": "ThePassword"
+    }
+}
+```
+
+##### Response
+
+When successful, the Reponse will return the new user, without the password, but including the newly allocated `"id"`:
+
+```
+{
+    "displayName":"Example User",
+    "id":"c067b139-c91c-4e47-8be6-669156a0587b",
+    "mail":"example@example.org",
+    "onPremisesSamAccountName":"example"
+}
+```
+
+#### `DELETE /users/{id}`
+
+Example:
+
+```
+curl -k --request DELETE 'https://localhost:9200/graph/v1.0/users/c067b139-c91c-4e47-8be6-669156a0587b' -u user:password
+```
+
+When successful the API returns no response body and the HTTP status code 204 (No Content)
+
+
+#### `PATCH /users/{id}`
+
+Updating attributes of a single user can be done with a patch request. The Request Body contains the new values of the attributes
+to be updated. E.g. to update the `displayName` Attribute:
+
+```
+ curl -k --header "Content-Type: application/json" \
+         --request PATCH  --data '{"displayName": "Test User" }' \
+	 'https://localhost:9200/graph/v1.0/users/c54b0588-7157-4521-bb52-c1c8ca84ea71' -u user:password
+```
+
+Similar to creating a user via `POST`,  the `PATCH` request will return the user object containing the new attribute values.
diff --git a/docs/ocis/adr/0003-external-user-management.md b/docs/ocis/adr/0003-external-user-management.md
index 025c2ec2101..7cdb66dda17 100644
--- a/docs/ocis/adr/0003-external-user-management.md
+++ b/docs/ocis/adr/0003-external-user-management.md
@@ -7,9 +7,9 @@ geekdocEditPath: edit/master/docs/ocis/adr
 geekdocFilePath: 0003-external-user-management.md
 ---
 
-* Status: accepted
+* Status: superseded by [17. Allow read only external User Management]({{< ref "0017-allow-read-only-external-user-management.md" >}})
 * Deciders: @butonic, @micbar, @dragotin, @hodyroff, @pmaier1
-* Date: 2020-12-09
+* Date: 2022-02-08
 
 Technical Story: [Skip account-service by talking to CS3 user-api](https://github.com/owncloud/ocis/pull/1020)
 
@@ -112,3 +112,4 @@ We should use an existing LDAP server and make GLAuth a drop in replacement for
 
 ## Links
 * supersedes [ADR-0001]({{< ref "0001-introduce-accounts-service.md" >}})
+* superseded by [17. Allow read only external User Management]({{< ref "0017-allow-read-only-external-user-management.md" >}})
diff --git a/docs/ocis/adr/0017-allow-read-only-external-user-management.md b/docs/ocis/adr/0017-allow-read-only-external-user-management.md
new file mode 100644
index 00000000000..879171b3705
--- /dev/null
+++ b/docs/ocis/adr/0017-allow-read-only-external-user-management.md
@@ -0,0 +1,111 @@
+---
+title: "17. Allow read only external User Management"
+weight: 17
+date: 2022-02-08T10:53:00+01:00
+geekdocRepo: https://github.com/owncloud/ocis
+geekdocEditPath: edit/master/docs/ocis/adr
+geekdocFilePath: 0017-allow-read-only-external-user-management.md
+---
+
+* Status: proposed
+* Deciders: @butonic, @micbar, @rhafer
+* Date: 2022-02-08
+
+## Context and Problem Statement
+
+oCIS needs to be integrated with various external Authentication and Identity Management Systems.
+Usually oCIS will have no administrative access to such a system and we will not be allowed to
+reconfigure it to suit our needs (e.g. we will not be able to enhance the schema of an already existing
+LDAP Directory). In most of the cases our access will be read-only. 
+
+Sidenote: There is a difference between users, identities and accounts: A user may have multiple
+identities which he can authenticate with, e.g. his facebook, twitter, microsoft or google
+identity. Multiple identities can be linked to an account in ocis, allowing to fall back to another
+identity provider should one of them shut down. This also allows migrating from one identity
+provider to another.
+
+There are different cases where oCIS requires access to users:
+
+1. While we settled on using OpenID Connect (OIDC) as the authentication protocol for oCIS, we
+   we need to build a user object during authentication with at least an account UUID (to identify
+   the account) and the email or a name (for display purposes). 
+2. When searching for share recipients we need to be able to query existing users in the external
+   identity management system
+3. When listing files we need to be able to look up a users display properties (username, email,
+   avatar...) based on the account UUID
+
+oCIS internally relies on a stable and persistent identifier (e.g. a UUID) for accounts in order to
+implement permissions and sharing. Unfortunately, some deployments are unable to deliver this kind
+of stable identifier for users:
+
+- In OIDC itself the only stable identifier that is guaranteed to be provided by the IDP is
+  combination of the sub and iss claims. IDPs can optionally return other claims, but we cannot
+  rely on a specific claim being present.
+- When no other services (LDAP, SCIM, ...) are available that could be used look up a user UUID
+
+
+## Decision Drivers
+
+* oCIS should be a single binary that can run out of the box without external dependencies like an
+  LDAP server.
+* Time: we want to build a release candidate asap.
+* oCIS should be easy to integrate with standard external identity mangement systems
+
+## Considered Options
+
+There are two case to consider:
+* External identity management system provides an OIDC IdP and an interface to query users
+* External identity management system provides just an OIDC IdP with no possibility to query users
+
+## Decision Outcome
+
+It's not really possible single out any of the options for this ADR. In the end we will likely need
+to support both scenarios.
+
+### Positive Consequences: <!-- optional -->
+
+* Very flexible integration with a wide range of external systems
+
+### Negative consequences: <!-- optional -->
+
+* configuration complexity, high support efforts
+* Increasingly complex code in oCIS
+
+## Pros and Cons of the Options <!-- optional -->
+
+### External identity management system is read only and provides an interface to query users (e.g. Coporate Active Directy)
+
+IdP sends sub & iss and mail or username claims, Identity Management System provides APIs (e.g.
+LDAP, SCIM, REST ...) to lookup additional user information. All oCIS services use the CS3 API to
+look up the account for the given email or username, where CS3 then uses a backend that relies on
+the APIs provided by the IdM.
+
+* Good, because we can rely on the external identity management
+* Good, because ocis services only need to know about the CS3 user provider API, which acts as an
+  abstraction layer for different identitiy management systems
+* Good, because there is only a single source of truth (the external IdM) and we don't need to
+  implement a synchronization mechanism to maintain an internal user database (we will likely need
+  some form of caching though, see below)
+* Bad, because the identity managment needs to provide a stable, persistent, non-reassignable user
+  identifier for an account, e.g. `owncloudUUID` or `ms-DS-ConsistencyGuid`
+* Bad, because we need to implment tools that can change the account id when it did change anyway
+* Bad, because without caching we will hammer the identity management system with lookup requests
+
+### External identity management system is read only and does NOT provide an API to query users
+
+Idp sends sub & iss and mail or username claims. We need to provision an internal account mapping,
+creating a unique ID, upon the first login of a user to be able to look up user properties by account
+id. 
+
+* Good, because this has very little external requirements
+* Good, because we have accounts fully under our control
+* Bad, because we have to provide the user lookup APIs
+* Bad, because users will only a visible after the first login
+* Bad, because our internal account mapping might get out of date when user attribute (e.g. name or
+  mail) change. At least until the next time that user logs in
+
+## Links <!-- optional -->
+
+* [Link type] [Link to ADR] <!-- example: Refined by [ADR-0005](0005-example.md) -->
+* … <!-- numbers of links can vary -->
+* supersedes [3. Use external User Management]({{< ref "0003-external-user-management.md" >}})
diff --git a/docs/ocis/deployment/oc10_ocis_parallel.md b/docs/ocis/deployment/oc10_ocis_parallel.md
index f0d210d8981..cceb3047149 100644
--- a/docs/ocis/deployment/oc10_ocis_parallel.md
+++ b/docs/ocis/deployment/oc10_ocis_parallel.md
@@ -122,7 +122,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oC10 and oCIS frontend in `CLOUD_DOMAIN=`, eg. `CLOUD_DOMAIN=cloud.owncloud.test`.
 
-  You also must override the default secrets in `STORAGE_TRANSFER_SECRET` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   By default ownCloud 10 will be started in the `latest` version. If you want to start a specific version of oCIS set the version to `OC10_DOCKER_TAG=`. Available versions can be found on [Docker Hub](https://hub.docker.com/r/owncloud/ocis/tags?page=1&ordering=last_updated).
 
diff --git a/docs/ocis/deployment/ocis_hello.md b/docs/ocis/deployment/ocis_hello.md
index 6449ce47a78..2afd77a633d 100644
--- a/docs/ocis/deployment/ocis_hello.md
+++ b/docs/ocis/deployment/ocis_hello.md
@@ -95,7 +95,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=ocis.owncloud.test`.
 
-  You also must override three default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   By default the oCIS Hello extension will be started in the `latest` version. If you want to start a specific version of oCIS Hello set the version to `OCIS_HELLO_DOCKER_TAG=`. Available versions can be found on [Docker Hub](https://hub.docker.com/r/owncloud/ocis-hello/tags?page=1&ordering=last_updated).
 
diff --git a/docs/ocis/deployment/ocis_individual_services.md b/docs/ocis/deployment/ocis_individual_services.md
new file mode 100644
index 00000000000..bb8de24f289
--- /dev/null
+++ b/docs/ocis/deployment/ocis_individual_services.md
@@ -0,0 +1,121 @@
+---
+title: "oCIS as individual services"
+date: 2020-10-12T14:04:00+01:00
+weight: 24
+geekdocRepo: https://github.com/owncloud/ocis
+geekdocEditPath: edit/master/docs/ocis/deployment
+geekdocFilePath: ocis_individual_services.md
+---
+
+{{< toc >}}
+
+## Overview
+
+* oCIS running behind Traefik as reverse proxy
+* Traefik generating self signed certificates for local setup or obtaining valid SSL certificates for a server setup
+* oCIS running as individual services (each extension in it's own containers)
+
+[Find this example on GitHub](https://github.com/owncloud/ocis/tree/master/deployments/examples/ocis_individual_services)
+
+The docker stack consists of at least 24 containers. One of them is Traefik, a proxy which is terminating ssl and forwards the requests to oCIS in the internal docker network.
+
+The other containers are oCIS extensions, running each one in a separate container. In this example oCIS uses its internal IDP [LibreGraph Connect]({{< ref "../../extensions/idp" >}}) and the [oCIS storage driver]({{< ref "../../extensions/storage/storagedrivers" >}}). You also can start more than one container of each service by setting `OCIS_SCALE` to a number greater than 1. Currently this won't scale all services, but we are working on making all service easily scalable.
+
+## Server Deployment
+
+### Requirements
+
+* Linux server with docker and docker-compose installed
+* Two domains set up and pointing to your server
+  - ocis.* for serving oCIS
+  - traefik.* for serving the Traefik dashboard
+
+See also [example server setup]({{< ref "preparing_server" >}})
+
+
+### Install oCIS and Traefik
+
+* Clone oCIS repository
+
+  `git clone https://github.com/owncloud/ocis.git`
+
+* Go to the deployment example
+
+  `cd ocis/deployment/examples/ocis_traefik`
+
+* Open the `.env` file in a text editor
+  The file by default looks like this:
+  ```bash
+  # If you're on a internet facing server please comment out following line.
+  # It skips certificate validation for various parts of oCIS and is needed if you use self signed certificates.
+  INSECURE=true
+
+  ### Traefik settings ###
+  # Serve Treafik dashboard. Defaults to "false".
+  TRAEFIK_DASHBOARD=
+  # Domain of Traefik, where you can find the dashboard. Defaults to "traefik.owncloud.test"
+  TRAEFIK_DOMAIN=
+  # Basic authentication for the dashboard. Defaults to user "admin" and password "admin"
+  TRAEFIK_BASIC_AUTH_USERS=
+  # Email address for obtaining LetsEncrypt certificates, needs only be changed if this is a public facing server
+  TRAEFIK_ACME_MAIL=
+
+  ### oCIS settings ###
+  # oCIS version. Defaults to "latest"
+  OCIS_DOCKER_TAG=
+  # Domain of oCIS, where you can find the frontend. Defaults to "ocis.owncloud.test"
+  OCIS_DOMAIN=
+  # IDP LDAP bind password. Must be changed in order to have a secure oCIS. Defaults to "idp".
+  IDP_LDAP_BIND_PASSWORD=
+  # Storage LDAP bind password. Must be changed in order to have a secure oCIS. Defaults to "reva".
+  STORAGE_LDAP_BIND_PASSWORD=
+  # JWT secret which is used for the storage provider. Must be changed in order to have a secure oCIS. Defaults to "Pive-Fumkiu4"
+  OCIS_JWT_SECRET=
+  # JWT secret which is used for uploads to create transfer tokens. Must be changed in order to have a secure oCIS. Defaults to "replace-me-with-a-transfer-secret"
+  STORAGE_TRANSFER_SECRET=
+  # Machine auth api key secret. Must be changed in order to have a secure oCIS. Defaults to "change-me-please"
+  OCIS_MACHINE_AUTH_API_KEY=
+  # Number of services to run for extensions, that currently can be easily scaled. Defaults to 1.
+  OCIS_SCALE=
+  ```
+
+  You are installing oCIS on a server and Traefik will obtain valid certificates for you so please remove `INSECURE=true` or set it to `false`.
+
+  If you want to use the Traefik dashboard, set TRAEFIK_DASHBOARD to `true` (default is `false` and therefore not active). If you activate it, you must set a domain for the Traefik dashboard in `TRAEFIK_DOMAIN=` eg. `TRAEFIK_DOMAIN=traefik.owncloud.test`.
+
+  The Traefik dashboard is secured by basic auth. Default credentials are the user `admin` with the password `admin`. To set your own credentials, generate a htpasswd (eg. by using [an online tool](https://htpasswdgenerator.de/) or a cli tool).
+
+  Traefik will issue certificates with LetsEncrypt and therefore you must set an email address in `TRAEFIK_ACME_MAIL=`.
+
+  By default ocis will be started in the `latest` version. If you want to start a specific version of oCIS set the version to `OCIS_DOCKER_TAG=`. Available versions can be found on [Docker Hub](https://hub.docker.com/r/owncloud/ocis/tags?page=1&ordering=last_updated).
+
+  Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=ocis.owncloud.test`.
+
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+
+  You also can run more than one instance of the service by setting `OCIS_SCALE` to number greater than one.
+
+  Now you have configured everything and can save the file.
+
+* Start the docker stack
+
+  `docker-compose up -d`
+
+* You now can visit oCIS and Traefik dashboard on your configured domains. You may need to wait some minutes until all services are fully ready, so make sure that you try to reload the pages from time to time.
+
+## Local setup
+For a more simple local ocis setup see [Getting started]({{< ref "../getting-started" >}})
+
+This docker stack can also be run locally. One downside is that Traefik can not obtain valid SSL certificates and therefore will create self signed ones. This means that your browser will show scary warnings. Another downside is that you can not point DNS entries to your localhost. So you have to add static host entries to your computer.
+
+On Linux and macOS you can add them to your `/etc/hosts` files like this:
+```
+127.0.0.1 ocis.owncloud.test
+127.0.0.1 traefik.owncloud.test
+```
+
+After that you're ready to start the application stack:
+
+`docker-compose up -d`
+
+Open https://ocis.owncloud.test in your browser and accept the invalid certificate warning. You now can login to oCIS with the default users, which also can be found here: [Getting started]({{< ref "../getting-started#login-to-ocis-web" >}}). You may need to wait some minutes until all services are fully ready, so make sure that you try to reload the pages from time to time.
diff --git a/docs/ocis/deployment/ocis_keycloak.md b/docs/ocis/deployment/ocis_keycloak.md
index 73b8e3c5343..7d8c189ca89 100644
--- a/docs/ocis/deployment/ocis_keycloak.md
+++ b/docs/ocis/deployment/ocis_keycloak.md
@@ -108,7 +108,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   If you want to change the OIDC client id of th ownCloud Web frontend, you can do this by setting the name to `OCIS_OIDC_CLIENT_ID=`.
 
-  You also must override three default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   Set your domain for the Keycloak administration panel and authentication endpoints to `KEYCLOAK_DOMAIN=` eg. `KEYCLOAK_DOMAIN=keycloak.owncloud.test`.
 
diff --git a/docs/ocis/deployment/ocis_ldap.md b/docs/ocis/deployment/ocis_ldap.md
index 05f035e979b..655dae94cc3 100644
--- a/docs/ocis/deployment/ocis_ldap.md
+++ b/docs/ocis/deployment/ocis_ldap.md
@@ -93,7 +93,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=cloud.owncloud.test`.
 
-  You also must override the default secrets in `STORAGE_TRANSFER_SECRET` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   The OpenLDAP server in this example deployment has an admin users, which is also used as bind user in order to keep theses examples simple. You can change the default password "admin" to a different one by setting it to `LDAP_ADMIN_PASSWORD=...`.
 
diff --git a/docs/ocis/deployment/ocis_s3.md b/docs/ocis/deployment/ocis_s3.md
index e353a7617d5..b129ac66316 100644
--- a/docs/ocis/deployment/ocis_s3.md
+++ b/docs/ocis/deployment/ocis_s3.md
@@ -104,7 +104,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=ocis.owncloud.test`.
 
-  You also must override three default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   Set your domain for the MinIO frontend in `MINIO_DOMAIN=`, eg. `MINIO_DOMAIN=minio.owncloud.test`. If you are using other S3-compatible providers you need to configure the respective endpoint here.
 
diff --git a/docs/ocis/deployment/ocis_traefik.md b/docs/ocis/deployment/ocis_traefik.md
index 2aaf2aedd12..9adaebbbf5b 100644
--- a/docs/ocis/deployment/ocis_traefik.md
+++ b/docs/ocis/deployment/ocis_traefik.md
@@ -88,7 +88,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=ocis.owncloud.test`.
 
-  You also must override three default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   Now you have configured everything and can save the file.
 
diff --git a/docs/ocis/deployment/ocis_wopi.md b/docs/ocis/deployment/ocis_wopi.md
index 16f75a88884..5b8e7f22279 100644
--- a/docs/ocis/deployment/ocis_wopi.md
+++ b/docs/ocis/deployment/ocis_wopi.md
@@ -130,7 +130,7 @@ See also [example server setup]({{< ref "preparing_server" >}})
 
   Set your domain for the oCIS frontend in `OCIS_DOMAIN=`, eg. `OCIS_DOMAIN=ocis.owncloud.test`.
 
-  You also must override three default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD` and `OCIS_JWT_SECRET` in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
+  You also must override the default secrets in `IDP_LDAP_BIND_PASSWORD`, `STORAGE_LDAP_BIND_PASSWORD`, `OCIS_JWT_SECRET`, `STORAGE_TRANSFER_SECRET` and `OCIS_MACHINE_AUTH_API_KEY`  in order to secure your oCIS instance. Choose some random strings eg. from the output of `openssl rand -base64 32`. For more information see [secure an oCIS instance]({{< ref "./#secure-an-ocis-instance" >}}).
 
   By default the CS3Org WOPI server will also be started in the `latest` version. If you want to start a specific version of it, you can set the version to `WOPISERVER_DOCKER_TAG=`. Available versions can be found on [Docker Hub](https://hub.docker.com/r/cs3org/wopiserver/tags?page=1&ordering=last_updated).
 
diff --git a/go.mod b/go.mod
index 7b9425c0925..ceb98782107 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,7 @@ require (
 	github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e
 	github.com/ReneKroon/ttlcache/v2 v2.11.0
 	github.com/asim/go-micro/plugins/client/grpc/v4 v4.0.0-20220118152736-9e0be6c85d75
+	github.com/asim/go-micro/plugins/events/nats/v4 v4.0.0-20220118152736-9e0be6c85d75
 	github.com/asim/go-micro/plugins/logger/zerolog/v4 v4.0.0-20220118152736-9e0be6c85d75
 	github.com/asim/go-micro/plugins/registry/consul/v4 v4.0.0-20220118152736-9e0be6c85d75
 	github.com/asim/go-micro/plugins/registry/etcd/v4 v4.0.0-20220118152736-9e0be6c85d75
@@ -18,16 +19,17 @@ require (
 	github.com/asim/go-micro/plugins/wrapper/breaker/gobreaker/v4 v4.0.0-20220118152736-9e0be6c85d75
 	github.com/asim/go-micro/plugins/wrapper/monitoring/prometheus/v4 v4.0.0-20220118152736-9e0be6c85d75
 	github.com/asim/go-micro/plugins/wrapper/trace/opencensus/v4 v4.0.0-20220118152736-9e0be6c85d75
-	github.com/blevesearch/bleve/v2 v2.3.0
+	github.com/blevesearch/bleve/v2 v2.3.1
 	github.com/coreos/go-oidc/v3 v3.1.0
 	github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19
-	github.com/cs3org/reva v1.16.1-0.20220221135950-8cc813ecfc4c
+	github.com/cs3org/reva v1.16.1-0.20220224115936-e17c65a48a5a
 	github.com/disintegration/imaging v1.6.2
 	github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733
 	github.com/go-chi/chi/v5 v5.0.7
 	github.com/go-chi/cors v1.2.0
 	github.com/go-chi/render v1.0.1
 	github.com/go-ldap/ldap/v3 v3.4.2
+	github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
 	github.com/go-logr/logr v1.2.2
 	github.com/go-ozzo/ozzo-validation/v4 v4.3.0
 	github.com/gofrs/uuid v4.2.0+incompatible
@@ -39,7 +41,7 @@ require (
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.3
 	github.com/iancoleman/strcase v0.2.0
 	github.com/justinas/alice v1.2.0
-	github.com/libregraph/idm v0.3.1-0.20220120080913-d0003ade935e
+	github.com/libregraph/idm v0.3.1-0.20220222123017-f9d520ac1f11
 	github.com/libregraph/lico v0.53.1
 	github.com/mennanov/fieldmask-utils v0.5.0
 	github.com/mitchellh/mapstructure v1.4.3
@@ -51,7 +53,7 @@ require (
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/onsi/ginkgo v1.16.5
 	github.com/onsi/gomega v1.18.1
-	github.com/owncloud/libre-graph-api-go v0.10.0
+	github.com/owncloud/libre-graph-api-go v0.11.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.12.1
 	github.com/rs/zerolog v1.26.1
@@ -69,6 +71,7 @@ require (
 	go.opentelemetry.io/otel/trace v1.4.1
 	golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
 	golang.org/x/image v0.0.0-20211028202545-6944b10bf410
+	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
 	google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5
 	google.golang.org/grpc v1.44.0
@@ -89,9 +92,11 @@ require (
 	github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 // indirect
 	github.com/RoaringBitmap/roaring v0.9.4 // indirect
 	github.com/acomagu/bufpipe v1.0.3 // indirect
+	github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 // indirect
+	github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 // indirect
 	github.com/armon/go-metrics v0.3.10 // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
-	github.com/asim/go-micro/plugins/events/nats/v4 v4.0.0-20220118152736-9e0be6c85d75 // indirect
 	github.com/aws/aws-sdk-go v1.42.39 // indirect
 	github.com/beevik/etree v1.1.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
@@ -105,11 +110,11 @@ require (
 	github.com/blevesearch/snowballstem v0.9.0 // indirect
 	github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
 	github.com/blevesearch/vellum v1.0.7 // indirect
-	github.com/blevesearch/zapx/v11 v11.3.2 // indirect
-	github.com/blevesearch/zapx/v12 v12.3.2 // indirect
-	github.com/blevesearch/zapx/v13 v13.3.2 // indirect
-	github.com/blevesearch/zapx/v14 v14.3.2 // indirect
-	github.com/blevesearch/zapx/v15 v15.3.2 // indirect
+	github.com/blevesearch/zapx/v11 v11.3.3 // indirect
+	github.com/blevesearch/zapx/v12 v12.3.3 // indirect
+	github.com/blevesearch/zapx/v13 v13.3.3 // indirect
+	github.com/blevesearch/zapx/v14 v14.3.3 // indirect
+	github.com/blevesearch/zapx/v15 v15.3.3 // indirect
 	github.com/bluele/gcache v0.0.2 // indirect
 	github.com/bmizerany/pat v0.0.0-20210406213842-e4b6760bdd6f // indirect
 	github.com/boombuler/barcode v1.0.1 // indirect
@@ -128,6 +133,7 @@ require (
 	github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
 	github.com/dgraph-io/ristretto v0.1.0 // indirect
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
+	github.com/dlclark/regexp2 v1.4.0 // indirect
 	github.com/dustin/go-humanize v1.0.0 // indirect
 	github.com/emirpasic/gods v1.12.0 // indirect
 	github.com/eternnoir/gncp v0.0.0-20170707042257-c70df2d0cd68 // indirect
@@ -234,9 +240,11 @@ require (
 	github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
 	github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect
 	github.com/sony/gobreaker v0.5.0 // indirect
+	github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/steveyen/gtreap v0.1.0 // indirect
 	github.com/stretchr/objx v0.3.0 // indirect
+	github.com/trustelem/zxcvbn v1.0.1 // indirect
 	github.com/tus/tusd v1.8.0 // indirect
 	github.com/wk8/go-ordered-map v0.2.0 // indirect
 	github.com/xanzy/ssh-agent v0.3.1 // indirect
@@ -249,7 +257,6 @@ require (
 	go.uber.org/multierr v1.7.0 // indirect
 	go.uber.org/zap v1.19.1 // indirect
 	golang.org/x/mod v0.5.1 // indirect
-	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
 	golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
 	golang.org/x/text v0.3.7 // indirect
diff --git a/go.sum b/go.sum
index 4643f0bee54..b82561e52cd 100644
--- a/go.sum
+++ b/go.sum
@@ -134,9 +134,11 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
 github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90vF44BPW4ZYOkE3tDkGTy7yHURusOJimt+I=
 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.976/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
-github.com/amoghe/go-crypt v0.0.0-20191109212615-b2ff80594b7f/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
+github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4=
+github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
@@ -153,6 +155,7 @@ github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQh
 github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo=
 github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
@@ -219,8 +222,8 @@ github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBE
 github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
 github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
-github.com/blevesearch/bleve/v2 v2.3.0 h1:5XKlSdpcjeJdE7n0FUEDeJRJwLuhPxq+k5n7h5UaJkg=
-github.com/blevesearch/bleve/v2 v2.3.0/go.mod h1:egW/6gZEhM3oBvRjuHXGvGb92cKZ9867OqPZAmCG8MQ=
+github.com/blevesearch/bleve/v2 v2.3.1 h1:rbMTDM17tvZ7wTrTp4lJINYRnz57N5oMSw8cYuJ4l0k=
+github.com/blevesearch/bleve/v2 v2.3.1/go.mod h1:kAJuWn2L1TNSUyxtPJD4AGma2/PgMSm7GBlx61F9OBs=
 github.com/blevesearch/bleve_index_api v1.0.1 h1:nx9++0hnyiGOHJwQQYfsUGzpRdEVE5LsylmmngQvaFk=
 github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
 github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
@@ -238,16 +241,16 @@ github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15a
 github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
 github.com/blevesearch/vellum v1.0.7 h1:+vn8rfyCRHxKVRgDLeR0FAXej2+6mEb5Q15aQE/XESQ=
 github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE=
-github.com/blevesearch/zapx/v11 v11.3.2 h1:TDdcbaA0Yz3Y5zpTrpvyW1AeicqWTJL3g8D5g48RiHM=
-github.com/blevesearch/zapx/v11 v11.3.2/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
-github.com/blevesearch/zapx/v12 v12.3.2 h1:XB09XMg/3ibeIJRCm2zjkaVwrtAuk6c55YRSmVlwUDk=
-github.com/blevesearch/zapx/v12 v12.3.2/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
-github.com/blevesearch/zapx/v13 v13.3.2 h1:mTvALh6oayreac07VRAv94FLvTHeSBM9sZ1gmVt0N2k=
-github.com/blevesearch/zapx/v13 v13.3.2/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
-github.com/blevesearch/zapx/v14 v14.3.2 h1:oW36JVaZDzrzmBa1X5jdTIYzdhkOQnr/ie13Cb2X7MQ=
-github.com/blevesearch/zapx/v14 v14.3.2/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
-github.com/blevesearch/zapx/v15 v15.3.2 h1:OZNE4CQ9hQhnB21ySC7x2/9Q35U3WtRXLAh5L2gdCXc=
-github.com/blevesearch/zapx/v15 v15.3.2/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
+github.com/blevesearch/zapx/v11 v11.3.3 h1:8vQMO5hdA2qPCmicIMuKS+qcvUAEh6Vcb0uve4Nh8e4=
+github.com/blevesearch/zapx/v11 v11.3.3/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
+github.com/blevesearch/zapx/v12 v12.3.3 h1:MQO5YNI8MqdPz12ALCoXiJw5cl9QQamYZSp285Z/+Mo=
+github.com/blevesearch/zapx/v12 v12.3.3/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
+github.com/blevesearch/zapx/v13 v13.3.3 h1:TS4xpMK1ARPYHq+1WwuEOKMOiwvKpTK3RuWOkKlI7BE=
+github.com/blevesearch/zapx/v13 v13.3.3/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
+github.com/blevesearch/zapx/v14 v14.3.3 h1:dqqAzGphKl0yehHKKntDHKlEMhi9B/tJrD4OsWpY7YE=
+github.com/blevesearch/zapx/v14 v14.3.3/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
+github.com/blevesearch/zapx/v15 v15.3.3 h1:60oE+qsJkveLenJmbc0eaH59GWYCbJJsPDV6Z5hEoYY=
+github.com/blevesearch/zapx/v15 v15.3.3/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
 github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
 github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
@@ -339,8 +342,8 @@ github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S
 github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
 github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19 h1:1jqPH58jCxvbaJ9WLIJ7W2/m622bWS6ChptzljSG6IQ=
 github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
-github.com/cs3org/reva v1.16.1-0.20220221135950-8cc813ecfc4c h1:52qF91Pu/jUVVWgZo4kl2GaQT5SPCdV0b5s6SQG2jrM=
-github.com/cs3org/reva v1.16.1-0.20220221135950-8cc813ecfc4c/go.mod h1:M+Nausi93NaMDoinwiUX/Ekgrp/RrYv715FG5KrIarY=
+github.com/cs3org/reva v1.16.1-0.20220224115936-e17c65a48a5a h1:LgwfJ4N+ekLRFOK2vwVKbgtnQYYcrNiMtu5kekJvJ54=
+github.com/cs3org/reva v1.16.1-0.20220224115936-e17c65a48a5a/go.mod h1:M+Nausi93NaMDoinwiUX/Ekgrp/RrYv715FG5KrIarY=
 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
 github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
@@ -364,6 +367,7 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
 github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
 github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
+github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
 github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
@@ -461,6 +465,7 @@ github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd
 github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
 github.com/go-ldap/ldap/v3 v3.4.2 h1:zFZKcXKLqZpFMrMQGHeHWKXbDTdNCmhGY9AK41zPh+8=
 github.com/go-ldap/ldap/v3 v3.4.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
+github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 h1:sfz1YppV05y4sYaW7kXZtrocU/+vimnIWt4cxAYh7+o=
 github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3/go.mod h1:ZXFhGda43Z2TVbfGZefXyMJzsDHhCh0go3bZUcwTx7o=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -933,8 +938,8 @@ github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
 github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/libregraph/idm v0.3.1-0.20220120080913-d0003ade935e h1:iO7Gf/cMCn2sn28CoWsHUQ/O7VfH0DAJrhHyTE/xQk4=
-github.com/libregraph/idm v0.3.1-0.20220120080913-d0003ade935e/go.mod h1:gdDXfHsvrrmoNwqcXroOGIi2+Lrx5iAipbpVwR7goeY=
+github.com/libregraph/idm v0.3.1-0.20220222123017-f9d520ac1f11 h1:ReFrghRLQhQdt5BW7HXtEzySmsgUCXL1U36gnmka73U=
+github.com/libregraph/idm v0.3.1-0.20220222123017-f9d520ac1f11/go.mod h1:wB8ApGAQsXDXXGWEeFimK/3q8Z/jRa+m3nqnvoYjBsQ=
 github.com/libregraph/lico v0.53.1 h1:c5JYFg0mrIgk6Ktj77rNJ2K8X01hs28JJ9Vw1N1iMAk=
 github.com/libregraph/lico v0.53.1/go.mod h1:EXf6Y9s9TygW6unSXosBpVXWUURoN2sPX0053o4zVfQ=
 github.com/linode/linodego v0.25.3/go.mod h1:GSBKPpjoQfxEfryoCRcgkuUOCuVtGHWhzI8OMdycNTE=
@@ -1153,8 +1158,8 @@ github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:L
 github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
 github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
 github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
-github.com/owncloud/libre-graph-api-go v0.10.0 h1:4PPA7MBbf9du04WOty4jayyjLfs9C4Ei5rokhSoy1Bw=
-github.com/owncloud/libre-graph-api-go v0.10.0/go.mod h1:579sFrPP7aP24LZXGPopLfvE+hAka/2DYHk0+Ij+w+U=
+github.com/owncloud/libre-graph-api-go v0.11.0 h1:E260P0EJQvtdkUHYk/l2GeKoDxcbsazAqY9MnAQxUt8=
+github.com/owncloud/libre-graph-api-go v0.11.0/go.mod h1:579sFrPP7aP24LZXGPopLfvE+hAka/2DYHk0+Ij+w+U=
 github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
 github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -1198,7 +1203,6 @@ github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQ
 github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
 github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1321,6 +1325,7 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
 github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 h1:0jjO3HdJfOn6gYHD/ZNZh0LLMxEAqkYX7xoDPQReEgs=
 github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784/go.mod h1:ff/5myEGgtsAwf26goQCO905GrEm5ugEZSd6OWTsrhM=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -1368,6 +1373,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/studio-b12/gowebdav v0.0.0-20211109083228-3f8721cd4b6f/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
 github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
 github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo=
 github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
@@ -1377,6 +1383,7 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
+github.com/trustelem/zxcvbn v1.0.1 h1:mp4JFtzdDYGj9WYSD3KQSkwwUumWNFzXaAjckaTYpsc=
 github.com/trustelem/zxcvbn v1.0.1/go.mod h1:zonUyKeh7sw6psPf/e3DtRqkRyZvAbOfjNz/aO7YQ5s=
 github.com/tus/tusd v1.1.0/go.mod h1:3DWPOdeCnjBwKtv98y5dSws3itPqfce5TVa0s59LRiA=
 github.com/tus/tusd v1.8.0 h1:QODQ5uMhL2tFX3Ouk7rUHHqPqeDBvi2+gYIoyUO0n8Q=
diff --git a/idm/Makefile b/idm/Makefile
new file mode 100644
index 00000000000..7eb26a3ecb5
--- /dev/null
+++ b/idm/Makefile
@@ -0,0 +1,32 @@
+SHELL := bash
+NAME := ocs
+
+TAGS := disable_crypt
+
+include ../.make/recursion.mk
+
+############ tooling ############
+ifneq (, $(shell which go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
+include ../.bingo/Variables.mk
+endif
+
+############ go tooling ############
+include ../.make/go.mk
+
+############ release ############
+include ../.make/release.mk
+
+############ docs generate ############
+include ../.make/docs.mk
+
+.PHONY: docs-generate
+docs-generate: config-docs-generate
+
+############ generate ############
+include ../.make/generate.mk
+
+.PHONY: ci-go-generate
+ci-go-generate: # CI runs ci-node-generate automatically before this target
+
+.PHONY: ci-node-generate
+ci-node-generate:
diff --git a/idm/cmd/idm/main.go b/idm/cmd/idm/main.go
new file mode 100644
index 00000000000..680d58dafb4
--- /dev/null
+++ b/idm/cmd/idm/main.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+	"os"
+
+	"github.com/owncloud/ocis/idm/pkg/command"
+	"github.com/owncloud/ocis/idm/pkg/config"
+)
+
+func main() {
+	if err := command.Execute(config.DefaultConfig()); err != nil {
+		os.Exit(1)
+	}
+}
diff --git a/idm/pkg/command/health.go b/idm/pkg/command/health.go
new file mode 100644
index 00000000000..2de74ad1280
--- /dev/null
+++ b/idm/pkg/command/health.go
@@ -0,0 +1,53 @@
+package command
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/idm/pkg/config/parser"
+	"github.com/owncloud/ocis/idm/pkg/logging"
+	"github.com/urfave/cli/v2"
+)
+
+// Health is the entrypoint for the health command.
+func Health(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "health",
+		Usage:    "check health status",
+		Category: "info",
+		Before: func(c *cli.Context) error {
+			return parser.ParseConfig(cfg)
+		},
+		Action: func(c *cli.Context) error {
+			logger := logging.Configure(cfg.Service.Name, cfg.Log)
+
+			resp, err := http.Get(
+				fmt.Sprintf(
+					"http://%s/healthz",
+					cfg.Debug.Addr,
+				),
+			)
+
+			if err != nil {
+				logger.Fatal().
+					Err(err).
+					Msg("Failed to request health check")
+			}
+
+			defer resp.Body.Close()
+
+			if resp.StatusCode != http.StatusOK {
+				logger.Fatal().
+					Int("code", resp.StatusCode).
+					Msg("Health seems to be in bad state")
+			}
+
+			logger.Debug().
+				Int("code", resp.StatusCode).
+				Msg("Health got a good state")
+
+			return nil
+		},
+	}
+}
diff --git a/idm/pkg/command/root.go b/idm/pkg/command/root.go
new file mode 100644
index 00000000000..2be9e0a1772
--- /dev/null
+++ b/idm/pkg/command/root.go
@@ -0,0 +1,64 @@
+package command
+
+import (
+	"context"
+	"os"
+
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/clihelper"
+	ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
+	"github.com/thejerf/suture/v4"
+	"github.com/urfave/cli/v2"
+)
+
+// GetCommands provides all commands for this service
+func GetCommands(cfg *config.Config) cli.Commands {
+	return []*cli.Command{
+		// start this service
+		Server(cfg),
+
+		// interaction with this service
+
+		// infos about this service
+		Health(cfg),
+		Version(cfg),
+	}
+}
+
+// Execute is the entry point for the ocis-idm command.
+func Execute(cfg *config.Config) error {
+	app := clihelper.DefaultApp(&cli.App{
+		Name:     "ocis-idm",
+		Usage:    "Embedded LDAP service for oCIS",
+		Commands: GetCommands(cfg),
+	})
+
+	cli.HelpFlag = &cli.BoolFlag{
+		Name:  "help,h",
+		Usage: "Show the help",
+	}
+
+	return app.Run(os.Args)
+}
+
+// SutureService allows for the idm command to be embedded and supervised by a suture supervisor tree.
+type SutureService struct {
+	cfg *config.Config
+}
+
+// NewSutureService creates a new idm.SutureService
+func NewSutureService(cfg *ociscfg.Config) suture.Service {
+	cfg.IDM.Commons = cfg.Commons
+	return SutureService{
+		cfg: cfg.IDM,
+	}
+}
+
+func (s SutureService) Serve(ctx context.Context) error {
+	s.cfg.Context = ctx
+	if err := Execute(s.cfg); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/idm/pkg/command/server.go b/idm/pkg/command/server.go
new file mode 100644
index 00000000000..eee544ac1fa
--- /dev/null
+++ b/idm/pkg/command/server.go
@@ -0,0 +1,153 @@
+package command
+
+import (
+	"context"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"html/template"
+	"os"
+	"strings"
+
+	"github.com/go-ldap/ldif"
+	"github.com/libregraph/idm/pkg/ldappassword"
+	"github.com/libregraph/idm/pkg/ldbbolt"
+	"github.com/libregraph/idm/server"
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/idm/pkg/config/parser"
+	"github.com/owncloud/ocis/idm/pkg/logging"
+	pkgcrypto "github.com/owncloud/ocis/ocis-pkg/crypto"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+	"github.com/urfave/cli/v2"
+)
+
+// Server is the entrypoint for the server command.
+func Server(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "server",
+		Usage:    fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
+		Category: "server",
+		Before: func(c *cli.Context) error {
+			return parser.ParseConfig(cfg)
+		},
+		Action: func(c *cli.Context) error {
+			logger := logging.Configure(cfg.Service.Name, cfg.Log)
+			ctx, cancel := func() (context.Context, context.CancelFunc) {
+				if cfg.Context == nil {
+					return context.WithCancel(context.Background())
+				}
+				return context.WithCancel(cfg.Context)
+			}()
+
+			defer cancel()
+			start(ctx, logger, cfg)
+			return nil
+		},
+	}
+}
+
+func start(ctx context.Context, logger log.Logger, cfg *config.Config) error {
+	servercfg := server.Config{
+		Logger:          log.LogrusWrap(logger.Logger),
+		LDAPHandler:     "boltdb",
+		LDAPSListenAddr: cfg.IDM.LDAPSAddr,
+		TLSCertFile:     cfg.IDM.Cert,
+		TLSKeyFile:      cfg.IDM.Key,
+		LDAPBaseDN:      "o=libregraph-idm",
+		LDAPAdminDN:     "uid=libregrah,o=libregraph-idm",
+
+		BoltDBFile: cfg.IDM.DatabasePath,
+	}
+
+	if cfg.IDM.LDAPSAddr != "" {
+		// Generate a self-signing cert if no certificate is present
+		if err := pkgcrypto.GenCert(cfg.IDM.Cert, cfg.IDM.Key, logger); err != nil {
+			logger.Fatal().Err(err).Msgf("Could not generate test-certificate")
+		}
+	}
+	if _, err := os.Stat(servercfg.BoltDBFile); errors.Is(err, os.ErrNotExist) {
+		logger.Debug().Msg("Bootstrapping IDM database")
+		err = bootstrap(logger, cfg, servercfg)
+		logger.Error().Err(err).Msg("failed")
+	}
+
+	svc, err := server.NewServer(&servercfg)
+	if err != nil {
+		return err
+	}
+	return svc.Serve(ctx)
+}
+
+func bootstrap(logger log.Logger, cfg *config.Config, srvcfg server.Config) error {
+	// Hash password if the config does not supply a hash already
+	var pwhash string
+	var err error
+	if strings.HasPrefix(cfg.IDM.AdminPassword, "$argon2id$") {
+		// password is alread hashed
+		pwhash = "{ARGON2}" + cfg.IDM.AdminPassword
+	} else {
+		if pwhash, err = ldappassword.Hash(cfg.IDM.AdminPassword, "{ARGON2}"); err != nil {
+			return err
+		}
+	}
+
+	bdb := &ldbbolt.LdbBolt{}
+
+	if err := bdb.Configure(srvcfg.Logger, srvcfg.LDAPBaseDN, srvcfg.BoltDBFile, nil); err != nil {
+		return err
+	}
+	defer bdb.Close()
+
+	if err := bdb.Initialize(); err != nil {
+		return err
+	}
+
+	// Prepare the initial Data from template. To be able to set the
+	// supplied admin password
+	tmpl, err := template.New("baseldif").Parse(baseldif)
+	if err != nil {
+		return err
+	}
+
+	var tmplWriter strings.Builder
+	// We need to treat the hash as binary in the LDIF template to avoid
+	// go-ldap/ldif to to any fancy escaping
+	b64 := base64.StdEncoding.EncodeToString([]byte(pwhash))
+	err = tmpl.Execute(&tmplWriter, b64)
+	if err != nil {
+		return err
+	}
+
+	s := strings.NewReader(tmplWriter.String())
+	lf := &ldif.LDIF{}
+	err = ldif.Unmarshal(s, lf)
+	if err != nil {
+		return err
+	}
+
+	for _, entry := range lf.AllEntries() {
+		logger.Debug().Str("dn", entry.DN).Msg("Adding entry")
+		if err := bdb.EntryPut(entry); err != nil {
+			return fmt.Errorf("error adding Entry '%s': %w", entry.DN, err)
+		}
+	}
+	return nil
+}
+
+var baseldif string = `dn: o=libregraph-idm
+o: libregraph-idm
+objectClass: organization
+
+dn: ou=users,o=libregraph-idm
+objectClass: organizationalUnit
+ou: users
+
+dn: ou=groups,o=libregraph-idm
+objectClass: organizationalUnit
+ou: groups
+
+dn: uid=libregraph,o=libregraph-idm
+objectClass: account
+objectClass: simpleSecurityObject
+uid: libregraph
+userPassword:: {{.}}`
diff --git a/idm/pkg/command/version.go b/idm/pkg/command/version.go
new file mode 100644
index 00000000000..4a6faa0c96c
--- /dev/null
+++ b/idm/pkg/command/version.go
@@ -0,0 +1,19 @@
+package command
+
+import (
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/urfave/cli/v2"
+)
+
+// Version prints the service versions of all running instances.
+func Version(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "version",
+		Usage:    "print the version of this binary and the running extension instances",
+		Category: "info",
+		Action: func(c *cli.Context) error {
+			// not implemented
+			return nil
+		},
+	}
+}
diff --git a/idm/pkg/config/config.go b/idm/pkg/config/config.go
new file mode 100644
index 00000000000..da0fd1bcab5
--- /dev/null
+++ b/idm/pkg/config/config.go
@@ -0,0 +1,30 @@
+package config
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/ocis-pkg/shared"
+)
+
+// Config combines all available configuration parts.
+type Config struct {
+	*shared.Commons
+
+	Service Service
+
+	Tracing *Tracing `ocisConfig:"tracing"`
+	Log     *Log     `ocisConfig:"log"`
+	Debug   Debug    `ocisConfig:"debug"`
+
+	IDM Settings `ocisConfig:"idm"`
+
+	Context context.Context
+}
+
+type Settings struct {
+	LDAPSAddr     string `ocisConfig:"ldaps_addr" env:"IDM_LDAPS_ADDR"`
+	Cert          string `ocisConfig:"cert" env:"IDM_LDAPS_CERT"`
+	Key           string `ocisConfig:"cert" env:"IDM_LDAPS_KEY"`
+	DatabasePath  string `ocisConfig:"database" env:"IDM_DATABASE_PATH"`
+	AdminPassword string `ocisConfig:"admin_password" env:"IDM_ADMIN_PASSWORD"`
+}
diff --git a/idm/pkg/config/debug.go b/idm/pkg/config/debug.go
new file mode 100644
index 00000000000..c90432afac7
--- /dev/null
+++ b/idm/pkg/config/debug.go
@@ -0,0 +1,9 @@
+package config
+
+// Debug defines the available debug configuration.
+type Debug struct {
+	Addr   string `ocisConfig:"addr" env:"IDM_DEBUG_ADDR"`
+	Token  string `ocisConfig:"token" env:"IDM_DEBUG_TOKEN"`
+	Pprof  bool   `ocisConfig:"pprof" env:"IDM_DEBUG_PPROF"`
+	Zpages bool   `ocisConfig:"zpages" env:"IDM_DEBUG_ZPAGES"`
+}
diff --git a/idm/pkg/config/defaultconfig.go b/idm/pkg/config/defaultconfig.go
new file mode 100644
index 00000000000..aaec93bdea1
--- /dev/null
+++ b/idm/pkg/config/defaultconfig.go
@@ -0,0 +1,22 @@
+package config
+
+import (
+	"path"
+
+	"github.com/owncloud/ocis/ocis-pkg/config/defaults"
+)
+
+func DefaultConfig() *Config {
+	return &Config{
+		Service: Service{
+			Name: "idm",
+		},
+		IDM: Settings{
+			LDAPSAddr:     "127.0.0.1:9235",
+			Cert:          path.Join(defaults.BaseDataPath(), "idm", "ldap.crt"),
+			Key:           path.Join(defaults.BaseDataPath(), "idm", "ldap.key"),
+			DatabasePath:  path.Join(defaults.BaseDataPath(), "idm", "ocis.boltdb"),
+			AdminPassword: "admin",
+		},
+	}
+}
diff --git a/idm/pkg/config/log.go b/idm/pkg/config/log.go
new file mode 100644
index 00000000000..780628b79d7
--- /dev/null
+++ b/idm/pkg/config/log.go
@@ -0,0 +1,9 @@
+package config
+
+// Log defines the available log configuration.
+type Log struct {
+	Level  string `mapstructure:"level" env:"OCIS_LOG_LEVEL;IDM_LOG_LEVEL"`
+	Pretty bool   `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;IDM_LOG_PRETTY"`
+	Color  bool   `mapstructure:"color" env:"OCIS_LOG_COLOR;IDM_LOG_COLOR"`
+	File   string `mapstructure:"file" env:"OCIS_LOG_FILE;IDM_LOG_FILE"`
+}
diff --git a/idm/pkg/config/parser/parse.go b/idm/pkg/config/parser/parse.go
new file mode 100644
index 00000000000..22b3429cc18
--- /dev/null
+++ b/idm/pkg/config/parser/parse.go
@@ -0,0 +1,51 @@
+package parser
+
+import (
+	"errors"
+
+	"github.com/owncloud/ocis/idm/pkg/config"
+	ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
+
+	"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
+)
+
+// ParseConfig loads accounts configuration from known paths.
+func ParseConfig(cfg *config.Config) error {
+	_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
+	if err != nil {
+		return err
+	}
+
+	// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
+	if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
+		cfg.Log = &config.Log{
+			Level:  cfg.Commons.Log.Level,
+			Pretty: cfg.Commons.Log.Pretty,
+			Color:  cfg.Commons.Log.Color,
+			File:   cfg.Commons.Log.File,
+		}
+	} else if cfg.Log == nil {
+		cfg.Log = &config.Log{}
+	}
+	// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
+	if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {
+		cfg.Tracing = &config.Tracing{
+			Enabled:   cfg.Commons.Tracing.Enabled,
+			Type:      cfg.Commons.Tracing.Type,
+			Endpoint:  cfg.Commons.Tracing.Endpoint,
+			Collector: cfg.Commons.Tracing.Collector,
+		}
+	} else if cfg.Tracing == nil {
+		cfg.Tracing = &config.Tracing{}
+	}
+
+	// load all env variables relevant to the config in the current context.
+	if err := envdecode.Decode(cfg); err != nil {
+		// no environment variable set for this config is an expected "error"
+		if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/idm/pkg/config/service.go b/idm/pkg/config/service.go
new file mode 100644
index 00000000000..f98aa3d27e5
--- /dev/null
+++ b/idm/pkg/config/service.go
@@ -0,0 +1,6 @@
+package config
+
+// Service defines the available service configuration.
+type Service struct {
+	Name string
+}
diff --git a/idm/pkg/config/tracing.go b/idm/pkg/config/tracing.go
new file mode 100644
index 00000000000..df9b377e1f5
--- /dev/null
+++ b/idm/pkg/config/tracing.go
@@ -0,0 +1,9 @@
+package config
+
+// Tracing defines the available tracing configuration.
+type Tracing struct {
+	Enabled   bool   `ocisConfig:"enabled" env:"OCIS_TRACING_ENABLED;IDM_TRACING_ENABLED"`
+	Type      string `ocisConfig:"type" env:"OCIS_TRACING_TYPE;IDM_TRACING_TYPE"`
+	Endpoint  string `ocisConfig:"endpoint" env:"OCIS_TRACING_ENDPOINT;IDM_TRACING_ENDPOINT"`
+	Collector string `ocisConfig:"collector" env:"OCIS_TRACING_COLLECTOR;IDM_TRACING_COLLECTOR"`
+}
diff --git a/idm/pkg/logging/logging.go b/idm/pkg/logging/logging.go
new file mode 100644
index 00000000000..b43451cf7fd
--- /dev/null
+++ b/idm/pkg/logging/logging.go
@@ -0,0 +1,17 @@
+package logging
+
+import (
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+)
+
+// LoggerFromConfig initializes a service-specific logger instance.
+func Configure(name string, cfg *config.Log) log.Logger {
+	return log.NewLogger(
+		log.Name(name),
+		log.Level(cfg.Level),
+		log.Pretty(cfg.Pretty),
+		log.Color(cfg.Color),
+		log.File(cfg.File),
+	)
+}
diff --git a/idm/pkg/server/debug/option.go b/idm/pkg/server/debug/option.go
new file mode 100644
index 00000000000..1fbc9046544
--- /dev/null
+++ b/idm/pkg/server/debug/option.go
@@ -0,0 +1,50 @@
+package debug
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+)
+
+// Option defines a single option function.
+type Option func(o *Options)
+
+// Options defines the available options for this package.
+type Options struct {
+	Logger  log.Logger
+	Context context.Context
+	Config  *config.Config
+}
+
+// newOptions initializes the available default options.
+func newOptions(opts ...Option) Options {
+	opt := Options{}
+
+	for _, o := range opts {
+		o(&opt)
+	}
+
+	return opt
+}
+
+// Logger provides a function to set the logger option.
+func Logger(val log.Logger) Option {
+	return func(o *Options) {
+		o.Logger = val
+	}
+}
+
+// Context provides a function to set the context option.
+func Context(val context.Context) Option {
+	return func(o *Options) {
+		o.Context = val
+	}
+}
+
+// Config provides a function to set the config option.
+func Config(val *config.Config) Option {
+	return func(o *Options) {
+		o.Config = val
+	}
+}
diff --git a/idm/pkg/server/debug/server.go b/idm/pkg/server/debug/server.go
new file mode 100644
index 00000000000..426f95a6238
--- /dev/null
+++ b/idm/pkg/server/debug/server.go
@@ -0,0 +1,59 @@
+package debug
+
+import (
+	"io"
+	"net/http"
+
+	"github.com/owncloud/ocis/idm/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/service/debug"
+	"github.com/owncloud/ocis/ocis-pkg/version"
+)
+
+// Server initializes the debug service and server.
+func Server(opts ...Option) (*http.Server, error) {
+	options := newOptions(opts...)
+
+	return debug.NewService(
+		debug.Logger(options.Logger),
+		debug.Name(options.Config.Service.Name),
+		debug.Version(version.String),
+		debug.Address(options.Config.Debug.Addr),
+		debug.Token(options.Config.Debug.Token),
+		debug.Pprof(options.Config.Debug.Pprof),
+		debug.Zpages(options.Config.Debug.Zpages),
+		debug.Health(health(options.Config)),
+		debug.Ready(ready(options.Config)),
+	), nil
+}
+
+// health implements the health check.
+func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "text/plain")
+		w.WriteHeader(http.StatusOK)
+
+		// TODO: check if services are up and running
+
+		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
+		// io.WriteString should not fail but if it does we want to know.
+		if err != nil {
+			panic(err)
+		}
+	}
+}
+
+// ready implements the ready check.
+func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
+	return func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "text/plain")
+		w.WriteHeader(http.StatusOK)
+
+		// TODO: check if services are up and running
+
+		_, err := io.WriteString(w, http.StatusText(http.StatusOK))
+		// io.WriteString should not fail but if it does we want to know.
+		if err != nil {
+			panic(err)
+		}
+	}
+}
diff --git a/idp/pkg/service/v0/service.go b/idp/pkg/service/v0/service.go
index 24fb3132d3a..cf486f16214 100644
--- a/idp/pkg/service/v0/service.go
+++ b/idp/pkg/service/v0/service.go
@@ -21,7 +21,6 @@ import (
 	"github.com/libregraph/lico/server"
 	"github.com/owncloud/ocis/idp/pkg/assets"
 	"github.com/owncloud/ocis/idp/pkg/config"
-	"github.com/owncloud/ocis/idp/pkg/logging"
 	"github.com/owncloud/ocis/idp/pkg/middleware"
 	"github.com/owncloud/ocis/ocis-pkg/log"
 	"stash.kopano.io/kgol/rndm"
@@ -59,7 +58,7 @@ func NewService(opts ...Option) Service {
 	idpSettings := bootstrap.Settings(options.Config.IDP)
 
 	bs, err := bootstrap.Boot(ctx, &idpSettings, &licoconfig.Config{
-		Logger: logging.Wrap(logger),
+		Logger: log.LogrusWrap(logger),
 	})
 
 	if err != nil {
diff --git a/notifications/cmd/notifications/main.go b/notifications/cmd/notifications/main.go
new file mode 100644
index 00000000000..6b43234330b
--- /dev/null
+++ b/notifications/cmd/notifications/main.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+	"os"
+
+	"github.com/owncloud/ocis/notifications/pkg/command"
+	"github.com/owncloud/ocis/notifications/pkg/config"
+)
+
+func main() {
+	if err := command.Execute(config.DefaultConfig()); err != nil {
+		os.Exit(1)
+	}
+}
diff --git a/notifications/pkg/channels/channels.go b/notifications/pkg/channels/channels.go
new file mode 100644
index 00000000000..f4e427b018c
--- /dev/null
+++ b/notifications/pkg/channels/channels.go
@@ -0,0 +1,105 @@
+// Package channels provides different communication channels to notify users.
+package channels
+
+import (
+	"context"
+	"net/smtp"
+
+	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
+	groups "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
+	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
+	"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+	"github.com/pkg/errors"
+)
+
+// Channel defines the methods of a communication channel.
+type Channel interface {
+	// SendMessage sends a message to users.
+	SendMessage(userIDs []string, msg string) error
+	// SendMessageToGroup sends a message to a group.
+	SendMessageToGroup(groupdID *groups.GroupId, msg string) error
+}
+
+// NewMailChannel instantiates a new mail communication channel.
+func NewMailChannel(cfg config.Config, logger log.Logger) (Channel, error) {
+	gc, err := pool.GetGatewayServiceClient(cfg.Notifications.RevaGateway)
+	if err != nil {
+		logger.Error().Err(err).Msg("could not get gateway client")
+		return nil, err
+	}
+	return Mail{
+		gatewayClient: gc,
+		conf:          cfg,
+		logger:        logger,
+	}, nil
+}
+
+// Mail is the communcation channel for email.
+type Mail struct {
+	gatewayClient gateway.GatewayAPIClient
+	conf          config.Config
+	logger        log.Logger
+}
+
+// SendMessage sends a message to all given users.
+func (m Mail) SendMessage(userIDs []string, msg string) error {
+	to, err := m.getReceiverAddresses(userIDs)
+	if err != nil {
+		return err
+	}
+	body := []byte(msg)
+
+	smtpConf := m.conf.Notifications.SMTP
+	auth := smtp.PlainAuth("", smtpConf.Sender, smtpConf.Password, smtpConf.Host)
+	if err := smtp.SendMail(smtpConf.Host+":"+smtpConf.Port, auth, smtpConf.Sender, to, body); err != nil {
+		return errors.Wrap(err, "could not send mail")
+	}
+	return nil
+}
+
+// SendMessageToGroup sends a message to all members of the given group.
+func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error {
+	// TODO We need an authenticated context here...
+	res, err := m.gatewayClient.GetGroup(context.Background(), &groups.GetGroupRequest{GroupId: groupID})
+	if err != nil {
+		return err
+	}
+	if res.Status.Code != rpc.Code_CODE_OK {
+		return errors.New("could not get group")
+	}
+
+	members := make([]string, 0, len(res.Group.Members))
+	for _, id := range res.Group.Members {
+		members = append(members, id.OpaqueId)
+	}
+
+	return m.SendMessage(members, msg)
+}
+
+func (m Mail) getReceiverAddresses(receivers []string) ([]string, error) {
+	addresses := make([]string, 0, len(receivers))
+	for _, id := range receivers {
+		// Authenticate is too costly but at the moment our only option to get the user.
+		// We don't have an authenticated context so calling `GetUser` doesn't work.
+		res, err := m.gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{
+			Type:         "machine",
+			ClientId:     "userid:" + id,
+			ClientSecret: m.conf.Notifications.MachineAuthSecret,
+		})
+		if err != nil {
+			return nil, err
+		}
+		if res.Status.Code != rpc.Code_CODE_OK {
+			m.logger.Error().
+				Interface("status", res.Status).
+				Str("receiver_id", id).
+				Msg("could not get user")
+			continue
+		}
+		addresses = append(addresses, res.User.Mail)
+	}
+
+	return addresses, nil
+}
diff --git a/notifications/pkg/command/health.go b/notifications/pkg/command/health.go
new file mode 100644
index 00000000000..7f2adb85b5d
--- /dev/null
+++ b/notifications/pkg/command/health.go
@@ -0,0 +1,18 @@
+package command
+
+import (
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/urfave/cli/v2"
+)
+
+// Health is the entrypoint for the health command.
+func Health(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:  "health",
+		Usage: "Check health status",
+		Action: func(c *cli.Context) error {
+			// Not implemented
+			return nil
+		},
+	}
+}
diff --git a/notifications/pkg/command/root.go b/notifications/pkg/command/root.go
new file mode 100644
index 00000000000..805d8cec3ac
--- /dev/null
+++ b/notifications/pkg/command/root.go
@@ -0,0 +1,64 @@
+package command
+
+import (
+	"context"
+	"os"
+
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/clihelper"
+	ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
+	"github.com/thejerf/suture/v4"
+	"github.com/urfave/cli/v2"
+)
+
+// GetCommands provides all commands for this service
+func GetCommands(cfg *config.Config) cli.Commands {
+	return []*cli.Command{
+		// start this service
+		Server(cfg),
+
+		// interaction with this service
+
+		// infos about this service
+		Health(cfg),
+		Version(cfg),
+	}
+}
+
+// Execute is the entry point for the notifications command.
+func Execute(cfg *config.Config) error {
+	app := clihelper.DefaultApp(&cli.App{
+		Name:     "notifications",
+		Usage:    "starts notifications service",
+		Commands: GetCommands(cfg),
+	})
+
+	cli.HelpFlag = &cli.BoolFlag{
+		Name:  "help,h",
+		Usage: "Show the help",
+	}
+
+	return app.Run(os.Args)
+}
+
+// SutureService allows for the notifications command to be embedded and supervised by a suture supervisor tree.
+type SutureService struct {
+	cfg *config.Config
+}
+
+// NewSutureService creates a new notifications.SutureService
+func NewSutureService(cfg *ociscfg.Config) suture.Service {
+	cfg.Settings.Commons = cfg.Commons
+	return SutureService{
+		cfg: cfg.Notifications,
+	}
+}
+
+func (s SutureService) Serve(ctx context.Context) error {
+	s.cfg.Context = ctx
+	if err := Execute(s.cfg); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/notifications/pkg/command/server.go b/notifications/pkg/command/server.go
new file mode 100644
index 00000000000..7f22fa1cb7c
--- /dev/null
+++ b/notifications/pkg/command/server.go
@@ -0,0 +1,50 @@
+package command
+
+import (
+	"fmt"
+
+	"github.com/asim/go-micro/plugins/events/nats/v4"
+	"github.com/cs3org/reva/pkg/events"
+	"github.com/cs3org/reva/pkg/events/server"
+	"github.com/owncloud/ocis/notifications/pkg/channels"
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/owncloud/ocis/notifications/pkg/config/parser"
+	"github.com/owncloud/ocis/notifications/pkg/logging"
+	"github.com/owncloud/ocis/notifications/pkg/service"
+	"github.com/urfave/cli/v2"
+)
+
+// Server is the entrypoint for the server command.
+func Server(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "server",
+		Usage:    fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
+		Category: "server",
+		Before: func(c *cli.Context) error {
+			return parser.ParseConfig(cfg)
+		},
+		Action: func(c *cli.Context) error {
+			logger := logging.Configure(cfg.Service.Name, cfg.Log)
+
+			evs := []events.Unmarshaller{
+				events.ShareCreated{},
+			}
+
+			evtsCfg := cfg.Notifications.Events
+			client, err := server.NewNatsStream(nats.Address(evtsCfg.Endpoint), nats.ClusterID(evtsCfg.Cluster))
+			if err != nil {
+				return err
+			}
+			evts, err := events.Consume(client, evtsCfg.ConsumerGroup, evs...)
+			if err != nil {
+				return err
+			}
+			channel, err := channels.NewMailChannel(*cfg, logger)
+			if err != nil {
+				return err
+			}
+			svc := service.NewEventsNotifier(evts, channel, logger)
+			return svc.Run()
+		},
+	}
+}
diff --git a/notifications/pkg/command/version.go b/notifications/pkg/command/version.go
new file mode 100644
index 00000000000..f2d47a569a5
--- /dev/null
+++ b/notifications/pkg/command/version.go
@@ -0,0 +1,19 @@
+package command
+
+import (
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/urfave/cli/v2"
+)
+
+// Version prints the service versions of all running instances.
+func Version(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "version",
+		Usage:    "print the version of this binary and the running extension instances",
+		Category: "info",
+		Action: func(c *cli.Context) error {
+			// not implemented
+			return nil
+		},
+	}
+}
diff --git a/notifications/pkg/config/config.go b/notifications/pkg/config/config.go
new file mode 100644
index 00000000000..8ac7da5d8f6
--- /dev/null
+++ b/notifications/pkg/config/config.go
@@ -0,0 +1,44 @@
+package config
+
+import (
+	"context"
+
+	"github.com/owncloud/ocis/ocis-pkg/shared"
+)
+
+// Config combines all available configuration parts.
+type Config struct {
+	*shared.Commons
+
+	Service Service
+
+	Log   *Log  `ocisConfig:"log"`
+	Debug Debug `ocisConfig:"debug"`
+
+	Notifications Notifications `ocisConfig:"notifications"`
+
+	Context context.Context
+}
+
+// Notifications definces the config options for the notifications service.
+type Notifications struct {
+	SMTP              SMTP   `ocisConfig:"SMTP"`
+	Events            Events `ocisConfig:"events"`
+	RevaGateway       string `ocisConfig:"reva_gateway" env:"REVA_GATEWAY;NOTIFICATIONS_REVA_GATEWAY"`
+	MachineAuthSecret string `ocisConfig:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;NOTIFICATIONS_MACHINE_AUTH_API_KEY"`
+}
+
+// SMTP combines the smtp configuration options.
+type SMTP struct {
+	Host     string `ocisConfig:"smtp_host" env:"NOTIFICATIONS_SMTP_HOST"`
+	Port     string `ocisConfig:"smtp_port" env:"NOTIFICATIONS_SMTP_PORT"`
+	Sender   string `ocisConfig:"smtp_sender" env:"NOTIFICATIONS_SMTP_SENDER"`
+	Password string `ocisConfig:"smtp_password" env:"NOTIFICATIONS_SMTP_PASSWORD"`
+}
+
+// Events combines the configuration options for the event bus.
+type Events struct {
+	Endpoint      string `ocisConfig:"events_endpoint" env:"NOTIFICATIONS_EVENTS_ENDPOINT"`
+	Cluster       string `ocisConfig:"events_cluster" env:"NOTIFICATIONS_EVENTS_CLUSTER"`
+	ConsumerGroup string `ocisConfig:"events_group" env:"NOTIFICATIONS_EVENTS_GROUP"`
+}
diff --git a/notifications/pkg/config/debug.go b/notifications/pkg/config/debug.go
new file mode 100644
index 00000000000..da6d2d59060
--- /dev/null
+++ b/notifications/pkg/config/debug.go
@@ -0,0 +1,9 @@
+package config
+
+// Debug defines the available debug configuration.
+type Debug struct {
+	Addr   string `ocisConfig:"addr" env:"NOTIFICATIONS_DEBUG_ADDR"`
+	Token  string `ocisConfig:"token" env:"NOTIFICATIONS_DEBUG_TOKEN"`
+	Pprof  bool   `ocisConfig:"pprof" env:"NOTIFICATIONS_DEBUG_PPROF"`
+	Zpages bool   `ocisConfig:"zpages" env:"NOTIFICATIONS_DEBUG_ZPAGES"`
+}
diff --git a/notifications/pkg/config/defaultconfig.go b/notifications/pkg/config/defaultconfig.go
new file mode 100644
index 00000000000..d5fb6e34987
--- /dev/null
+++ b/notifications/pkg/config/defaultconfig.go
@@ -0,0 +1,27 @@
+package config
+
+// NOTE: Most of this configuration is not needed to keep it as simple as possible
+// TODO: Clean up unneeded configuration
+
+func DefaultConfig() *Config {
+	return &Config{
+		Service: Service{
+			Name: "notifications",
+		},
+		Notifications: Notifications{
+			SMTP: SMTP{
+				Host:     "127.0.0.1",
+				Port:     "1025",
+				Sender:   "god@example.com",
+				Password: "godisdead",
+			},
+			Events: Events{
+				Endpoint:      "127.0.0.1:9233",
+				Cluster:       "test-cluster",
+				ConsumerGroup: "notifications",
+			},
+			RevaGateway:       "127.0.0.1:9142",
+			MachineAuthSecret: "change-me-please",
+		},
+	}
+}
diff --git a/notifications/pkg/config/log.go b/notifications/pkg/config/log.go
new file mode 100644
index 00000000000..ddb4d391f04
--- /dev/null
+++ b/notifications/pkg/config/log.go
@@ -0,0 +1,9 @@
+package config
+
+// Log defines the available log configuration.
+type Log struct {
+	Level  string `mapstructure:"level" env:"OCIS_LOG_LEVEL;NOTIFICATIONS_LOG_LEVEL"`
+	Pretty bool   `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;NOTIFICATIONS_LOG_PRETTY"`
+	Color  bool   `mapstructure:"color" env:"OCIS_LOG_COLOR;NOTIFICATIONS_LOG_COLOR"`
+	File   string `mapstructure:"file" env:"OCIS_LOG_FILE;NOTIFICATIONS_LOG_FILE"`
+}
diff --git a/notifications/pkg/config/parser/parse.go b/notifications/pkg/config/parser/parse.go
new file mode 100644
index 00000000000..5bc4e6e5713
--- /dev/null
+++ b/notifications/pkg/config/parser/parse.go
@@ -0,0 +1,40 @@
+package parser
+
+import (
+	"errors"
+
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
+
+	"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
+)
+
+// ParseConfig loads accounts configuration from known paths.
+func ParseConfig(cfg *config.Config) error {
+	_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
+	if err != nil {
+		return err
+	}
+
+	// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
+	if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
+		cfg.Log = &config.Log{
+			Level:  cfg.Commons.Log.Level,
+			Pretty: cfg.Commons.Log.Pretty,
+			Color:  cfg.Commons.Log.Color,
+			File:   cfg.Commons.Log.File,
+		}
+	} else if cfg.Log == nil {
+		cfg.Log = &config.Log{}
+	}
+
+	// load all env variables relevant to the config in the current context.
+	if err := envdecode.Decode(cfg); err != nil {
+		// no environment variable set for this config is an expected "error"
+		if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/notifications/pkg/config/service.go b/notifications/pkg/config/service.go
new file mode 100644
index 00000000000..f98aa3d27e5
--- /dev/null
+++ b/notifications/pkg/config/service.go
@@ -0,0 +1,6 @@
+package config
+
+// Service defines the available service configuration.
+type Service struct {
+	Name string
+}
diff --git a/notifications/pkg/logging/logging.go b/notifications/pkg/logging/logging.go
new file mode 100644
index 00000000000..039b0451c47
--- /dev/null
+++ b/notifications/pkg/logging/logging.go
@@ -0,0 +1,17 @@
+package logging
+
+import (
+	"github.com/owncloud/ocis/notifications/pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+)
+
+// LoggerFromConfig initializes a service-specific logger instance.
+func Configure(name string, cfg *config.Log) log.Logger {
+	return log.NewLogger(
+		log.Name(name),
+		log.Level(cfg.Level),
+		log.Pretty(cfg.Pretty),
+		log.Color(cfg.Color),
+		log.File(cfg.File),
+	)
+}
diff --git a/notifications/pkg/service/service.go b/notifications/pkg/service/service.go
new file mode 100644
index 00000000000..81e4a26b4ac
--- /dev/null
+++ b/notifications/pkg/service/service.go
@@ -0,0 +1,64 @@
+package service
+
+import (
+	"os"
+	"os/signal"
+	"syscall"
+
+	"github.com/cs3org/reva/pkg/events"
+	"github.com/owncloud/ocis/notifications/pkg/channels"
+	"github.com/owncloud/ocis/ocis-pkg/log"
+)
+
+type Service interface {
+	Run() error
+}
+
+func NewEventsNotifier(events <-chan interface{}, channel channels.Channel, logger log.Logger) Service {
+	return eventsNotifier{
+		logger:  logger,
+		channel: channel,
+		events:  events,
+		signals: make(chan os.Signal, 1),
+	}
+}
+
+type eventsNotifier struct {
+	logger  log.Logger
+	channel channels.Channel
+	events  <-chan interface{}
+	signals chan os.Signal
+}
+
+func (s eventsNotifier) Run() error {
+	signal.Notify(s.signals, syscall.SIGINT, syscall.SIGTERM)
+	s.logger.Debug().
+		Msg("eventsNotifier started")
+	for {
+		select {
+		case evt := <-s.events:
+			go func() {
+				switch e := evt.(type) {
+				case events.ShareCreated:
+					msg := "You got a share!"
+					var err error
+					if e.GranteeUserID != nil {
+						err = s.channel.SendMessage([]string{e.GranteeUserID.OpaqueId}, msg)
+					} else if e.GranteeGroupID != nil {
+						err = s.channel.SendMessageToGroup(e.GranteeGroupID, msg)
+					}
+					if err != nil {
+						s.logger.Error().
+							Err(err).
+							Str("event", "ShareCreated").
+							Msg("failed to send a message")
+					}
+				}
+			}()
+		case <-s.signals:
+			s.logger.Debug().
+				Msg("eventsNotifier stopped")
+			return nil
+		}
+	}
+}
diff --git a/ocis-pkg/config/config.go b/ocis-pkg/config/config.go
index 76aaeb35f69..2f0495b1f80 100644
--- a/ocis-pkg/config/config.go
+++ b/ocis-pkg/config/config.go
@@ -7,8 +7,10 @@ import (
 	glauth "github.com/owncloud/ocis/glauth/pkg/config"
 	graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/config"
 	graph "github.com/owncloud/ocis/graph/pkg/config"
+	idm "github.com/owncloud/ocis/idm/pkg/config"
 	idp "github.com/owncloud/ocis/idp/pkg/config"
 	nats "github.com/owncloud/ocis/nats/pkg/config"
+	notifications "github.com/owncloud/ocis/notifications/pkg/config"
 	ocs "github.com/owncloud/ocis/ocs/pkg/config"
 	proxy "github.com/owncloud/ocis/proxy/pkg/config"
 	settings "github.com/owncloud/ocis/settings/pkg/config"
@@ -61,7 +63,9 @@ type Config struct {
 	Graph         *graph.Config         `ocisConfig:"graph"`
 	GraphExplorer *graphExplorer.Config `ocisConfig:"graph_explorer"`
 	IDP           *idp.Config           `ocisConfig:"idp"`
+	IDM           *idm.Config           `ocisConfig:"idm"`
 	Nats          *nats.Config          `ocisConfig:"nats"`
+	Notifications *notifications.Config `ocisConfig:"notifications"`
 	OCS           *ocs.Config           `ocisConfig:"ocs"`
 	Web           *web.Config           `ocisConfig:"web"`
 	Proxy         *proxy.Config         `ocisConfig:"proxy"`
diff --git a/ocis-pkg/config/defaultconfig.go b/ocis-pkg/config/defaultconfig.go
index 53853cbfaf0..222b04b0fbb 100644
--- a/ocis-pkg/config/defaultconfig.go
+++ b/ocis-pkg/config/defaultconfig.go
@@ -5,8 +5,10 @@ import (
 	glauth "github.com/owncloud/ocis/glauth/pkg/config"
 	graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/config"
 	graph "github.com/owncloud/ocis/graph/pkg/config"
+	idm "github.com/owncloud/ocis/idm/pkg/config"
 	idp "github.com/owncloud/ocis/idp/pkg/config"
 	nats "github.com/owncloud/ocis/nats/pkg/config"
+	notifications "github.com/owncloud/ocis/notifications/pkg/config"
 	ocs "github.com/owncloud/ocis/ocs/pkg/config"
 	proxy "github.com/owncloud/ocis/proxy/pkg/config"
 	settings "github.com/owncloud/ocis/settings/pkg/config"
@@ -30,7 +32,9 @@ func DefaultConfig() *Config {
 		GLAuth:        glauth.DefaultConfig(),
 		Graph:         graph.DefaultConfig(),
 		IDP:           idp.DefaultConfig(),
+		IDM:           idm.DefaultConfig(),
 		Nats:          nats.DefaultConfig(),
+		Notifications: notifications.DefaultConfig(),
 		Proxy:         proxy.DefaultConfig(),
 		GraphExplorer: graphExplorer.DefaultConfig(),
 		OCS:           ocs.DefaultConfig(),
diff --git a/idp/pkg/logging/logrus_wrapper.go b/ocis-pkg/log/logrus_wrapper.go
similarity index 96%
rename from idp/pkg/logging/logrus_wrapper.go
rename to ocis-pkg/log/logrus_wrapper.go
index 38e302005df..e4c29240d90 100644
--- a/idp/pkg/logging/logrus_wrapper.go
+++ b/ocis-pkg/log/logrus_wrapper.go
@@ -1,4 +1,4 @@
-package logging
+package log
 
 import (
 	"io/ioutil"
@@ -26,7 +26,7 @@ type LogrusWrapper struct {
 
 // Wrap return a logrus logger which internally logs to /dev/null. Messages are passed to the
 // underlying zerolog via hooks.
-func Wrap(zr zerolog.Logger) *logrus.Logger {
+func LogrusWrap(zr zerolog.Logger) *logrus.Logger {
 	lr := logrus.New()
 	lr.SetOutput(ioutil.Discard)
 	lr.SetLevel(logrusLevel(zr.GetLevel()))
diff --git a/ocis/Makefile b/ocis/Makefile
index 4608380188b..94d351a04a6 100644
--- a/ocis/Makefile
+++ b/ocis/Makefile
@@ -1,6 +1,8 @@
 SHELL := bash
 NAME := ocis
 
+TAGS := disable_crypt
+
 include ../.make/recursion.mk
 
 ############ tooling ############
diff --git a/ocis/pkg/command/idm.go b/ocis/pkg/command/idm.go
new file mode 100644
index 00000000000..fbfa4ba0695
--- /dev/null
+++ b/ocis/pkg/command/idm.go
@@ -0,0 +1,26 @@
+package command
+
+import (
+	"github.com/owncloud/ocis/idm/pkg/command"
+	"github.com/owncloud/ocis/ocis-pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/config/parser"
+	"github.com/owncloud/ocis/ocis/pkg/register"
+	"github.com/urfave/cli/v2"
+)
+
+// IDMCommand is the entrypoint for the idm server command.
+func IDMCommand(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "idm",
+		Usage:    "idm extension commands",
+		Category: "extensions",
+		Before: func(ctx *cli.Context) error {
+			return parser.ParseConfig(cfg)
+		},
+		Subcommands: command.GetCommands(cfg.IDM),
+	}
+}
+
+func init() {
+	register.AddCommand(IDMCommand)
+}
diff --git a/ocis/pkg/command/notifications.go b/ocis/pkg/command/notifications.go
new file mode 100644
index 00000000000..ec2eb357066
--- /dev/null
+++ b/ocis/pkg/command/notifications.go
@@ -0,0 +1,26 @@
+package command
+
+import (
+	"github.com/owncloud/ocis/notifications/pkg/command"
+	"github.com/owncloud/ocis/ocis-pkg/config"
+	"github.com/owncloud/ocis/ocis-pkg/config/parser"
+	"github.com/owncloud/ocis/ocis/pkg/register"
+	"github.com/urfave/cli/v2"
+)
+
+// NatsServerCommand is the entrypoint for the nats server command.
+func NotificationsCommand(cfg *config.Config) *cli.Command {
+	return &cli.Command{
+		Name:     "notifications",
+		Usage:    "start notifications service",
+		Category: "extensions",
+		Before: func(ctx *cli.Context) error {
+			return parser.ParseConfig(cfg)
+		},
+		Subcommands: command.GetCommands(cfg.Notifications),
+	}
+}
+
+func init() {
+	register.AddCommand(NotificationsCommand)
+}
diff --git a/ocis/pkg/runtime/service/service.go b/ocis/pkg/runtime/service/service.go
index d160305ee06..c055f310464 100644
--- a/ocis/pkg/runtime/service/service.go
+++ b/ocis/pkg/runtime/service/service.go
@@ -22,8 +22,10 @@ import (
 	glauth "github.com/owncloud/ocis/glauth/pkg/command"
 	graphExplorer "github.com/owncloud/ocis/graph-explorer/pkg/command"
 	graph "github.com/owncloud/ocis/graph/pkg/command"
+	idm "github.com/owncloud/ocis/idm/pkg/command"
 	idp "github.com/owncloud/ocis/idp/pkg/command"
 	nats "github.com/owncloud/ocis/nats/pkg/command"
+	notifications "github.com/owncloud/ocis/notifications/pkg/command"
 	"github.com/owncloud/ocis/ocis-pkg/config"
 	ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
 	"github.com/owncloud/ocis/ocis-pkg/log"
@@ -98,6 +100,7 @@ func NewService(options ...Option) (*Service, error) {
 	s.ServicesRegistry["graph"] = graph.NewSutureService
 	s.ServicesRegistry["graph-explorer"] = graphExplorer.NewSutureService
 	s.ServicesRegistry["idp"] = idp.NewSutureService
+	s.ServicesRegistry["idm"] = idm.NewSutureService
 	s.ServicesRegistry["ocs"] = ocs.NewSutureService
 	s.ServicesRegistry["store"] = store.NewSutureService
 	s.ServicesRegistry["thumbnails"] = thumbnails.NewSutureService
@@ -114,6 +117,7 @@ func NewService(options ...Option) (*Service, error) {
 	s.ServicesRegistry["storage-shares"] = storage.NewStorageShares
 	s.ServicesRegistry["storage-public-link"] = storage.NewStoragePublicLink
 	s.ServicesRegistry["storage-appprovider"] = storage.NewAppProvider
+	s.ServicesRegistry["notifications"] = notifications.NewSutureService
 
 	// populate delayed services
 	s.Delayed["storage-sharing"] = storage.NewSharing
diff --git a/proxy/pkg/middleware/basic_auth.go b/proxy/pkg/middleware/basic_auth.go
index 6b26dbd0ce7..64e467497ef 100644
--- a/proxy/pkg/middleware/basic_auth.go
+++ b/proxy/pkg/middleware/basic_auth.go
@@ -11,8 +11,6 @@ import (
 	"github.com/owncloud/ocis/proxy/pkg/webdav"
 )
 
-const publicFilesEndpoint = "/remote.php/dav/public-files/"
-
 // BasicAuth provides a middleware to check if BasicAuth is provided
 func BasicAuth(optionSetters ...Option) func(next http.Handler) http.Handler {
 	options := newOptions(optionSetters...)
@@ -111,7 +109,25 @@ type basicAuth struct {
 
 func (m basicAuth) isPublicLink(req *http.Request) bool {
 	login, _, ok := req.BasicAuth()
-	return ok && login == "public" && strings.HasPrefix(req.URL.Path, publicFilesEndpoint)
+
+	if !ok || login != "public" {
+		return false
+	}
+
+	publicPaths := []string{
+		"/remote.php/dav/public-files/",
+		"/ocs/v1.php/cloud/capabilities",
+	}
+	isPublic := false
+
+	for _, p := range publicPaths {
+		if strings.HasPrefix(req.URL.Path, p) {
+			isPublic = true
+			break
+		}
+	}
+
+	return isPublic
 }
 
 // The token auth endpoint uses basic auth for clients, see https://openid.net/specs/openid-connect-basic-1_0.html#TokenRequest
diff --git a/settings/package.json b/settings/package.json
index c35cc6dc0a5..427e9696965 100644
--- a/settings/package.json
+++ b/settings/package.json
@@ -64,7 +64,7 @@
     "nightwatch-api": "3.0.2",
     "nightwatch-vrt": "^0.2.10",
     "node-fetch": "^2.6.1",
-    "qs": "^6.10.1",
+    "qs": "^6.10.3",
     "rimraf": "^3.0.0",
     "rollup": "^2.55.1",
     "rollup-plugin-babel": "^4.3.3",
diff --git a/settings/yarn.lock b/settings/yarn.lock
index 86f46c8eb15..fb193841d7a 100644
--- a/settings/yarn.lock
+++ b/settings/yarn.lock
@@ -6801,10 +6801,10 @@ punycode@^2.1.0, punycode@^2.1.1:
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
   integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
 
-qs@^6.10.1:
-  version "6.10.1"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a"
-  integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==
+qs@^6.10.3:
+  version "6.10.3"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
+  integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
   dependencies:
     side-channel "^1.0.4"
 
diff --git a/storage/pkg/command/groups.go b/storage/pkg/command/groups.go
index b7195143142..57d1d38998f 100644
--- a/storage/pkg/command/groups.go
+++ b/storage/pkg/command/groups.go
@@ -32,6 +32,7 @@ func Groups(cfg *config.Config) *cli.Command {
 			tracing.Configure(cfg, logger)
 			gr := run.Group{}
 			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
 
 			// pre-create folders
 			if cfg.Reva.Groups.Driver == "json" && cfg.Reva.Groups.JSON != "" {
@@ -40,9 +41,8 @@ func Groups(cfg *config.Config) *cli.Command {
 				}
 			}
 
-			uuid := uuid.Must(uuid.NewV4())
-			pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+uuid.String()+".pid")
-			defer cancel()
+			cuuid := uuid.Must(uuid.NewV4())
+			pidFile := path.Join(os.TempDir(), "revad-"+c.Command.Name+"-"+cuuid.String()+".pid")
 
 			rcfg := groupsConfigFromStruct(c, cfg)
 
diff --git a/thumbnails/pkg/service/v0/service.go b/thumbnails/pkg/service/v0/service.go
index eb80ef9738c..b4978e3fb10 100644
--- a/thumbnails/pkg/service/v0/service.go
+++ b/thumbnails/pkg/service/v0/service.go
@@ -217,11 +217,24 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *thumbnailssvc.Ge
 func (g Thumbnail) stat(path, auth string) (*provider.StatResponse, error) {
 	ctx := metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, auth)
 
-	req := &provider.StatRequest{
-		Ref: &provider.Reference{
+	var ref *provider.Reference
+	if strings.Contains(path, "!") {
+		parts := strings.Split(path, "!")
+		spaceID, path := parts[0], parts[1]
+		ref = &provider.Reference{
+			ResourceId: &provider.ResourceId{
+				StorageId: spaceID,
+				OpaqueId:  spaceID,
+			},
 			Path: path,
-		},
+		}
+	} else {
+		ref = &provider.Reference{
+			Path: path,
+		}
 	}
+
+	req := &provider.StatRequest{Ref: ref}
 	rsp, err := g.cs3Client.Stat(ctx, req)
 	if err != nil {
 		g.logger.Error().Err(err).Str("path", path).Msg("could not stat file")
diff --git a/thumbnails/pkg/thumbnail/imgsource/cs3.go b/thumbnails/pkg/thumbnail/imgsource/cs3.go
index 9cf3db58abd..9795d129236 100644
--- a/thumbnails/pkg/thumbnail/imgsource/cs3.go
+++ b/thumbnails/pkg/thumbnail/imgsource/cs3.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"strings"
 
 	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
 	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -42,12 +43,25 @@ func (s CS3) Get(ctx context.Context, path string) (io.ReadCloser, error) {
 	if !ok {
 		return nil, errors.New("cs3source: authorization missing")
 	}
-	ctx = metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, auth)
-	rsp, err := s.client.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{
-		Ref: &provider.Reference{
+	var ref *provider.Reference
+	if strings.Contains(path, "!") {
+		parts := strings.Split(path, "!")
+		spaceID, path := parts[0], parts[1]
+		ref = &provider.Reference{
+			ResourceId: &provider.ResourceId{
+				StorageId: spaceID,
+				OpaqueId:  spaceID,
+			},
+			// Spaces requests need relative paths.
+			Path: "." + path,
+		}
+	} else {
+		ref = &provider.Reference{
 			Path: path,
-		},
-	})
+		}
+	}
+	ctx = metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, auth)
+	rsp, err := s.client.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{Ref: ref})
 
 	if err != nil {
 		return nil, err
diff --git a/web/pkg/assets/server.go b/web/pkg/assets/server.go
new file mode 100644
index 00000000000..527134330c8
--- /dev/null
+++ b/web/pkg/assets/server.go
@@ -0,0 +1,80 @@
+package assets
+
+import (
+	"bytes"
+	"golang.org/x/net/html"
+	"io"
+	"mime"
+	"net/http"
+	"path"
+	"path/filepath"
+)
+
+type fileServer struct {
+	root http.FileSystem
+}
+
+func FileServer(root http.FileSystem) http.Handler {
+	return &fileServer{root}
+}
+
+func (f *fileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	upath := path.Clean(path.Join("/", r.URL.Path))
+	r.URL.Path = upath
+
+	asset, err := f.root.Open(upath)
+	if err != nil {
+		r.URL.Path = "/index.html"
+		f.ServeHTTP(w, r)
+		return
+	}
+	defer asset.Close()
+
+	s, _ := asset.Stat()
+	if s.IsDir() {
+		r.URL.Path = "/index.html"
+		f.ServeHTTP(w, r)
+		return
+	}
+
+	w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(s.Name())))
+
+	buf := new(bytes.Buffer)
+
+	switch s.Name() {
+	case "index.html", "oidc-callback.html", "oidc-silent-redirect.html":
+		_ = withBase(buf, asset, "/")
+	default:
+		_, _ = buf.ReadFrom(asset)
+	}
+
+	_, _ = w.Write(buf.Bytes())
+}
+
+func withBase(w io.Writer, r io.Reader, base string) error {
+	doc, _ := html.Parse(r)
+	var parse func(*html.Node)
+	parse = func(n *html.Node) {
+		if n.Type == html.ElementNode && n.Data == "head" {
+			n.InsertBefore(&html.Node{
+				Type: html.ElementNode,
+				Data: "base",
+				Attr: []html.Attribute{
+					{
+						Key: "href",
+						Val: base,
+					},
+				},
+			}, n.FirstChild)
+
+			return
+		}
+
+		for c := n.FirstChild; c != nil; c = c.NextSibling {
+			parse(c)
+		}
+	}
+	parse(doc)
+
+	return html.Render(w, doc)
+}
diff --git a/web/pkg/service/v0/service.go b/web/pkg/service/v0/service.go
index 49b78d14454..d7a92c3ad5f 100644
--- a/web/pkg/service/v0/service.go
+++ b/web/pkg/service/v0/service.go
@@ -2,10 +2,12 @@ package svc
 
 import (
 	"encoding/json"
+	"fmt"
 	"io/ioutil"
 	"net/http"
 	"net/url"
 	"os"
+	"strconv"
 	"strings"
 	"time"
 
@@ -141,28 +143,19 @@ func (p Web) Static(ttl int) http.HandlerFunc {
 	if !strings.HasSuffix(rootWithSlash, "/") {
 		rootWithSlash = rootWithSlash + "/"
 	}
-	assets := assets.New(
-		assets.Logger(p.logger),
-		assets.Config(p.config),
-	)
-
-	notFoundFunc := func(w http.ResponseWriter, r *http.Request) {
-		// TODO: replace the redirect with a not found page containing a link to the Web UI
-		http.Redirect(w, r, rootWithSlash, http.StatusTemporaryRedirect)
-	}
 
 	static := http.StripPrefix(
 		rootWithSlash,
-		interceptNotFound(
-			http.FileServer(assets),
-			notFoundFunc,
+		assets.FileServer(
+			assets.New(
+				assets.Logger(p.logger),
+				assets.Config(p.config),
+			),
 		),
 	)
 
-	// TODO: investigate broken caching - https://github.com/owncloud/ocis/issues/1094
-	// we don't have a last modification date of the static assets, so we use the service start date
-	//lastModified := time.Now().UTC().Format(http.TimeFormat)
-	//expires := time.Now().Add(time.Second * time.Duration(ttl)).UTC().Format(http.TimeFormat)
+	lastModified := time.Now().UTC().Format(http.TimeFormat)
+	expires := time.Now().Add(time.Second * time.Duration(ttl)).UTC().Format(http.TimeFormat)
 
 	return func(w http.ResponseWriter, r *http.Request) {
 		if rootWithSlash != "/" && r.URL.Path == p.config.HTTP.Root {
@@ -175,49 +168,11 @@ func (p Web) Static(ttl int) http.HandlerFunc {
 			return
 		}
 
-		if r.URL.Path != rootWithSlash && strings.HasSuffix(r.URL.Path, "/") {
-			notFoundFunc(w, r)
-			return
-		}
-
-		// TODO: investigate broken caching - https://github.com/owncloud/ocis/issues/1094
-		//w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%s, must-revalidate", strconv.Itoa(ttl)))
-		//w.Header().Set("Expires", expires)
-		//w.Header().Set("Last-Modified", lastModified)
-		w.Header().Set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
-		w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
-		w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
+		w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%s, must-revalidate", strconv.Itoa(ttl)))
+		w.Header().Set("Expires", expires)
+		w.Header().Set("Last-Modified", lastModified)
 		w.Header().Set("SameSite", "Strict")
 
 		static.ServeHTTP(w, r)
 	}
 }
-
-func interceptNotFound(h http.Handler, notFoundFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		notFoundInterceptor := &NotFoundInterceptor{ResponseWriter: w}
-		h.ServeHTTP(notFoundInterceptor, r)
-		if notFoundInterceptor.status == http.StatusNotFound {
-			notFoundFunc(w, r)
-		}
-	}
-}
-
-type NotFoundInterceptor struct {
-	http.ResponseWriter
-	status int
-}
-
-func (w *NotFoundInterceptor) WriteHeader(status int) {
-	w.status = status
-	if status != http.StatusNotFound {
-		w.ResponseWriter.WriteHeader(status)
-	}
-}
-
-func (w *NotFoundInterceptor) Write(p []byte) (int, error) {
-	if w.status != http.StatusNotFound {
-		return w.ResponseWriter.Write(p)
-	}
-	return len(p), nil
-}
diff --git a/webdav/pkg/dav/requests/thumbnail.go b/webdav/pkg/dav/requests/thumbnail.go
index be1e7d43c4e..48b80ad4882 100644
--- a/webdav/pkg/dav/requests/thumbnail.go
+++ b/webdav/pkg/dav/requests/thumbnail.go
@@ -33,13 +33,13 @@ type ThumbnailRequest struct {
 	Height int32
 	// In case of a public share the public link token.
 	PublicLinkToken string
-	// The username from the requested URL
-	Username string
+	// The Identifier from the requested URL
+	Identifier string
 }
 
 // ParseThumbnailRequest extracts all required parameters from a http request.
 func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
-	fp, username, err := extractFilePath(r)
+	fp, id, err := extractFilePath(r)
 	if err != nil {
 		return nil, err
 	}
@@ -57,7 +57,7 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
 		Width:           int32(width),
 		Height:          int32(height),
 		PublicLinkToken: chi.URLParam(r, "token"),
-		Username:        username,
+		Identifier:      id,
 	}, nil
 }
 
@@ -68,16 +68,17 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
 // User and filepath are dynamic and filepath can contain slashes
 // So using the URLParam function is not possible.
 func extractFilePath(r *http.Request) (string, string, error) {
-	user := chi.URLParam(r, "user")
-	user, err := url.QueryUnescape(user)
+	id := chi.URLParam(r, "id")
+	id, err := url.QueryUnescape(id)
 	if err != nil {
 		return "", "", errors.New("could not unescape user")
 	}
-	if user != "" {
-		parts := strings.SplitN(r.URL.Path, user, 2)
-		return parts[1], user, nil
+	if id != "" {
+		parts := strings.SplitN(r.URL.Path, id, 2)
+		return parts[1], id, nil
 	}
 
+	// This is for public links
 	token := chi.URLParam(r, "token")
 	if token != "" {
 		parts := strings.SplitN(r.URL.Path, token, 2)
diff --git a/webdav/pkg/service/v0/service.go b/webdav/pkg/service/v0/service.go
index 2ab53bd486f..a5562171f19 100644
--- a/webdav/pkg/service/v0/service.go
+++ b/webdav/pkg/service/v0/service.go
@@ -66,7 +66,8 @@ func NewService(opts ...Option) (Service, error) {
 	}
 
 	m.Route(options.Config.HTTP.Root, func(r chi.Router) {
-		r.Get("/remote.php/dav/files/{user}/*", svc.Thumbnail)
+		r.Get("/remote.php/dav/spaces/{id}/*", svc.SpacesThumbnail)
+		r.Get("/remote.php/dav/files/{id}/*", svc.Thumbnail)
 		r.Get("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnail)
 		r.Head("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnailHead)
 	})
@@ -88,6 +89,53 @@ func (g Webdav) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	g.mux.ServeHTTP(w, r)
 }
 
+// SpacesThumbnail is the endpoint for retrieving thumbnails inside of spaces.
+func (g Webdav) SpacesThumbnail(w http.ResponseWriter, r *http.Request) {
+	tr, err := requests.ParseThumbnailRequest(r)
+	if err != nil {
+		g.log.Error().Err(err).Msg("could not create Request")
+		renderError(w, r, errBadRequest(err.Error()))
+		return
+	}
+	t := r.Header.Get(TokenHeader)
+
+	fullPath := tr.Identifier + "!" + tr.Filepath
+	rsp, err := g.thumbnailsClient.GetThumbnail(r.Context(), &thumbnailssvc.GetThumbnailRequest{
+		Filepath:      strings.TrimLeft(tr.Filepath, "/"),
+		ThumbnailType: extensionToThumbnailType(strings.TrimLeft(tr.Extension, ".")),
+		Width:         tr.Width,
+		Height:        tr.Height,
+		Source: &thumbnailssvc.GetThumbnailRequest_Cs3Source{
+			Cs3Source: &thumbnailsmsg.CS3Source{
+				Path:          fullPath,
+				Authorization: t,
+			},
+		},
+	})
+	if err != nil {
+		e := merrors.Parse(err.Error())
+		switch e.Code {
+		case http.StatusNotFound:
+			// StatusNotFound is expected for unsupported files
+			renderError(w, r, errNotFound(notFoundMsg(tr.Filename)))
+			return
+		case http.StatusBadRequest:
+			renderError(w, r, errBadRequest(err.Error()))
+		default:
+			renderError(w, r, errInternalError(err.Error()))
+		}
+		g.log.Error().Err(err).Msg("could not get thumbnail")
+		return
+	}
+
+	if len(rsp.Thumbnail) == 0 {
+		renderError(w, r, errNotFound(""))
+		return
+	}
+
+	g.mustRender(w, r, newThumbnailResponse(rsp))
+}
+
 // Thumbnail implements the Service interface.
 func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
 	tr, err := requests.ParseThumbnailRequest(r)
@@ -101,7 +149,7 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
 	ctx := metadata.AppendToOutgoingContext(r.Context(), TokenHeader, t)
 	userRes, err := g.revaClient.GetUserByClaim(ctx, &userv1beta1.GetUserByClaimRequest{
 		Claim: "username",
-		Value: tr.Username,
+		Value: tr.Identifier,
 	})
 	if err != nil || userRes.Status.Code != rpcv1beta1.Code_CODE_OK {
 		g.log.Error().Err(err).Msg("could not get user")


Test patch:
diff --git a/deployments/continuous-deployment-config/oc10_ocis_parallel/latest.yml b/deployments/continuous-deployment-config/oc10_ocis_parallel/latest.yml
index 8f78eb26476..6d2cbb8a423 100644
--- a/deployments/continuous-deployment-config/oc10_ocis_parallel/latest.yml
+++ b/deployments/continuous-deployment-config/oc10_ocis_parallel/latest.yml
@@ -25,8 +25,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_hello/latest.yml b/deployments/continuous-deployment-config/ocis_hello/latest.yml
index 04e58aa1407..d4b38625fb6 100644
--- a/deployments/continuous-deployment-config/ocis_hello/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_hello/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_individual_services/latest.yml b/deployments/continuous-deployment-config/ocis_individual_services/latest.yml
new file mode 100644
index 00000000000..b4c7273c8ca
--- /dev/null
+++ b/deployments/continuous-deployment-config/ocis_individual_services/latest.yml
@@ -0,0 +1,49 @@
+---
+- name: continuous-deployment-ocis-individual-services-latest
+  server:
+    server_type: cx31
+    image: ubuntu-20.04
+    location: nbg1
+    initial_ssh_key_names:
+      - owncloud-ocis@drone.owncloud.com
+    labels:
+      owner: wkloucek
+      for: oCIS-continuous-deployment-examples
+    rebuild: $REBUILD
+    rebuild_carry_paths:
+      - /var/lib/docker/volumes/ocis_certs
+
+  domains:
+    - "*.ocis-individual-services.latest.owncloud.works"
+
+  vars:
+    ssh_authorized_keys:
+      - https://github.com/butonic.keys
+      - https://github.com/C0rby.keys
+      - https://github.com/fschade.keys
+      - https://github.com/kulmann.keys
+      - https://github.com/micbar.keys
+      - https://github.com/pascalwengerter.keys
+      - https://github.com/wkloucek.keys
+    docker_compose_projects:
+      - name: ocis
+        git_url: https://github.com/owncloud/ocis.git
+        ref: master
+        docker_compose_path: deployments/examples/ocis_individual_services
+        env:
+          INSECURE: "false"
+          TRAEFIK_ACME_MAIL: wkloucek@owncloud.com
+          OCIS_DOCKER_TAG: latest
+          OCIS_SCALE: 6
+          OCIS_DOMAIN: ocis.ocis-individual-services.latest.owncloud.works
+          COMPOSE_FILE: docker-compose.yml:monitoring_tracing/docker-compose-additions.yml
+      - name: monitoring
+        git_url: https://github.com/owncloud-devops/monitoring-tracing-client.git
+        ref: master
+        env:
+          NETWORK_NAME: ocis-net
+          TELEMETRY_SERVE_DOMAIN: telemetry.ocis-individual-services.latest.owncloud.works
+          JAEGER_COLLECTOR: jaeger-collector.infra.owncloud.works:443
+          TELEGRAF_SPECIFIC_CONFIG: ocis_individual_services
+          OCIS_URL: ocis.ocis-individual-services.latest.owncloud.works
+          OCIS_DEPLOYMENT_ID: continuous-deployment-ocis-individual-services-latest
diff --git a/deployments/continuous-deployment-config/ocis_keycloak/latest.yml b/deployments/continuous-deployment-config/ocis_keycloak/latest.yml
index afa3503a197..e923589d873 100644
--- a/deployments/continuous-deployment-config/ocis_keycloak/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_keycloak/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_ldap/latest.yml b/deployments/continuous-deployment-config/ocis_ldap/latest.yml
index 26348b942af..ecd85c75d78 100644
--- a/deployments/continuous-deployment-config/ocis_ldap/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_ldap/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_s3/latest.yml b/deployments/continuous-deployment-config/ocis_s3/latest.yml
index f49ad1a48c6..76d8fcb7e67 100644
--- a/deployments/continuous-deployment-config/ocis_s3/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_s3/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_traefik/latest.yml b/deployments/continuous-deployment-config/ocis_traefik/latest.yml
index fe5b7293859..0f5e22d5179 100644
--- a/deployments/continuous-deployment-config/ocis_traefik/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_traefik/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/deployments/continuous-deployment-config/ocis_wopi/latest.yml b/deployments/continuous-deployment-config/ocis_wopi/latest.yml
index 006c1160a4b..f44c59e7070 100644
--- a/deployments/continuous-deployment-config/ocis_wopi/latest.yml
+++ b/deployments/continuous-deployment-config/ocis_wopi/latest.yml
@@ -24,8 +24,6 @@
       - https://github.com/kulmann.keys
       - https://github.com/micbar.keys
       - https://github.com/pascalwengerter.keys
-      - https://github.com/paulcod3.keys
-      - https://github.com/refs.keys
       - https://github.com/wkloucek.keys
     docker_compose_projects:
       - name: ocis
diff --git a/proxy/pkg/middleware/basic_auth_test.go b/proxy/pkg/middleware/basic_auth_test.go
index fbdfab057f6..46c7f48285e 100644
--- a/proxy/pkg/middleware/basic_auth_test.go
+++ b/proxy/pkg/middleware/basic_auth_test.go
@@ -1,3 +1,40 @@
 package middleware
 
+import (
+	"net/http/httptest"
+	"testing"
+)
+
 /**/
+
+func TestBasicAuth__isPublicLink(t *testing.T) {
+	tests := []struct {
+		url      string
+		username string
+		expected bool
+	}{
+		{url: "/remote.php/dav/public-files/", username: "", expected: false},
+		{url: "/remote.php/dav/public-files/", username: "abc", expected: false},
+		{url: "/remote.php/dav/public-files/", username: "private", expected: false},
+		{url: "/remote.php/dav/public-files/", username: "public", expected: true},
+		{url: "/ocs/v1.php/cloud/capabilities", username: "", expected: false},
+		{url: "/ocs/v1.php/cloud/capabilities", username: "abc", expected: false},
+		{url: "/ocs/v1.php/cloud/capabilities", username: "private", expected: false},
+		{url: "/ocs/v1.php/cloud/capabilities", username: "public", expected: true},
+		{url: "/ocs/v1.php/cloud/users/admin", username: "public", expected: false},
+	}
+	ba := basicAuth{}
+
+	for _, tt := range tests {
+		req := httptest.NewRequest("", tt.url, nil)
+
+		if tt.username != "" {
+			req.SetBasicAuth(tt.username, "")
+		}
+
+		result := ba.isPublicLink(req)
+		if result != tt.expected {
+			t.Errorf("with %s expected %t got %t", tt.url, tt.expected, result)
+		}
+	}
+}
diff --git a/tests/acceptance/expected-failures-API-on-OCIS-storage.md b/tests/acceptance/expected-failures-API-on-OCIS-storage.md
index 7d4a1ea327d..180a071e7f6 100644
--- a/tests/acceptance/expected-failures-API-on-OCIS-storage.md
+++ b/tests/acceptance/expected-failures-API-on-OCIS-storage.md
@@ -5,10 +5,10 @@ The expected failures in this file are from features in the owncloud/core repo.
 Basic file management like up and download, move, copy, properties, trash, versions and chunking.
 
 #### [Getting information about a folder overwritten by a file gives 500 error instead of 404](https://github.com/owncloud/ocis/issues/1239)
+-   [apiWebdavProperties1/copyFile.feature:286](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L286)
 -   [apiWebdavProperties1/copyFile.feature:287](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L287)
--   [apiWebdavProperties1/copyFile.feature:288](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L288)
+-   [apiWebdavProperties1/copyFile.feature:309](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L309)
 -   [apiWebdavProperties1/copyFile.feature:310](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L310)
--   [apiWebdavProperties1/copyFile.feature:311](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L311)
 
 
 #### [Custom dav properties with namespaces are rendered incorrectly](https://github.com/owncloud/ocis/issues/2140)
@@ -21,12 +21,12 @@ _ocdav: double check the webdav property parsing when custom namespaces are used
 -   [apiWebdavProperties1/setFileProperties.feature:84](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/setFileProperties.feature#L84)
 
 #### [Cannot set custom webDav properties](https://github.com/owncloud/product/issues/264)
--   [apiWebdavProperties2/getFileProperties.feature:348](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L348)
--   [apiWebdavProperties2/getFileProperties.feature:353](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L353)
--   [apiWebdavProperties2/getFileProperties.feature:358](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L358)
--   [apiWebdavProperties2/getFileProperties.feature:389](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L389)
--   [apiWebdavProperties2/getFileProperties.feature:394](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L394)
--   [apiWebdavProperties2/getFileProperties.feature:399](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L399)
+-   [apiWebdavProperties2/getFileProperties.feature:360](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L360)
+-   [apiWebdavProperties2/getFileProperties.feature:365](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L365)
+-   [apiWebdavProperties2/getFileProperties.feature:370](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L370)
+-   [apiWebdavProperties2/getFileProperties.feature:401](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L401)
+-   [apiWebdavProperties2/getFileProperties.feature:406](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L406)
+-   [apiWebdavProperties2/getFileProperties.feature:411](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L411)
 
 #### [downloading an old version of a file returns 501](https://github.com/owncloud/ocis/issues/2261)
 -    [apiVersions/fileVersions.feature:426](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersions.feature#L426)
@@ -538,12 +538,6 @@ cannot share a folder with create permission
 -   [apiSharePublicLink2/copyFromPublicLink.feature:182](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/copyFromPublicLink.feature#L182)
 -   [apiSharePublicLink2/updatePublicLinkShare.feature:45](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L45)
 -   [apiSharePublicLink2/updatePublicLinkShare.feature:46](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L46)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:118](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L118)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:119](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L119)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:120](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L120)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:121](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L121)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:126](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L126)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:127](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L127)
 
 #### [OCIS share permissions not enforced](https://github.com/owncloud/product/issues/270)
 
@@ -554,10 +548,10 @@ cannot share a folder with create permission
 
 #### [Adding public upload to a read only shared folder as a recipient is allowed ](https://github.com/owncloud/ocis/issues/2164)
 
--   [apiSharePublicLink2/updatePublicLinkShare.feature:342](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L342)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:343](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L343)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:402](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L402)
--   [apiSharePublicLink2/updatePublicLinkShare.feature:403](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L403)
+-   [apiSharePublicLink2/updatePublicLinkShare.feature:338](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L338)
+-   [apiSharePublicLink2/updatePublicLinkShare.feature:339](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L339)
+-   [apiSharePublicLink2/updatePublicLinkShare.feature:398](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L398)
+-   [apiSharePublicLink2/updatePublicLinkShare.feature:399](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiSharePublicLink2/updatePublicLinkShare.feature#L399)
 
 #### [Upload-only shares must not overwrite but create a separate file](https://github.com/owncloud/ocis-reva/issues/286)
 
@@ -651,32 +645,32 @@ _getting and setting quota_
 -   [apiMain/quota.feature:269](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/quota.feature#L269)
 -   [apiMain/quota.feature:283](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/quota.feature#L283)
 -   [apiMain/quota.feature:289](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/quota.feature#L289)
+    Scenario Outline: Retrieving folder quota when no quota is set
+-   [apiWebdavProperties1/getQuota.feature:18](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L18)
+-   [apiWebdavProperties1/getQuota.feature:19](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L19)
+-   [apiWebdavProperties1/getQuota.feature:24](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L24)
+    Scenario Outline: Retrieving folder quota when quota is set
+-   [apiWebdavProperties1/getQuota.feature:34](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L34)
+-   [apiWebdavProperties1/getQuota.feature:35](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L35)
+-   [apiWebdavProperties1/getQuota.feature:40](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L40)
     Scenario Outline: Retrieving folder quota of shared folder with quota when no quota is set for recipient
--   [apiWebdavProperties1/getQuota.feature:58](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L58)
--   [apiWebdavProperties1/getQuota.feature:59](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L59)
--   [apiWebdavProperties1/getQuota.feature:64](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L64)
+-   [apiWebdavProperties1/getQuota.feature:61](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L61)
+-   [apiWebdavProperties1/getQuota.feature:62](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L62)
+-   [apiWebdavProperties1/getQuota.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L67)
     Scenario Outline: Retrieving folder quota when quota is set and a file was uploaded
--   [apiWebdavProperties1/getQuota.feature:77](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L77)
--   [apiWebdavProperties1/getQuota.feature:78](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L78)
--   [apiWebdavProperties1/getQuota.feature:83](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L83)
+-   [apiWebdavProperties1/getQuota.feature:81](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L81)
+-   [apiWebdavProperties1/getQuota.feature:82](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L82)
+-   [apiWebdavProperties1/getQuota.feature:87](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L87)
     Scenario Outline: Retrieving folder quota when quota is set and a file was received
--   [apiWebdavProperties1/getQuota.feature:98](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L98)
--   [apiWebdavProperties1/getQuota.feature:99](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L99)
+-   [apiWebdavProperties1/getQuota.feature:103](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L103)
 -   [apiWebdavProperties1/getQuota.feature:104](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L104)
-    Scenario Outline: Retrieving folder quota when no quota is set
--   [apiWebdavProperties1/getQuota.feature:17](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L17)
--   [apiWebdavProperties1/getQuota.feature:18](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L18)
--   [apiWebdavProperties1/getQuota.feature:23](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L23)
-    Scenario Outline: Retrieving folder quota when quota is set
--   [apiWebdavProperties1/getQuota.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L32)
--   [apiWebdavProperties1/getQuota.feature:33](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L33)
--   [apiWebdavProperties1/getQuota.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L38)
+-   [apiWebdavProperties1/getQuota.feature:109](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/getQuota.feature#L109)
 
 #### [Private link support](https://github.com/owncloud/product/issues/201)
 #### [oc:privatelink property not returned in webdav responses](https://github.com/owncloud/product/issues/262)
--   [apiWebdavProperties2/getFileProperties.feature:295](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L295)
--   [apiWebdavProperties2/getFileProperties.feature:296](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L296)
--   [apiWebdavProperties2/getFileProperties.feature:301](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L301)
+-   [apiWebdavProperties2/getFileProperties.feature:306](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L306)
+-   [apiWebdavProperties2/getFileProperties.feature:307](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L307)
+-   [apiWebdavProperties2/getFileProperties.feature:312](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L312)
 
 #### [changing user quota gives ocs status 103 / Cannot set quota](https://github.com/owncloud/product/issues/247)
 -   [apiShareOperationsToShares2/uploadToShare.feature:193](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L193)
@@ -1104,10 +1098,6 @@ API, search, favorites, config, capabilities, not existing endpoints, CORS and o
 #### [no robots.txt available](https://github.com/owncloud/ocis/issues/1314)
 -   [apiMain/main.feature:5](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/main.feature#L5) Scenario: robots.txt file should be accessible
 
-#### [Different version, edition and productname in status request and capabilities request](https://github.com/owncloud/ocis/issues/2174)
--   [apiMain/status.feature:5](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/status.feature#L5) Scenario: Status.php is correct
-#### [ocs config endpoint only accessible by authorized users](https://github.com/owncloud/ocis/issues/1338)
-
 #### [Ability to return error messages in Webdav response bodies](https://github.com/owncloud/ocis/issues/1293)
 -   [apiAuthOcs/ocsDELETEAuth.feature:10](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiAuthOcs/ocsDELETEAuth.feature#L10) Scenario: send DELETE requests to OCS endpoints as admin with wrong password
 -   [apiAuthOcs/ocsGETAuth.feature:10](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiAuthOcs/ocsGETAuth.feature#L10) Scenario: using OCS anonymously
@@ -1197,24 +1187,24 @@ _ocdav: api compatibility, return correct status code_
 -   [apiWebdavOperations/search.feature:270](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavOperations/search.feature#L270)
 
 And other missing implementation of favorites
--   [apiFavorites/favorites.feature:158](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L158)
--   [apiFavorites/favorites.feature:159](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L159)
--   [apiFavorites/favorites.feature:183](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L183)
--   [apiFavorites/favorites.feature:184](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L184)
--   [apiFavorites/favorites.feature:189](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L189)
--   [apiFavorites/favorites.feature:216](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L216)
--   [apiFavorites/favorites.feature:217](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L217)
--   [apiFavorites/favorites.feature:222](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L222)
--   [apiFavorites/favoritesSharingToShares.feature:77](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L77)
--   [apiFavorites/favoritesSharingToShares.feature:78](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L78)
+-   [apiFavorites/favorites.feature:162](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L162)
+-   [apiFavorites/favorites.feature:163](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L163)
+-   [apiFavorites/favorites.feature:187](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L187)
+-   [apiFavorites/favorites.feature:188](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L188)
+-   [apiFavorites/favorites.feature:193](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L193)
+-   [apiFavorites/favorites.feature:220](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L220)
+-   [apiFavorites/favorites.feature:221](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L221)
+-   [apiFavorites/favorites.feature:226](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L226)
+-   [apiFavorites/favoritesSharingToShares.feature:82](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L82)
+-   [apiFavorites/favoritesSharingToShares.feature:88](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L88)
 
 #### [resource inside Shares dir is not found using the spaces WebDAV API](https://github.com/owncloud/ocis/issues/2968)
--   [apiFavorites/favorites.feature:164](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L164)
--   [apiFavorites/favoritesSharingToShares.feature:27](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L27)
--   [apiFavorites/favoritesSharingToShares.feature:46](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L46)
--   [apiFavorites/favoritesSharingToShares.feature:64](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L64)
+-   [apiFavorites/favorites.feature:168](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L168)
+-   [apiFavorites/favoritesSharingToShares.feature:28](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L28)
+-   [apiFavorites/favoritesSharingToShares.feature:48](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L48)
+-   [apiFavorites/favoritesSharingToShares.feature:67](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L67)
 -   [apiFavorites/favoritesSharingToShares.feature:83](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L83)
--   [apiFavorites/favoritesSharingToShares.feature:102](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L102)
+-   [apiFavorites/favoritesSharingToShares.feature:108](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favoritesSharingToShares.feature#L108)
 -   [apiMain/checksums.feature:203](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiMain/checksums.feature#L203)
 -   [apiShareOperationsToShares2/getWebDAVSharePermissions.feature:49](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/getWebDAVSharePermissions.feature#L49)
 -   [apiShareOperationsToShares2/getWebDAVSharePermissions.feature:75](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/getWebDAVSharePermissions.feature#L75)
@@ -1239,18 +1229,18 @@ And other missing implementation of favorites
 -   [apiShareOperationsToShares2/uploadToShare.feature:171](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L171)
 -   [apiShareOperationsToShares2/uploadToShare.feature:346](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L346)
 -   [apiShareOperationsToShares2/uploadToShare.feature:347](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/uploadToShare.feature#L347)
--   [apiWebdavProperties1/copyFile.feature:90](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L90)
--   [apiWebdavProperties1/copyFile.feature:117](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L117)
--   [apiWebdavProperties1/copyFile.feature:293](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L293)
--   [apiWebdavProperties1/copyFile.feature:316](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L316)
--   [apiWebdavProperties1/copyFile.feature:344](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L344)
--   [apiWebdavProperties1/copyFile.feature:374](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L374)
--   [apiWebdavProperties1/copyFile.feature:403](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L403)
--   [apiWebdavProperties1/copyFile.feature:432](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L432)
--   [apiWebdavProperties1/copyFile.feature:516](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L516)
--   [apiWebdavProperties1/copyFile.feature:549](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L549)
--   [apiWebdavProperties1/copyFile.feature:581](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L581)
--   [apiWebdavProperties1/copyFile.feature:613](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L613)
+-   [apiWebdavProperties1/copyFile.feature:89](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L89)
+-   [apiWebdavProperties1/copyFile.feature:116](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L116)
+-   [apiWebdavProperties1/copyFile.feature:292](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L292)
+-   [apiWebdavProperties1/copyFile.feature:315](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L315)
+-   [apiWebdavProperties1/copyFile.feature:343](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L343)
+-   [apiWebdavProperties1/copyFile.feature:373](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L373)
+-   [apiWebdavProperties1/copyFile.feature:402](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L402)
+-   [apiWebdavProperties1/copyFile.feature:431](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L431)
+-   [apiWebdavProperties1/copyFile.feature:515](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L515)
+-   [apiWebdavProperties1/copyFile.feature:548](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L548)
+-   [apiWebdavProperties1/copyFile.feature:580](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L580)
+-   [apiWebdavProperties1/copyFile.feature:612](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L612)
 -   [apiWebdavProperties1/createFileFolderWhenSharesExist.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFileFolderWhenSharesExist.feature#L37)
 -   [apiWebdavProperties1/createFileFolderWhenSharesExist.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFileFolderWhenSharesExist.feature#L38)
 -   [apiWebdavProperties1/createFileFolderWhenSharesExist.feature:39](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFileFolderWhenSharesExist.feature#L39)
@@ -1559,26 +1549,26 @@ And other missing implementation of favorites
 -   [apiShareOperationsToShares2/shareAccessByID.feature:163](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareOperationsToShares2/shareAccessByID.feature#L163)
 
 #### [[OC-storage] share-types field empty for shared file folder in webdav response](https://github.com/owncloud/ocis/issues/2144)
--   [apiWebdavProperties2/getFileProperties.feature:207](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L207)
--   [apiWebdavProperties2/getFileProperties.feature:208](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L208)
--   [apiWebdavProperties2/getFileProperties.feature:213](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L213)
+-   [apiWebdavProperties2/getFileProperties.feature:215](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L215)
+-   [apiWebdavProperties2/getFileProperties.feature:216](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L216)
+-   [apiWebdavProperties2/getFileProperties.feature:221](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L221)
 
 #### [Creating a public link with all permissions(31) fails](https://github.com/owncloud/ocis/issues/2145)
--   [apiWebdavProperties2/getFileProperties.feature:265](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L265)
--   [apiWebdavProperties2/getFileProperties.feature:266](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L266)
--   [apiWebdavProperties2/getFileProperties.feature:271](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L271)
+-   [apiWebdavProperties2/getFileProperties.feature:275](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L275)
+-   [apiWebdavProperties2/getFileProperties.feature:276](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L276)
+-   [apiWebdavProperties2/getFileProperties.feature:281](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties2/getFileProperties.feature#L281)
 
 #### [Shares to deleted group listed in the response](https://github.com/owncloud/ocis/issues/2441)
 -   [apiShareManagementBasicToShares/createShareToSharesFolder.feature:504](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L504)
 -   [apiShareManagementBasicToShares/createShareToSharesFolder.feature:505](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L505)
 
 #### [Trying to copy a file into a readonly share gives HTTP 500 error](https://github.com/owncloud/ocis/issues/2166)
+-   [apiWebdavProperties1/copyFile.feature:452](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L452)
 -   [apiWebdavProperties1/copyFile.feature:453](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L453)
--   [apiWebdavProperties1/copyFile.feature:454](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L454)
--   [apiWebdavProperties1/copyFile.feature:459](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L459)
+-   [apiWebdavProperties1/copyFile.feature:458](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L458)
+-   [apiWebdavProperties1/copyFile.feature:478](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L478)
 -   [apiWebdavProperties1/copyFile.feature:479](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L479)
--   [apiWebdavProperties1/copyFile.feature:480](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L480)
--   [apiWebdavProperties1/copyFile.feature:485](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L485)
+-   [apiWebdavProperties1/copyFile.feature:484](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L484)
 
 ### Won't fix
 Not everything needs to be implemented for ocis. While the oc10 testsuite covers these things we are not looking at them right now.
@@ -1598,12 +1588,12 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers
 -   [apiWebdavUpload1/uploadFileToExcludedDirectory.feature:87](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavUpload1/uploadFileToExcludedDirectory.feature#L87)
 
 #### [Blacklist files extensions](https://github.com/owncloud/ocis/issues/2177)
+-   [apiWebdavProperties1/copyFile.feature:132](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L132)
 -   [apiWebdavProperties1/copyFile.feature:133](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L133)
--   [apiWebdavProperties1/copyFile.feature:134](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L134)
--   [apiWebdavProperties1/copyFile.feature:139](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L139)
--   [apiWebdavProperties1/createFolder.feature:92](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L92)
--   [apiWebdavProperties1/createFolder.feature:93](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L93)
--   [apiWebdavProperties1/createFolder.feature:98](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L98)
+-   [apiWebdavProperties1/copyFile.feature:138](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/copyFile.feature#L138)
+-   [apiWebdavProperties1/createFolder.feature:95](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L95)
+-   [apiWebdavProperties1/createFolder.feature:96](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L96)
+-   [apiWebdavProperties1/createFolder.feature:101](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavProperties1/createFolder.feature#L101)
 -   [apiWebdavUpload1/uploadFile.feature:181](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavUpload1/uploadFile.feature#L181)
 -   [apiWebdavUpload1/uploadFile.feature:182](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavUpload1/uploadFile.feature#L182)
 -   [apiWebdavUpload1/uploadFile.feature:187](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavUpload1/uploadFile.feature#L187)
@@ -1721,9 +1711,9 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers
 -   [apiWebdavMove2/moveFileToBlacklistedName.feature:80](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavMove2/moveFileToBlacklistedName.feature#L80)
 
 #### [REPORT method on spaces returns an incorrect d:href response](https://github.com/owncloud/ocis/issues/3111)
--   [apiFavorites/favorites.feature:117](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L117)
--   [apiFavorites/favorites.feature:143](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L143)
--   [apiFavorites/favorites.feature:268](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L268)
+-   [apiFavorites/favorites.feature:121](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L121)
+-   [apiFavorites/favorites.feature:147](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L147)
+-   [apiFavorites/favorites.feature:273](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiFavorites/favorites.feature#L273)
 
 #### [could not create system tag](https://github.com/owncloud/ocis/issues/3092)
 -   [apiWebdavOperations/search.feature:273](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiWebdavOperations/search.feature#L273)
diff --git a/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md b/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
index cb8afc016d5..0bcc91b8498 100644
--- a/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
+++ b/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
@@ -491,9 +491,6 @@ Other free text and markdown formatting can be used elsewhere in the document if
 -   [webUISharingInternalGroups/shareWithGroups.feature:77](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalGroups/shareWithGroups.feature#L77)
 -   [webUISharingInternalUsers/shareWithUsers.feature:57](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingInternalUsers/shareWithUsers.feature#L57)
 
-### [shares are not listed with full paths](https://github.com/owncloud/ocis/issues/2462)
--   [webUISharingPublicBasic/publicLinkCreate.feature:88](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingPublicBasic/publicLinkCreate.feature#L88)
-
 ### [web config update is not properly reflected after the ocis start](https://github.com/owncloud/ocis/issues/2944)
 -   [webUIFiles/breadcrumb.feature:50](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIFiles/breadcrumb.feature#L50)