LDAP 故障排查指南

如果您是管理员,使用如下信息进行 LDAP 故障排查。 ## 常见问题 & 工作流

连接问题

连接拒绝

当您尝试连接到 LDAP 服务器时,可能会遇到 Connection Refused 错误信息,在极狐GitLab 上检查 portencryption 设置。通常的配置为 encryption: 'plain'port: 389encryption: 'simple_tls' 以及 port: 636

连接超时

如果极狐GitLab 无法连接到您的 LDAP 端点,您可能会看到如下信息:

Could not authenticate you from Ldapmain because "Connection timed out - user specified timeout".

如果您配置的 LDAP 提供商和/或端点是离线或无法通过 GitLab 访问,则无法通过 LDAP 用户进行身份验证和登录。在 LDAP 无法使用期间,极狐GitLab 无法缓存或存储 LDAP 用户的凭据。

如果看到此错误,请联系您的 LDAP 提供商或管理员。

Referral 错误

如果您在日志中看到 LDAP search error: Referral,或在对 LDAP 群组同步进行故障排查时看到此错误,这意味着有配置问题。LDAP 配置 /etc/gitlab/gitlab.rb (Omnibus 安装) 或 config/gitlab.yml (源代码安装)是 YAML 格式的,对缩进敏感。检查 group_baseadmin_group 配置键是否缩进 2 个空格。默认标识符为 main,示例片段如下所示:

main: # 'main' is the GitLab 'provider ID' of this LDAP server
  label: 'LDAP'
  host: 'ldap.example.com'
  ...
  group_base: 'cn=my_group,ou=groups,dc=example,dc=com'
  admin_group: 'my_admin_group'

查询 LDAP

以下内容允许您使用 Rails 控制台来在 LDAP 中执行搜索。根据你想要做的事情,直接查询 LDAP 中的用户或者 LDAP 中的,甚至改用ldapsearch,可能会更合理。

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
    # :base is required
    # use .base or .group_base
    base: adapter.config.group_base,

    # :filter is optional
    # 'cn' looks for all "cn"s under :base
    # '*' is the search string - here, it's a wildcard
    filter: Net::LDAP::Filter.eq('cn', '*'),

    # :attributes is optional
    # the attributes we want to get returned
    attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)

当在过滤器中使用 OIDs 时,用 Net::LDAP::Filter.construct 替换 Net::LDAP::Filter.eq

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
    # :base is required
    # use .base or .group_base
    base: adapter.config.base,

    # :filter is optional
    # This filter includes OID 1.2.840.113556.1.4.1941
    # It will search for all direct and nested members of the group gitlab_grp in the LDAP directory
    filter: Net::LDAP::Filter.construct("(memberOf:1.2.840.113556.1.4.1941:=CN=gitlab_grp,DC=example,DC=com)"),

    # :attributes is optional
    # the attributes we want to get returned
    attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)

关于此部分是如何运行的,可以查看 审核 Adapter 模块

用户登录

未发现用户

如果 您已经确定 LDAP 的连接已经建立,但是却没有在输出中看到 LDAP 用户,可能的原因有:

在这种情况下,您可以在 /etc/gitlab/gitlab.rb 中使用 ldapsearch 和既有配置来确定到底是上面的哪个问题导致。

用户无法登录

用户可能有多种登录问题。开始之前,您需要询问自己:

  • 在 LDAP 中,用户是否在配置的 base 下?用户必须要在此 base 下才能登录。
  • 用户是否传递了配置的 user_filter?如果没有配置此项,则可忽略此问题。如果是,则用户必须传递此过滤器以允许登录。

如果上述内容都 OK,下一步就是要查看问题产生时的日志了。

  • 让用户登录并让登录失败。
  • 对于任何错误或其他任何关于登录的信息,都要查看输出。您可能会在页面上看到其他错误,这些都可能帮助您解决此问题。

如果日志无法分析错误根因,使用 Rails 控制台查询此用户以查看极狐GitLab 是否可以从 LDAP 服务器读取此用户。

调试用户同步对于进一步调查也是非常有帮助的。

用户看见错误 “Invalid login or password.”

  • 引入极狐GitLab 16.10。

如果用户看到此错误,可能是因为他们在使用 标准的 登录表单而非 LDAP 登录表单。

要解决此问题,让用户将他们的 LDAP 用户名和密码输入进 LDAP 登录表单。

无效的登录凭据

如果在 LDAP 中,使用的登录凭据是准确的,确保如下问题中的内容对用户来说是正确的:

LDAP 账号访问拒绝

有一个缺陷可能会影响具有审计者访问权限的用户。当从专业版/旗舰版降级时,尝试登录的审计者用户可能会看到如下信息:Access denied for your LDAP account

我们有一个解决方案,基于受影响用户的访问级别开关:

  1. 在左侧导航栏,底部,选择 管理员
  2. 选择 概览 > 用户
  3. 选择受影响用户的名称。
  4. 在右上角,选择 编辑
  5. 将用户的访问级别从 Regular 修改为 Administrator (反之亦然)。
  6. 在页面底部,选择 保存更改
  7. 在右上角,再次选择 编辑
  8. 恢复用户的原始访问级别(RegularAdministrator)并在此选择 保存更改

用户应该就可以登录了。

邮件已经被占用

用户尝试用正确的 LDAP 凭据登录,但被拒绝访问,且 production.log 显示如下错误:

(LDAP) Error saving user <USER DN> (email@example.com): ["Email has already been taken"]

此错误指向 LDAP 中的邮件地址 email@example.com。邮件地址必须在极狐GitLab 中唯一且 LDAP链接到用户的主邮箱(与他们可能众多的次要电子邮件中的任何一个相对)。另外的用户(甚至是相同用户)已经将 email@example.com 设置为了次要邮箱,因此导致此错误。

我们可以使用 Rails 控制台来检查此冲突的邮件地址到底来自哪儿。在控制台上,运行如下内容:

# This searches for an email among the primary AND secondary emails
user = User.find_by_any_email('email@example.com')
user.username

此命令会展示到底是哪个用户在使用此邮箱。以下两个步骤必须要执行其一:

  • 当使用 LDAP 登录时,必需为此用户创建一个新的极狐GitLab 用户/用户名,然后移除次要邮箱以解决冲突。
  • 为使用 LDAP 的此用户使用既有的极狐GitLab 用户/用户名,将此邮箱在次要邮箱中移除,并将其设置为主要邮箱,这样极狐GitLab 就会将此个人资料和 LDAP 身份识别进行关联了。

用户可以在[他们的个人资料]](../../../user/profile/index.md#access-your-user-profile)中完成这些步骤,或者管理员也可以完成此事。

项目限制错误

以下错误意味着某些限制被触发了,但是相关联的数据字段却不包含任何数据:

  • Projects limit can't be blank.
  • Projects limit is not a number.

要解决此问题:

  1. 在左侧导航栏,底部,选择 管理员
  2. 选择 设置 > 通用
  3. 同时展开如下内容:
    • 账号和限制
    • 注册限制
  4. 检查,比如,默认项目限制注册允许的域名 字段并确保配置了相关值。

调试 LDAP 用户过滤器

ldapsearch 允许您测试您配置的用户过滤器以确认它返回了您期望的那些用户。

ldapsearch -H ldaps://$host:$port -D "$bind_dn" -y bind_dn_password.txt  -b "$base" "$user_filter" sAMAccountName
  • $ 开头的变量引用你配置文件的 LDAP 部分的一个变量。
  • Variables beginning with a $ refer to a variable from the LDAP section of your configuration file.
  • 如果您正在使用明文认证方式,将 ldaps:// 替换为 ldap://ldaps// 的默认端口为 389,而 ldaps:// 的默认端口为 636
  • 我们假定 bind_dn 用户的密码在 bind_dn_password.txt 中。

同步所有用户

手动用户同步的输出为您展示,当极狐GitLab 尝试同步其用户与 LDAP 时,会发生什么。进入 Rails 控制台 并运行:

Rails.logger.level = Logger::DEBUG

LdapSyncWorker.new.perform

接着,学习如何读取输出

用户同步后的控制台输出示例

来自手动用户同步的输出非常冗长,并且单个用户成功同步看起来像这样:

Syncing user John, email@example.com
  Identity Load (0.9ms)  SELECT  "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1
Instantiating Gitlab::Auth::Ldap::Person with LDIF:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: email@example.com
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John

  UserSyncedAttributesMetadata Load (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
  Namespace Load (1.0ms)  SELECT  "namespaces".* FROM "namespaces" WHERE "namespaces"."owner_id" = 20 AND "namespaces"."type" IS NULL LIMIT 1
  Route Load (0.8ms)  SELECT  "routes".* FROM "routes" WHERE "routes"."source_id" = 27 AND "routes"."source_type" = 'Namespace' LIMIT 1
  Ci::Runner Load (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
  Route Load (0.8ms)  SELECT "routes".* FROM "routes" WHERE (LOWER("routes"."path") = LOWER('John'))
  Namespace Load (1.0ms)  SELECT  "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 27 LIMIT 1
  Route Exists (0.9ms)  SELECT  1 AS one FROM "routes" WHERE LOWER("routes"."path") = LOWER('John') AND "routes"."id" != 50 LIMIT 1
  User Update (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 中:

Syncing user John, email@example.com

如果您在LDAP 中找不到此用户的极狐GitLab 邮箱,那么此用户还没有使用 LDAP 登录过。

接下来,极狐GitLab 会在其 identities 表中搜索该用户与已配置的 LDAP 提供程序之间的现有链接:

  Identity Load (0.9ms)  SELECT  "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1

识别对象有极狐GitLab 用来在 LDAP 中查找用户的 DN。如果 DN 没有找到,那么极狐GitLab 会使用邮箱来查找用户。我们可以在 LDAP 中看到此用户:

Instantiating Gitlab::Auth::Ldap::Person with LDIF:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: email@example.com
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John

如果用 DN 或邮箱都没在 LDAP 中找到此用户,您可能会看到如下信息:

LDAP search error: No Such Object

用户被阻塞的情况:

  User Update (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]]

在 LDAP 中找到用户后,剩余的输出会更新极狐GitLab 数据库的任意变更。

在 LDAP 中查询用户

这可以测试极狐GitLab 能够连接到 LDAP 并读取特定用户。它可以暴露在连接和/或查询 LDAP 时可能出现的潜在错误,这些错误在极狐GitLab 用户界面中可能看似悄无声息地失败了。

Rails.logger.level = Logger::DEBUG

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # If `main` is the LDAP provider
Gitlab::Auth::Ldap::Person.find_by_uid('<uid>', adapter)

群组成员关系

无法赋予成员关系

有时候您可能想通过 LDAP 群组同步来将特定用户添加到极狐GitLab 群组中,但是在某些情况下,这种方法却不工作。为此,您可以检查多项来对此进行调试:

  • 确保 LDAP 配置有 group_base此项配置对于群组同步正常工作来讲是必需的。
  • 确保正确的LDAP 群组连接被添加到了极狐GitLab 群组中
  • 检查用户是否有 LDAP 身份识别:
    1. 以管理员身份登录极狐GitLab。
    2. 在左侧导航栏,底部,选择 管理员
    3. 在左侧导航栏,选择 概览 > 用户
    4. 搜索用户。
    5. 通过选择他们的用户名开发用户。不要选择 编辑
    6. 选择 身份识别 选项卡。这儿应该有一个以 LDAP 专有名称(DN)作为 Identifier 的 LDAP 身份标识。如果没有,说明此用户还未登录极狐GitLab,因此必需首先先登录一下。
  • 您已经等待了一个小时或等待了群组同步的配置间隔时长。为了加速进度,要么前往极狐GitLab 群组的 管理 > 成员 并点击 现在同步 (同步一个群组)或运行群组同步 Rake 任务(同步所有群组)。

如果上述的一切都没问题,可以进一步的在 Rails 控制台上进行调试了:

  1. 进入 Rails 控制台
  2. 选择要测试的极狐GitLab群组。次群组应该有一个已经配置好的 LDAP 群组连接。
  3. 启用调试日志,找到上述的群组并用 LDAP 同步
  4. 查看同步输出。关于如何读取输出,可以查看示例日志输出。1
  5. 如果您依旧未看到为什么用户没有被添加进来,直接查询 LDAP 群组来查看列出了哪些成员。
  6. 要查看在上面的输出中,用户的 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 上的现在同步按钮卡住

群组 群组 > 成员 页面上的 现在同步 那妞可能会变成卡住状态。按钮被按下且页面开始重新加载后,按钮就会变为卡住状态。按钮也无法被再次选择。

现在同步 按钮变卡住可能有多种原因,需要针对不同情况进行具体调试。下面是两种可能的情况和可用的解决方案。

无效的成员关系

如果有些群组的成员或请求的成员是无效的,则 现在 同步按钮就会卡住。您可以在 Rails 控制台上确认是否是该问题导致了 现在同步 按钮卡住:

# Find the group in question
group = Group.find_by(name: 'my_gitlab_group')

# Look for errors on the Group itself
group.valid?
group.errors.map(&:full_messages)

# Look for errors among the group's members and requesters
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)
=> [["The member's email address is not allowed for this group. Go to the group's &#39;Settings &gt; General&#39; page, and check &#39;Restrict membership by email domain&#39;."]]

此错误展示了管理员选择通过邮箱限制群组成员关系,但是在域名中有一个错误。在修复域名问题后,现在同步 按钮再次可用。

在 Sidekiq 节点上丢失了 LDAP 配置

当极狐GitLab 扩容为多个节点并从运行 Sidekiq 节点的 /etc/gitlab/gitlab.rb 中丢失了 LDAP 配置,现在同步 按钮就会卡住。在此情况下,Sidekiq 作业看起来消失了。

Sidekiq节点上需要安装LDAP,因为LDAP有多个异步运行的任务,这些任务需要本地的LDAP配置。

您可以通过在每个运行 Sidekiq 的节点上运行 Rake 任务检查 LDAP来测试是否是丢失的 LDAP 配置引起了按钮不可用的问题。如果在节点上正确设置了 LDAP,它就能连接到 LDAP 服务器并返回用户。

要解决此问题,在 Sidekiq 节点上配置 LDAP。当配置时,运行 Rake 任务检查 LDAP来确认极狐GitLab 节点可以连接到 LDAP。

同步所有群组

note 当不需要调试时,想要手动同步所有群组,使用 Rake 任务来代替。

手动群组同步中的输出可以为您展示当极狐GitLab 通过 LDAP 同步它的 LDAP 群组成员关系时都发生了什么。在 Rails 控制台中运行如下命令:

Rails.logger.level = Logger::DEBUG

LdapAllGroupsSyncWorker.new.perform

接着,学习如何阅读输出

群组同步后的控制台输出示例

像用户同步输出,从手动群组同步的输出是非常冗长的。然而,

指示同步实际开始的地方:

Started syncing 'ldapmain' provider for 'my_group' group

以下内容展示了极狐GitLab 在 LDAP 服务器中看到的所有用户 DN 数组。这些 DN 是单个 LDAP 群组中用户的,而不是极狐GitLab 群组的。如果您有多个链接到极狐GitLab 群组的 LDAP 群组,您可以像这样看到多个日志条目 - 每个 LDAP 群组一个。如果您在日志条目中没有看到 LDAP 用户 DN,则当我们查询的时候 LDAP 就不会返回用户。所以需要验证用户实际存在于 LDAP 群组中。

Members in 'ldap_group_1' LDAP group: ["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"]

在上述每一项记录之后不久,您会看到一个已解析的成员访问级别的哈希值。 此哈希代表了所有用户 DN,用户是极狐GitLab 认为应该能访问此群组的,而且以何种级别(角色)进行访问。这个哈希是可累加的,基于额外的 LDAP 组查找,可能会添加更多的 DN,或者修改现有的条目。 此条目的最后一次出现应该确切表明极狐GitLab 认为哪些用户应该被添加到该组中。

note 10 是 Guest、20 是 Reporter、30 是 Developer、40 是 Maintainer以及 50 是 Owner
Resolved 'my_group' group member access: {"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 身份识别。

User with DN `uid=john0,ou=people,dc=example,dc=com` should have access
to 'my_group' group but there is no user in GitLab with that
identity. Membership will be updated when the user signs in for
the first time.

最终,如下条目提示群组同步已经完成:

Finished syncing all providers for 'my_group' group

当所有配置好的群组链接已经被同步时,极狐GitLab 寻求管理员或外部用户来同步:

Syncing admin users for 'ldapmain' provider

输出看起来与单个组的情况类似,然后这一行表明同步已完成:

Finished syncing admin users for 'ldapmain' provider

如果未配置管理员同步,您可以看到如下内容:

No `admin_group` configured for 'ldapmain' provider. Skipping

同步单个群组

同步所有群组可以在输出中生成需要噪音,当您只对排查单个极狐GitLab 群组的成员资格问题感兴趣时,这可能会让人分心。在这种情况下,下面是您仅同步此群组并查看其调试输出的方法:

Rails.logger.level = Logger::DEBUG

# Find the GitLab group.
# If the output is `nil`, the group could not be found.
# If a bunch of group attributes are in the output, your group was found successfully.
group = Group.find_by(name: 'my_gitlab_group')

# Sync this group against LDAP
EE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)

输出与您从同步所有群组获取的信息相似。

在 LDAP 查询群组

当您想要确认极狐GitLab 可以读取 LDAP 群组和查看所有的用户时,您可以运行如下命令:

# Find the adapter and the group itself
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # If `main` is the LDAP provider
ldap_group = EE::Gitlab::Auth::Ldap::Group.find_by_cn('group_cn_here', adapter)

# Find the members of the LDAP group
ldap_group.member_dns
ldap_group.member_uids

LDAP 同步不能够从群组移除群组创建器

如果用户在群组中不存在,则LDAP 同步应该从群组中移除群组创建器。如果运行 LDAP 同步不能够实现移除,则:

  1. 将用户添加到 LDAP 群组。
  2. 等待,直到 LDAP 群组同步完成。
  3. 从 LDAP 群组移除用户。

用户 DN 和邮箱发生了变化

如果 LDAP 中的主邮箱 DN 发生了变化,极狐GitLab 就不能够正确识别 LDAP 用户记录。结果就是,极狐GitLab 会阻塞用户。如要极狐GitLab 能够找到 LDAP 记录,则用如下内容更新既有的极狐GitLab 用户个人资料:

  • 新的主邮箱。
  • DN 值。

下面的脚本能够更新所有创建用户的邮箱,以便他们不能够被阻塞或者无法访问他们的账号。

note 以下脚本要求首先删除任何使用新电子邮件地址的新账户。在极狐GitLab中,电子邮件地址必须是唯一的。

前往 Rails 控制台并运行:

# Each entry must include the old username and the new email
emails = {
  'ORIGINAL_USERNAME' => 'NEW_EMAIL_ADDRESS',
  ...
}

emails.each do |username, email|
  user = User.find_by_username(username)
  user.email = email
  user.skip_reconfirmation!
  user.save!
end

然后您需要运行 UserSync来为每一个用户同步最新的 DN。

因为 “Invalid grant” 导致无法从 AzureActivedirectoryV2 进行认证

当从 LDAP 转换成 SAML 时,您可能会在 Azure 中看到如下错误:

Authentication failure! invalid_credentials: OAuth2::Error, invalid_grant.

当如下内容都为真时,此错误就会发生:

  • 在为用户配置了 SAML 之后,这些用户的 LDAP 身份仍然存在。
  • 您为那些用户禁用了 LDAP。

您可能在日志中同时接收到 LDAP 和 Azure 元数据,这会在 Azure 中产生错误。

针对单个用户的解决方法是,在 管理 > 身份 中从该用户那里删除 LDAP 身份。

要移除多个 LDAP 身份识别,使用此解决方案或 Could not authenticate you from Ldapmain because "Unknown provider" 错误中的方法。

Could not authenticate you from Ldapmain because "Unknown provider"

当使用 LDAP 服务器认证时,可能会接收到如下错误:

Could not authenticate you from Ldapmain because "Unknown provider (ldapsecondary). available providers: ["ldapmain"]".

当使用已经在极狐GitLab 配置中重命名或被移除的LDAP 服务器时进行认证时,就会出现此错误。比如:

  • 最开始,在极狐GitLab 配置中,mainsecondary 被设置在 ldap_servers
  • secondary 设置被移除或重命名为 main
  • 尝试登录的用户有一个针对 secondaryidentify 记录,但该记录已不再配置。

使用 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 "user: #{u.username}\n   #{u.email}\n   last activity: #{u.last_activity_on}\n   #{identity.provider} ID: #{identity.id} external: #{identity.extern_uid}"
  puts "   all identities:"
  ui.each do |alli|
    puts "    - #{alli.provider} ID: #{alli.id} external: #{alli.extern_uid}"
  end
end;nil

您可以用如下两种方式解决此错误。

重命名到 LDAP 服务器的引用

当 LDAP 服务器是彼此的副本且受影响的用户应该能够使用配置的 LDAP 服务器进行登录时,此方案是非常合适的。比如,如果使用负载均衡来管理 LDAP 的高可用,而且不再需要单独的 secondary 登录选项。

note 如果 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 "Destroying identity: #{identity.id} #{identity.provider}: #{identity.extern_uid}"
  identity.destroy!
rescue => e
  puts 'Error generated when destroying identity:\n ' + e.to_s
end; nil

过期许可证引起多个 LDAP 服务器错误

使用多个 LDAP 服务器需要有效的许可证。过期的许可证可能会导致:

  • 在 web 页面上的 502 错误。
  • 日志中出现如下错误(实际的策略名称取决于 /etc/gitlab/gitlab.rb 中配置的名称):

    Could not find a strategy with name `Ldapsecondary'. Please ensure it is required or explicitly set it using the :strategy_class option. (Devise::OmniAuth::StrategyNotFound)
    

要解决此错误,您需要为极狐GitLab 实例应用新的许可证:

  1. 删除或注释掉所有非主 LDAP 服务器的极狐GitLab 配置行。
  2. 重新配置极狐GitLab以便它暂时仅使用一个 LDAP 服务器。
  3. 进入 Rails 控制台和添加许可证
  4. 在极狐GitLab 配置中重新启用额外的 LDAP 服务器并再次重新配置极狐GitLab。

用户从群组中被移除并被再次添加

如果在群组同步期间,有用户被添加到群组中,但是在下次同步期间被移除,而且这种情况重复发生,那么您需要确保用户没有多个或冗余的 LDAP 身份。

如果被添加的其中一个身份识别已经不再使用,您需要移除与移除的 LDAP 服务器相关的 identity 记录

调试工具

LDAP 检查

Rake 任务检查 LDAP 是一个极具价值的工作,能够帮助确定极狐GitLab 是否能够成功建立与 LDAP 的连接,以及是否能够读取用户。

如果连接未建立,可能是因为配置问题或被防火墙阻止。

  • 请确保您没有防火墙阻塞连接的问题,并且 LDAP 服务器能够被极狐GitLab 宿主机访问。
  • 在 Rake 检查输出中查看错误信息,这可以让您确认您的 LDAP 配置的值(特别是 hostportbind_dnpassword)是否正确。
  • 日志中查看错误信息以进一步调试连接失败问题。

如果极狐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' # remember to close this block with 'EOS' below
   main: # 'main' is the GitLab 'provider ID' of this LDAP server
     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_dnpasswordporthostbase 要与 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 控制台

caution 使用 Rails 控制台来创建、读取、修改和销毁数据是非常容易的。但是需要确保正确运行相关命令。

Rails 控制台是一个非常有价值的工具,可以帮助调试 LDAP 问题。它允许您通过运行命令和应用程序直接交互来查看极狐GitLab 是如何响应的。

关于如何使用 Rails 控制台的详细情况,参看此指南

启用调试输出

这提供了调试输出,展示了极狐GitLab 正在做什么以及处理哪些内容。该值不会被持久保存,仅在Rails控制台的当前会话中启用。

要在 Rails 控制台上启用调试输出,输入 Rails 控制台并运行:

Rails.logger.level = Logger::DEBUG

获取所有与群组、子群组、成员和请求者相关联的错误信息

手机与群组、子群组、成员和请求者相关的错误信息。这种方式捕获的错误信息不会显示在 Web 界面上。这在 LDAP 群组同步相关问题,以及处理用户及其在群组和子群组中的成员身份出现的异常行为时,格外有帮助。

# Find the group and subgroup
group = Group.find_by_full_path("parent_group")
subgroup = Group.find_by_full_path("parent_group/child_group")

# Group and subgroup errors
group.valid?
group.errors.map(&:full_messages)

subgroup.valid?
subgroup.errors.map(&:full_messages)

# Group and subgroup errors for the members AND requesters
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)

极狐GitLab 技术支持

如果您在迁移过程中遇到任何问题,您可以在极狐GitLab 官方论坛上发帖求助,您也可以直接扫描下方二维码咨询专业人员:

support-wechat