ownCloud oCIS 常用 CLI 命令详解

ownCloud oCIS 常用 CLI 命令实践篇:ocis 主命令树、version/list/init 信息查看与初始化、备份与存储维护(trash/revisions/backup/decomposedfs/shares)、迁移(migrate)、基准测试(benchmark)子命令参数与真实回显,Graph API 与 LDAP 双路线用户管理实测(含 LDAP 绑定 49 排障全记录)。

ownCloudownCloudGo文件管理2026/10/22

ownCloud oCIS 常用 CLI 命令详解

目标:把 ownCloud Infinite Scale(oCIS)唯一的管理入口——ocis 命令行工具讲透:主命令树、信息查看、初始化、备份与存储维护、迁移、基准测试的子命令与参数(全部参数取自 --help 实测回显,默认值照抄真实输出),并给出两条用户管理路线(Graph API / LDAP)的逐条输入与实测输出。本文与部署篇、配置篇同属一个系列:安装过程见《Ubuntu 22.04 安装 ownCloud oCIS 指南》,环境变量见《ownCloud oCIS 配置参数详解》。本文全部命令均于 2026-10-22 在真实服务器上逐条执行,输出逐行照抄实测回显。

一、环境信息

项目取值
服务器操作系统Ubuntu 22.04 LTS(x86_64)
服务器 IP10.89.61.3
oCIS 版本8.1.0+730d9a04(Production 通道,编译于 2026-07-06)
部署方式单二进制 /usr/local/bin/ocis + systemd 托管(ocis.service),配置目录 /etc/ocis,数据目录 /var/lib/ocis
管理员账号admin / q1w2e3r4
实测日期2026-10-22

ocis version --skip-services 实测输出(跳过对运行中服务的逐一询问,只打印本二进制版本):

Version: 8.1.0+730d9a04
Compiled: 2026-07-06 00:00:00 +0000 UTC

💡 oCIS 8.x 存在 Production(约每 6 个月)与 Rolling(约每 3 周)两条发布通道,版本选型依据见《ownCloud 介绍与选型指南》;ocis 是一个静态链接的 Go 单二进制,不依赖 PHP、数据库等外部组件。

二、工具概览

2.1 主命令树

ocis --help 实测输出(原样沉淀):

NAME:
   ocis - ownCloud Infinite Scale

USAGE:
   ocis [global options] command [command options]

AUTHOR:
   ownCloud GmbH <support@owncloud.com>

COMMANDS:
   backup     ocis backup functionality
   init       initialise an ocis config
   revisions  ocis revisions functionality
   trash      ocis trash functionality
   help, h    Shows a list of commands or help for one command
   benchmark:
     benchmark  cli tools to test low and high level performance
   fullstack:
     server  start a fullstack server (runtime and all services in supervised mode)
   info:
     version  print the version of this binary and all running service instances
   maintenance:
     decomposedfs  cli tools to inspect and manipulate a decomposedfs storage.
     shares        CLI tools to manage entries in the share manager.
   migration:
     migrate  migrate data from an existing to another instance
   runtime:
     list  list oCIS services running in the runtime (supervised mode)
   services:
     activitylog         activitylog service commands
     antivirus           antivirus service commands
     app-provider        app-provider service commands
     app-registry        app-registry service commands
     audit               audit service commands
     auth-app            auth-app service commands
     auth-basic          auth-basic service commands
     auth-bearer         auth-bearer service commands
     auth-machine        auth-machine service commands
     auth-service        auth-service service commands
     clientlog           clientlog service commands
     collaboration       collaboration service commands
     eventhistory        eventhistory service commands
     frontend            frontend service commands
     gateway             gateway service commands
     graph               graph service commands
     groups              groups service commands
     idm                 idm service commands
     idp                 idp service commands
     invitations         invitations service commands
     nats                nats service commands
     notifications       notifications service commands
     ocdav               ocdav service commands
     ocm                 ocm service commands
     ocs                 ocs service commands
     policies            policies service commands
     postprocessing      postprocessing service commands
     proxy               proxy service commands
     search              search service commands
     settings            settings service commands
     sharing             sharing service commands
     sse                 sse service commands
     storage-publiclink  storage-publiclink service commands
     storage-shares      storage-shares service commands
     storage-system      storage-system service commands
     storage-users       storage-users service commands
     thumbnails          thumbnails service commands
     userlog             userlog service commands
     users               users service commands
     web                 web service commands
     webdav              webdav service commands
     webfinger           webfinger service commands

GLOBAL OPTIONS:
   --help, -h  show help

2.2 命令分类速查表

