OpenProject 开发实战:用 Docker 容器化 SAML idP 快速搭建本地 SSO 联调环境
【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject
本文聚焦 OpenProject 官方开发文档中的 SAML 开发环境搭建指南:如何在本地开发实例中,用容器化的 SimpleSAMLphp 身份提供商(idP)完成 SAML SSO 的端到端联调。读完后,你将掌握users.php属性配置、docker 环境变量(SP Entity ID、ACS 回调地址、SLO 地址)的完整含义、configuration.yml中 SAML 各配置项与 OpenProject 源码字段的对应关系,并能用两个内置测试账号验证登录与登出全流程。
一、这份指南的适用范围
该指南(docs/development/saml/README.md)明确指出:仅面向 OpenProject 开发者本地联调,不是生产环境的 SAML 接入指南。生产/管理侧的 SAML 配置请参见 系统管理员 SAML 文档。
核心思路是:使用现成的测试 idP 镜像kristophjunge/test-saml-idp(内含 SimpleSAMLphp),通过挂载自定义authsources.php补充 OpenProject 期望接收的属性,再以 OpenProject 作为 SP(服务提供方)完成标准 SAML 2.0 断言流程。
前置条件:
- 一套可用的 Docker 环境;
- 一套可自由修改配置的 OpenProject 开发实例。
二、编写补充属性的 users.php
容器内自带的 SimpleSAMLphp 默认用户配置缺少 OpenProject 需要的一批默认属性,因此官方指南要求在本地新建一个saml-idp目录,并写入如下users.php(该文件稍后会挂载为容器内的authsources.php):
<?php $config = array( 'admin' => array( 'core:AdminPassword', ), 'example-userpass' => array( 'exampleauth:UserPass', 'user1:user1pass' => array( 'uid' => 'user1', 'givenName' => 'foo', 'sn' => 'bar', 'eduPersonAffiliation' => array('group1'), 'email' => 'user1@example.com', ), 'user2:user2pass' => array( 'uid' => 'user2', 'givenName' => 'user', 'sn' => 'second', 'eduPersonAffiliation' => array('group2'), 'email' => 'user2@example.com', ), ), );这里为两个测试账号(user1/user1pass、user2/user2pass)分别声明了uid、givenName、sn、eduPersonAffiliation、email五类属性。这些属性名并非随意命名——它们正是 OpenProject 侧 SAML 属性映射的默认取值。从源码看,默认映射常量 中内置了邮箱(mail/email/emailAddress等)、名字(givenName等)、姓氏(sn/surname等)的候选属性列表,开发文档中的attribute_statements也是按uid → login、givenName → first_name、sn → last_name、email → email来映射的,二者完全吻合,这也是"默认用户配置缺属性就收不到用户"这一说法的直接来源。
三、启动 SAML idP 容器
在saml-idp目录中执行(本机开发环境,OpenProject 运行在localhost:3000):
mkdir saml-idp && cd saml-idpdocker run \ -p 8080:8080 \ -p 8443:8443 \ -e SIMPLESAMLPHP_SP_ENTITY_ID=http://localhost:3000 \ -e SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE=http://localhost:3000/auth/saml/callback \ -e SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE=http://localhost:3000/auth/saml/slo \ -v $(pwd)/users.php:/var/www/simplesamlphp/config/authsources.php \ --network host \ kristophjunge/test-saml-idp如果不是标准开发实例,需要把三个环境变量中的http://localhost:3000替换为你的 OpenProject 实际主机名:
docker run \ -p 8080:8080 \ -p 8443:8443 \ -e SIMPLESAMLPHP_SP_ENTITY_ID=http://<YOUR OPENPROJECT HOSTNAME> \ -e SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE=http://<YOUR OPENPROJECT HOSTNAME>/auth/saml/callback \ -e SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE=http://<YOUR OPENPROJECT HOSTNAME>/auth/saml/slo \ -v $(pwd)/users.php:/var/www/simplesamlphp/config/authsources.php \ --network host \ kristophjunge/test-saml-idp各参数含义(结合源码印证):
| 参数 | 含义 |
|---|---|
-p 8080:8080 | idP 的 HTTP SSO 入口,对应下文 SP 配置中的idp_sso_target_url |
-p 8443:8443 | idP 的 HTTPS 端口(SimpleSAMLphp 默认启用 TLS 演示) |
SIMPLESAMLPHP_SP_ENTITY_ID | 告诉 idP:SP 的 Entity ID 是什么。对应 OpenProject 的sp_entity_id/issuer字段 |
SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE | 断言回调地址(ACS),即 OpenProject 的/auth/saml/callback。源码中该地址由AuthProvider#callback_url生成,Saml::Provider 通过assertion_consumer_service_url委托给callback_url提供 |
SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE | 单点登出(SLO)地址/auth/saml/slo |
-v $(pwd)/users.php:/var/www/simplesamlphp/config/authsources.php | 用自定义用户/属性配置覆盖容器默认的 authsources |
--network host | 直接使用宿主机网络,保证localhost可达 |
四、在 configuration.yml 中配置 OpenProject 侧 SAML
在 OpenProject 的config/configuration.yml中加入如下最小配置(完整示例可参考 config/configuration.yml.example):
default: saml: name: "saml" display_name: "simplesaml-docker" # 使用默认 SAML 图标 icon: "auth_provider-saml.png" # omniauth-saml 配置 assertion_consumer_service_url: "http://localhost:3000/auth/saml/callback" issuer: "http://localhost:3000" idp_cert_fingerprint: "119b9e027959cdb7c662cfd075d9e2ef384e445f" idp_sso_target_url: "http://localhost:8080/simplesaml/saml2/idp/SSOService.php" idp_slo_target_url: "http://localhost:8080/simplesaml/saml2/idp/SingleLogoutService.php" attribute_statements: email: ['email'] login: ['uid'] first_name: ['givenName'] last_name: ['sn']逐项说明:
name/display_name:name是内部标识(用于生成/auth/saml这类 OmniAuth 路由前缀),display_name是登录页上显示的名称。重启后登录按钮即显示为 "simplesaml-docker";assertion_consumer_service_url:SP 接收断言的回调 URL,必须与容器侧SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE完全一致;issuer:SP Entity ID,对应容器侧的SP_ENTITY_ID;idp_cert_fingerprint:测试 idP 证书的 SHA-1 指纹。注意 OpenProject 同时支持完整证书 PEM——Saml::Provider 中idp_cert是首选字段,idp_cert_fingerprint仅作为旧版本的回退兼容保留,UI 上已不再提供指纹入口;idp_sso_target_url:idP 的 SSO 入口,即容器 8080 端口下的SSOService.php;idp_slo_target_url:idP 的单点登出入口SingleLogoutService.php;attribute_statements:声明"OpenProject 需要的字段 ← idP 断言中的哪个属性"的映射,与users.php中的属性名一一对应。
从源码结构看,configuration.yml中的这些键最终会被 HashBuilder#to_h 转换为 omniauth-saml 的策略参数:attribute_statements经formatted_attribute_statements拆分(支持多属性候选,按换行分隔)、idp_cert_fingerprint/idp_cert经idp_cert_options_hash决定用证书还是指纹校验,再合并security_options_hash(签名/摘要算法、want_assertions_signed等)后交给 omniauth-saml 使用。
如果你的 OpenProject 不跑在localhost:3000,需要把assertion_consumer_service_url、issuer换成本机实际主机名;如果 idP 不在本机,idp_sso_target_url、idp_slo_target_url也要同步调整。官方建议两端都放本地,最省事。
五、验证登录与底层调用链
重启 OpenProject 后,登录页会出现名为 "simplesaml-docker" 的按钮,点击后被重定向到 SimpleSAMLphp 容器,使用以下任一账号登录:
- 登录名
user1,密码user1pass; - 登录名
user2,密码user2pass。
登录成功的背后调用链在 AuthSaml 引擎注册代码 中可以看到:每个可用 provider 的配置被转换为一个 omniauth-saml 策略;retain_from_session会把saml_uid、saml_session_index、saml_transaction_id暂存会话,供后续登出使用;single_sign_out_callback则检查会话中是否存在这两个字段,存在时恢复它们并重定向到omni_auth_start_path(...)/spslo,从而走 SP 发起的 SLO 流程——这解释了为什么idp_slo_target_url和容器侧SP_SINGLE_LOGOUT_SERVICE两侧都要配置。
另外两点值得注意的源码事实:
- provider 的"可用"判定由 configured? 与 mapping_configured? 控制:
sp_entity_id、idp_sso_service_url、idP 证书(或指纹)齐备才算配置完成,mapping_login/mail/firstname/lastname四项映射齐备才算映射完成。上面configuration.yml恰好把这三类字段配齐,因此可直接通过; - 该方式(
configuration.yml+seed)适合开发环境;产品化路径是在后台"身份与访问 → SAML 提供方"页面管理 provider,对应路由见 modules/auth_saml/config/routes.rb,并支持从 idP 的 metadata URL/XML 自动导入实体 ID、SSO/SLO 地址与证书(相关服务位于 metadata_fetcher.rb 与 update_metadata_service.rb)。开发文档走静态配置是为了最小化步骤,两者殊途同归。
六、常见问题速查
| 现象 | 排查点 |
|---|---|
| 登录页没有 "simplesaml-docker" 按钮 | configuration.yml未重启生效;或 provider 未通过configured?(缺少 idP 证书/指纹) |
| 断言 400/签名错误 | issuer与容器SP_ENTITY_ID不一致;或idp_cert_fingerprint换证书后未更新 |
| 登录成功但用户字段为空 | attribute_statements的属性名与users.php实际下发的属性不匹配 |
| 登出后 idP 会话仍在 | 检查idp_slo_target_url与SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE是否两侧对齐 |
这套"容器 idP + 最小 YAML 配置"的组合,让你无需任何企业级 IdP 就能在本地完整复现 SAML 登录、属性映射与单点登出,是开发 OpenProject 认证相关功能时最便捷的联调基座。
【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考