From ab6054bdc66d43fe6bc4e31749f20eb7ccc7faa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 12 Jan 2022 09:41:16 +0000 Subject: [PATCH 01/20] update REVA to v1.16.1-0.20220112085026-07451f6cd806 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- changelog/unreleased/reva-update-07451f6cd8067.md | 5 +++++ go.mod | 5 +---- go.sum | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 changelog/unreleased/reva-update-07451f6cd8067.md diff --git a/changelog/unreleased/reva-update-07451f6cd8067.md b/changelog/unreleased/reva-update-07451f6cd8067.md new file mode 100644 index 000000000..1959d2666 --- /dev/null +++ b/changelog/unreleased/reva-update-07451f6cd8067.md @@ -0,0 +1,5 @@ +Enhancement: update REVA to v1.16.1-0.20220112085026-07451f6cd806 + +Update REVA to v1.16.1-0.20220112085026-07451f6cd806 + +https://github.com/owncloud/ocis/pull/2953 diff --git a/go.mod b/go.mod index d28bb821b..8087dfd32 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/blevesearch/bleve/v2 v2.3.0 github.com/coreos/go-oidc/v3 v3.1.0 github.com/cs3org/go-cs3apis v0.0.0-20211214102047-7ce3134d7bf8 - github.com/cs3org/reva v1.17.1-0.20220105095955-fa1d1fc01d85 + github.com/cs3org/reva v1.16.1-0.20220112085026-07451f6cd806 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 @@ -243,7 +243,4 @@ require ( stash.kopano.io/kgol/oidc-go v0.3.2 // indirect ) -//replace github.com/cs3org/reva => github.com/cs3org/reva v1.16.1-0.20211208164450-3abd76eecf8b //replace github.com/cs3org/reva => ../reva - -replace github.com/cs3org/reva => github.com/cs3org/reva v1.16.1-0.20220111150347-1b21aefbf8db diff --git a/go.sum b/go.sum index eefeacae1..d3585581f 100644 --- a/go.sum +++ b/go.sum @@ -324,8 +324,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-20211214102047-7ce3134d7bf8 h1:PqOprF37OvwCbAN5W23znknGk6N/LMayqLAeP904FHE= github.com/cs3org/go-cs3apis v0.0.0-20211214102047-7ce3134d7bf8/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva v1.16.1-0.20220111150347-1b21aefbf8db h1:YCzbz8N0OHkO6AcA2SfXHCc02Y/DqSkO+hm8Pj+eDZ4= -github.com/cs3org/reva v1.16.1-0.20220111150347-1b21aefbf8db/go.mod h1:WqO2/NkAmx1qes09G92lGPxxyroQgnZetJrCPItCcDo= +github.com/cs3org/reva v1.16.1-0.20220112085026-07451f6cd806 h1:kwGCQOlC/x0sz4KZ28n7GgZ+aBlmqbKn8CmbkNK6WU4= +github.com/cs3org/reva v1.16.1-0.20220112085026-07451f6cd806/go.mod h1:HisUI5sBYaR3kqqtP+O8MzY7XRjqpV8IgxzK4aK0BtI= 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= @@ -1277,7 +1277,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s= +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/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= From 6927cfd0dc2f18d96d855f1cef26e1065abb82be Mon Sep 17 00:00:00 2001 From: Willy Kloucek Date: Thu, 13 Jan 2022 11:20:36 +0100 Subject: [PATCH 02/20] remove unused templates --- .drone.star | 2 - accounts/templates/CONFIGURATION.tmpl | 78 ----------- .../oc10_ocis_parallel/docker-compose.yml | 1 - .../docker-compose-additions.yml | 1 - .../docker-compose-additions.yml | 1 - .../docker-compose-additions.yml | 1 - .../docker-compose-additions.yml | 1 - .../examples/ocis_s3/docker-compose.yml | 1 - .../docker-compose-additions.yml | 1 - .../docker-compose-additions.yml | 1 - .../docker-compose-additions.yml | 1 - docs/extensions/storage/storagedrivers.md | 1 - glauth/templates/CONFIGURATION.tmpl | 78 ----------- graph-explorer/templates/CONFIGURATION.tmpl | 78 ----------- graph/templates/CONFIGURATION.tmpl | 78 ----------- idp/templates/CONFIGURATION.tmpl | 78 ----------- ocis/templates/CONFIGURATION.tmpl | 98 -------------- ocs/templates/CONFIGURATION.tmpl | 78 ----------- proxy/templates/CONFIGURATION.tmpl | 78 ----------- settings/templates/CONFIGURATION.tmpl | 78 ----------- storage/templates/CONFIGURATION.tmpl | 123 ------------------ store/templates/CONFIGURATION.tmpl | 78 ----------- tests/acceptance/docker/src/ocis-base.yml | 1 - thumbnails/templates/CONFIGURATION.tmpl | 78 ----------- web/templates/CONFIGURATION.tmpl | 78 ----------- webdav/templates/CONFIGURATION.tmpl | 78 ----------- 26 files changed, 1170 deletions(-) delete mode 100644 accounts/templates/CONFIGURATION.tmpl delete mode 100644 glauth/templates/CONFIGURATION.tmpl delete mode 100644 graph-explorer/templates/CONFIGURATION.tmpl delete mode 100644 graph/templates/CONFIGURATION.tmpl delete mode 100644 idp/templates/CONFIGURATION.tmpl delete mode 100644 ocis/templates/CONFIGURATION.tmpl delete mode 100644 ocs/templates/CONFIGURATION.tmpl delete mode 100644 proxy/templates/CONFIGURATION.tmpl delete mode 100644 settings/templates/CONFIGURATION.tmpl delete mode 100644 storage/templates/CONFIGURATION.tmpl delete mode 100644 store/templates/CONFIGURATION.tmpl delete mode 100644 thumbnails/templates/CONFIGURATION.tmpl delete mode 100644 web/templates/CONFIGURATION.tmpl delete mode 100644 webdav/templates/CONFIGURATION.tmpl diff --git a/.drone.star b/.drone.star index 5315f4fc4..54724ed0d 100644 --- a/.drone.star +++ b/.drone.star @@ -1400,7 +1400,6 @@ def notify(ctx): def ocisServer(storage, accounts_hash_difficulty = 4, volumes = []): environment = { "OCIS_URL": "https://ocis-server:9200", - "STORAGE_HOME_DRIVER": "%s" % (storage), "STORAGE_USERS_DRIVER": "%s" % (storage), "STORAGE_USERS_DRIVER_LOCAL_ROOT": "/srv/app/tmp/ocis/local/root", "STORAGE_USERS_DRIVER_OWNCLOUD_DATADIR": "/srv/app/tmp/ocis/owncloud/data", @@ -2082,7 +2081,6 @@ def latestOcisServer(): "STORAGE_LDAP_USERFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))", "STORAGE_LDAP_USERFINDFILTER": "(&(objectclass=posixAccount)(objectclass=owncloud)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))", # ownCloud storage driver - "STORAGE_HOME_DRIVER": "owncloudsql", "STORAGE_USERS_DRIVER": "owncloudsql", "STORAGE_METADATA_DRIVER": "ocis", "STORAGE_USERS_DRIVER_OWNCLOUDSQL_DATADIR": "/mnt/data/files", diff --git a/accounts/templates/CONFIGURATION.tmpl b/accounts/templates/CONFIGURATION.tmpl deleted file mode 100644 index c180d7a56..000000000 --- a/accounts/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/accounts/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-accounts reads `accounts.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/accounts/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "accounts" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `accounts [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "accounts" -}} -### accounts {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `accounts {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/deployments/examples/oc10_ocis_parallel/docker-compose.yml b/deployments/examples/oc10_ocis_parallel/docker-compose.yml index ec5185b86..3d7622e04 100644 --- a/deployments/examples/oc10_ocis_parallel/docker-compose.yml +++ b/deployments/examples/oc10_ocis_parallel/docker-compose.yml @@ -91,7 +91,6 @@ services: STORAGE_LDAP_USERFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(|(ownclouduuid={{.OpaqueId}})(uid={{.OpaqueId}})))" STORAGE_LDAP_USERFINDFILTER: "(&(objectclass=posixAccount)(objectclass=owncloud)(|(cn={{query}}*)(displayname={{query}}*)(mail={{query}}*)))" # ownCloud storage driver - STORAGE_HOME_DRIVER: owncloudsql STORAGE_USERS_DRIVER: owncloudsql STORAGE_METADATA_DRIVER: ocis # keep metadata on ocis storage since this are only small files atm STORAGE_USERS_DRIVER_OWNCLOUDSQL_DATADIR: /mnt/data/files diff --git a/deployments/examples/oc10_ocis_parallel/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/oc10_ocis_parallel/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/oc10_ocis_parallel/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/oc10_ocis_parallel/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_hello/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_hello/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_hello/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_hello/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_keycloak/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_keycloak/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_keycloak/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_keycloak/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_ldap/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_ldap/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_ldap/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_ldap/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_s3/docker-compose.yml b/deployments/examples/ocis_s3/docker-compose.yml index aed2b45f4..a8a168273 100644 --- a/deployments/examples/ocis_s3/docker-compose.yml +++ b/deployments/examples/ocis_s3/docker-compose.yml @@ -60,7 +60,6 @@ services: STORAGE_TRANSFER_SECRET: ${STORAGE_TRANSFER_SECRET:-replace-me-with-a-transfer-secret} OCIS_MACHINE_AUTH_API_KEY: ${OCIS_MACHINE_AUTH_API_KEY:-change-me-please} # activate s3ng storage driver - STORAGE_HOME_DRIVER: s3ng STORAGE_USERS_DRIVER: s3ng STORAGE_METADATA_DRIVER: ocis # keep metadata on ocis storage since this are only small files atm # s3ng specific settings diff --git a/deployments/examples/ocis_s3/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_s3/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_s3/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_s3/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_traefik/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_traefik/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_traefik/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_traefik/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/deployments/examples/ocis_wopi/monitoring_tracing/docker-compose-additions.yml b/deployments/examples/ocis_wopi/monitoring_tracing/docker-compose-additions.yml index 8abdf4e83..705cfccd9 100644 --- a/deployments/examples/ocis_wopi/monitoring_tracing/docker-compose-additions.yml +++ b/deployments/examples/ocis_wopi/monitoring_tracing/docker-compose-additions.yml @@ -23,7 +23,6 @@ services: STORAGE_FRONTEND_DEBUG_ADDR: 0.0.0.0:9141 STORAGE_GATEWAY_DEBUG_ADDR: 0.0.0.0:9143 STORAGE_GROUPPROVIDER_DEBUG_ADDR: 0.0.0.0:9161 - STORAGE_HOME_DEBUG_ADDR: 0.0.0.0:9156 STORAGE_METADATA_DEBUG_ADDR: 0.0.0.0:9217 STORAGE_PUBLIC_LINK_DEBUG_ADDR: 0.0.0.0:9179 STORAGE_USERPROVIDER_DEBUG_ADDR: 0.0.0.0:9145 diff --git a/docs/extensions/storage/storagedrivers.md b/docs/extensions/storage/storagedrivers.md index 936dd9f96..375ffa330 100644 --- a/docs/extensions/storage/storagedrivers.md +++ b/docs/extensions/storage/storagedrivers.md @@ -168,7 +168,6 @@ For a simple docker-compose setup, you can create a volume which will be used by The CERN eos storage has evolved with ownCloud and natively supports id based lookup, ETag propagation, subtree size accounting, sharing, trash and versions. To use it you need to change the default configuration of the `storage storage-home` command (or have a look at the Makefile ̀ eos-start` target): ``` -export STORAGE_HOME_DRIVER=eos export STORAGE_DRIVER_EOS_NAMESPACE=/eos export STORAGE_DRIVER_EOS_MASTER_URL="root://eos-mgm1.eoscluster.cern.ch:1094" export STORAGE_DRIVER_EOS_ENABLE_HOME=true diff --git a/glauth/templates/CONFIGURATION.tmpl b/glauth/templates/CONFIGURATION.tmpl deleted file mode 100644 index ac2fd7974..000000000 --- a/glauth/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/glauth/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-glauth reads `glauth.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/glauth/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "glauth" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `glauth [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "glauth" -}} -### glauth {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `glauth {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/graph-explorer/templates/CONFIGURATION.tmpl b/graph-explorer/templates/CONFIGURATION.tmpl deleted file mode 100644 index ba9282bc2..000000000 --- a/graph-explorer/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/graph-explorer/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/graph-explorer/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "graph-explorer" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `graph-explorer [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "graph-explorer" -}} -### graph-explorer {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `graph-explorer {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/graph/templates/CONFIGURATION.tmpl b/graph/templates/CONFIGURATION.tmpl deleted file mode 100644 index 24c1c4a99..000000000 --- a/graph/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/graph/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/graph/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "graph" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `graph [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "graph" -}} -### graph {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `graph {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/idp/templates/CONFIGURATION.tmpl b/idp/templates/CONFIGURATION.tmpl deleted file mode 100644 index a2fbcdad1..000000000 --- a/idp/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/idp/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-idp reads `idp.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/idp/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "idp" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `idp [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "idp" -}} -### idp {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `idp {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/ocis/templates/CONFIGURATION.tmpl b/ocis/templates/CONFIGURATION.tmpl deleted file mode 100644 index 465d32e27..000000000 --- a/ocis/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 2 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/ocis/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -oCIS Single Binary is not responsible for configuring extensions. Instead, each extension could either be configured by environment variables, cli flags or config files. - -Each extension has its dedicated documentation page (e.g. [proxy configuration]({{"{{"}}< relref "../extensions/accounts/configuration.md" >{{"}}"}})) which lists all possible configurations. Config files and environment variables are picked up if you use the `./bin/ocis server` command within the oCIS single binary. Command line flags must be set explicitly on the extensions subcommands. - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/ocis/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "ocis" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `ocis [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if eq $c.Name "server" "health" "kill" "list" "run" -}} -{{- if ne $c.FnName "Simple" -}} -### ocis {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `ocis {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} -{{- end -}} - -### List of available Extension subcommands - -There are more subcommands to start the individual extensions. Please check the documentation about their usage and options in the dedicated section of the documentation. - -{{ range $com := .Commands }}{{ with $com -}} -{{ if and (ne .Name "health") (ne .Name "server") (ne .Name "ocis") (ne .Name "kill") (ne .Name "list") (ne .Name "run") -}} -#### ocis {{ .Name }} - -{{ .Usage }} - -{{ end -}} -{{- end -}} -{{- end -}} diff --git a/ocs/templates/CONFIGURATION.tmpl b/ocs/templates/CONFIGURATION.tmpl deleted file mode 100644 index 5b58de073..000000000 --- a/ocs/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/ocs/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-ocs reads `ocs.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/ocs/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "ocs" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `ocs [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "ocs" -}} -### ocs {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `ocs {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/proxy/templates/CONFIGURATION.tmpl b/proxy/templates/CONFIGURATION.tmpl deleted file mode 100644 index b944a5892..000000000 --- a/proxy/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/proxy/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/proxy/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "proxy" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `proxy [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "proxy" -}} -### proxy {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `proxy {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/settings/templates/CONFIGURATION.tmpl b/settings/templates/CONFIGURATION.tmpl deleted file mode 100644 index 0bbef699e..000000000 --- a/settings/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/settings/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/settings/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "settings" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `settings [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "settings" -}} -### settings {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `settings {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/storage/templates/CONFIGURATION.tmpl b/storage/templates/CONFIGURATION.tmpl deleted file mode 100644 index ad41b82c7..000000000 --- a/storage/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/storage/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} -{{- define "option"}} -{{- $options := first . }} -{{- $oName := last . }} -{{- range $o := $options }}{{ with (list $o $oName) -}} -{{- $o := first . }} -{{- if eq $o.FnName (last .) -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{- end -}} -{{- end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/storage/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "storage" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `storage [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "ocis-reva" -}} -### storage {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `storage {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} -## Config for the different Storage Drivers - -You can set different storage drivers for the Storage Providers. Please check the storage provider configuration. - -Example: Set the home and users Storage Provider to `ocis` - -`STORAGE_HOME_DRIVER=ocis` -`STORAGE_USERS_DRIVER=ocis` - -### Local Driver - -{{ template "option" (list .Options "DriverLocalWithConfig") -}} - -### Eos Driver - -{{ template "option" (list .Options "DriverEOSWithConfig") -}} - -### owCloud Driver - -{{ template "option" (list .Options "DriverOwnCloudWithConfig") -}} - -### ownCloudSQL Driver - -{{ template "option" (list .Options "DriverOwnCloudSQLWithConfig") -}} - -### Ocis Driver - -{{ template "option" (list .Options "DriverOCISWithConfig") -}} - -### S3ng Driver - -{{ template "option" (list .Options "DriverS3NGWithConfig") -}} diff --git a/store/templates/CONFIGURATION.tmpl b/store/templates/CONFIGURATION.tmpl deleted file mode 100644 index b783d239b..000000000 --- a/store/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/store/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/store/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "store" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `store [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "store" -}} -### store {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `store {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/tests/acceptance/docker/src/ocis-base.yml b/tests/acceptance/docker/src/ocis-base.yml index 837921b58..94e26e0cd 100644 --- a/tests/acceptance/docker/src/ocis-base.yml +++ b/tests/acceptance/docker/src/ocis-base.yml @@ -4,7 +4,6 @@ services: user: root environment: OCIS_URL: "https://ocis-server:9200" - STORAGE_HOME_DRIVER: $STORAGE_DRIVER STORAGE_USERS_DRIVER: $STORAGE_DRIVER STORAGE_USERS_DRIVER_LOCAL_ROOT: /srv/app/tmp/ocis/local/root STORAGE_USERS_DRIVER_OWNCLOUD_DATADIR: /srv/app/tmp/ocis/owncloud/data diff --git a/thumbnails/templates/CONFIGURATION.tmpl b/thumbnails/templates/CONFIGURATION.tmpl deleted file mode 100644 index 02a7f7843..000000000 --- a/thumbnails/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/thumbnails/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/thumbnails/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "thumbnails" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `thumbnails [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "thumbnails" -}} -### thumbnails {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `thumbnails {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/web/templates/CONFIGURATION.tmpl b/web/templates/CONFIGURATION.tmpl deleted file mode 100644 index 066be9045..000000000 --- a/web/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/web/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-web reads `web.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/web/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "web" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `web [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "web" -}} -### web {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `web {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} diff --git a/webdav/templates/CONFIGURATION.tmpl b/webdav/templates/CONFIGURATION.tmpl deleted file mode 100644 index 6533998dc..000000000 --- a/webdav/templates/CONFIGURATION.tmpl +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Configuration" -date: "{{ date "2006-01-02T15:04:05-0700" now }}" -weight: 20 -geekdocRepo: https://github.com/owncloud/ocis -geekdocEditPath: edit/master/webdav/templates -geekdocFilePath: CONFIGURATION.tmpl ---- -{{- define "options"}} -{{ $fnNames := (last . ).Flags -}} -{{ range $opt := first . }} -{{ range $fnName := $fnNames }}{{ with list $fnName $opt -}} -{{ $o := last . -}} -{{ if eq $o.FnName $fnName -}} --{{ $o.Name }} | {{ range $i, $e := $o.Env }} {{ if $i }}, {{ end }}${{ $e }}{{ end }} -: {{ $o.Usage }}. {{- if $o.Default }} Default: `{{ $o.Default }}`.{{ end }} - -{{ end -}} -{{ end -}} -{{ end -}} -{{ end -}} -{{ end }} - -{{`{{< toc >}}`}} - -## Configuration - -### Configuration using config files - -Out of the box extensions will attempt to read configuration details from: - -```console -/etc/ocis -$HOME/.ocis -./config -``` - -For this configuration to be picked up, have a look at your extension `root` command and look for which default config name it has assigned. *i.e: ocis-proxy reads `proxy.json | yaml | toml ...`*. - -So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis/tree/master/webdav/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/ocis.yml`, `${HOME}/.ocis/ocis.yml` or `$(pwd)/config/ocis.yml`. - -### Environment variables - -If you prefer to configure the service with environment variables you can see the available variables below. - -If multiple variables are listed for one option, they are in order of precedence. This means the leftmost variable will always win if given. - -### Command-line flags - -If you prefer to configure the service with command-line flags you can see the available variables below. Command line flags are only working when calling the subcommand directly. - -{{ $options := .Options -}} -{{ range $com := .Commands }}{{ with (list $options $com) -}} -{{ $c := last . -}} -{{ if eq $c.Name "webdav" -}} -## Root Command - -{{ $c.Usage }} - -Usage: `webdav [global options] command [command options] [arguments...]` -{{ template "options" . -}} -## Sub Commands - -{{ end -}} -{{ end -}} -{{ end -}} -{{- range $com := .Commands }}{{ with (list $options $com) -}} -{{- $c := last . }} -{{- if ne $c.Name "webdav" -}} -### webdav {{ $c.Name }} - -{{ $c.Usage }} - -Usage: `webdav {{ $c.Name }} [command options] [arguments...]` -{{ template "options" . }} -{{- end -}} -{{- end -}} -{{- end -}} From 5d6e361cffcf13d767f5a50cdd85b992c0676491 Mon Sep 17 00:00:00 2001 From: Alex Unger Date: Tue, 4 Jan 2022 23:12:49 +0100 Subject: [PATCH 03/20] Implement CreateUser support for the Graph LDAP backend This adds basic support for creating users via the GraphAPI LDAP backend. This currently just maintains the bare minimum Attributes for the inetOrgPerson objectclass. Co-authored-by: Ralf Haferkamp --- graph/pkg/config/defaultconfig.go | 4 +- graph/pkg/identity/backend.go | 3 + graph/pkg/identity/cs3.go | 5 ++ graph/pkg/identity/ldap.go | 92 +++++++++++++++++++++++++++- graph/pkg/identity/ldap/reconnect.go | 9 ++- graph/pkg/service/v0/service.go | 1 + graph/pkg/service/v0/users.go | 30 ++++++++- 7 files changed, 137 insertions(+), 7 deletions(-) diff --git a/graph/pkg/config/defaultconfig.go b/graph/pkg/config/defaultconfig.go index 3bb022786..acd24e838 100644 --- a/graph/pkg/config/defaultconfig.go +++ b/graph/pkg/config/defaultconfig.go @@ -33,13 +33,13 @@ func DefaultConfig() *Config { BindPassword: "", UserBaseDN: "ou=users,dc=ocis,dc=test", UserSearchScope: "sub", - UserFilter: "(objectClass=posixaccount)", + UserFilter: "(objectClass=inetOrgPerson)", UserEmailAttribute: "mail", UserDisplayNameAttribute: "displayName", UserNameAttribute: "uid", // FIXME: switch this to some more widely available attribute by default // ideally this needs to be constant for the lifetime of a users - UserIDAttribute: "ownclouduuid", + UserIDAttribute: "entryUUID", GroupBaseDN: "ou=groups,dc=ocis,dc=test", GroupSearchScope: "sub", GroupFilter: "(objectclass=groupOfNames)", diff --git a/graph/pkg/identity/backend.go b/graph/pkg/identity/backend.go index f7b497251..d716009af 100644 --- a/graph/pkg/identity/backend.go +++ b/graph/pkg/identity/backend.go @@ -9,6 +9,9 @@ import ( ) type Backend interface { + // CreateUser creates a given user in the identity backend. + CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) + GetUser(ctx context.Context, nameOrId string) (*libregraph.User, error) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error) diff --git a/graph/pkg/identity/cs3.go b/graph/pkg/identity/cs3.go index f76da144f..272bccfe6 100644 --- a/graph/pkg/identity/cs3.go +++ b/graph/pkg/identity/cs3.go @@ -20,6 +20,11 @@ type CS3 struct { Logger *log.Logger } +// CreateUser implements the Backend Interface. It's currently not supported for the CS3 backend +func (i *CS3) CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) { + return nil, errorcode.New(errorcode.NotSupported, "not implemented") +} + func (i *CS3) GetUser(ctx context.Context, userID string) (*libregraph.User, error) { client, err := pool.GetGatewayServiceClient(i.Config.Address) if err != nil { diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index 5942c6f99..1becb2ca4 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -84,6 +84,95 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD }, nil } +// CreateUser implements the Backend Interface. It converts the libregraph.User into an +// LDAP User Entry (using the inetOrgPerson LDAP Objectclass) add adds that to the +// configured LDAP server +func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) { + + ar := ldap.AddRequest{ + DN: fmt.Sprintf("uid=%s,%s", *user.OnPremisesSamAccountName, i.userBaseDN), + Attributes: []ldap.Attribute{ + { + Type: "objectClass", + Vals: []string{"inetOrgPerson", "organizationalPerson", "person", "top"}, + }, + // inetOrgPerson requires "cn" + { + Type: "cn", + Vals: []string{*user.OnPremisesSamAccountName}, + }, + { + Type: i.userAttributeMap.mail, + Vals: []string{*user.Mail}, + }, + { + Type: i.userAttributeMap.userName, + Vals: []string{*user.OnPremisesSamAccountName}, + }, + { + Type: i.userAttributeMap.displayName, + Vals: []string{*user.DisplayName}, + }, + }, + } + + if user.PasswordProfile != nil && user.PasswordProfile.Password != nil { + // TODO? This relies to the LDAP server to properly hash the password. + // We might want to add support for the Password Modify LDAP Extended + // Operation for servers that implement it. (Or implement client-side + // hashing here. + ar.Attribute("userPassword", []string{*user.PasswordProfile.Password}) + } + + // inetOrgPerson requires "sn" to be set. Set it to the Username if + // Surname is not set in the Request + var sn string + if user.Surname != nil && *user.Surname != "" { + sn = *user.Surname + } else { + sn = *user.OnPremisesSamAccountName + } + ar.Attribute("sn", []string{sn}) + + if err := i.conn.Add(&ar); err != nil { + return nil, err + } + + // Read back user from LDAP to get the generated UUID + e, err := i.getUserByDN(ar.DN) + if err != nil { + return nil, err + } + return i.createUserModelFromLDAP(e), nil +} + +func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) { + searchRequest := ldap.NewSearchRequest( + dn, ldap.ScopeBaseObject, ldap.NeverDerefAliases, 1, 0, false, + "(objectclass=*)", + []string{ + i.userAttributeMap.displayName, + i.userAttributeMap.id, + i.userAttributeMap.mail, + i.userAttributeMap.userName, + }, + nil, + ) + + i.logger.Debug().Str("backend", "ldap").Str("dn", dn).Msg("Search user by DN") + res, err := i.conn.Search(searchRequest) + + if err != nil { + i.logger.Error().Err(err).Str("backend", "ldap").Str("dn", dn).Msg("Search user by DN failed") + return nil, errorcode.New(errorcode.ItemNotFound, err.Error()) + } + if len(res.Entries) == 0 { + return nil, errorcode.New(errorcode.ItemNotFound, "not found") + } + + return res.Entries[0], nil +} + func (i *LDAP) GetUser(ctx context.Context, userID string) (*libregraph.User, error) { i.logger.Debug().Str("backend", "ldap").Msg("GetUser") userID = ldap.EscapeFilter(userID) @@ -106,7 +195,8 @@ func (i *LDAP) GetUser(ctx context.Context, userID string) (*libregraph.User, er if lerr, ok := err.(*ldap.Error); ok { if lerr.ResultCode == ldap.LDAPResultSizeLimitExceeded { errmsg = fmt.Sprintf("too many results searching for user '%s'", userID) - i.logger.Debug().Str("backend", "ldap").Err(lerr).Msg(errmsg) + i.logger.Debug().Str("backend", "ldap").Err(lerr). + Str("user", userID).Msg("too many results searching for user") } } return nil, errorcode.New(errorcode.ItemNotFound, errmsg) diff --git a/graph/pkg/identity/ldap/reconnect.go b/graph/pkg/identity/ldap/reconnect.go index f929e57a5..bf5c7a1bd 100644 --- a/graph/pkg/identity/ldap/reconnect.go +++ b/graph/pkg/identity/ldap/reconnect.go @@ -162,8 +162,13 @@ func (c ConnWithReconnect) ExternalBind() error { return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) } -func (c ConnWithReconnect) Add(*ldap.AddRequest) error { - return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) +func (c ConnWithReconnect) Add(a *ldap.AddRequest) error { + conn, err := c.GetConnection() + if err != nil { + return err + } + + return conn.Add(a) } func (c ConnWithReconnect) Del(*ldap.DelRequest) error { diff --git a/graph/pkg/service/v0/service.go b/graph/pkg/service/v0/service.go index 36d0cf451..15fa77e43 100644 --- a/graph/pkg/service/v0/service.go +++ b/graph/pkg/service/v0/service.go @@ -67,6 +67,7 @@ func NewService(opts ...Option) Service { }) r.Route("/users", func(r chi.Router) { r.Get("/", svc.GetUsers) + r.Post("/", svc.PostUser) r.Route("/{userID}", func(r chi.Router) { r.Get("/", svc.GetUser) }) diff --git a/graph/pkg/service/v0/users.go b/graph/pkg/service/v0/users.go index c62337cbc..7cdd802e5 100644 --- a/graph/pkg/service/v0/users.go +++ b/graph/pkg/service/v0/users.go @@ -1,6 +1,7 @@ package svc import ( + "encoding/json" "errors" "net/http" "net/url" @@ -8,9 +9,9 @@ import ( revactx "github.com/cs3org/reva/pkg/ctx" "github.com/go-chi/chi/v5" "github.com/go-chi/render" + libregraph "github.com/owncloud/libre-graph-api-go" "github.com/owncloud/ocis/graph/pkg/identity" "github.com/owncloud/ocis/graph/pkg/service/v0/errorcode" - //msgraph "github.com/owncloud/open-graph-api-go" // FIXME needs OnPremisesSamAccountName, OnPremisesDomainName and AdditionalData ) // GetMe implements the Service interface. @@ -32,7 +33,6 @@ func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) { } // GetUsers implements the Service interface. -// TODO use cs3 api to look up user func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) { users, err := g.identityBackend.GetUsers(r.Context(), r.URL.Query()) if err != nil { @@ -47,6 +47,28 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, &listResponse{Value: users}) } +func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) { + u := libregraph.NewUser() + err := json.NewDecoder(r.Body).Decode(u) + if err != nil { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) + return + } + + if isNilOrEmpty(u.DisplayName) || isNilOrEmpty(u.OnPremisesSamAccountName) || isNilOrEmpty(u.Mail) { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "Missing Required Attribute") + return + } + + if u, err = g.identityBackend.CreateUser(r.Context(), *u); err != nil { + errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) + return + } + + render.Status(r, http.StatusOK) + render.JSON(w, r, u) +} + // GetUser implements the Service interface. func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) { userID := chi.URLParam(r, "userID") @@ -74,3 +96,7 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) { render.Status(r, http.StatusOK) render.JSON(w, r, user) } + +func isNilOrEmpty(s *string) bool { + return s == nil || *s == "" +} From 4915195d9c250909fbe4836056b21d8cb4fed7e7 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Tue, 11 Jan 2022 17:22:48 +0100 Subject: [PATCH 04/20] Implement DeleteUser support for the Graph LDAP backend --- graph/pkg/identity/backend.go | 3 +++ graph/pkg/identity/cs3.go | 5 ++++ graph/pkg/identity/ldap.go | 36 ++++++++++++++++++++++------ graph/pkg/identity/ldap/reconnect.go | 9 +++++-- graph/pkg/service/v0/service.go | 1 + graph/pkg/service/v0/users.go | 26 ++++++++++++++++++++ 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/graph/pkg/identity/backend.go b/graph/pkg/identity/backend.go index d716009af..1a71a7b5d 100644 --- a/graph/pkg/identity/backend.go +++ b/graph/pkg/identity/backend.go @@ -12,6 +12,9 @@ type Backend interface { // CreateUser creates a given user in the identity backend. CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) + // DeleteUser deletes a given user, identified by username or id, from the backend + DeleteUser(ctx context.Context, nameOrId string) error + GetUser(ctx context.Context, nameOrId string) (*libregraph.User, error) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error) diff --git a/graph/pkg/identity/cs3.go b/graph/pkg/identity/cs3.go index 272bccfe6..5fe0117c8 100644 --- a/graph/pkg/identity/cs3.go +++ b/graph/pkg/identity/cs3.go @@ -25,6 +25,11 @@ func (i *CS3) CreateUser(ctx context.Context, user libregraph.User) (*libregraph return nil, errorcode.New(errorcode.NotSupported, "not implemented") } +// DeleteUser implements the Backend Interface. It's currently not supported for the CS3 backend +func (i *CS3) DeleteUser(ctx context.Context, nameOrID string) error { + return errorcode.New(errorcode.NotSupported, "not implemented") +} + func (i *CS3) GetUser(ctx context.Context, userID string) (*libregraph.User, error) { client, err := pool.GetGatewayServiceClient(i.Config.Address) if err != nil { diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index 1becb2ca4..b9f9c65cf 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -146,6 +146,20 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap return i.createUserModelFromLDAP(e), nil } +// DeleteUser implements the Backend Interface. It permanently deletes a User identified +// by name or id from the LDAP server +func (i *LDAP) DeleteUser(ctx context.Context, nameOrID string) error { + e, err := i.getLDAPUserByNameOrID(nameOrID) + if err != nil { + return err + } + dr := ldap.DelRequest{DN: e.DN} + if err = i.conn.Del(&dr); err != nil { + return err + } + return nil +} + func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) { searchRequest := ldap.NewSearchRequest( dn, ldap.ScopeBaseObject, ldap.NeverDerefAliases, 1, 0, false, @@ -173,12 +187,11 @@ func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) { return res.Entries[0], nil } -func (i *LDAP) GetUser(ctx context.Context, userID string) (*libregraph.User, error) { - i.logger.Debug().Str("backend", "ldap").Msg("GetUser") - userID = ldap.EscapeFilter(userID) +func (i *LDAP) getLDAPUserByNameOrID(nameOrID string) (*ldap.Entry, error) { + nameOrID = ldap.EscapeFilter(nameOrID) searchRequest := ldap.NewSearchRequest( i.userBaseDN, i.userScope, ldap.NeverDerefAliases, 1, 0, false, - fmt.Sprintf("(&%s(|(%s=%s)(%s=%s)))", i.userFilter, i.userAttributeMap.userName, userID, i.userAttributeMap.id, userID), + fmt.Sprintf("(&%s(|(%s=%s)(%s=%s)))", i.userFilter, i.userAttributeMap.userName, nameOrID, i.userAttributeMap.id, nameOrID), []string{ i.userAttributeMap.displayName, i.userAttributeMap.id, @@ -194,9 +207,9 @@ func (i *LDAP) GetUser(ctx context.Context, userID string) (*libregraph.User, er var errmsg string if lerr, ok := err.(*ldap.Error); ok { if lerr.ResultCode == ldap.LDAPResultSizeLimitExceeded { - errmsg = fmt.Sprintf("too many results searching for user '%s'", userID) + errmsg = fmt.Sprintf("too many results searching for user '%s'", nameOrID) i.logger.Debug().Str("backend", "ldap").Err(lerr). - Str("user", userID).Msg("too many results searching for user") + Str("user", nameOrID).Msg("too many results searching for user") } } return nil, errorcode.New(errorcode.ItemNotFound, errmsg) @@ -205,7 +218,16 @@ func (i *LDAP) GetUser(ctx context.Context, userID string) (*libregraph.User, er return nil, errorcode.New(errorcode.ItemNotFound, "not found") } - return i.createUserModelFromLDAP(res.Entries[0]), nil + return res.Entries[0], nil +} + +func (i *LDAP) GetUser(ctx context.Context, nameOrID string) (*libregraph.User, error) { + i.logger.Debug().Str("backend", "ldap").Msg("GetUser") + e, err := i.getLDAPUserByNameOrID(nameOrID) + if err != nil { + return nil, err + } + return i.createUserModelFromLDAP(e), nil } func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error) { diff --git a/graph/pkg/identity/ldap/reconnect.go b/graph/pkg/identity/ldap/reconnect.go index bf5c7a1bd..272a0043e 100644 --- a/graph/pkg/identity/ldap/reconnect.go +++ b/graph/pkg/identity/ldap/reconnect.go @@ -171,8 +171,13 @@ func (c ConnWithReconnect) Add(a *ldap.AddRequest) error { return conn.Add(a) } -func (c ConnWithReconnect) Del(*ldap.DelRequest) error { - return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) +func (c ConnWithReconnect) Del(d *ldap.DelRequest) error { + conn, err := c.GetConnection() + if err != nil { + return err + } + + return conn.Del(d) } func (c ConnWithReconnect) Modify(*ldap.ModifyRequest) error { diff --git a/graph/pkg/service/v0/service.go b/graph/pkg/service/v0/service.go index 15fa77e43..004d36892 100644 --- a/graph/pkg/service/v0/service.go +++ b/graph/pkg/service/v0/service.go @@ -70,6 +70,7 @@ func NewService(opts ...Option) Service { r.Post("/", svc.PostUser) r.Route("/{userID}", func(r chi.Router) { r.Get("/", svc.GetUser) + r.Delete("/", svc.DeleteUser) }) }) r.Route("/groups", func(r chi.Router) { diff --git a/graph/pkg/service/v0/users.go b/graph/pkg/service/v0/users.go index 7cdd802e5..0593c6bcb 100644 --- a/graph/pkg/service/v0/users.go +++ b/graph/pkg/service/v0/users.go @@ -97,6 +97,32 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, user) } +func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) { + userID := chi.URLParam(r, "userID") + userID, err := url.PathUnescape(userID) + if err != nil { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed") + } + + if userID == "" { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing user id") + return + } + + err = g.identityBackend.DeleteUser(r.Context(), userID) + + if err != nil { + var errcode errorcode.Error + if errors.As(err, &errcode) { + errcode.Render(w, r) + } else { + errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) + } + } + render.Status(r, http.StatusNoContent) + render.NoContent(w, r) +} + func isNilOrEmpty(s *string) bool { return s == nil || *s == "" } From 775a556c23eb9f356dcec8c2541fbfccf7ac90b3 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Wed, 12 Jan 2022 13:15:16 +0100 Subject: [PATCH 05/20] graph: Add missing methods to Service Interface --- graph/pkg/service/v0/instrument.go | 12 +++++++++++- graph/pkg/service/v0/logging.go | 10 ++++++++++ graph/pkg/service/v0/service.go | 2 ++ graph/pkg/service/v0/tracing.go | 10 ++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/graph/pkg/service/v0/instrument.go b/graph/pkg/service/v0/instrument.go index 878945f78..aeb9106f5 100644 --- a/graph/pkg/service/v0/instrument.go +++ b/graph/pkg/service/v0/instrument.go @@ -34,7 +34,17 @@ func (i instrument) GetUsers(w http.ResponseWriter, r *http.Request) { i.next.GetUsers(w, r) } -// GetUsers implements the Service interface. +// GetUser implements the Service interface. func (i instrument) GetUser(w http.ResponseWriter, r *http.Request) { i.next.GetUser(w, r) } + +// PostUser implements the Service interface. +func (i instrument) PostUser(w http.ResponseWriter, r *http.Request) { + i.next.PostUser(w, r) +} + +// DeleteUser implements the Service interface. +func (i instrument) DeleteUser(w http.ResponseWriter, r *http.Request) { + i.next.DeleteUser(w, r) +} diff --git a/graph/pkg/service/v0/logging.go b/graph/pkg/service/v0/logging.go index 124a54cf3..2c1a10e17 100644 --- a/graph/pkg/service/v0/logging.go +++ b/graph/pkg/service/v0/logging.go @@ -38,3 +38,13 @@ func (l logging) GetUsers(w http.ResponseWriter, r *http.Request) { func (l logging) GetUser(w http.ResponseWriter, r *http.Request) { l.next.GetUser(w, r) } + +// PostUser implements the Service interface. +func (l logging) PostUser(w http.ResponseWriter, r *http.Request) { + l.next.PostUser(w, r) +} + +// DeleteUser implements the Service interface. +func (l logging) DeleteUser(w http.ResponseWriter, r *http.Request) { + l.next.DeleteUser(w, r) +} diff --git a/graph/pkg/service/v0/service.go b/graph/pkg/service/v0/service.go index 004d36892..59a2c2f30 100644 --- a/graph/pkg/service/v0/service.go +++ b/graph/pkg/service/v0/service.go @@ -18,6 +18,8 @@ type Service interface { GetMe(http.ResponseWriter, *http.Request) GetUsers(http.ResponseWriter, *http.Request) GetUser(http.ResponseWriter, *http.Request) + PostUser(http.ResponseWriter, *http.Request) + DeleteUser(http.ResponseWriter, *http.Request) } // NewService returns a service implementation for Service. diff --git a/graph/pkg/service/v0/tracing.go b/graph/pkg/service/v0/tracing.go index 64cbc9708..27bbeb817 100644 --- a/graph/pkg/service/v0/tracing.go +++ b/graph/pkg/service/v0/tracing.go @@ -34,3 +34,13 @@ func (t tracing) GetUsers(w http.ResponseWriter, r *http.Request) { func (t tracing) GetUser(w http.ResponseWriter, r *http.Request) { t.next.GetUser(w, r) } + +// PostUser implements the Service interface. +func (t tracing) PostUser(w http.ResponseWriter, r *http.Request) { + t.next.PostUser(w, r) +} + +// DeleteUser implements the Service interface. +func (t tracing) DeleteUser(w http.ResponseWriter, r *http.Request) { + t.next.DeleteUser(w, r) +} From 840c9a7dddc9ed1868c84a4ada280f8a4dcc36a8 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Wed, 12 Jan 2022 16:28:37 +0100 Subject: [PATCH 06/20] Implement UpdateUser support for the GraphAPI backend --- graph/pkg/identity/backend.go | 3 ++ graph/pkg/identity/cs3.go | 5 +++ graph/pkg/identity/ldap.go | 51 ++++++++++++++++++++++++++++ graph/pkg/identity/ldap/reconnect.go | 27 +++++++++++---- graph/pkg/service/v0/instrument.go | 5 +++ graph/pkg/service/v0/logging.go | 5 +++ graph/pkg/service/v0/service.go | 2 ++ graph/pkg/service/v0/tracing.go | 5 +++ graph/pkg/service/v0/users.go | 35 +++++++++++++++++++ 9 files changed, 132 insertions(+), 6 deletions(-) diff --git a/graph/pkg/identity/backend.go b/graph/pkg/identity/backend.go index 1a71a7b5d..d230a6b13 100644 --- a/graph/pkg/identity/backend.go +++ b/graph/pkg/identity/backend.go @@ -15,6 +15,9 @@ type Backend interface { // DeleteUser deletes a given user, identified by username or id, from the backend DeleteUser(ctx context.Context, nameOrId string) error + // UpdateUser applies changes to given user, identified by username or id + UpdateUser(ctx context.Context, nameOrId string, user libregraph.User) (*libregraph.User, error) + GetUser(ctx context.Context, nameOrId string) (*libregraph.User, error) GetUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.User, error) diff --git a/graph/pkg/identity/cs3.go b/graph/pkg/identity/cs3.go index 5fe0117c8..231107d11 100644 --- a/graph/pkg/identity/cs3.go +++ b/graph/pkg/identity/cs3.go @@ -30,6 +30,11 @@ func (i *CS3) DeleteUser(ctx context.Context, nameOrID string) error { return errorcode.New(errorcode.NotSupported, "not implemented") } +// UpdateUser implements the Backend Interface. It's currently not suported for the CS3 backend +func (i *CS3) UpdateUser(ctx context.Context, nameOrID string, user libregraph.User) (*libregraph.User, error) { + return nil, errorcode.New(errorcode.NotSupported, "not implemented") +} + func (i *CS3) GetUser(ctx context.Context, userID string) (*libregraph.User, error) { client, err := pool.GetGatewayServiceClient(i.Config.Address) if err != nil { diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index b9f9c65cf..47433c7e6 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -160,6 +160,57 @@ func (i *LDAP) DeleteUser(ctx context.Context, nameOrID string) error { return nil } +// UpdateUser implements the Backend Interface. It's currently not suported for the CS3 backedn +func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.User) (*libregraph.User, error) { + e, err := i.getLDAPUserByNameOrID(nameOrID) + if err != nil { + return nil, err + } + + // Don't allow updates of the ID + if user.Id != nil && *user.Id != "" { + if e.GetEqualFoldAttributeValue(i.userAttributeMap.id) != *user.Id { + return nil, errorcode.New(errorcode.NotAllowed, "changing the UserId is not allowed") + } + } + // TODO: In order to allow updating the user name we'd need to issue a ModRDN operation + // As we currently using uid as the naming Attribute for the user entries. (Do we even + // want to allow changing the user name?). For now just disallow it. + if user.OnPremisesSamAccountName != nil && *user.OnPremisesSamAccountName != "" { + if e.GetEqualFoldAttributeValue(i.userAttributeMap.userName) != *user.OnPremisesSamAccountName { + return nil, errorcode.New(errorcode.NotSupported, "changing the user name is currently not supported") + } + } + + mr := ldap.ModifyRequest{DN: e.DN} + if user.DisplayName != nil && *user.DisplayName != "" { + if e.GetEqualFoldAttributeValue(i.userAttributeMap.displayName) != *user.DisplayName { + mr.Replace(i.userAttributeMap.displayName, []string{*user.DisplayName}) + } + } + if user.Mail != nil && *user.Mail != "" { + if e.GetEqualFoldAttributeValue(i.userAttributeMap.mail) != *user.Mail { + mr.Replace(i.userAttributeMap.mail, []string{*user.Mail}) + } + } + if user.PasswordProfile != nil && user.PasswordProfile.Password != nil && *user.PasswordProfile.Password != "" { + // password are hashed server side there is no need to check if the new password + // is actually different from the old one. + mr.Replace("userPassword", []string{*user.PasswordProfile.Password}) + } + + if err := i.conn.Modify(&mr); err != nil { + return nil, err + } + + // Read back user from LDAP to get the generated UUID + e, err = i.getUserByDN(e.DN) + if err != nil { + return nil, err + } + return i.createUserModelFromLDAP(e), nil +} + func (i *LDAP) getUserByDN(dn string) (*ldap.Entry, error) { searchRequest := ldap.NewSearchRequest( dn, ldap.ScopeBaseObject, ldap.NeverDerefAliases, 1, 0, false, diff --git a/graph/pkg/identity/ldap/reconnect.go b/graph/pkg/identity/ldap/reconnect.go index 272a0043e..b4e868846 100644 --- a/graph/pkg/identity/ldap/reconnect.go +++ b/graph/pkg/identity/ldap/reconnect.go @@ -180,16 +180,31 @@ func (c ConnWithReconnect) Del(d *ldap.DelRequest) error { return conn.Del(d) } -func (c ConnWithReconnect) Modify(*ldap.ModifyRequest) error { - return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) +func (c ConnWithReconnect) Modify(m *ldap.ModifyRequest) error { + conn, err := c.GetConnection() + if err != nil { + return err + } + + return conn.Modify(m) } -func (c ConnWithReconnect) ModifyDN(*ldap.ModifyDNRequest) error { - return ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) +func (c ConnWithReconnect) ModifyDN(m *ldap.ModifyDNRequest) error { + conn, err := c.GetConnection() + if err != nil { + return err + } + + return conn.ModifyDN(m) } -func (c ConnWithReconnect) ModifyWithResult(*ldap.ModifyRequest) (*ldap.ModifyResult, error) { - return nil, ldap.NewError(ldap.LDAPResultNotSupported, fmt.Errorf("not implemented")) +func (c ConnWithReconnect) ModifyWithResult(m *ldap.ModifyRequest) (*ldap.ModifyResult, error) { + conn, err := c.GetConnection() + if err != nil { + return nil, err + } + + return conn.ModifyWithResult(m) } func (c ConnWithReconnect) Compare(dn, attribute, value string) (bool, error) { diff --git a/graph/pkg/service/v0/instrument.go b/graph/pkg/service/v0/instrument.go index aeb9106f5..a0fb82542 100644 --- a/graph/pkg/service/v0/instrument.go +++ b/graph/pkg/service/v0/instrument.go @@ -48,3 +48,8 @@ func (i instrument) PostUser(w http.ResponseWriter, r *http.Request) { func (i instrument) DeleteUser(w http.ResponseWriter, r *http.Request) { i.next.DeleteUser(w, r) } + +// PatchUser implements the Service interface. +func (i instrument) PatchUser(w http.ResponseWriter, r *http.Request) { + i.next.PatchUser(w, r) +} diff --git a/graph/pkg/service/v0/logging.go b/graph/pkg/service/v0/logging.go index 2c1a10e17..d5ce3373a 100644 --- a/graph/pkg/service/v0/logging.go +++ b/graph/pkg/service/v0/logging.go @@ -48,3 +48,8 @@ func (l logging) PostUser(w http.ResponseWriter, r *http.Request) { func (l logging) DeleteUser(w http.ResponseWriter, r *http.Request) { l.next.DeleteUser(w, r) } + +// PatchUser implements the Service interface. +func (l logging) PatchUser(w http.ResponseWriter, r *http.Request) { + l.next.PatchUser(w, r) +} diff --git a/graph/pkg/service/v0/service.go b/graph/pkg/service/v0/service.go index 59a2c2f30..451cdd872 100644 --- a/graph/pkg/service/v0/service.go +++ b/graph/pkg/service/v0/service.go @@ -20,6 +20,7 @@ type Service interface { GetUser(http.ResponseWriter, *http.Request) PostUser(http.ResponseWriter, *http.Request) DeleteUser(http.ResponseWriter, *http.Request) + PatchUser(http.ResponseWriter, *http.Request) } // NewService returns a service implementation for Service. @@ -73,6 +74,7 @@ func NewService(opts ...Option) Service { r.Route("/{userID}", func(r chi.Router) { r.Get("/", svc.GetUser) r.Delete("/", svc.DeleteUser) + r.Patch("/", svc.PatchUser) }) }) r.Route("/groups", func(r chi.Router) { diff --git a/graph/pkg/service/v0/tracing.go b/graph/pkg/service/v0/tracing.go index 27bbeb817..c1e544214 100644 --- a/graph/pkg/service/v0/tracing.go +++ b/graph/pkg/service/v0/tracing.go @@ -44,3 +44,8 @@ func (t tracing) PostUser(w http.ResponseWriter, r *http.Request) { func (t tracing) DeleteUser(w http.ResponseWriter, r *http.Request) { t.next.DeleteUser(w, r) } + +// PatchUser implements the Service interface. +func (t tracing) PatchUser(w http.ResponseWriter, r *http.Request) { + t.next.PatchUser(w, r) +} diff --git a/graph/pkg/service/v0/users.go b/graph/pkg/service/v0/users.go index 0593c6bcb..4a0ae17b8 100644 --- a/graph/pkg/service/v0/users.go +++ b/graph/pkg/service/v0/users.go @@ -123,6 +123,41 @@ func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) { render.NoContent(w, r) } +// PatchUser implements the Service Interface. Updates the specified attributes of an +// ExistingUser +func (g Graph) PatchUser(w http.ResponseWriter, r *http.Request) { + nameOrID := chi.URLParam(r, "userID") + nameOrID, err := url.PathUnescape(nameOrID) + if err != nil { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed") + } + + if nameOrID == "" { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing user id") + return + } + changes := libregraph.NewUser() + err = json.NewDecoder(r.Body).Decode(changes) + if err != nil { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) + return + } + + u, err := g.identityBackend.UpdateUser(r.Context(), nameOrID, *changes) + if err != nil { + var errcode errorcode.Error + if errors.As(err, &errcode) { + errcode.Render(w, r) + } else { + errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) + } + } + + render.Status(r, http.StatusOK) + render.JSON(w, r, u) + +} + func isNilOrEmpty(s *string) bool { return s == nil || *s == "" } From 53efa9ca145c2e0e0aa8c29c685b15fa1d3f611f Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Thu, 13 Jan 2022 15:14:51 +0100 Subject: [PATCH 07/20] Switch to generating our own UUIDs for users By default the GraphAPI will generate the UUID itself now instead of relying on the LDAP server to generate a valid entryUUID attribute. This can been be switched off via the new `use_server_uuid` toggle in the LDAP config. --- graph/pkg/config/config.go | 7 ++++--- graph/pkg/config/defaultconfig.go | 5 +++-- graph/pkg/identity/ldap.go | 16 +++++++++++----- graph/pkg/service/v0/users.go | 8 ++++++++ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/graph/pkg/config/config.go b/graph/pkg/config/config.go index d094cf54f..6196bcdfc 100644 --- a/graph/pkg/config/config.go +++ b/graph/pkg/config/config.go @@ -34,9 +34,10 @@ type Spaces struct { } type LDAP struct { - URI string `ocisConfig:"uri" env:"GRAPH_LDAP_URI"` - BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` - BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` + URI string `ocisConfig:"uri" env:"GRAPH_LDAP_URI"` + BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` + BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` + UseServerUUID bool `ocisConfig:"use_server_uuid" env:"GRAPH_LDAP_SERVER_UUID"` UserBaseDN string `ocisConfig:"user_base_dn" env:"GRAPH_LDAP_USER_BASE_DN"` UserSearchScope string `ocisConfig:"user_search_scope" env:"GRAPH_LDAP_USER_SCOPE"` diff --git a/graph/pkg/config/defaultconfig.go b/graph/pkg/config/defaultconfig.go index acd24e838..ae04f752a 100644 --- a/graph/pkg/config/defaultconfig.go +++ b/graph/pkg/config/defaultconfig.go @@ -31,6 +31,7 @@ func DefaultConfig() *Config { URI: "ldap://localhost:9125", BindDN: "", BindPassword: "", + UseServerUUID: false, UserBaseDN: "ou=users,dc=ocis,dc=test", UserSearchScope: "sub", UserFilter: "(objectClass=inetOrgPerson)", @@ -39,12 +40,12 @@ func DefaultConfig() *Config { UserNameAttribute: "uid", // FIXME: switch this to some more widely available attribute by default // ideally this needs to be constant for the lifetime of a users - UserIDAttribute: "entryUUID", + UserIDAttribute: "owncloudUUID", GroupBaseDN: "ou=groups,dc=ocis,dc=test", GroupSearchScope: "sub", GroupFilter: "(objectclass=groupOfNames)", GroupNameAttribute: "cn", - GroupIDAttribute: "cn", + GroupIDAttribute: "owncloudUUID", }, }, } diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index 47433c7e6..b9d1cae2b 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/go-ldap/ldap/v3" + "github.com/gofrs/uuid" libregraph "github.com/owncloud/libre-graph-api-go" "github.com/owncloud/ocis/graph/pkg/config" @@ -14,6 +15,8 @@ import ( ) type LDAP struct { + useServerUUID bool + userBaseDN string userFilter string userScope int @@ -71,6 +74,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD } return &LDAP{ + useServerUUID: config.UseServerUUID, userBaseDN: config.UserBaseDN, userFilter: config.UserFilter, userScope: userScope, @@ -88,14 +92,9 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD // LDAP User Entry (using the inetOrgPerson LDAP Objectclass) add adds that to the // configured LDAP server func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) { - ar := ldap.AddRequest{ DN: fmt.Sprintf("uid=%s,%s", *user.OnPremisesSamAccountName, i.userBaseDN), Attributes: []ldap.Attribute{ - { - Type: "objectClass", - Vals: []string{"inetOrgPerson", "organizationalPerson", "person", "top"}, - }, // inetOrgPerson requires "cn" { Type: "cn", @@ -116,6 +115,8 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap }, } + objectClasses := []string{"inetOrgPerson", "organizationalPerson", "person", "top"} + if user.PasswordProfile != nil && user.PasswordProfile.Password != nil { // TODO? This relies to the LDAP server to properly hash the password. // We might want to add support for the Password Modify LDAP Extended @@ -123,6 +124,11 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap // hashing here. ar.Attribute("userPassword", []string{*user.PasswordProfile.Password}) } + if !i.useServerUUID { + ar.Attribute("owncloudUUID", []string{uuid.Must(uuid.NewV4()).String()}) + objectClasses = append(objectClasses, "owncloud") + } + ar.Attribute("objectClass", objectClasses) // inetOrgPerson requires "sn" to be set. Set it to the Username if // Surname is not set in the Request diff --git a/graph/pkg/service/v0/users.go b/graph/pkg/service/v0/users.go index 4a0ae17b8..88d87a420 100644 --- a/graph/pkg/service/v0/users.go +++ b/graph/pkg/service/v0/users.go @@ -60,6 +60,14 @@ func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) { return } + // Disallow user-supplied IDs. It's supposed to be readonly. We're either + // generating them in the backend ourselves or rely on the Backend's + // storage (e.g. LDAP) to provide a unique ID. + if !isNilOrEmpty(u.Id) { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "user id is a read-only attribute") + return + } + if u, err = g.identityBackend.CreateUser(r.Context(), *u); err != nil { errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) return From cb7f9f792200327e4ed1d5fd4a1cbf778a8faa36 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Thu, 13 Jan 2022 16:25:27 +0100 Subject: [PATCH 08/20] Introduce write_enabled flag for graph user backend Defaults to `false` (for now). So the /graph/users endpoints are read-only by default, which should be the default configured against and existing external LDAP server. --- graph/pkg/config/config.go | 1 + graph/pkg/config/defaultconfig.go | 1 + graph/pkg/identity/ldap.go | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/graph/pkg/config/config.go b/graph/pkg/config/config.go index 6196bcdfc..953a5ad55 100644 --- a/graph/pkg/config/config.go +++ b/graph/pkg/config/config.go @@ -38,6 +38,7 @@ type LDAP struct { BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` UseServerUUID bool `ocisConfig:"use_server_uuid" env:"GRAPH_LDAP_SERVER_UUID"` + WriteEnabled bool `ocisConfig:"write_enabled" env:"GRAPH_LDAP_SERVER_WRITE_ENABLED"` UserBaseDN string `ocisConfig:"user_base_dn" env:"GRAPH_LDAP_USER_BASE_DN"` UserSearchScope string `ocisConfig:"user_search_scope" env:"GRAPH_LDAP_USER_SCOPE"` diff --git a/graph/pkg/config/defaultconfig.go b/graph/pkg/config/defaultconfig.go index ae04f752a..3c98b0b27 100644 --- a/graph/pkg/config/defaultconfig.go +++ b/graph/pkg/config/defaultconfig.go @@ -32,6 +32,7 @@ func DefaultConfig() *Config { BindDN: "", BindPassword: "", UseServerUUID: false, + WriteEnabled: false, UserBaseDN: "ou=users,dc=ocis,dc=test", UserSearchScope: "sub", UserFilter: "(objectClass=inetOrgPerson)", diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index b9d1cae2b..bf16afe93 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -16,6 +16,7 @@ import ( type LDAP struct { useServerUUID bool + writeEnabled bool userBaseDN string userFilter string @@ -85,6 +86,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD groupAttributeMap: gam, logger: logger, conn: lc, + writeEnabled: config.WriteEnabled, }, nil } @@ -92,6 +94,9 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD // LDAP User Entry (using the inetOrgPerson LDAP Objectclass) add adds that to the // configured LDAP server func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) { + if !i.writeEnabled { + return nil, errorcode.New(errorcode.NotAllowed, "server is configured read-only") + } ar := ldap.AddRequest{ DN: fmt.Sprintf("uid=%s,%s", *user.OnPremisesSamAccountName, i.userBaseDN), Attributes: []ldap.Attribute{ @@ -155,6 +160,9 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap // DeleteUser implements the Backend Interface. It permanently deletes a User identified // by name or id from the LDAP server func (i *LDAP) DeleteUser(ctx context.Context, nameOrID string) error { + if !i.writeEnabled { + return errorcode.New(errorcode.NotAllowed, "server is configured read-only") + } e, err := i.getLDAPUserByNameOrID(nameOrID) if err != nil { return err @@ -168,6 +176,9 @@ func (i *LDAP) DeleteUser(ctx context.Context, nameOrID string) error { // UpdateUser implements the Backend Interface. It's currently not suported for the CS3 backedn func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph.User) (*libregraph.User, error) { + if !i.writeEnabled { + return nil, errorcode.New(errorcode.NotAllowed, "server is configured read-only") + } e, err := i.getLDAPUserByNameOrID(nameOrID) if err != nil { return nil, err From d56ea4c585ec53a1113d979b6f82b81f07484569 Mon Sep 17 00:00:00 2001 From: Swikriti Tripathi Date: Fri, 14 Jan 2022 09:10:31 +0545 Subject: [PATCH 09/20] Bump the commit id for tests --- .drone.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.env b/.drone.env index 895c99c06..7e845b679 100644 --- a/.drone.env +++ b/.drone.env @@ -1,5 +1,5 @@ # The test runner source for API tests -CORE_COMMITID=09d584745d6cbd6aebc557d9b78f6130e9b99e2b +CORE_COMMITID=88dc1fc01b8afd254d59cbface6ef48670848e22 CORE_BRANCH=master # The test runner source for UI tests From e3a1e2b364ef54b83ce30d097ddb286b8da74990 Mon Sep 17 00:00:00 2001 From: Swikriti Tripathi Date: Fri, 14 Jan 2022 09:45:35 +0545 Subject: [PATCH 10/20] Adding failing tests to expected to failure --- tests/acceptance/expected-failures-API-on-OCIS-storage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/acceptance/expected-failures-API-on-OCIS-storage.md b/tests/acceptance/expected-failures-API-on-OCIS-storage.md index f56635878..caf82fa29 100644 --- a/tests/acceptance/expected-failures-API-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-API-on-OCIS-storage.md @@ -34,6 +34,8 @@ _ocdav: double check the webdav property parsing when custom namespaces are used - [apiVersions/fileVersionAuthor.feature:101](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersionAuthor.feature:#L101) - [apiVersions/fileVersionAuthor.feature:128](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersionAuthor.feature:#L128) - [apiVersions/fileVersionAuthor.feature:155](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersionAuthor.feature:#L155) +- [apiVersions/fileVersionAuthor.feature:180](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersionAuthor.feature:#L180) +- [apiVersions/fileVersionAuthor.feature:220](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiVersions/fileVersionAuthor.feature:#L220) ### Sync Synchronization features like etag propagation, setting mtime and locking files From a45f717d3ffc6d508515399734652b2a81b23ee1 Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Fri, 14 Jan 2022 10:42:36 +0100 Subject: [PATCH 11/20] Make the project spaces capability configurable Some deployments don't want to show early stages of the spaces feature set in the clients. It can now be disabled in the capabilities. --- storage/pkg/command/frontend.go | 2 +- storage/pkg/config/config.go | 5 +++++ storage/pkg/config/defaultconfig.go | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/pkg/command/frontend.go b/storage/pkg/command/frontend.go index e96d2c147..81eb0a268 100644 --- a/storage/pkg/command/frontend.go +++ b/storage/pkg/command/frontend.go @@ -294,7 +294,7 @@ func frontendConfigFromStruct(c *cli.Context, cfg *config.Config, filesCfg map[s }, "spaces": map[string]interface{}{ "version": "0.0.1", - "enabled": true, + "enabled": cfg.Reva.Frontend.ProjectSpaces, }, }, "version": map[string]interface{}{ diff --git a/storage/pkg/config/config.go b/storage/pkg/config/config.go index 6cd62c35d..a2c738bfc 100644 --- a/storage/pkg/config/config.go +++ b/storage/pkg/config/config.go @@ -155,6 +155,7 @@ type FrontendPort struct { ArchiverPrefix string `ocisConfig:"archiver_prefix"` DatagatewayPrefix string `ocisConfig:"data_gateway_prefix"` Favorites bool `ocisConfig:"favorites"` + ProjectSpaces bool `ocisConfig:"project_spaces"` OCDavInsecure bool `ocisConfig:"ocdav_insecure"` OCDavPrefix string `ocisConfig:"ocdav_prefix"` OCSPrefix string `ocisConfig:"ocs_prefix"` @@ -815,6 +816,10 @@ func structMappings(cfg *Config) []shared.EnvBinding { EnvVars: []string{"STORAGE_FRONTEND_FAVORITES"}, Destination: &cfg.Reva.Frontend.Favorites, }, + { + EnvVars: []string{"STORAGE_FRONTEND_PROJECT_SPACES"}, + Destination: &cfg.Reva.Frontend.ProjectSpaces, + }, { EnvVars: []string{"STORAGE_FRONTEND_OCDAV_PREFIX"}, Destination: &cfg.Reva.Frontend.OCDavPrefix, diff --git a/storage/pkg/config/defaultconfig.go b/storage/pkg/config/defaultconfig.go index 0f266d4d6..23602bbf1 100644 --- a/storage/pkg/config/defaultconfig.go +++ b/storage/pkg/config/defaultconfig.go @@ -239,6 +239,7 @@ func DefaultConfig() *Config { ArchiverPrefix: "archiver", DatagatewayPrefix: "data", Favorites: false, + ProjectSpaces: true, OCDavInsecure: false, // true? OCDavPrefix: "", OCSPrefix: "ocs", From 68fa5d06f70128d427fe90ff74dd7c8f3320269d Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Fri, 14 Jan 2022 10:46:13 +0100 Subject: [PATCH 12/20] Adjust spaces capability changelog item --- changelog/unreleased/enhancement-spaces-capability.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog/unreleased/enhancement-spaces-capability.md b/changelog/unreleased/enhancement-spaces-capability.md index 8129de09c..7b056135d 100644 --- a/changelog/unreleased/enhancement-spaces-capability.md +++ b/changelog/unreleased/enhancement-spaces-capability.md @@ -1,6 +1,7 @@ Enhancement: Add spaces capability -We've added the spaces capability with version 0.0.1 and enabled set to true. +We've added the spaces capability with version 0.0.1 and enabled defaulting to true. https://github.com/owncloud/ocis/pull/2931 https://github.com/cs3org/reva/pull/2015 +https://github.com/owncloud/ocis/pull/2965 From d731570319de335355ea5c6dd00147fcbf5c45a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Fri, 14 Jan 2022 10:51:37 +0000 Subject: [PATCH 13/20] Automated changelog update [skip ci] --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2292e090..51518314d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,10 +79,11 @@ The following sections list the changes for unreleased. * Enhancement - Add spaces capability: [#2931](https://github.com/owncloud/ocis/pull/2931) - We've added the spaces capability with version 0.0.1 and enabled set to true. + We've added the spaces capability with version 0.0.1 and enabled defaulting to true. https://github.com/owncloud/ocis/pull/2931 https://github.com/cs3org/reva/pull/2015 + https://github.com/owncloud/ocis/pull/2965 * Enhancement - Support signature auth in the public share auth middleware: [#2831](https://github.com/owncloud/ocis/pull/2831) From 19abda978dd0d89c57d354bf680f4c0b63f031de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Fri, 14 Jan 2022 10:52:44 +0000 Subject: [PATCH 14/20] Automated changelog update [skip ci] --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51518314d..1a4297413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The following sections list the changes for unreleased. * Enhancement - Add new file url of the app provider to the ocs capabilities: [#2884](https://github.com/owncloud/ocis/pull/2884) * Enhancement - Add spaces capability: [#2931](https://github.com/owncloud/ocis/pull/2931) * Enhancement - Support signature auth in the public share auth middleware: [#2831](https://github.com/owncloud/ocis/pull/2831) +* Enhancement - Update REVA to v1.16.1-0.20220112085026-07451f6cd806: [#2953](https://github.com/owncloud/ocis/pull/2953) * Enhancement - Update REVA to xxx: [#2878](https://github.com/owncloud/ocis/pull/2878) * Enhancement - Update ownCloud Web to v4.8.0: [#2895](https://github.com/owncloud/ocis/pull/2895) @@ -91,6 +92,12 @@ The following sections list the changes for unreleased. https://github.com/owncloud/ocis/pull/2831 +* Enhancement - Update REVA to v1.16.1-0.20220112085026-07451f6cd806: [#2953](https://github.com/owncloud/ocis/pull/2953) + + Update REVA to v1.16.1-0.20220112085026-07451f6cd806 + + https://github.com/owncloud/ocis/pull/2953 + * Enhancement - Update REVA to xxx: [#2878](https://github.com/owncloud/ocis/pull/2878) Updated REVA to xxx This update includes: From 624a2a956c778ef3af337f0b9684d0452c9d1787 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 11 Jan 2022 15:04:06 +0100 Subject: [PATCH 15/20] add filter by id and driveType --- changelog/unreleased/spaces-filters.md | 6 ++++ graph/pkg/service/v0/drives.go | 38 +++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 changelog/unreleased/spaces-filters.md diff --git a/changelog/unreleased/spaces-filters.md b/changelog/unreleased/spaces-filters.md new file mode 100644 index 000000000..7b3f675e3 --- /dev/null +++ b/changelog/unreleased/spaces-filters.md @@ -0,0 +1,6 @@ +Enhancement: Add filter by driveType and id to /me/drives + +We added two possible filter terms (driveType, id) to the /me/drives endpoint on the graph api. These can be used with the odata query parameter "$filter". +We only support the "eq" operator for now. + +https://github.com/owncloud/ocis/pull/2946 diff --git a/graph/pkg/service/v0/drives.go b/graph/pkg/service/v0/drives.go index 12059dd0b..abc6ae474 100644 --- a/graph/pkg/service/v0/drives.go +++ b/graph/pkg/service/v0/drives.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/CiscoM31/godata" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" @@ -31,6 +32,14 @@ import ( // GetDrives implements the Service interface. func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { + sanitized := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/") + // Parse the request with odata parser + odataReq, err := godata.ParseRequest(r.Context(), sanitized, r.URL.Query()) + if err != nil { + g.logger.Err(err).Msg("unable to parse odata request") + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) + return + } g.logger.Info().Msg("Calling GetDrives") ctx := r.Context() @@ -64,7 +73,7 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { Value: value, }, }}, - // TODO add filters? + Filters: generateCs3Filters(odataReq), }) switch { case err != nil: @@ -553,3 +562,30 @@ func canSetSpaceQuota(ctx context.Context, user *userv1beta1.User) (bool, error) } return true, nil } + +func generateCs3Filters(request *godata.GoDataRequest) []*storageprovider.ListStorageSpacesRequest_Filter { + var filters []*storageprovider.ListStorageSpacesRequest_Filter + if request.Query.Filter != nil && request.Query.Filter.Tree.Token.Value == "eq" { + switch request.Query.Filter.Tree.Children[0].Token.Value { + case "driveType": + filter1 := &storageprovider.ListStorageSpacesRequest_Filter{ + Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE, + Term: &storageprovider.ListStorageSpacesRequest_Filter_SpaceType{ + SpaceType: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), + }, + } + filters = append(filters, filter1) + case "id": + filter2 := &storageprovider.ListStorageSpacesRequest_Filter{ + Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_ID, + Term: &storageprovider.ListStorageSpacesRequest_Filter_Id{ + Id: &storageprovider.StorageSpaceId{ + OpaqueId: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), + }, + }, + } + filters = append(filters, filter2) + } + } + return filters +} From bca954cae70cfef4afa13fafc039b1720303f52b Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Tue, 11 Jan 2022 23:42:05 +0100 Subject: [PATCH 16/20] more detailed logging --- graph/pkg/service/v0/drives.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/graph/pkg/service/v0/drives.go b/graph/pkg/service/v0/drives.go index abc6ae474..b0acbd22e 100644 --- a/graph/pkg/service/v0/drives.go +++ b/graph/pkg/service/v0/drives.go @@ -32,11 +32,11 @@ import ( // GetDrives implements the Service interface. func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { - sanitized := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/") + sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/") // Parse the request with odata parser - odataReq, err := godata.ParseRequest(r.Context(), sanitized, r.URL.Query()) + odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query()) if err != nil { - g.logger.Err(err).Msg("unable to parse odata request") + g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error") errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) return } @@ -66,6 +66,12 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) return } + filters, err := generateCs3Filters(odataReq) + if err != nil { + g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error") + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) + return + } res, err := client.ListStorageSpaces(ctx, &storageprovider.ListStorageSpacesRequest{ Opaque: &types.Opaque{Map: map[string]*types.OpaqueEntry{ "permissions": { @@ -73,7 +79,7 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { Value: value, }, }}, - Filters: generateCs3Filters(odataReq), + Filters: filters, }) switch { case err != nil: @@ -563,7 +569,7 @@ func canSetSpaceQuota(ctx context.Context, user *userv1beta1.User) (bool, error) return true, nil } -func generateCs3Filters(request *godata.GoDataRequest) []*storageprovider.ListStorageSpacesRequest_Filter { +func generateCs3Filters(request *godata.GoDataRequest) ([]*storageprovider.ListStorageSpacesRequest_Filter, error) { var filters []*storageprovider.ListStorageSpacesRequest_Filter if request.Query.Filter != nil && request.Query.Filter.Tree.Token.Value == "eq" { switch request.Query.Filter.Tree.Children[0].Token.Value { @@ -586,6 +592,9 @@ func generateCs3Filters(request *godata.GoDataRequest) []*storageprovider.ListSt } filters = append(filters, filter2) } + } else { + err := fmt.Errorf("unsupported filter operand: %s", request.Query.Filter.Tree.Token.Value) + return nil, err } - return filters + return filters, nil } From f7bf42bce001618fe95a5105a49de0353a352d63 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Wed, 12 Jan 2022 20:27:40 +0100 Subject: [PATCH 17/20] fix case for unsupported operators --- graph/pkg/service/v0/drives.go | 44 ++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/graph/pkg/service/v0/drives.go b/graph/pkg/service/v0/drives.go index b0acbd22e..c83fc5dd3 100644 --- a/graph/pkg/service/v0/drives.go +++ b/graph/pkg/service/v0/drives.go @@ -571,30 +571,32 @@ func canSetSpaceQuota(ctx context.Context, user *userv1beta1.User) (bool, error) func generateCs3Filters(request *godata.GoDataRequest) ([]*storageprovider.ListStorageSpacesRequest_Filter, error) { var filters []*storageprovider.ListStorageSpacesRequest_Filter - if request.Query.Filter != nil && request.Query.Filter.Tree.Token.Value == "eq" { - switch request.Query.Filter.Tree.Children[0].Token.Value { - case "driveType": - filter1 := &storageprovider.ListStorageSpacesRequest_Filter{ - Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE, - Term: &storageprovider.ListStorageSpacesRequest_Filter_SpaceType{ - SpaceType: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), - }, - } - filters = append(filters, filter1) - case "id": - filter2 := &storageprovider.ListStorageSpacesRequest_Filter{ - Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_ID, - Term: &storageprovider.ListStorageSpacesRequest_Filter_Id{ - Id: &storageprovider.StorageSpaceId{ - OpaqueId: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), + if request.Query.Filter != nil { + if request.Query.Filter.Tree.Token.Value == "eq" { + switch request.Query.Filter.Tree.Children[0].Token.Value { + case "driveType": + filter1 := &storageprovider.ListStorageSpacesRequest_Filter{ + Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE, + Term: &storageprovider.ListStorageSpacesRequest_Filter_SpaceType{ + SpaceType: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), }, - }, + } + filters = append(filters, filter1) + case "id": + filter2 := &storageprovider.ListStorageSpacesRequest_Filter{ + Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_ID, + Term: &storageprovider.ListStorageSpacesRequest_Filter_Id{ + Id: &storageprovider.StorageSpaceId{ + OpaqueId: strings.Trim(request.Query.Filter.Tree.Children[1].Token.Value, "'"), + }, + }, + } + filters = append(filters, filter2) } - filters = append(filters, filter2) + } else { + err := fmt.Errorf("unsupported filter operand: %s", request.Query.Filter.Tree.Token.Value) + return nil, err } - } else { - err := fmt.Errorf("unsupported filter operand: %s", request.Query.Filter.Tree.Token.Value) - return nil, err } return filters, nil } From 1db13d8a391b5fc754e5cdd7e2e987b7e97e3572 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Thu, 13 Jan 2022 15:28:33 +0100 Subject: [PATCH 18/20] add tests --- graph/pkg/service/v0/drives.go | 2 +- .../features/apiSpaces/listSpaces.feature | 29 +++++++++ .../features/bootstrap/SpacesContext.php | 61 ++++++++++++++++++- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/graph/pkg/service/v0/drives.go b/graph/pkg/service/v0/drives.go index c83fc5dd3..bfed8d4dc 100644 --- a/graph/pkg/service/v0/drives.go +++ b/graph/pkg/service/v0/drives.go @@ -69,7 +69,7 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { filters, err := generateCs3Filters(odataReq) if err != nil { g.logger.Err(err).Interface("query", r.URL.Query()).Msg("query error") - errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) + errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error()) return } res, err := client.ListStorageSpaces(ctx, &storageprovider.ListStorageSpacesRequest{ diff --git a/tests/acceptance/features/apiSpaces/listSpaces.feature b/tests/acceptance/features/apiSpaces/listSpaces.feature index 8705184e3..aca06e03b 100644 --- a/tests/acceptance/features/apiSpaces/listSpaces.feature +++ b/tests/acceptance/features/apiSpaces/listSpaces.feature @@ -19,6 +19,35 @@ Feature: List and create spaces | name | Alice Hansen | | quota@@@state | normal | | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | + And the json responded should contain a space "Shares Jail" with these key and value pairs: + | key | value | + | driveType | virtual | + | id | %space_id% | + | name | Shares Jail | + | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | + + Scenario: An ordinary user can request information about their Space via the Graph API using a filter + When user "Alice" lists all available spaces via the GraphApi with query "$filter=driveType eq 'personal'" + Then the HTTP status code should be "200" + And the json responded should contain a space "Alice Hansen" with these key and value pairs: + | key | value | + | driveType | personal | + | id | %space_id% | + | name | Alice Hansen | + | quota@@@state | normal | + | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | + And the json responded should not contain a space with name "Shares Jail" + And the json responded should contain spaces of type "personal" + And the json responded should only contain spaces of type "personal" + And the json responded should not contain spaces of type "project" + And the json responded should not contain spaces of type "virtual" + And the json responded should not contain spaces of type "public" + + Scenario: An ordinary user will not see any space when using a filter for project + When user "Alice" lists all available spaces via the GraphApi with query "$filter=driveType eq 'project'" + Then the HTTP status code should be "200" + And the json responded should not contain a space with name "Alice Hansen" + And the json responded should not contain spaces of type "personal" Scenario: An ordinary user can access their Space via the webDav API When user "Alice" lists all available spaces via the GraphApi diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php index 7de32c7e3..c5d5a220a 100644 --- a/tests/acceptance/features/bootstrap/SpacesContext.php +++ b/tests/acceptance/features/bootstrap/SpacesContext.php @@ -350,6 +350,26 @@ class SpacesContext implements Context { $this->rememberTheAvailableSpaces(); } + /** + * @When /^user "([^"]*)" lists all available spaces via the GraphApi with query "([^"]*)"$/ + * + * @param string $user + * @param string $query + * + * @return void + * + * @throws GuzzleException + */ + public function theUserListsAllHisAvailableSpacesUsingTheGraphApiWithFilter(string $user, string $query): void { + $this->featureContext->setResponse( + $this->listSpacesRequest( + $user, + $this->featureContext->getPasswordForUser($user), + "?". $query + ) + ); + } + /** * @When /^user "([^"]*)" creates a space "([^"]*)" of type "([^"]*)" with the default quota using the GraphApi$/ * @@ -659,7 +679,7 @@ class SpacesContext implements Context { } /** - * @Then /^the json responded should not contain a space "([^"]*)"$/ + * @Then /^the json responded should not contain a space with name "([^"]*)"$/ * * @param string $spaceName * @@ -672,6 +692,45 @@ class SpacesContext implements Context { Assert::assertEmpty($this->getSpaceByNameFromResponse($spaceName), "space $spaceName should not be available for a user"); } + /** + * @Then /^the json responded should (not|only|)\s?contain spaces of type "([^"]*)"$/ + * + * @param string $shoulOrNot (not|only|) + * @param string $type + * + * @return void + * @throws Exception + */ + public function jsonRespondedShouldNotContainSpaceType( + string $onlyOrNot, + string $type + ): void { + Assert::assertNotEmpty( + $spaces = json_decode( + (string)$this->featureContext + ->getResponse()->getBody(), + true, + 512, + JSON_THROW_ON_ERROR + ) + ); + $matches = []; + foreach($spaces["value"] as $space) { + if($onlyOrNot === "not") { + Assert::assertNotEquals($space["driveType"], $type); + } + if($onlyOrNot === "only") { + Assert::assertEquals($space["driveType"], $type); + } + if($onlyOrNot === "" && $space["driveType"] === $type) { + $matches[] = $space; + } + } + if($onlyOrNot === "") { + Assert::assertNotEmpty($matches); + } + } + /** * @param string $shouldOrNot (not|) * @param TableNode $expectedFiles From 16c7706d6221160a6a3f1e81261aad860e3bdd5c Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 14 Jan 2022 00:13:17 +0100 Subject: [PATCH 19/20] remove redundancy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jörn Friedrich Dreyer --- tests/acceptance/features/apiSpaces/listSpaces.feature | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/acceptance/features/apiSpaces/listSpaces.feature b/tests/acceptance/features/apiSpaces/listSpaces.feature index aca06e03b..175c562cc 100644 --- a/tests/acceptance/features/apiSpaces/listSpaces.feature +++ b/tests/acceptance/features/apiSpaces/listSpaces.feature @@ -37,11 +37,7 @@ Feature: List and create spaces | quota@@@state | normal | | root@@@webDavUrl | %base_url%/dav/spaces/%space_id% | And the json responded should not contain a space with name "Shares Jail" - And the json responded should contain spaces of type "personal" And the json responded should only contain spaces of type "personal" - And the json responded should not contain spaces of type "project" - And the json responded should not contain spaces of type "virtual" - And the json responded should not contain spaces of type "public" Scenario: An ordinary user will not see any space when using a filter for project When user "Alice" lists all available spaces via the GraphApi with query "$filter=driveType eq 'project'" From 08e36b37f00f8f157923662a6daa33c064e248c2 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Sun, 16 Jan 2022 20:44:27 +0000 Subject: [PATCH 20/20] Automated changelog update [skip ci] --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a4297413..4fdd3ce67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The following sections list the changes for unreleased. * Enhancement - Add spaces capability: [#2931](https://github.com/owncloud/ocis/pull/2931) * Enhancement - Support signature auth in the public share auth middleware: [#2831](https://github.com/owncloud/ocis/pull/2831) * Enhancement - Update REVA to v1.16.1-0.20220112085026-07451f6cd806: [#2953](https://github.com/owncloud/ocis/pull/2953) +* Enhancement - Add filter by driveType and id to /me/drives: [#2946](https://github.com/owncloud/ocis/pull/2946) * Enhancement - Update REVA to xxx: [#2878](https://github.com/owncloud/ocis/pull/2878) * Enhancement - Update ownCloud Web to v4.8.0: [#2895](https://github.com/owncloud/ocis/pull/2895) @@ -98,6 +99,14 @@ The following sections list the changes for unreleased. https://github.com/owncloud/ocis/pull/2953 +* Enhancement - Add filter by driveType and id to /me/drives: [#2946](https://github.com/owncloud/ocis/pull/2946) + + We added two possible filter terms (driveType, id) to the /me/drives endpoint on the graph api. + These can be used with the odata query parameter "$filter". We only support the "eq" operator + for now. + + https://github.com/owncloud/ocis/pull/2946 + * Enhancement - Update REVA to xxx: [#2878](https://github.com/owncloud/ocis/pull/2878) Updated REVA to xxx This update includes: