LDAP 故障排查
- 版本:免费版、高级版、旗舰版
- 提供方式:GitLab 自托管版
如果您是管理员,请使用以下信息排查 LDAP 问题。
常见问题与工作流
连接问题
连接被拒绝
尝试连接 LDAP 服务器时若收到 Connection Refused 错误,请检查 GitLab 使用的 LDAP 端口 和 加密 设置。常见组合为 encryption: 'plain' 和 port: 389,或 encryption: 'simple_tls' 和 port: 636。
连接超时
若 GitLab 无法访问您的 LDAP 端点,会显示类似信息:
无法从 Ldapmain 认证您,因为 "连接超时 - 用户指定超时"。若配置的 LDAP 提供商和/或端点离线或 GitLab 无法访问,则所有 LDAP 用户均无法认证登录。GitLab 不会在 LDAP 服务中断时缓存或存储 LDAP 用户凭据。
遇到此错误请联系您的 LDAP 提供商或管理员。
引用错误
日志中若出现 LDAP search error: Referral,或在排查 LDAP 组同步时遇到此错误,可能表示配置问题。LDAP 配置文件 /etc/gitlab/gitlab.rb(Omnibus)或 config/gitlab.yml(源码)为 YAML 格式且对缩进敏感。检查 group_base 和 admin_group 配置键是否在服务器标识符后缩进 2 个空格。默认标识符为 main,示例片段如下:
main: # 'main' 是此 LDAP 服务器的 GitLab 'provider ID'
label: 'LDAP'
host: 'ldap.example.com'
# ...
group_base: 'cn=my_group,ou=groups,dc=example,dc=com'
admin_group: 'my_admin_group'查询 LDAP
- 版本:高级版、旗舰版
- 提供方式:GitLab 自托管版
以下代码可通过 rails 控制台执行 LDAP 搜索。根据您的需求,可能更适合直接查询 用户 或 组,甚至直接使用 ldapsearch。
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
# :base 是必需的
# 使用 .base 或 .group_base
base: adapter.config.group_base,
# :filter 是可选的
# 'cn' 在 :base 下查找所有 "cn"
# '*' 是搜索字符串 - 此处为通配符
filter: Net::LDAP::Filter.eq('cn', '*'),
# :attributes 是可选的
# 需要返回的属性
attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)在过滤器中使用 OID 时,将 Net::LDAP::Filter.eq 替换为 Net::LDAP::Filter.construct:
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
# :base 是必需的
# 使用 .base 或 .group_base
base: adapter.config.base,
# :filter 是可选的
# 此过滤器包含 OID 1.2.840.113556.1.4.1941
# 将搜索 LDAP 目录中组 gitlab_grp 的所有直接和嵌套成员
filter: Net::LDAP::Filter.construct("(memberOf:1.2.840.113556.1.4.1941:=CN=gitlab_grp,DC=example,DC=com)"),
# :attributes 是可选的
# 需要返回的属性
attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)运行示例参考 Adapter 模块。
用户登录
未找到用户
若 已确认 可建立 LDAP 连接但 GitLab 未显示 LDAP 用户,可能原因如下:
bind_dn用户权限不足,无法遍历用户树。- 用户不在配置的
base下。 - 配置的
user_filter阻止用户访问。
可通过 ldapsearch 使用 /etc/gitlab/gitlab.rb 中的现有配置确认具体原因。
用户无法登录
用户登录失败可能有多种原因。请先自查以下问题:
- 用户是否在 LDAP 中位于配置的
base下?用户必须在此base下才能登录。 - 用户是否通过配置的 [
user_filter](_index.md#set-up-ldap-user-filter)?若未配置则忽略;若已配置,用户必须通过此过滤器才能登录。- 参考 调试
user_filter文档。
- 参考 调试
若以上问题均正常,请重现问题并检查日志:
- 让用户尝试登录并观察失败过程。
- 查看输出 中是否有登录相关的错误信息。若出现本页其他错误信息,对应章节可帮助解决问题。
若日志未定位问题,使用 rails 控制台 查询该用户,检查 GitLab 能否读取 LDAP 服务器上的用户信息。
也可 调试用户同步 进一步排查。
用户看到 “无效登录或密码” 错误
若用户看到此错误,可能是因为他们使用了 标准 登录表单而非 LDAP 登录表单。
解决方法:请用户在 LDAP 登录表单中输入其 LDAP 用户名和密码。
登录凭据无效
若 LDAP 上的登录凭据正确,请确认以下条件:
- 确保绑定用户有足够权限读取并遍历用户树。
- 检查
user_filter是否阻止了有效用户。 - 运行 LDAP 检查命令 确保 LDAP 设置正确且 GitLab 能看到您的用户。
LDAP 账户访问被拒绝
存在一个 缺陷,可能影响具有 审计员级别权限 的用户。从高级版/旗舰版降级后,审计员用户尝试登录时可能看到以下消息:Access denied for your LDAP account。
临时解决方案:切换受影响用户的访问级别:
- 在左侧边栏底部选择 管理员。
- 选择 概览 > 用户。
- 选择受影响用户的名称。
- 在右上角选择 编辑。
- 将用户访问级别从
常规更改为管理员(或反之)。 - 在页面底部选择 保存更改。
- 再次在右上角选择 编辑。
- 恢复用户原始访问级别(
常规或管理员)并再次选择 保存更改。
用户现在应能登录。
邮箱已被占用
用户使用正确的 LDAP 凭据登录被拒绝,且 production.log 显示类似错误:
(LDAP) 保存用户 <用户 DN> ([email protected]) 时出错:["邮箱已被占用"]此错误指 LDAP 中的邮箱地址 [email protected]。邮箱地址在 GitLab 中必须唯一,且 LDAP 关联用户的主邮箱(而非可能的多个次级邮箱)。另一个用户(甚至同一用户)将 [email protected] 设置为次级邮箱,导致此错误。
可通过 rails 控制台 检查冲突邮箱来源:
# 在主邮箱和次级邮箱中搜索
user = User.find_by_any_email('[email protected]')
user.username此命令显示拥有该邮箱的用户。必须执行以下步骤之一:
- 为该用户创建新的 GitLab 用户名:移除次级邮箱消除冲突。
- 使用现有 GitLab 用户名:将该邮箱从次级改为主邮箱,使 GitLab 将其关联到 LDAP 身份。
用户或管理员可在 其个人资料 中执行这些操作。
项目限制错误
以下错误表示激活了限制但关联数据字段为空:
项目限制不能为空。项目限制不是数字。
解决方法:
- 在左侧边栏底部选择 管理员。
- 选择 设置 > 常规。
- 展开以下两项:
- 账户和限制。
- 注册限制。
- 检查 默认项目限制 或 注册允许域名 等字段,确保配置了有效值。
调试 LDAP 用户过滤器
ldapsearch 可测试配置的 用户过滤器,确认返回预期用户:
ldapsearch -H ldaps://$host:$port -D "$bind_dn" -y bind_dn_password.txt -b "$base" "$user_filter" sAMAccountName- 以
$开头的变量指配置文件 LDAP 部分的变量。 - 若使用纯认证方式,将
ldaps://替换为ldap://。端口389是ldap://默认端口,636是ldaps://默认端口。 - 假设
bind_dn用户密码在bind_dn_password.txt中。
同步所有用户
- 版本:高级版、旗舰版
- 提供方式:GitLab 自托管版
手动 用户同步 的输出可展示 GitLab 尝试同步用户与 LDAP 的过程。进入 rails 控制台 并运行:
Rails.logger.level = Logger::DEBUG
LdapSyncWorker.new.perform接下来,学习如何解读输出。
用户同步后的控制台输出示例
- 版本:高级版、旗舰版
- 提供方式:GitLab 自托管版
手动用户同步 的输出非常详细,单个用户成功同步可能如下:
同步用户 John, [email protected]
身份加载 (0.9ms) SELECT "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1
使用 LDIF 实例化 Gitlab::Auth::Ldap::Person:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: [email protected]
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John
用户同步属性元数据加载 (0.9ms) SELECT "user_synced_attributes_metadata".* FROM "user_synced_attributes_metadata" WHERE "user_synced_attributes_metadata"."user_id" = 20 LIMIT 1
(0.3ms) BEGIN
命名空间加载 (1.0ms) SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."owner_id" = 20 AND "namespaces"."type" IS NULL LIMIT 1
路由加载 (0.8ms) SELECT "routes".* FROM "routes" WHERE "routes"."source_id" = 27 AND "routes"."source_type" = 'Namespace' LIMIT 1
CI 运行器加载 (1.1ms) SELECT "ci_runners".* FROM "ci_runners" INNER JOIN "ci_runner_namespaces" ON "ci_runners"."id" = "ci_runner_namespaces"."runner_id" WHERE "ci_runner_namespaces"."namespace_id" = 27
(0.7ms) COMMIT
(0.4ms) BEGIN
路由加载 (0.8ms) SELECT "routes".* FROM "routes" WHERE (LOWER("routes"."path") = LOWER('John'))
命名空间加载 (1.0ms) SELECT "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 27 LIMIT 1
路由存在 (0.9ms) SELECT 1 AS one FROM "routes" WHERE LOWER("routes"."path") = LOWER('John') AND "routes"."id" != 50 LIMIT 1
用户更新 (1.1ms) UPDATE "users" SET "updated_at" = '2019-10-17 14:40:59.751685', "last_credential_check_at" = '2019-10-17 14:40:59.738714' WHERE "users"."id" = 20输出信息量大,调试时重点关注:
- GitLab 首先查找所有曾通过 LDAP 登录的用户并遍历。每个用户同步以包含用户名和当前 GitLab 邮箱的行开始:
同步用户 John, [email protected]若输出中未找到特定用户的 GitLab 邮箱,说明该用户尚未通过 LDAP 登录。
- GitLab 在
identities表中查找用户与配置的 LDAP 提供商之间的现有链接:
身份加载 (0.9ms) SELECT "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1身份对象包含 GitLab 在 LDAP 中查找用户时使用的 DN。若未找到 DN,则使用邮箱。此示例显示用户在 LDAP 中找到:
使用 LDIF 实例化 Gitlab::Auth::Ldap::Person:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: [email protected]
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John若用户通过 DN 或邮箱均未在 LDAP 中找到,可能显示:
LDAP 搜索错误:无此类对象此时用户被阻止:
用户更新 (0.4ms) UPDATE "users" SET "state" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["state", "ldap_blocked"], ["updated_at", "2019-10-18 15:46:22.902177"], ["id", 20]]找到用户后,其余输出更新 GitLab 数据库中的变更。
查询 LDAP 中的用户
此操作测试 GitLab 能否访问 LDAP 并读取特定用户,可暴露连接和/或查询 LDAP 的潜在错误(这些错误在 GitLab UI 中可能静默失败):
Rails.logger.level = Logger::DEBUG
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # 若 `main` 是 LDAP 提供商
Gitlab::Auth::Ldap::Person.find_by_uid('<uid>', adapter)组成员资格
- 版本:高级版、旗舰版
- 提供方式:GitLab 自托管版
未授予成员资格
有时您认为特定用户应通过 LDAP 组同步添加到 GitLab 组,但未发生。可检查以下内容调试:
- 确保 LDAP 配置指定了
group_base。此配置 是组同步正常工作的必要条件。 - 确保已将正确的 LDAP 组链接添加到 GitLab 组。
- 检查用户是否有 LDAP 身份:
- 以管理员身份登录 GitLab。
- 在左侧边栏底部选择 管理员。
- 在左侧边栏选择 概览 > 用户。
- 搜索用户。
- 选择用户名称打开其信息(不要选择 编辑)。
- 选择 身份 标签。应有包含 LDAP DN 作为
标识符的 LDAP 身份。若无,说明用户尚未通过 LDAP 登录,必须先登录。
- 您已等待一小时或 配置的间隔 进行组同步。为加快进程,可前往 GitLab 组 管理 > 成员 并按 立即同步(同步单个组),或 运行组同步 Rake 任务(同步所有组)。
若所有检查正常,可在 rails 控制台中深入调试:
- 进入 rails 控制台。
- 选择一个已配置 LDAP 组链接的 GitLab 组进行测试。
- 启用调试日志,找到选定的 GitLab 组并 与 LDAP 同步。
- 查看同步输出。参考 示例日志输出 了解如何解读。
- 若仍无法确定用户未被添加的原因,直接查询 LDAP 组 查看成员列表。
- 用户的 DN 或 UID 是否在查询组的列表中?此处某个 DN 或 UID 应与之前检查的 LDAP 身份中的
标识符匹配。若不匹配,用户似乎不在 LDAP 组中。
启用 LDAP 同步时无法将服务账户用户添加到组
当组启用 LDAP 同步时,无法使用 “邀请” 对话框邀请新组成员。
在 GitLab 16.8 及更高版本中,可通过 组成员 API 端点 邀请和移除服务账户。
未授予管理员权限
当 管理员同步 已配置但用户未获得正确管理员权限时,确认以下条件:
- 同时配置了
group_base。 gitlab.rb中的admin_group是 CN(而非 DN 或数组)。- 此 CN 位于配置的
group_base范围内。 admin_group的成员已使用 LDAP 凭据登录 GitLab。GitLab 仅向已连接到 LDAP 的用户授予管理员权限。
若以上条件均满足但用户仍未获得权限,在 rails 控制台中 运行手动组同步 并 查看输出 了解 GitLab 同步 admin_group 时的行为。
UI 中 “立即同步” 按钮卡住
组 管理 > 成员 页面的 立即同步 按钮可能卡住。按钮在点击并刷新页面后卡住,无法再次选择。
按钮卡住可能有多种原因,需针对具体案例调试。以下是两种可能原因及解决方案:
无效成员资格
若组中某些成员或请求成员无效,立即同步 按钮可能卡住。可跟踪改进此问题可见性的 相关 issue。使用 Rails 控制台 确认是否导致按钮卡住:
# 查找相关组
group = Group.find_by(name: 'my_gitlab_group')
# 检查组本身的错误
group.valid?
group.errors.map(&:full_messages)
# 检查组成员和请求者的错误
group.requesters.map(&:valid?)
group.requesters.map(&:errors).map(&:full_messages)
group.members.map(&:valid?)
group.members.map(&:errors).map(&:full_messages)显示的错误可定位问题并提供解决方案。例如,支持团队曾看到以下错误:
irb(main):018:0> group.members.map(&:errors).map(&:full_messages)
=> [["成员的邮箱地址不允许加入此组。请前往组的 **设置 > 常规** 页面,检查 **按邮箱域名限制成员**。"]]此错误表明管理员选择了 按邮箱域名限制组访问,但域名有拼写错误。修复域名设置后,立即同步 按钮恢复正常。
Sidekiq 节点上缺少 LDAP 配置
当 GitLab 跨多个节点扩展且 运行 Sidekiq 的节点上缺少 /etc/gitlab/gitlab.rb 中的 LDAP 配置 时,立即同步 按钮可能卡住。此时 Sidekiq 任务似乎消失。
Sidekiq 节点需要 LDAP,因为 LDAP 有多个异步运行的任务,需要本地 LDAP 配置:
可通过在每个运行 Sidekiq 的节点上运行 LDAP 检查 Rake 任务 测试是否缺少 LDAP 配置。若节点上 LDAP 配置正确,将连接到 LDAP 服务器并返回用户。
解决方案:在 Sidekiq 节点上 配置 LDAP。配置后运行 LDAP 检查 Rake 任务 确认 GitLab 节点可连接 LDAP。
同步所有组
调试时无需手动同步所有组,请改用 Rake 任务。
手动 组同步 的输出可展示 GitLab 同步 LDAP 组成员资格的过程。进入 rails 控制台 并运行:
Rails.logger.level = Logger::DEBUG
LdapAllGroupsSyncWorker.new.perform接下来,学习如何解读输出。
组同步后的控制台输出示例
与用户同步输出类似,手动组同步 的输出也非常详细,包含大量有用信息。
同步实际开始的标志:
开始同步 'ldapmain' 提供商的 'my_group' 组以下条目显示 GitLab 在 LDAP 服务器中看到的所有用户 DN。这些 DN 是单个 LDAP 组的用户,而非 GitLab 组。若此 GitLab 组链接到多个 LDAP 组,会看到多个类似条目(每个 LDAP 组一个)。若此日志条目中未看到 LDAP 用户 DN,说明 LDAP 在查找时未返回该用户。请验证用户是否确实在 LDAP 组中。
'ldap_group_1' LDAP 组中的成员:["uid=john0,ou=people,dc=example,dc=com",
"uid=mary0,ou=people,dc=example,dc=com", "uid=john1,ou=people,dc=example,dc=com",
"uid=mary1,ou=people,dc=example,dc=com", "uid=john2,ou=people,dc=example,dc=com",
"uid=mary2,ou=people,dc=example,dc=com", "uid=john3,ou=people,dc=example,dc=com",
"uid=mary3,ou=people,dc=example,dc=com", "uid=john4,ou=people,dc=example,dc=com",
"uid=mary4,ou=people,dc=example,dc=com"]每个条目后不久,会看到已解析成员访问级别的哈希值。此哈希值表示 GitLab 认为应有权访问该组的所有用户 DN 及其访问级别(角色)。此哈希值是累加的,可能根据额外的 LDAP 组查找添加更多 DN 或修改现有条目。最后一个条目应准确指示 GitLab 认为应添加到组中的用户。
10 为 访客,20 为 报告者,30 为 开发者,40 为 维护者,50 为 所有者。
已解析 'my_group' 组成员访问:{"uid=john0,ou=people,dc=example,dc=com"=>30,
"uid=mary0,ou=people,dc=example,dc=com"=>30, "uid=john1,ou=people,dc=example,dc=com"=>30,
"uid=mary1,ou=people,dc=example,dc=com"=>30, "uid=john2,ou=people,dc=example,dc=com"=>30,
"uid=mary2,ou=people,dc=example,dc=com"=>30, "uid=john3,ou=people,dc=example,dc=com"=>30,
"uid=mary3,ou=people,dc=example,dc=com"=>30, "uid=john4,ou=people,dc=example,dc=com"=>30,
"uid=mary4,ou=people,dc=example,dc=com"=>30}看到类似以下警告很常见。这些警告表示 GitLab 本会添加用户到组,但无法在 GitLab 中找到该用户。通常无需担心。
若认为特定用户应已存在于 GitLab 中,但看到此条目,可能是 GitLab 中存储的 DN 不匹配。参考 用户 DN 和邮箱已更改 更新用户的 LDAP 身份。
用户 DN `uid=john0,ou=people,dc=example,dc=com` 应有权访问 'my_group' 组,
但 GitLab 中无此身份的用户。用户首次登录时将更新成员资格。最后,以下条目表示该组同步完成:
完成所有提供商的 'my_group' 组同步当所有配置的组链接同步后,GitLab 会查找管理员或外部用户进行同步:
同步 'ldapmain' 提供商的管理员用户输出与单个组同步类似,以下行表示同步完成:
完成 'ldapmain' 提供商的管理员用户同步若未配置 管理员同步,会显示:
未为 'ldapmain' 提供商配置 'admin_group'。跳过同步单个组
同步所有组 可能产生大量输出,干扰排查单个 GitLab 组成员资格。此时可仅同步该组并查看调试输出:
Rails.logger.level = Logger::DEBUG
# 查找 GitLab 组。
# 若输出为 `nil`,则未找到组。
# 若输出包含大量组属性,则成功找到组。
group = Group.find_by(name: 'my_gitlab_group')
# 将此组与 LDAP 同步
EE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)输出与 同步所有组 类似。
查询 LDAP 中的组
当需要确认 GitLab 能读取 LDAP 组及其所有成员时,可运行:
# 查找适配器和组本身
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # 若 `main` 是 LDAP 提供商
ldap_group = EE::Gitlab::Auth::Ldap::Group.find_by_cn('group_cn_here', adapter)
# 查找 LDAP 组的成员
ldap_group.member_dns
ldap_group.member_uidsLDAP 同步未移除组创建者
LDAP 同步 应移除 LDAP 组的创建者(若该用户不在组中)。若运行 LDAP 同步未执行此操作:
- 将用户添加到 LDAP 组。
- 等待 LDAP 组同步完成。
- 从 LDAP 组中移除用户。
用户 DN 和邮箱已更改
若 LDAP 中用户的主邮箱 和 DN 均更改,GitLab 无法识别正确的 LDAP 记录,从而阻止该用户。为使 GitLab 能找到 LDAP 记录,请使用以下至少一项更新用户现有 GitLab 资料:
- 新的主邮箱。
- DN 值。
以下脚本更新所有提供用户的邮箱,避免其被阻止或无法访问账户。
以下脚本要求先删除具有新邮箱地址的任何新账户。邮箱地址在 GitLab 中必须唯一。
进入 rails 控制台 并运行:
# 每条记录必须包含旧用户名和新邮箱
emails = {
'原始用户名' => '新邮箱地址',
...
}
emails.each do |username, email|
user = User.find_by_username(username)
user.email = email
user.skip_reconfirmation!
user.save!
end然后可运行 用户同步 同步这些用户的最新 DN。
无法从 AzureActivedirectoryV2 认证,因为 “无效授权”
从 LDAP 转换为 SAML 时,Azure 中可能出现以下错误:
认证失败!invalid_credentials: OAuth2::Error, invalid_grant.当以下两个条件同时满足时会发生此问题:
- 用户配置 SAML 后仍存在 LDAP 身份。
- 您为这些用户禁用了 LDAP。
日志中会同时包含 LDAP 和 Azure 元数据,导致 Azure 中出现错误。
单个用户的解决方法是:在 管理员 > 身份 中移除用户的 LDAP 身份。
要移除多个 LDAP 身份,使用 无法从 Ldapmain 认证,因为 "未知提供商" 错误 的任一临时解决方案。
无法从 Ldapmain 认证,因为 “未知提供商”
使用 LDAP 服务器认证时可能收到以下错误:
无法从 Ldapmain 认证,因为 "未知提供商 (ldapsecondary)。可用提供商:["ldapmain"]"。此错误由以下情况引起:使用曾通过已重命名或从 GitLab 配置中移除的 LDAP 服务器认证的账户。例如:
- 初始时,GitLab 配置中的
ldap_servers设置了main和secondary。 - 移除或重命名
secondary为main。 - 尝试登录的用户拥有
secondary的identity记录,但该配置已不存在。
使用 Rails 控制台 列出受影响用户并检查其 LDAP 服务器身份:
ldap_identities = Identity.where(provider: "ldapsecondary")
ldap_identities.each do |identity|
u=User.find_by_id(identity.user_id)
ui=Identity.where(user_id: identity.user_id)
puts "用户: #{u.username}\n #{u.email}\n 最后活动时间: #{u.last_activity_on}\n #{identity.provider} ID: #{identity.id} 外部: #{identity.extern_uid}"
puts " 所有身份:"
ui.each do |alli|
puts " - #{alli.provider} ID: #{alli.id} 外部: #{alli.extern_uid}"
end
end;nil可通过两种方式解决此错误。
重命名 LDAP 服务器引用
当 LDAP 服务器互为副本,且受影响用户应能通过配置的 LDAP 服务器登录时,此方案适用。例如,若现在使用负载均衡器管理 LDAP 高可用性,不再需要单独的次要登录选项。
若 LDAP 服务器互不为副本,此方案将阻止受影响用户登录。
要 重命名不再配置的 LDAP 服务器引用,运行:
sudo gitlab-rake gitlab:ldap:rename_provider[ldapsecondary,ldapmain]移除与已移除 LDAP 服务器相关的 identity 记录
前提条件:
- 确保
auto_link_ldap_user已启用。
此方案下,删除身份后,受影响用户可通过配置的 LDAP 服务器登录,GitLab 会创建新的 identity 记录。
由于移除的 LDAP 服务器是 ldapsecondary,在 Rails 控制台 中删除所有 ldapsecondary 身份:
ldap_identities = Identity.where(provider: "ldapsecondary")
ldap_identities.each do |identity|
puts "删除身份: #{identity.id} #{identity.provider}: #{identity.extern_uid}"
identity.destroy!
rescue => e
puts '删除身份时生成错误:\n ' + e.to_s
end; nil过期许可证导致多 LDAP 服务器错误
使用 多个 LDAP 服务器 需要有效许可证。过期许可证可能导致:
- Web 界面出现
502错误。 - 日志中出现以下错误(实际策略名称取决于
/etc/gitlab/gitlab.rb中配置的名称):无法找到名称为 `Ldapsecondary' 的策略。请确保需要它或使用 :strategy_class 选项显式设置。(Devise::OmniAuth::StrategyNotFound)
解决此错误,必须在不使用 Web 界面的情况下为 GitLab 实例应用新许可证:
- 移除或注释掉所有非主要 LDAP 服务器的 GitLab 配置行。
- 重新配置 GitLab 使其临时仅使用一个 LDAP 服务器。
- 进入 Rails 控制台并添加许可证密钥。
- 在 GitLab 配置中重新启用额外的 LDAP 服务器并再次重新配置 GitLab。
用户被反复移除和添加到组
若用户在组同步中被添加,又在下一次同步中被移除,且反复发生,请确保用户没有多个或冗余的 LDAP 身份。
若其中某个身份是为不再使用的旧 LDAP 提供商添加的,移除与已移除 LDAP 服务器相关的 identity 记录。
调试工具
LDAP 检查
LDAP 检查 Rake 任务 是帮助确定 GitLab 能否成功连接 LDAP 并读取用户的重要工具。
若无法建立连接,可能是配置问题或防火墙阻止连接:
- 确保没有防火墙阻止连接,且 LDAP 服务器可被 GitLab 主机访问。
- 查看 Rake 检查输出中的错误信息,可能指向您的 LDAP 配置,确认配置值(特别是
host、port、bind_dn和password)是否正确。 - 查看 日志 中的 错误 进一步调试连接失败。
若 GitLab 成功连接 LDAP 但未返回用户,参考未找到用户时的处理方法。
GitLab 日志
若用户账户因 LDAP 配置被阻止或解除阻止,消息会 记录到 application_json.log。
若 LDAP 查找期间出现意外错误(配置错误、超时),登录被拒绝并记录消息到 production.log。
ldapsearch
ldapsearch 是允许查询 LDAP 服务器的工具。可用于测试 LDAP 设置并确保设置获得预期结果。
使用 ldapsearch 时,请使用已在 gitlab.rb 配置中指定的相同设置,以确认使用这些确切设置时的行为。
在 GitLab 主机上运行此命令也有助于确认 GitLab 主机和 LDAP 之间无障碍。
例如,考虑以下 GitLab 配置:
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' # 记得在下面用 'EOS' 关闭此块
main: # 'main' 是此 LDAP 服务器的 GitLab 'provider ID'
label: 'LDAP'
host: '127.0.0.1'
port: 389
uid: 'uid'
encryption: 'plain'
bind_dn: 'cn=admin,dc=ldap-testing,dc=example,dc=com'
password: 'Password1'
active_directory: true
allow_username_or_email_login: false
block_auto_created_users: false
base: 'dc=ldap-testing,dc=example,dc=com'
user_filter: ''
attributes:
username: ['uid', 'userid', 'sAMAccountName']
email: ['mail', 'email', 'userPrincipalName']
name: 'cn'
first_name: 'givenName'
last_name: 'sn'
group_base: 'ou=groups,dc=ldap-testing,dc=example,dc=com'
admin_group: 'gitlab_admin'
EOS您将运行以下 ldapsearch 查找 bind_dn 用户:
ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
-w Password1 \
-p 389 \
-h 127.0.0.1 \
-b "dc=ldap-testing,dc=example,dc=com"bind_dn、password、port、host 和 base 均与 gitlab.rb 中的配置一致。
使用 start_tls 加密的 ldapsearch
上述示例在端口 389 上执行明文 LDAP 测试。若使用 start_tls 加密,在 ldapsearch 命令中包含:
-Z标志。- LDAP 服务器的 FQDN。
必须包含这些,因为 TLS 协商期间会评估 LDAP 服务器的 FQDN 与其证书的匹配:
ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
-w Password1 \
-p 389 \
-h "testing.ldap.com" \
-b "dc=ldap-testing,dc=example,dc=com" -Z使用 simple_tls 加密的 ldapsearch
若使用 simple_tls 加密(通常在端口 636),在 ldapsearch 命令中包含:
- 使用
-H标志和端口指定 LDAP 服务器 FQDN。 - 完整构造的 URI。
ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
-w Password1 \
-H "ldaps://testing.ldap.com:636" \
-b "dc=ldap-testing,dc=example,dc=com"更多信息请参阅官方 ldapsearch 文档。
使用 AdFind (Windows)
您可使用 AdFind 工具(基于 Windows 的系统)测试 LDAP 服务器是否可访问且认证是否正常工作。AdFind 是由 Joe Richards 构建的免费工具。
返回所有对象
可使用过滤器 objectclass=* 返回所有目录对象:
adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*)使用过滤器返回单个对象
也可通过 指定 对象名称或完整 DN 检索单个对象。本示例仅指定对象名称 CN=Leroy Fox:
adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f "(&(objectcategory=person)(CN=Leroy Fox))"Rails 控制台
在 rails 控制台中创建、读取、修改和销毁数据非常容易。请务必完全按列出的命令执行。
Rails 控制台是调试 LDAP 问题的重要工具。它允许您通过运行命令直接与应用程序交互,观察 GitLab 的响应。
关于如何使用 rails 控制台的说明,请参考此 指南。
启用调试输出
此操作提供调试输出,显示 GitLab 的操作对象。此值不会持久化,仅在本次 Rails 控制台会话中启用。
要在 rails 控制台中启用调试输出,进入 rails 控制台 并运行:
Rails.logger.level = Logger::DEBUG获取与组、子组、成员和请求者相关的所有错误消息
收集与组、子组、成员和请求者相关的错误消息。这可捕获 Web 界面中可能未显示的错误信息,对排查 LDAP 组同步 及用户在组和子组中的意外行为特别有帮助。
# 查找组和子组
group = Group.find_by_full_path("parent_group")
subgroup = Group.find_by_full_path("parent_group/child_group")
# 组和子组错误
group.valid?
group.errors.map(&:full_messages)
subgroup.valid?
subgroup.errors.map(&:full_messages)
# 组和子组的成员及请求者错误
group.requesters.map(&:valid?)
group.requesters.map(&:errors).map(&:full_messages)
group.members.map(&:valid?)
group.members.map(&:errors).map(&:full_messages)
group.members_and_requesters.map(&:errors).map(&:full_messages)
subgroup.requesters.map(&:valid?)
subgroup.requesters.map(&:errors).map(&:full_messages)
subgroup.members.map(&:valid?)
subgroup.members.map(&:errors).map(&:full_messages)
subgroup.members_and_requesters.map(&:errors).map(&:full_messages)