LDAP Auth not invoked

Hi All,

I’m trying to join SuiteCRM with my company LDAP but it turns up that LDAP module not working at all.
I set my configurations in the file “.env.local”, something like that:

#Enable LDAP authentication
AUTH_TYPE=ldap
###> LDAP CONFIG ###
LDAP_HOST=‘myhost.example.local’
LDAP_PORT=389
LDAP_ENCRYPTION=tls
LDAP_PROTOCOL_VERSION=3
LDAP_REFERRALS=false
LDAP_DN_STRING=‘OU=…,DC=example,DC=local’
LDAP_QUERY_STRING=‘(memberOf=CN=…,OU=…,OU=…,OU=…,DC=example,DC=local)’
LDAP_SEARCH_DN=‘cn=user,ou=…,ou=…,ou=…,dc=example,dc=local’
LDAP_SEARCH_PASSWORD=‘*****’
###< LDAP CONFIG ###

###> LDAP AUTO CREATE CONFIG ###
LDAP_AUTO_CREATE=enabled
LDAP_PROVIDER_BASE_DN=‘DC=example,DC=local’
LDAP_PROVIDER_SEARCH_DN=‘cn=user,ou=…,ou=…,ou=…,dc=example,dc=local’
LDAP_PROVIDER_SEARCH_PASSWORD=‘******’
###< LDAP AUTO CREATE CONFIG ###

Trying to make an ldapsearch manually (within the server) it works (ldapsearch -x -b “dc=example,dc=local” -H ldap://myhost.example.local -D user -W) but when trying to login with SuiteCRM ui I cannot see any search to ldap server from logs (suitecrm.log) e.g: ldapauth is not invoked.

Has anyone had the same issues?
p.s: the version of SuiteCRM is 8.5.0 (ITA language) installed on Ubuntu 22.04 LTS.

Many thanks

  1. After changing .env or ldap.yaml, did you run bin/console cache:clear and then try to login ?
  2. From looking at the LDAP configuration page, the example shows LDAP_HOST=ldap is not quoted. An entry should show up in the log if this caused an error.
  3. The LDAP login is using Symfony PHP code, not necessarily calling ldapauth binary. You should check both logs (php_errors.log and suitecrm.log) for errors timestamped when you tried to login thru the login page and it failed.

Hi Chris, thanks for you response. In line my answers:

  1. After changing .env or ldap.yaml, did you run bin/console cache:clear and then try to login ?
  • Yes
  1. From looking at the LDAP configuration page, the example shows LDAP_HOST=ldap is not quoted. An entry should show up in the log if this caused an error.
  • I do not see any errors in /var/www/html/suitecrm/public/legacy/suitecrm.log
  1. The LDAP login is using Symfony PHP code, not necessarily calling ldapauth binary. You should check both logs (php_errors.log and suitecrm.log) for errors timestamped when you tried to login thru the login page and it failed.
  • I don’t have any file “php_errors.log”

Thanks, Emanuele

In SuiteCRM, in Admin / Diagnostics, get the phpinfo from there.
What does it say for the location of the php.ini file?
Inside that exact php.ini (there’s more than one), what does it say for the value of error_log?

The php configuration file path is “/etc/php/8.1/apache2/php.ini”. The “error_log” directive inside the file was commented out, now I uncommented it and set: error_log = php_errors.log.

  • Now, when I try to login with an ldap user, in the php_errors.log I see:

[11-Jan-2024 10:21:58 Europe/Rome] PHP Deprecated: Return type of Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag::getIterator() should either be compatible with IteratorAggregate::getIterator(): Traversable, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/suitecrm/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php on line 134
[11-Jan-2024 10:21:58 Europe/Rome] PHP Deprecated: Return type of Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/suitecrm/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php on line 144
[11-Jan-2024 10:21:58 Europe/Rome] PHP Deprecated: Return type of Symfony\Component\HttpFoundation\Session\Session::getIterator() should either be compatible with IteratorAggregate::getIterator(): Traversable, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/suitecrm/vendor/symfony/http-foundation/Session/Session.php on line 131
[11-Jan-2024 10:21:58 Europe/Rome] PHP Deprecated: Return type of Symfony\Component\HttpFoundation\Session\Session::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/suitecrm/vendor/symfony/http-foundation/Session/Session.php on line 141

  • It doesn’t seem to be an ldap error. Instead, in the file suitecrm.log I see this:

Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] current_language is: it_IT
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheAPC
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheWincache
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCachesMash
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheFile
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheMemory
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Using cache backend SugarCacheMemory, since 999 is less than 1000
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheMemcached
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheZend
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheMemcache
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Found cache backend SugarCacheRedis
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Found language file: en_us.lang.php
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Found language file: it_IT.lang.php
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query:SELECT id, name, symbol, conversion_rate FROM currencies WHERE status = ‘Active’ and deleted = 0
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query Execution Time:0.00021696090698242
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query:SELECT category, name, value FROM config
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query Execution Time:0.00015711784362793
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query:SELECT id FROM outbound_email WHERE type = ‘system’ AND deleted = 0
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query Execution Time:0.00013303756713867
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query:SELECT * FROM outbound_email WHERE id = ‘14e2b3a0-de0b-3fab-9738-6571f4953f5e’
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query Execution Time:9.8943710327148E-5
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Hook called: ::after_entry_point
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Including module specific hook file for custom/modules
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Including Ext hook file for custom/application
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Found language file: en_us.lang.php
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Found language file: it_IT.lang.php
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Hook called: Users::before_retrieve
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Including module specific hook file for custom/modules/Users
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Retrieve User : SELECT users.* FROM users WHERE users.id = ‘1’ AND users.deleted=0
Thu Jan 11 09:33:01 2024 [3915142][-none-][DEBUG] Limit Query:SELECT users.* FROM users WHERE users.id = ‘1’ AND users.deleted=0 Start: 0 count: 1
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query:SELECT users.* FROM users WHERE users.id = ‘1’ AND users.deleted=0 LIMIT 0,1
Thu Jan 11 09:33:01 2024 [3915142][-none-][INFO] Query Execution Time:0.00032210350036621
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Loading Preferences DB admin
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query:SELECT contents FROM user_preferences WHERE assigned_user_id=‘1’ AND category = ‘global’ AND deleted = 0
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query Execution Time:0.00020790100097656
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] get_user_array query: SELECT id, first_name, last_name, user_name FROM users WHERE 1=1 ORDER BY first_name, last_name ASC
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query:SELECT id, first_name, last_name, user_name FROM users WHERE 1=1 ORDER BY first_name, last_name ASC
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query Execution Time:0.00019311904907227
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query:SELECT u1.first_name, u1.last_name from users u1, users u2 where u1.id = u2.reports_to_id AND u2.id = ‘1’ and u1.deleted=0
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query Execution Time:0.00013995170593262
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] SugarBean[User].load_relationships, Loading relationship (reports_to_link).
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query:SELECT
ea.email_address,
ea.email_address_caps,
ea.invalid_email,
ea.opt_out,
ea.confirm_opt_in,
ea.date_created,
ea.date_modified,
ear.id,
ear.email_address_id,
ear.bean_id,
ear.bean_module,
ear.primary_address,
ear.reply_to_address,
ear.deleted
FROM email_addresses ea LEFT JOIN email_addr_bean_rel ear ON ea.id = ear.email_address_id
WHERE
ear.bean_module = ‘Users’
AND ear.bean_id = ‘1’
AND ear.deleted = 0
ORDER BY ear.reply_to_address, ear.primary_address DESC
Thu Jan 11 09:33:01 2024 [3915142][1][INFO] Query Execution Time:0.00032496452331543
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Hook called: Users::after_retrieve
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] --------------------------------------------> at cron.php <--------------------------------------------
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Using SugarCronJobs as CRON driver
Thu Jan 11 09:33:01 2024 [3915142][1][FATAL] Job runs too frequently, throttled to protect the system.
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Hook called: ::server_round_trip
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Calling MySQLi::disconnect()
Thu Jan 11 09:33:01 2024 [3915142][1][DEBUG] Calling MySQLi::disconnect()

  • It doesn’t seem to be calling the LDAP server at all.
  1. What happens when you set external_auth_only=0 (allow fallback to native username password login) and try to login?

  2. What happens when you set LDAP_AUTO_CREATE=enabled (enable auto create a Suite user who has an entry in LDAP and whose login is correct against their LDAP password) and try to login?

  1. I have already unchecked the “LDAP Only” option in the SuiteCRM UI for the domain user.

  2. In addition, I had also already set up (at the end of the file .env.local)

###> LDAP AUTO CREATE CONFIG ###
LDAP_AUTO_CREATE=enabled
LDAP_PROVIDER_BASE_DN=‘DC=example,DC=local’
LDAP_PROVIDER_SEARCH_DN=‘cn=user,ou=…,ou=…,ou=…,dc=example,dc=local’
LDAP_PROVIDER_SEARCH_PASSWORD=‘********’

Hello everyone, I am new here.
Apologies, I am only replying to report that I am in the same situation as Emanuele.

@emanuele @marcosegat Welcome!

  1. Which LDAP servers are you using? Microsoft? Linux OpenLDAP? Other?
  2. Would you try to copy the working LDAP config in this post, of course adapt the hostnames to your organizations, and post back your results:

OpenLDAP on linux

by "LDAP config " you mean the configuration of LDAP in linux?
ore the config in SuiteCRM?

Hello Chris,

I’m using Windows Server 2022 Std as Domain Controller.
The SuitCRM 8.5 is installed on Ubuntu 22.04-03 LTS.
Using “ldapsearch” I’m able to connect to my Domain but seems that SuitCRM don’t perform any LDAP queries (I don’t see ESTABLISHED connections. Domain Controller and SuiteCRM are in the same subnet both (10.10.80.0 /24) so no firewall rules doing problems).
My configuration on the SuiteCRM side using LDAP without TLS or SSL (it’s set to “none”) on standard port 389.
Below the .env.local file.

Note (if usefull): no problem with the SuiteCRM 7.14.2

Database connectionString

DATABASE_URL=“mysql://myUsername:myPassword@10.10.80.170:3306/suitecrm”

symfony/framework-bundle

#APP_ENV=prod
APP_ENV=qa

nelmio/cors-bundle

CORS_ALLOW_ORIGIN=^https?://(localhost|127.0.0.1)(:[0-9]+)?$

AUTH_TYPE

AUTH_TYPE=ldap

LDAP CONFIG

LDAP_HOST=‘mydomain.local’
LDAP_PORT=389
LDAP_ENCRYPTION=none
LDAP_PROTOCOL_VERSION=3
LDAP_REFERRALS=false
LDAP_DN_STRING=‘CN=myDomainUser,CN=Users,DC=mydomain,DC=local’
LDAP_QUERY_STRING=‘’
LDAP_SEARCH_DN=‘CN=myDomainUser,CN=Users,DC=mydomain,DC=local’
LDAP_SEARCH_PASSWORD=‘myDomainPassword’

LDAP AUTO CREATE CONFIG

LDAP_AUTO_CREATE=enabled
LDAP_PROVIDER_BASE_DN=‘CN=Users,DC=mydomain,DC=local’
LDAP_PROVIDER_SEARCH_DN=‘CN=myDomainUser,CN=Users,DC=mydomain,DC=local’
LDAP_PROVIDER_SEARCH_PASSWORD=‘myDomainPassword’
LDAP_PROVIDER_DEFAULT_ROLES=ROLE_USER
LDAP_PROVIDER_UID_KEY=‘’
LDAP_PROVIDER_FILTER=‘’

SAML CONFIG

SAML_AUTO_CREATE=disabled
SAML_USERNAME_ATTRIBUTE=uid
SAML_USE_ATTRIBUTE_FRIENDLY_NAME=true

symfony/lock

LOCK_DSN=flock

login throttling

LOGIN_THROTTLING_MAX_ATTEMPTS=5

login throttling

LOGIN_THROTTLING_IP_LOGIN_MAX_ATTEMPTS=50
LOGIN_THROTTLING_INTERVAL=“30 minutes”

Hi Chris, our LDAP server is a Microsoft AD.
It is very strange but by changing the .env.local file nothing happened. When I try to login in the UI with my domain user, it fails and I cannot see (on the log file ‘/var/www/html/suitecrm/public/legacy/suitecrm.log’) any attempt to reach my ldap server. It seems that the ldap connection does not start at all.

by "LDAP config " you mean the configuration of LDAP in linux?
ore the config in SuiteCRM?

The LDAP config on SuiteCRM.

@fraxx @marcosegat @emanuele
Would you check your LDAP settings in .env.local against the following detailed explanations of each of them, to make sure they’re what the LDAP login framework (of the version Suite is using) is expecting, and post back your results:

Fetching Users Using the LDAP User Provider

service

type: string default: ldap

This is the name of your configured LDAP client. You can freely choose the name, but it must be unique in your application and it cannot start with a number or contain white spaces.

base_dn

type: string default: null

This is the base DN for the directory

search_dn

type: string default: null

This is your read-only user’s DN, which will be used to authenticate against the LDAP server to fetch the user’s information.

search_password

type: string default: null

This is your read-only user’s password, which will be used to authenticate against the LDAP server to fetch the user’s information.

default_roles

type: array default: []

This is the default role you wish to give to a user fetched from the LDAP server. If you do not configure this key, your users won’t have any roles, and will not be considered as authenticated fully.

uid_key

type: string default: null

This is the entry’s key to use as its UID. Depends on your LDAP server implementation. Commonly used values are:

  • sAMAccountName (default)
  • userPrincipalName
  • uid

If you pass null as the value of this option, the default UID key is used sAMAccountName.

extra_fields

type: array default: null

Defines the custom fields to pull from the LDAP server. If any field does not exist, an \InvalidArgumentException will be thrown.

filter

type: string default: null

