The OpenLDAP project maintains a command-line LDAP query utility called ldapsearch
which can be run on a system hosting an Explorer or console, and used to check LDAP credential information against the LDAP server.
Note: Apple ships an old version of ldapsearch
with macOS Sonoma (14.0) and below. It’s so old that it won’t connect using TLS 1.2 or 1.3, which means it won’t talk to many recent LDAP servers. You can install a newer version using HomeBrew (brew install openldap
), but note that the binary ends up in /opt/homebrew/opt/openldap/bin/ldapsearch
and isn’t placed in your path, so as not to clash with the system-provided one.
One of the things that makes LDAP “lightweight” is that it doesn’t define many standard attributes, so attribute names and syntax can vary a lot between implementations.
Here’s a typical command to test looking up data from an LDAP server using OpenLDAP client tools:
ldapsearch -D "uid=root,cn=users,dc=ldapserver,dc=example,dc=com" -w "password-goes-here" \
-H ldap://apollo.local:389/ -b "dc=orgunit,dc=example,dc=com" -s sub -z 1 -x "(objectClass=*)"
Here’s what the parameters mean:
-D
specifies the bind DN. This is effectively the username to log in as. In this case it’suid=root,cn=users,dc=ldapserver,dc=example,dc=com
, a hierarchical DN under the base DN. It may not be in that format, though — the format depends on the LDAP server and how it has been set up.-w
specifies the password on the command line as the next parameter. Alternatively,-W
will make the client prompt for the password.-H
specifies the URL of the LDAP server to connect to. Typicallyldap
is on port 389,ldaps
is on port 636. (Same format runZero expects.)-b
specifies the base DN. This specifies the highest level of the directory that we want to query. In this case it’sdc=orgunit,dc=example,dc=com
because the directory setup was generated from a DNS domain using domain components (dc). It’s also common to see X.500 style DNs such asou=department,c=US,o=companyname
with organizational unit, country, and organization elements.-s sub
specifies that the search scope should be the subtree underneath the base DN.-x
specifies use of simple authentication rather than SASL.-z 1
specifies that we only want one sample result back, no matter how many matches there are.The final parameter is the search query. All objects in an LDAP directory are required to have an
objectClass
to specify what type of object they are, so this query matches the entire contents of the directory.
The result should be some LDIF output with comments on lines starting with #
, and some useful data on the non-comment lines. For example:
# extended LDIF
#
# LDAPv3
# base <dc=ldapserver,dc=example,dc=com> with scope subtree
# filter: (objectClass=*)
# requesting: ALL
#
# ldapserver.example.com
dn: dc=ldapserver,dc=example,dc=com
dc: ldapserver
objectClass: domain
# search result
search: 2
result: 4 Size limit exceeded
# numResponses: 2
# numEntries: 1
In the above example we’re getting the first result in the directory, which is typically the object representing the LDAP server itself.
If you don’t get any output, here are some things to try:
- Check the hostname in the LDAP server URL resolves.
- Check the port and protocol in the URL are correct.
- Check the username syntax.
- Try with
-v
for verbose, to see if there are any clues.
If you get TLS errors (in any of the runZero logs or from ldapsearch), you can debug TLS with certigo or openssl's s_client
command:
openssl s_client -connect servername:636
certigo connect servername:636
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article