类别(help 中分组)真实命令名用途
infoocis version打印二进制版本与运行中服务版本
runtimeocis list列出运行时正在监管的服务清单
fullstackocis server前台启动 runtime + 全部服务(supervised 模式)
servicesocis <服务名>单独启动某个服务(40+ 个,如 ocis idm)
maintenanceocis decomposedfs / ocis shares存储元数据检查 / 共享管理器维护
migrationocis migrate存储与共享数据迁移
—ocis backup / ocis trash / ocis revisions备份一致性检查 / 回收站与历史版本清理
benchmarkocis benchmarkHTTP 与系统调用基准测试
—ocis init初始化生成 ocis.yaml 配置

⚠️ 注意:maintenance、migration、fullstack 只是 --help 里的分组标题,不是可执行的命令。实测执行 ocis maintenance decomposedfs --help 会得到 No help topic for 'maintenance';真正的命令名是 ocis decomposedfs、ocis shares、ocis migrate、ocis server。这是照抄官方文档示例时最容易踩的第一个坑。

三、前置条件

  1. 服务已由 systemd 托管并运行:systemctl status ocis 为 active,服务单元与 ocis init 初始化过程见《Ubuntu 22.04 安装 ownCloud oCIS 指南》;
  2. 环境变量来源:生产部署通过 /etc/ocis/ocis.env(systemd EnvironmentFile)注入 OCIS_CONFIG_DIR、OCIS_BASE_DATA_PATH 等变量,各变量逐项含义见《ownCloud oCIS 配置参数详解》;
  3. ocis 在 PATH 中:本文安装路径为 /usr/local/bin/ocis;
  4. LDAP 查询工具:用户管理 LDAP 路线需要 ldap-utils 包(安装命令见 10.2 节);
  5. 读取 ocis.yaml 的权限:部分维护命令需要从 /etc/ocis/ocis.yaml 读取服务账号口令,该文件含全部密钥,务必 chmod 600 并仅限管理员读取。

四、信息查看命令

4.1 ocis version

ocis version --help 实测输出:

NAME:
   ocis version - print the version of this binary and all running service instances

USAGE:
   ocis version [command options]

CATEGORY:
   info

OPTIONS:
   --skip-services  skip service listing (default: false)
   --help, -h       show help

不带 --skip-services 执行 ocis version 时,会先打印二进制版本,再输出一张"运行中服务"表格(实测输出节选,表格共列出全部在运行服务,此处截取前两行以示格式):

Version: 8.1.0+730d9a04
Compiled: 2026-07-06 00:00:00 +0000 UTC

┌────────────────┬────────────────┬────────────────────────────────────────────────────────────────────┐
│    VERSION     │    ADDRESS     │                                 ID                                 │
├────────────────┼────────────────┼────────────────────────────────────────────────────────────────────┤
│ 8.1.0+730d9a04 │ 127.0.0.1:9164 │ com.owncloud.api.app-provider-a6c82132-9c64-4bb6-8479-9254c8c0526a │
│ 10.11.0        │ 127.0.0.1:9350 │ com.owncloud.web.ocdav-a6c82132-9c64-4bb6-8479-9254c8c0526a        │
└────────────────┴────────────────┴────────────────────────────────────────────────────────────────────┘

💡 注意 ocdav 服务显示的是协议版本 10.11.0(ownCloud WebDAV 协议版本号),不是 oCIS 版本;每个服务实例的 ID 由 服务名-实例 UUID 组成。排查"某服务是否跑起来"时,这张表比逐个看端口直观。

4.2 ocis list

ocis list --help 实测输出:

NAME:
   ocis list - list oCIS services running in the runtime (supervised mode)

USAGE:
   ocis list [command options]

CATEGORY:
   runtime

OPTIONS:
   --hostname value  (default: "localhost") [$OCIS_RUNTIME_HOST]
   --port value      (default: "9250") [$OCIS_RUNTIME_PORT]
   --help, -h        show help

实测输出(本机共 34 个服务在运行):

┌────────────────────┐
│      SERVICE       │
├────────────────────┤
│ activitylog        │
│ app-provider       │
│ app-registry       │
│ auth-basic         │
│ auth-machine       │
│ auth-service       │
│ clientlog          │
│ eventhistory       │
│ frontend           │
│ gateway            │
│ graph              │
│ groups             │
│ idm                │
│ idp                │
│ nats               │
│ ocdav              │
│ ocm                │
│ ocs                │
│ postprocessing     │
│ proxy              │
│ search             │
│ settings           │
│ sharing            │
│ sse                │
│ storage-publiclink │
│ storage-shares     │
│ storage-system     │
│ storage-users      │
│ thumbnails         │
│ userlog            │
│ users              │
│ web                │
│ webdav             │
│ webfinger          │
└────────────────────┘

