MailHub 的“一键登录 Webmail”使用两层短期凭据,不会向浏览器、URL 或 Roundcube 日志暴露邮箱原密码:
mailhub_ticket POST 到 WEBMAIL_SSO_URL,票据不会进入查询字符串或 Referer。mailhub_sso 插件在服务器端用共享密钥调用 MailHub 的 /internal/webmail-sso/exchange,取得邮箱地址和 mhw_ 临时凭据。INBOX。退出或销毁 Roundcube 会话时,插件会尽力调用 /internal/webmail-sso/revoke,凭据自身到期仍是最终边界。同一用户每分钟最多签发 20 个启动票据,同一邮箱最多保留 5 个有效 Webmail 临时会话;超过上限时会淘汰最久未使用的会话。过期或撤销记录会机会式清理,避免 SQLite 表无界增长。
在 .env 中设置:
WEBMAIL_SSO_URL=https://mail.us.ss5.xyz/
WEBMAIL_SSO_SECRET_FILE=./data/secrets/webmail_sso_secret
WEBMAIL_SSO_TICKET_TTL_SECONDS=60
WEBMAIL_SSO_CREDENTIAL_TTL_SECONDS=43200
WEBMAIL_SSO_URL 留空时功能关闭,便于未配置 Roundcube 的部署继续运行;一旦设置 URL,Secret 文件必须存在且有效,否则应用会快速失败。Compose 固定从 /data/secrets/webmail_sso_secret 读取(宿主机对应 ./data/secrets/webmail_sso_secret),功能关闭时不会因为旧部署缺少该文件而阻止容器升级。WEBMAIL_SSO_URL 必须是固定 HTTPS 起始地址。MailHub 会把它规范化成绝对 origin(例如 https://mail.us.ss5.xyz)并写入票据;Roundcube 的 mailhub_sso_audience 必须完全一致。
Secret 只接受 64–512 个十六进制字符。首次部署前可直接运行 npm run prepare:dovecot;也可以手工生成:
install -d -m 0700 data/secrets
openssl rand -hex 32 > data/secrets/webmail_sso_secret
chown 1000:1000 data/secrets/webmail_sso_secret
chmod 0440 data/secrets/webmail_sso_secret
同机 Roundcube 建议使用 0440、1000:1000,并仅把 Roundcube PHP 进程加入补充组 1000;不要改成全局可读。MailHub 的准备脚本会自动维持该权限。若 Roundcube 在另一台机器,复制相同内容到仅由其 PHP 运行用户可读的独立文件即可。
该 Secret 不能复用 Session、Dovecot、Token 或其他业务密钥,也不能提交到 Git。
Roundcube PHP 运行环境需要启用 cURL 扩展。
docker/roundcube/plugins/mailhub_sso 复制到 Roundcube 的 plugins/mailhub_sso。plugins/mailhub_sso/config.inc.php.dist 复制为 plugins/mailhub_sso/config.inc.php,按实际网络修改内部地址;不要把 Secret 内容写进 PHP 配置。mailhub_sso 加入 Roundcube $config['plugins']。可参考 docker/roundcube/config.inc.php.example。/run/secrets/webmail_sso_secret;同机容器为 PHP 用户增加补充组 1000,确保它能读取 0440 文件。mailhub_sso_audience 设置为精确 origin,不带路径和结尾斜杠。若 HTTPS 终止在 Roundcube 前方的反向代理,将 Roundcube 的 use_https 设为 true;不要同时启用与它互斥的 force_https。
生产示例:
$config['plugins'][] = 'mailhub_sso';
$config['imap_host'] = 'ssl://in.ss5.xyz:993';
$config['smtp_host'] = 'ssl://in.ss5.xyz:465';
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['mailhub_sso_internal_base_url'] = 'http://app:3000';
$config['mailhub_sso_audience'] = 'https://mail.us.ss5.xyz';
$config['mailhub_sso_secret_file'] = '/run/secrets/webmail_sso_secret';
$config['mailhub_sso_imap_host'] = 'ssl://in.ss5.xyz:993';
本仓库的 Compose 不运行 Roundcube。可按现有部署选择以下方式:
mailhub Compose 网络,使用 http://app:3000,并把宿主机同一个 Secret 文件以只读方式挂入两个容器。http://127.0.0.1:3025。/internal/webmail-sso/* 无保护地公开到互联网。Roundcube 使用独立 Compose 时,可将现有 MailHub 网络声明为 external;实际网络名以 docker network ls 为准:
services:
roundcube:
group_add:
- "1000"
volumes:
- /absolute/path/to/mailhub/data/secrets/webmail_sso_secret:/run/secrets/webmail_sso_secret:ro
networks:
- mailhub
networks:
mailhub:
external: true
name: <mailhub-compose-project>_mailhub
同时在对外反向代理中拒绝公网访问 /internal/webmail-sso/;Bearer Secret 是内网接口的第二层校验,不应代替网络隔离。
内部接口只接受 Authorization: Bearer <shared-secret> 和 JSON:
POST /internal/webmail-sso/exchange { ticket, audience }
POST /internal/webmail-sso/revoke { credential, audience }
插件不跟随 HTTP 重定向,不接受 GET 票据,不允许浏览器指定 IMAP 主机,也不记录内部响应、票据、临时凭据或共享密钥。仅有收信权限的临时凭据可以进入 Roundcube,但 SMTP 认证应由 MailHub 拒绝;有发信权限时 Roundcube 才能发信。
被分配用户通过 Webmail 登录时,Dovecot 使用固定 ACL 组将 IMAP 权限限制为列出、读取和更新 \Seen;不能删除/移动邮件、EXPUNGE,也不能创建、删除或重命名文件夹。邮箱所有者保持完整 IMAP 权限。撤销收信权限、停用用户或临时凭据到期后,新的 IMAP 认证会立即失败;已经建立的 IMAP TCP 连接会在连接关闭后生效,Roundcube 的典型按请求连接使该窗口通常很短,但它不是逐条 IMAP 命令的强制踢线。