adapter=Gitlab::Auth::Ldap::Adapter.new('ldapmain')options={# :base is required# use .base or .group_basebase: adapter.config.group_base,# :filter is optional# 'cn' looks for all "cn"s under :base# '*' is the search string - here, it's a wildcardfilter: Net::LDAP::Filter.eq('cn','*'),# :attributes is optional# the attributes we want to get returnedattributes: %w(dn cn memberuid member submember uniquemember memberof)adapter.ldap_search(options)
When using OIDs in the filter, replace Net::LDAP::Filter.eq with Net::LDAP::Filter.construct:
adapter=Gitlab::Auth::Ldap::Adapter.new('ldapmain')options={# :base is required# use .base or .group_basebase: 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 directoryfilter: 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 returnedattributes: %w(dn cn memberuid member submember uniquemember memberof)adapter.ldap_search(options)
If you’ve confirmed that a connection to LDAP can be
established but GitLab doesn’t show you LDAP users in the output, one of the
following is most likely true:
The bind_dn user doesn’t have enough permissions to traverse the user tree.
Does the user pass through the configured user_filter?
If one is not configured, this question can be ignored. If it is, then the
user must also pass through this filter to be allowed to sign in.
If the above are both okay, the next place to look for the problem is
the logs themselves while reproducing the issue.
Ask the user to sign in and let it fail.
Look through the output for any errors or other
messages about the sign-in. You may see one of the other error messages on
this page, in which case that section can help resolve the issue.
If the logs don’t lead to the root of the problem, use the
rails console to query this user
to see if GitLab can read this user on the LDAP server.
There is a bug that
may affect users with Auditor level access. When
downgrading from Premium/Ultimate, Auditor users who try to sign in
may see the following message: Access denied for your LDAP account.
We have a workaround, based on toggling the access level of affected users:
On the left sidebar, at the bottom, select Admin Area.
Select Overview > Users.
Select the name of the affected user.
In the upper-right corner, select Edit.
Change the user’s access level from Regular to Administrator (or vice versa).
At the bottom of the page, select Save changes.
In the upper-right corner, select Edit again.
Restore the user’s original access level (Regular or Administrator)
and select Save changes again.
(LDAP) Error saving user <USER DN> (email@example.com): ["Email has already been taken"]
This error is referring to the email address in LDAP, email@example.com. Email
addresses must be unique in GitLab and LDAP links to a user’s primary email (as opposed
to any of their possibly-numerous secondary emails). Another user (or even the
same user) has the email email@example.com set as a secondary email, which
is throwing this error.
We can check where this conflicting email address is coming from using the
rails console. In the console, run the following:
# This searches for an email among the primary AND secondary emailsuser=User.find_by_any_email('email@example.com')user.username
This shows you which user has this email address. One of two steps must be taken here:
To create a new GitLab user/username for this user when signing in with LDAP,
remove the secondary email to remove the conflict.
To use an existing GitLab user/username for this user to use with LDAP,
remove this email as a secondary email and make it a primary one so GitLab
associates this profile to the LDAP identity.
The user can do either of these steps
in their profile or an administrator can do it.
Variables beginning with a $ refer to a variable from the LDAP section of
your configuration file.
Replace ldaps:// with ldap:// if you are using the plain authentication method.
Port 389 is the default ldap:// port and 636 is the default ldaps://
port.
We are assuming the password for the bind_dn user is in bind_dn_password.txt.
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
There’s a lot here, so let’s go over what could be helpful when debugging.
First, GitLab looks for all users that have previously
signed in with LDAP and iterate on them. Each user’s sync starts with
the following line that contains the user’s username and email, as they
exist in GitLab now:
Syncing user John, email@example.com
If you don’t find a particular user’s GitLab email in the output, then that
user hasn’t signed in with LDAP yet.
Next, GitLab searches its identities table for the existing
link between this user and the configured LDAP providers:
The identity object has the DN that GitLab uses to look for the user
in LDAP. If the DN isn’t found, the email is used instead. We can see that
this user is found in 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
If the user wasn’t found in LDAP with either the DN or email, you may see the
following message instead:
LDAP search error: No Such Object
…in which case the user is blocked:
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]]
After the user is found in LDAP, the rest of the output updates the GitLab
database with any changes.
On the left sidebar, at the bottom, select Admin Area.
On the left sidebar, select Overview > Users.
Search for the user.
Open the user by selecting their name. Do not select Edit.
Select the Identities tab. There should be an LDAP identity with
an LDAP DN as the Identifier. If not, this user hasn’t signed in with
LDAP yet and must do so first.
You’ve waited an hour or the configured interval for
the group to sync. To speed up the process, either go to the GitLab group Manage > Members
and press Sync now (sync one group) or run the group sync Rake task
(sync all groups).
If all of the above looks good, jump in to a little more advanced debugging in
the rails console.
Look through the output of the sync. See example log output
for how to read the output.
If you still aren’t able to see why the user isn’t being added, query the LDAP group directly
to see what members are listed.
Is the user’s DN or UID in one of the lists from the above output? One of the DNs or
UIDs here should match the ‘Identifier’ from the LDAP identity checked earlier. If it doesn’t,
the user does not appear to be in the LDAP group.
Administrator privileges not granted
When Administrator sync has been configured
but the configured users aren’t granted the correct administrator privileges, confirm
the following are true:
The configured admin_group in the gitlab.rb is a CN, rather than a DN or an array.
This CN falls under the scope of the configured group_base.
The members of the admin_group have already signed into GitLab with their LDAP
credentials. GitLab only grants administrator access to the users whose
accounts are already connected to LDAP.
If all the above are true and the users are still not getting access,
run a manual group sync in the rails console and
look through the output to see what happens when
GitLab syncs the admin_group.
# Find the group in questiongroup=Group.find_by(name: 'my_gitlab_group')# Look for errors on the Group itselfgroup.valid?group.errors.map(&:full_messages)# Look for errors among the group's members and requestersgroup.requesters.map(&:valid?)group.requesters.map(&:errors).map(&:full_messages)group.members.map(&:valid?)group.members.map(&:errors).map(&:full_messages)
A displayed error can identify the problem and point to a solution. For example, the Support Team has seen the following error:
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 'Settings > General' page, and check 'Restrict membership by email domain'."]]
This error showed that an Administrator chose to restrict group membership by email domain,
but there was a typo in the domain. After the domain setting was fixed, the Sync now button functioned again.
LDAP is required on the Sidekiq nodes because LDAP has multiple jobs that are
run asynchronously that require a local LDAP configuration:
User sync.
Group sync.
You can test whether missing LDAP configuration is the problem by running the Rake task to check LDAP
on each node that is running Sidekiq. If LDAP is set up correctly on this node, it connects to the LDAP server and returns users.
Indicates the point where syncing actually begins:
Started syncing 'ldapmain' provider for'my_group' group
The following entry shows an array of all user DNs GitLab sees in the LDAP server.
These DNs are the users for a single LDAP group, not a GitLab group. If
you have multiple LDAP groups linked to this GitLab group, you see multiple
log entries like this - one for each LDAP group. If you don’t see an LDAP user
DN in this log entry, LDAP is not returning the user when we do the lookup.
Verify the user is actually in the LDAP group.
Shortly after each of the above entries, you see a hash of resolved member
access levels. This hash represents all user DNs GitLab thinks should have
access to this group, and at which access level (role). This hash is additive,
and more DNs may be added, or existing entries modified, based on additional
LDAP group lookups. The very last occurrence of this entry should indicate
exactly which users GitLab believes should be added to the group.
10 is Guest, 20 is Reporter, 30 is Developer, 40 is Maintainer
and 50 is 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}
It’s not uncommon to see warnings like the following. These indicate that GitLab
would have added the user to a group, but the user could not be found in GitLab.
Usually this is not a cause for concern.
If you think a particular user should already exist in GitLab, but you’re seeing
this entry, it could be due to a mismatched DN stored in GitLab. See
User DN and email have changed to update the user’s LDAP identity.
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.
Finally, the following entry says syncing has finished for this group:
Finished syncing all providers for'my_group' group
When all the configured group links have been synchronized, GitLab looks
for any Administrators or External users to sync:
Syncing admin users for'ldapmain' provider
The output looks similar to what happens with a single group, and then
this line indicates the sync is finished:
If administrator sync is not configured, you see a message
stating as such:
No `admin_group` configured for'ldapmain' provider. Skipping
Sync one group
Syncing all groups can produce a lot of noise in the output, which can be
distracting when you’re only interested in troubleshooting the memberships of
a single GitLab group. In that case, here’s how you can just sync this group
and see its debug output:
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 LDAPEE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)
LDAP synchronization should remove an LDAP group’s creator
from that group, if that user does not exist in the group. If running LDAP synchronization
does not do this:
Add the user to the LDAP group.
Wait until LDAP group synchronization has finished running.
# Each entry must include the old username and the new emailemails={'ORIGINAL_USERNAME'=>'NEW_EMAIL_ADDRESS',emails.eachdo|username,email|user=User.find_by_username(username)user.email=emailuser.skip_reconfirmation!user.save!
You can then run a UserSync to sync the latest DN
for each of these users.
Could not authenticate from AzureActivedirectoryV2 because “Invalid grant”
ldap_identities=Identity.where(provider: "ldapsecondary")ldap_identities.eachdo|identity|puts"Destroying identity: #{identity.id}#{identity.provider}: #{identity.extern_uid}"identity.destroy!rescue=>eputs'Error generated when destroying identity:\n '+e.to_send;nil
Expired license causes errors with multiple LDAP servers
Using multiple LDAP servers requires a valid license. An expired license can
cause:
502 errors in the web interface.
The following error in logs (the actual strategy name depends on the name configured in /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)
To resolve this error, you must apply a new license to the GitLab instance without the web interface:
Remove or comment out the GitLab configuration lines for all non-primary LDAP servers.
Reconfigure GitLab so that it temporarily uses only one LDAP server.
The Rake task to check LDAP is a valuable tool
to help determine whether GitLab can successfully establish a connection to
LDAP and can get so far as to even read users.
If a connection can’t be established, it is likely either because of a problem
with your configuration or a firewall blocking the connection.
Ensure you don’t have a firewall blocking the
connection, and that the LDAP server is accessible to the GitLab host.
Look for an error message in the Rake check output, which may lead to your LDAP configuration to
confirm that the configuration values (specifically host, port, bind_dn, and
password) are correct.
Look for errors in the logs to further debug connection failures.
If there is an unexpected error during an LDAP lookup (configuration error,
timeout), the sign-in is rejected and a message is logged to production.log.
You can use the AdFind utility (on Windows based systems) to test that your LDAP server is accessible and authentication is working correctly. AdFind is a freeware utility built by Joe Richards.
Return all objects
You can use the filter objectclass=* to return all directory objects.
# Find the group and subgroupgroup=Group.find_by_full_path("parent_group")subgroup=Group.find_by_full_path("parent_group/child_group")# Group and subgroup errorsgroup.valid?group.errors.map(&:full_messages)subgroup.valid?subgroup.errors.map(&:full_messages)# Group and subgroup errors for the members AND requestersgroup.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)
to fix an error or add an improvement in a merge request. Create an issue
to suggest an improvement to this page.
View pricing
to see all GitLab tiers and features, or to upgrade. Try GitLab for free
with access to all features for 30 days. search the docs.
If you want help with something specific and could use community support,
post on the GitLab forum.
For problems setting up or using this feature (depending on your GitLab
subscription). Request support