ocis list 通过 runtime 的 HTTP 接口(默认 localhost:9250,可用 OCIS_RUNTIME_PORT 覆盖)查询,因此只能在服务所在主机上执行。

五、初始化命令 ocis init

ocis init --help 实测输出:

NAME:
   ocis init - initialise an ocis config

USAGE:
   ocis init [command options]

OPTIONS:
   --insecure value                    Allow insecure oCIS config (default: "ask") [$OCIS_INSECURE]
   --diff, -d                          Show the difference between the current config and the new one (default: false)
   --force-overwrite, -f               Force overwrite existing config file (default: false) [$OCIS_FORCE_CONFIG_OVERWRITE]
   --config-path value                 Config path for the ocis runtime (default: "/root/.ocis/config") [$OCIS_CONFIG_DIR, $OCIS_BASE_DATA_PATH]
   --admin-password value, --ap value  Set admin password instead of using a random generated one [$ADMIN_PASSWORD, $IDM_ADMIN_PASSWORD]
   --help, -h                          show help

参数要点(默认值逐项取自上方实测回显):

参数默认值说明
--insecureask(交互询问)允许生成不安全(自签名/HTTP)配置;脚本化安装用 ocis init --insecure true 跳过询问
--difffalse与现有配置做差异比较后输出
--force-overwrite / -ffalse覆盖已存在的 ocis.yaml,对应环境变量 OCIS_FORCE_CONFIG_OVERWRITE
--config-path/root/.ocis/config配置目录;受 OCIS_CONFIG_DIR 影响(生产建议 /etc/ocis)
--admin-password / --ap随机生成指定管理员口令,对应 ADMIN_PASSWORD、IDM_ADMIN_PASSWORD

初始化的完整实测过程(四行回显块、生成的 ocis.yaml 结构)已在《Ubuntu 22.04 安装 ownCloud oCIS 指南》中逐步记录,此处不再重复。

六、数据维护命令(trash / revisions / backup)

这一组命令直接操作 decomposedfs 存储目录,执行前应停止 oCIS 服务(至少避免用户写入),且三者都内置了安全阀。

6.1 ocis trash purge-empty-dirs(清理空目录)

ocis trash purge-empty-dirs --help 实测输出:

NAME:
   ocis trash purge-empty-dirs - purge empty directories

USAGE:
   ocis trash purge-empty-dirs [command options]

OPTIONS:
   --basepath value, -p value  the basepath of the decomposedfs (e.g. /var/tmp/ocis/storage/users)
   --dry-run                   do not delete anything, just print what would be deleted (default: true)
   --help, -h                  show help

--basepath 指向 decomposedfs 的 users 存储(本文环境即 /var/lib/ocis/storage/users);--dry-run 默认就是 true——不显式加 --dry-run=false 它只打印将删除的内容,不会真正删除。

6.2 ocis revisions purge(清理历史版本)

ocis revisions purge --help 实测输出:

NAME:
   ocis revisions purge - purge revisions

USAGE:
   ocis revisions purge [command options]

OPTIONS:
   --basepath value, -p value     the basepath of the decomposedfs (e.g. /var/tmp/ocis/storage/metadata)
   --blobstore value, -b value    the blobstore type. Can be (none, ocis, s3ng). Default ocis. Note: When using s3ng this needs same configuration as the storage-users service (default: "ocis")
   --dry-run                      do not delete anything, just print what would be deleted (default: true)
   --verbose, -v                  print verbose output (default: false)
   --resource-id value, -r value  purge all revisions of this file/space. If not set, all revisions will be purged
   --glob-mechanism value         the glob mechanism to find all nodes. Can be 'glob', 'list' or 'workers'. 'glob' uses globbing with a single worker. 'workers' spawns multiple go routines, accelatering the command drastically but causing high cpu and ram usage. 'list' looks for references by listing directories with multiple workers. Default is 'glob' (default: "glob")
   --help, -h                     show help

参数要点:

  • --blobstore 有 none / ocis / s3ng 三种,默认 ocis(本地 blob 存储);若部署采用 s3ng(S3 后端),必须与 storage-users 服务的配置一致;
  • --resource-id 可以只清某个文件/空间的版本,不指定则清全部;
  • --glob-mechanism 决定扫描方式:glob(默认,单 worker)、workers(多协程并行,快但 CPU/内存占用高)、list(按目录列举);
  • 同样默认 --dry-run true。

6.3 ocis backup consistency(备份一致性检查)

ocis backup consistency --help 实测输出:

NAME:
   ocis backup consistency - check backup consistency

USAGE:
   ocis backup consistency [command options]

OPTIONS:
   --basepath value, -p value   the basepath of the decomposedfs (e.g. /var/tmp/ocis/storage/users)
   --blobstore value, -b value  the blobstore type. Can be (none, ocis, s3ng). Default ocis (default: "ocis")
   --fail                       exit with non-zero status if consistency check fails (default: false)
   --help, -h                   show help