This key lets you configure which LDAP query will be used. The {uid_key} string will be replaced by the value of the uid_key configuration value (by default, sAMAccountName), and the {username} string will be replaced by the username you are trying to load.

For example, with a uid_key of uid, and if you are trying to load the user fabpot, the final string will be: (uid=fabpot).

If you pass null as the value of this option, the default filter is used ({uid_key}={username}).

To prevent LDAP injection, the username will be escaped.

The syntax for the filter key is defined by RFC4515.

Authenticating against an LDAP server

Authenticating against an LDAP server can be done using either the form login or the HTTP Basic authentication providers.

They are configured exactly as their non-LDAP counterparts, with the addition of two configuration keys and one optional key:

service

type: string default: ldap

This is the name of your configured LDAP client. You can freely choose the name, but it must be unique in your application and it cannot start with a number or contain white spaces.

dn_string

type: string default: {username}

This key defines the form of the string used to compose the DN of the user, from the username. The {username} string is replaced by the actual username of the person trying to authenticate.

For example, if your users have DN strings in the form uid=einstein,dc=example,dc=com, then the dn_string will be uid={username},dc=example,dc=com.

query_string

type: string default: null

This (optional) key makes the user provider search for a user and then use the found DN for the bind process. This is useful when using multiple LDAP user providers with different base_dn. The value of this option must be a valid search string (e.g. uid="{username}"). The placeholder value will be replaced by the actual username.

When this option is used, query_string will search in the DN specified by dn_string and the DN resulted of the query_string will be used to authenticate the user with their password. Following the previous example, if your users have the following two DN: dc=companyA,dc=example,dc=com and dc=companyB,dc=example,dc=com, then dn_string should be dc=example,dc=com.

Bear in mind that usernames must be unique across both DN, as the authentication provider won’t be able to select the correct user for the bind process if more than one is found.

DATABASE_URL="mysql://crm:xxxxxxxxxxxxxxxxxxxxxx@localhost/crm"


# https://docs.suitecrm.com/8.x/admin/configuration/ldap-configuration/#_enabling_ldap_authentication
# note: the `username` in suiteCrm must be the user's email

AUTH_TYPE=ldap
###> LDAP CONFIG ###
LDAP_HOST='ldap.myorg.it'
LDAP_PORT=389
# LDAP_PORT=636
LDAP_ENCRYPTION=tls
# LDAP_ENCRYPTION=none
LDAP_PROTOCOL_VERSION=3
LDAP_REFERRALS=false
LDAP_DN_STRING='ou=users,dc=myorg,dc=it'
LDAP_QUERY_STRING='mail={username}'
# here a user dedicate to just query LDAP (mandatory)
LDAP_SEARCH_DN='cn=crm_ldap_user_for_queries,ou=users,dc=myorg,dc=it'
LDAP_SEARCH_PASSWORD='xxxxxx'
###< LDAP CONFIG ###
# auto create users found in LDAP
#LDAP_AUTO_CREATE=enabled
#LDAP_PROVIDER_BASE_DN='cn=crm,ou=groups,dc=myorg,dc=it'
#LDAP_PROVIDER_SEARCH_DN=''
#LDAP_PROVIDER_SEARCH_PASSWORD=''
#LDAP_PROVIDER_DEFAULT_ROLES=ROLE_USER
#LDAP_PROVIDER_UID_KEY=''
#LDAP_PROVIDER_FILTER=''

I also have a note: Any change of that file needs:

cd documentroot
rm -rf cache/ 
bin/console cache:clear
systemctl restart  php-fpm 

Another note:

“Warning, the CA of the certificate of the ldap server should be copied locally in the crm server, and referenced by TLS_CACERT in file /etc/openldap/ldap.conf”

I think the last is the “key” to solve: apparently php uses the bash ldap utilities

Delete the line rm -rf cache/ public/legacy/cache/ from your note. These cache directories are not really cache, they in fact contain essential data such as documents, emails, pdfs, uploaded images.

essential data in the cache dir in documentroot?
are you sure?

You’re right, the v8 document root cache/ contents can be deleted, it’s the symfony cache. Should not touch the public/legacy/cache/, it has the essential data e.g. docs, images, etc:

1 Like

Clear symfony cache

From your instance root folder run bin/console cache:clear

bin/console cache:clear

If you don’t have access to the terminal you can also delete the contents of: /<path-to-your-project>/cache

  • Please make sure that apache / php have access to write to the cache folder
  • The above is not the legacy cache folder. Do not delete the /<path-to-your-project>/public/legacy/cache
1 Like

omg, I see now Session Directory configuration :: SuiteCRM Documentation where it says, as you said, Do not delete the /<path-to-your-project>/public/legacy/cache (must admit it’s pretty absurd to call cache a data folder

1 Like