用于核对"元数据与实际 blob 文件"的一致性;--fail 让检查失败时以非零退出码结束,适合放进 cron/Nagios 类巡检脚本做判断。

七、存储维护命令(decomposedfs / shares)

7.1 ocis decomposedfs(存储元数据检查与修复)

ocis decomposedfs metadata --help 实测输出:

NAME:
   ocis decomposedfs metadata - cli tools to inspect and manipulate node metadata

USAGE:
   ocis decomposedfs metadata [command options]

COMMANDS:
   dump     print the metadata of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.
   get      print a specific attribute of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.
   set      manipulate metadata of the given node. Binary attributes can be given hex encoded (prefix by '0x') or base64 encoded (prefix by '0s').
   help, h  Shows a list of commands or help for one command

OPTIONS:
   --root value, -r value  Path to the decomposedfs
   --node value, -n value  Path to or ID of the node to inspect
   --help, -h              show help

dump / get / set 三个子命令分别对应"打印节点全部元数据 / 读取单个属性 / 修改属性",--root 指定存储根目录,--node 传节点路径或节点 ID。这是深排障(例如某文件元数据损坏)时才用的底层工具。

ocis decomposedfs check-treesize --help 实测输出:

NAME:
   ocis decomposedfs check-treesize - cli tool to check the treesize metadata of a Space

USAGE:
   ocis decomposedfs check-treesize [command options]

OPTIONS:
   --root value, -r value  Path to the root directory of the decomposedfs
   --node value, -n value  Space ID of the Space to inspect
   --repair                Try to repair nodes with incorrect treesize metadata. IMPORTANT: Only use this while ownCloud Infinite Scale is not running. (default: false)
   --force                 Do not prompt for confirmation when running in repair mode. (default: false)
   --help, -h              show help

用于核对/修复空间配额统计值(treesize);帮助原文特别强调:--repair 只能在 oCIS 完全停止的状态下执行,否则统计值会被运行中的服务再次写坏。

7.2 ocis shares(共享管理器维护)

这一组命令面向 share manager(8.x 默认为 jsoncs3),实测三个子命令的 help:

NAME:
   ocis shares cleanup - Clean up stale entries in the share manager.

USAGE:
   ocis shares cleanup [command options]

OPTIONS:
   --service-account-id value      Name of the service account to use for the cleanup [$OCIS_SERVICE_ACCOUNT_ID]
   --service-account-secret value  Secret for the service account [$OCIS_SERVICE_ACCOUNT_SECRET]
   --help, -h                      show help
NAME:
   ocis shares clean-orphaned-grants - Detect and clean orphaned share-manager grants.

USAGE:
   ocis shares clean-orphaned-grants [command options]

OPTIONS:
   --service-account-id value      Name of the service account to use for the scan [$OCIS_SERVICE_ACCOUNT_ID]
   --service-account-secret value  Secret for the service account [$OCIS_SERVICE_ACCOUNT_SECRET]
   --space-id value                Limit the scan to a specific storage space (opaque ID)
   --dry-run                       Dry run mode enabled (default: true)
   --force                         Force removal of suspected orphans even when listing shares fails (default: false)
   --verbose, -v                   Verbose logging enabled (default: false)
   --help, -h                      show help
NAME:
   ocis shares move-stuck-upload-blobs - Move stuck upload blobs to the jsoncs3 share-manager metadata

USAGE:
   ocis shares move-stuck-upload-blobs [command options]

OPTIONS:
   --dry-run                   Dry run mode enabled (default: false)
   --basepath value, -p value  the basepath of the decomposedfs (e.g. /var/tmp/ocis/storage/users)
   --filename value            File to move from uploads/ to share manager metadata blobs/ (default: "received.json")
   --verbose, -v               Verbose logging enabled (default: false)
   --help, -h                  show help

参数要点:

  • cleanup 与 clean-orphaned-grants 需要服务账号凭据:OCIS_SERVICE_ACCOUNT_ID / OCIS_SERVICE_ACCOUNT_SECRET,取值就是 ocis.yaml 中 proxy.service_account 段的 service_account_id 与 service_account_secret(本环境实测该段存在于 yaml,可直接 grep 取用);
  • clean-orphaned-grants 默认 --dry-run true,先扫后删;--force 允许在列举共享失败时仍强制删除疑似孤儿授权,慎用。

八、迁移命令 ocis migrate

8.1 ocis migrate decomposedfs

ocis migrate decomposedfs --help 实测输出:

NAME:
   ocis migrate decomposedfs - run a decomposedfs migration

USAGE:
   ocis migrate decomposedfs [command options]

COMMANDS:
   list     list decomposedfs migrations
   help, h  Shows a list of commands or help for one command

OPTIONS:
   --direction value, -d value  direction of the migration to run ('migrate' or 'rollback') (default: "migrate")
   --migration value, -m value  ID of the migration to run
   --root value, -r value       Path to the root directory of the decomposedfs
   --help, -h                   show help

decomposedfs 的数据结构升级通过编号迁移脚本完成:ocis migrate decomposedfs list 先列出可用迁移,-m <ID> 指定要执行的迁移,-d rollback 回滚。

8.2 ocis migrate shares / publicshares

两个命令的 help 实测输出:

NAME:
   ocis migrate shares - migrates shares from the previous to the new share manager

USAGE:
   ocis migrate shares [command options]

OPTIONS:
   --from value  Share manager to export the data from (default: "json")
   --to value    Share manager to import the data into (default: "jsoncs3")
   --help, -h    show help
NAME:
   ocis migrate publicshares - migrates public shares from the previous to the new public share manager

USAGE:
   ocis migrate publicshares [command options]

OPTIONS:
   --from value  Public share manager to export the data from (default: "json")
   --to value    Public share manager to import the data into (default: "jsoncs3")
   --help, -h    show help

两者默认值 --from json --to jsoncs3 印证了 8.x 的默认共享管理器已是 jsoncs3——这组命令主要用于从旧版(json 管理器)升级时搬迁共享/对外链接数据。

8.3 ocis migrate rebuild-jsoncs3-indexes

NAME:
   ocis migrate rebuild-jsoncs3-indexes - rebuild the share indexes from the shares json

USAGE:
   ocis migrate rebuild-jsoncs3-indexes [command options]

OPTIONS:
   --help, -h  show help

当 jsoncs3 共享索引出现不一致时,从共享 json 原始数据重建索引,无任何参数。

九、基准测试命令 ocis benchmark

9.1 ocis benchmark client(HTTP 压测)

ocis benchmark client --help 实测输出:

NAME:
   ocis benchmark client - Start a client that continuously makes web requests and prints stats. The options mimic curl, but URL must be at the end.

USAGE:
   ocis benchmark client [command options]

CATEGORY:
   benchmark

OPTIONS:
   --request value, -X value                              Specifies a custom request method to use when communicating with the HTTP server. (default: "PROPFIND")
   --user value, -u value                                 Specify the user name and password to use for server authentication. (default: "admin:admin")
   --insecure, -k                                         Skip the TLS verification step and proceed without checking. (default: false)
   --data value, -d value                                 Sends the specified data in a request to the HTTP server.
   --header value, -H value [ --header value, -H value ]  Extra header to include in information sent.
   --rate value                                           Specify the maximum transfer frequency you allow a client to use - in number of transfer starts per time unit (sometimes called request rate).
                                                          The request rate is provided as "N/U" where N is an integer number and U is a time unit. Supported units are 's' (second), 'm' (minute), 'h' (hour) and 'd' /(day, as in a 24 hour unit). The default time unit, if no "/U" is provided, is number of transfers per hour.
   --bearer-token-command value                           Command to execute for a bearer token, e.g. 'oidc-token OCIS'. When set, disables basic auth.
   --every value                                          Aggregate stats every time this amount of seconds has passed. (default: 0)
   --jobs value, -j value                                 Number of parallel clients to start. (default: 1)
   --help, -h                                             show help

典型用法(对 WebDAV 端点做 PROPFIND 压测,参数风格与 curl 一致):

ocis benchmark client -k -u admin:q1w2e3r4 -X PROPFIND \
  -H 'Content-Type: application/xml' \
  https://10.89.61.3:9200/remote.php/dav/files/admin/

注意三个真实默认值:请求方法默认 PROPFIND、Basic 认证默认 admin:admin(与本环境口令不同,务必显式 -u)、并发默认 1。

9.2 ocis benchmark syscalls(系统调用压测)

NAME:
   ocis benchmark syscalls - test the performance of syscalls

USAGE:
   ocis benchmark syscalls [command options]

CATEGORY:
   benchmark

OPTIONS:
   --path value        Path to test
   --iterations value  Number of iterations to execute (default: "100")
   --help, -h          show help

对指定路径做文件系统系统调用基准测试,--iterations 默认 100 次。选型/扩容前用它对比不同磁盘(如本地 SSD vs 网络存储挂载点)的元数据操作性能。

十、用户管理命令

oCIS 没有类似 ocis user add 的本地子命令,用户管理走两条路:Graph API(reST 接口,Web 管理界面的底层)与 LDAP(内置 idm 服务暴露的只读/服务接口)。两条路操作的是同一份数据,下文实测会做交叉验证。

10.1 路线一:Graph API

第一步:获取管理员 Bearer token。 用管理员 admin 登录 Web 界面后,浏览器按 F12 打开开发者工具 → Application → Local Storage → 找到以 oc_oAuth.user: 开头的键,其 JSON 中的 access_token 字段即为 token。实测提取到的 token 长度 1248 字符。该 token 有效期只有数分钟,过期后重新登录刷新即可。

第二步:查看当前身份与用户列表。 实测输入与输出:

curl -sk https://10.89.61.3:9200/graph/v1.0/me \
  -H "Authorization: Bearer $TOKEN"
{"accountEnabled":true,"displayName":"Admin","givenName":"Admin","id":"c0bd4b14-08a4-45b9-b6a9-15b2b69d93ac","identities":[{"issuer":"https://10.89.61.3:9200","issuerAssignedId":"c0bd4b14-08a4-45b9-b6a9-15b2b69d93ac"}],"mail":"admin@example.org","onPremisesSamAccountName":"admin","preferredLanguage":"en","signInActivity":{"lastSuccessfulSignInDateTime":"2026-10-22T03:18:04Z"},"surname":"Admin","userType":"Member"}
curl -sk https://10.89.61.3:9200/graph/v1.0/users \
  -H "Authorization: Bearer $TOKEN"
{"value":[{"accountEnabled":true,"attributes":[],"displayName":"Admin","givenName":"Admin","id":"c0bd4b14-08a4-45b9-b6a9-15b2b69d93ac","identities":[{"issuer":"https://10.89.61.3:9200","issuerAssignedId":"c0bd4b14-08a4-45b9-b6a9-15b2b69d93ac"}],"mail":"admin@example.org","onPremisesSamAccountName":"admin","signInActivity":{"lastSuccessfulSignInDateTime":"2026-10-22T03:18:04Z"},"surname":"Admin","userType":"Member"}]}

第三步:创建用户。 实测中连续踩到三次 400 字段校验错误(这些报错原文逐字照抄,本身就有参考价值):

  • 缺少登录名字段:{"error":{"code":"invalidRequest","message":"invalid request body: no value given for required property onPremisesSamAccountName"}}
  • 多写了 Microsoft Graph 风格的 userName 字段:{"error":{"code":"invalidRequest","message":"invalid request body: json: unknown field \"userName\""}}
  • 多写了 mailNotificationsEnabled 字段:{"error":{"code":"invalidRequest","message":"invalid request body: json: unknown field \"mailNotificationsEnabled\""}}

💡 oCIS 的 Graph API 对请求体做严格字段校验:必填的只有 onPremisesSamAccountName(登录名)、displayName、passwordProfile.password、accountEnabled,多余的未知字段一律拒绝。照抄 Microsoft Graph 文档的 payload 在 oCIS 上是行不通的。

用最小字段集重试,实测创建成功(HTTP 201):

curl -sk -X POST https://10.89.61.3:9200/graph/v1.0/users \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"onPremisesSamAccountName":"demo","displayName":"Demo User","passwordProfile":{"password":"q1w2e3r4"},"accountEnabled":true}'
{"accountEnabled":true,"displayName":"Demo User","id":"41575d9f-bb4f-4fbd-b02e-4e6c34273f29","onPremisesSamAccountName":"demo","surname":"demo","userType":"Member"}

第四步:查询与更新。 按登录名精确查询(HTTP 200,返回体与创建响应一致):

curl -sk https://10.89.61.3:9200/graph/v1.0/users/demo \
  -H "Authorization: Bearer $TOKEN"

PATCH 更新显示名(HTTP 200,响应即更新后的对象):

curl -sk -X PATCH https://10.89.61.3:9200/graph/v1.0/users/demo \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"displayName":"Demo User (updated)"}'
{"accountEnabled":true,"displayName":"Demo User (updated)","id":"41575d9f-bb4f-4fbd-b02e-4e6c34273f29","onPremisesSamAccountName":"demo","surname":"demo","userType":"Member"}

10.2 路线二:LDAP(ldapsearch)

第一步:安装 ldap-utils(Ubuntu 仓库实测装到 2.5.20):

apt-get install -y ldap-utils
Setting up ldap-utils (2.5.20+dfsg-0ubuntu0.22.04.1) ...

第二步:放行自签名证书。 idm 的 LDAPS 端口用自签名证书,ldapsearch 默认严格校验会握手失败,先写 /etc/ldap/ldap.conf:

echo "TLS_REQCERT never" >> /etc/ldap/ldap.conf

第三步:搞清真实 DN——这是 LDAP 路线最大的坑。 网上旧教程写 base DN 是 dc=ocis,dc=test、绑定账号是 uid=admin,ou=sysusers,dc=ocis,dc=test,实测在 8.1.0 上全部返回 ldap_bind: Invalid credentials (49)。完整的排障过程见第十二章 Q1,这里直接给出实测结论:

  • 数据树根:o=libregraph-idm;
  • 用户容器:ou=users,o=libregraph-idm;服务账号容器:ou=sysusers,o=libregraph-idm;
  • 服务账号实测只有三个:uid=libregraph(目录读取账号)、uid=idp、uid=reva——不存在 uid=admin 服务账号;
  • 口令对应关系(逐个绑定实测):libregraph 对应 ocis.yaml idm.service_user_passwords.idm_password,idp 对应 idp_password(也是 idp.ldap.bind_password),reva 对应 reva_password;yaml 里的 admin_password 对应的是普通用户 admin(Web 登录口令)。

第四步:从 ocis.yaml 取口令(不把密钥写进命令历史)。 实测验证过的提取方式:

IDM_PW=$(awk "/^idm:/{f=1} f&&/idm_password:/{print \$2; exit}" /etc/ocis/ocis.yaml)

第五步:搜索用户目录。 实测输入与输出:

ldapsearch -H ldaps://localhost:9235 -x \
  -D "uid=libregraph,ou=sysusers,o=libregraph-idm" -w "$IDM_PW" \
  -b "ou=sysusers,o=libregraph-idm" "(objectClass=*)" dn
# sysusers, libregraph-idm
dn: ou=sysusers,o=libregraph-idm
# libregraph, sysusers, libregraph-idm
dn: uid=libregraph,ou=sysusers,o=libregraph-idm
# idp, sysusers, libregraph-idm
dn: uid=idp,ou=sysusers,o=libregraph-idm
# reva, sysusers, libregraph-idm
dn: uid=reva,ou=sysusers,o=libregraph-idm
# search result
search: 2
result: 0 Success
# numResponses: 5
# numEntries: 4

查普通用户(创建 demo 之前的初始状态,管理员完整条目原样照抄,可见 oCIS 的 ownCloudUser 对象类、UUID、Argon2id 口令哈希等属性):

ldapsearch -H ldaps://localhost:9235 -x \
  -D "uid=libregraph,ou=sysusers,o=libregraph-idm" -w "$IDM_PW" \
  -b "ou=users,o=libregraph-idm"
# users, libregraph-idm
dn: ou=users,o=libregraph-idm
objectClass: organizationalUnit
ou: users

# admin, users, libregraph-idm
dn: uid=admin,ou=users,o=libregraph-idm
cn: admin
description: An admin for this oCIS instance.
displayName: Admin
givenName: Admin
mail: admin@example.org
oCExternalIdentity: $ https://10.89.61.3:9200 $ c0bd4b14-08a4-45b9-b6a9-15b2b6
 9d93ac
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: ownCloudUser
objectClass: ownCloud
objectClass: person
objectClass: top
ownCloudUUID: c0bd4b14-08a4-45b9-b6a9-15b2b69d93ac
sn: Admin
uid: admin
userPassword:: e0FSR09OMn0kYXJnb24yaWQkdj0xOSRtPTY1NTM2LHQ9MSxwPTEyJGp5S05neDl
 Ydml2QVo2M2xoKzQyUUEkZDRlditlNGxTQ0dnTFRpVDRHdkgyNTMrcjNIc2RIa0F1WEFKZisxVXQw
 RQ==
oCLastSignInTimestamp: 20261022031804Z

# search result
search: 2
result: 0 Success

# numResponses: 3
# numEntries: 2

第六步:交叉验证。 10.1 节通过 Graph API 创建并 PATCH 过 demo 用户后,再从 LDAP 侧查一次,实测两个入口看到的是同一份数据(displayName 已是更新后的值):

ldapsearch -H ldaps://localhost:9235 -x \
  -D "uid=libregraph,ou=sysusers,o=libregraph-idm" -w "$IDM_PW" \
  -b "ou=users,o=libregraph-idm" "(objectClass=person)" dn uid displayName
dn: uid=admin,ou=users,o=libregraph-idm
displayName: Admin
uid: admin
dn: uid=demo,ou=users,o=libregraph-idm
displayName: Demo User (updated)
uid: demo

⚠️ 注意:LDAP 路线在 oCIS 默认部署下只读(ou=users 下的用户数据由 graph 等服务写入,服务账号只授权读取),批量建号、改密、停启用请以 Graph API 为准;LDAP 的价值在于盘点、比对与对接外部目录工具。

十一、注意事项

  1. dry-run 安全阀:trash purge-empty-dirs、revisions purge、shares clean-orphaned-grants 三个破坏性命令默认 --dry-run true,先看清单再显式关闭;而 shares move-stuck-upload-blobs 默认 --dry-run false,是这一组里唯一的例外,执行前务必确认;
  2. 停服再动存储:decomposedfs check-treesize --repair 及一切直接改 decomposedfs 目录的命令,帮助原文明确要求在 oCIS 停止状态下执行;
  3. Graph API 字段白名单:请求体多一个字段就 400,照抄 Microsoft Graph 文档会连续碰壁,用第 10.1 节实测过的最小字段集;
  4. Bearer token 时效极短:实测仅数分钟即 401 token is expired,脚本化操作要么现取现用,要么改走服务账号(OCIS_SERVICE_ACCOUNT_ID/SECRET);
  5. LDAP 是服务内部协议:libregraph/idp/reva 三个服务账号是给 oCIS 内部服务用的,不要拿去做通用集成;idm_password 等密钥等于目录的读钥匙,泄露面要按生产密钥管理;
  6. 压测默认值会打错目标:benchmark client 默认 PROPFIND + admin:admin + 单并发,对生产压测前先核对 -X/-u/-j;
  7. ocis list 只能本机执行:runtime 接口默认只监听 localhost:9250。

十二、常见问题与排障实录

Q1:ldapsearch 一律报 Invalid credentials (49),账号密码明明是对的

现象:按旧教程用 -D "uid=admin,ou=sysusers,dc=ocis,dc=test" -w <管理口令> 绑定 ldaps://localhost:9235,无论换 admin/ldap/idm/idp/reva 哪个账号、yaml 里哪个口令,全部 ldap_bind: Invalid credentials (49),连 Web 登录正常的 uid=admin,ou=users,dc=ocis,dc=test 也一样。

排查手段:临时把 /etc/ocis/ocis.env 的 OCIS_LOG_LEVEL 改为 debug 并 systemctl restart ocis,再发起一次绑定,然后 journalctl -u ocis --since "-60 s" 看服务端的真实拒绝原因。实测抓到两种日志形态:

形态一——绑定 DN 在数据库树之外(树根不是你传的 base):

{"level":"debug","service":"idm","bind_dn":"uid=admin,ou=sysusers,o=libregraph","error":null,"op":"bind","remote_addr":"127.0.0.1:42684","time":"2026-10-22T03:26:52Z","message":"ldap bind request BindDN outside of Database tree"}

形态二——DN 已在树内,但条目不存在(账号名拼错/不存在):

{"level":"debug","service":"idm","bind_dn":"uid=admin,ou=sysusers,o=libregraph-idm","op":"bind","remote_addr":"127.0.0.1:43230","time":"2026-10-22T03:27:49Z","message":"Entry 'uid=admin,ou=sysusers,o=libregraph-idm' does not exist"}

条目存在但口令不匹配时,同样表现为 49,不再有独立提示——所以服务端日志 + 换口令对照是唯一可靠的定位方式。

结论(与实测相互印证的三个事实):数据库树根是 o=libregraph-idm(不是旧文档的 dc=ocis,dc=test,也不是字符串表里更短的 o=libregraph,少一个 -idm 后缀同样被判"树外");ou=sysusers 下只有 libregraph/idp/reva 三个服务账号;libregraph 账号用 idm_password 口令绑定后搜索成功(result: 0 Success,见 10.2 节)。排障完成后记得把日志级别改回原值。

Q2:ldapwhoami 绑定成功却报 Operations error (1)

实测 ldapwhoami -D "uid=libregraph,ou=sysusers,o=libregraph-idm" -w <正确口令> 返回 ldap_parse_result: Operations error (1),而同样的凭据用 ldapsearch 搜索一切正常。原因是 oCIS 内置的 LDAP 服务端不支持 WHOAMI 扩展操作,报错出现在绑定之后的扩展查询阶段,不代表绑定失败。判断绑定成功与否请用 ldapsearch 实际搜一次。

Q3:Graph API 创建用户报 400 invalidRequest

见 10.1 节实测:缺 onPremisesSamAccountName、多 userName、多 mailNotificationsEnabled 都会被逐字段拒绝。解决:只传 onPremisesSamAccountName / displayName / passwordProfile.password / accountEnabled 四项必填字段。

Q4:跟着旧教程配 dc=ocis,dc=test 全部失败

8.x 的目录树根已改为 o=libregraph-idm(见 Q1 实测)。旧教程对应的是早期版本,升级后 DN、服务账号命名都以本文 10.2 节的实测值为准。

Q5:Graph API 突然全部 401 token is expired

Web 登录拿到的 access_token 实测有效期只有数分钟。重新登录 Web 刷新 token,或改用服务账号机制(shares cleanup 等命令原生支持 --service-account-id/--service-account-secret)。

十三、参考链接