Repository: kimai/kimai (language: php)

Issue:
Built-in accounts cannot log in if ldap is also enabled
### Describe the issue

For installations which have built-in accounts (user db column type `kimai`) as well as ldap auth enabled. Only the LDAP users are able to log in.

This seems related to https://github.com/kimai/kimai/commit/92c6922afb625699322a0393cc31a7820f5216d9#diff-6e0fa87aa2dd10ec693f77efb0baded2b184c3d4b08ec20f52ddebfeac0c0660L87 where now all users are checked against LDAP source regardless of user auth source from the db.

This is happening since 2.4.0 

### I already tried

- [X] I've read and searched [the documentation](https://www.kimai.org/documentation/).
- [X] I've searched for similar issues in this repository.
- [X] I've searched for similar issues in [the discussions](https://github.com/kimai/kimai/discussions).

### Kimai version

2.4.0

### How do you run Kimai?

Virtual Server or alike

### Which PHP version are you using?

8.1

### Logfile

_No response_

### Screenshots

_No response_


Discussion / hints:

Fix patch:
diff --git a/src/Constants.php b/src/Constants.php
index 7a98d62939..403a1eee20 100644
--- a/src/Constants.php
+++ b/src/Constants.php
@@ -17,11 +17,11 @@ class Constants
     /**
      * The current release version
      */
-    public const VERSION = '2.4.0';
+    public const VERSION = '2.4.1';
     /**
      * The current release: major * 10000 + minor * 100 + patch
      */
-    public const VERSION_ID = 20400;
+    public const VERSION_ID = 20401;
     /**
      * The software name
      */
diff --git a/src/Ldap/FormLoginLdapFactory.php b/src/Ldap/FormLoginLdapFactory.php
index 3acf6bc6ea..682d780e29 100644
--- a/src/Ldap/FormLoginLdapFactory.php
+++ b/src/Ldap/FormLoginLdapFactory.php
@@ -10,6 +10,7 @@
 namespace App\Ldap;
 
 use App\Configuration\LdapConfiguration;
+use Psr\Log\LoggerInterface;
 use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
 use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
 use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -67,6 +68,7 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
             ->setArguments([
                 new Reference($authenticatorId),
                 new Reference(LdapConfiguration::class),
+                new Reference(LoggerInterface::class),
             ]);
 
         return $ldapAuthenticatorId;
diff --git a/src/Ldap/LdapAuthenticator.php b/src/Ldap/LdapAuthenticator.php
index ddc7694a67..6096cae7e4 100644
--- a/src/Ldap/LdapAuthenticator.php
+++ b/src/Ldap/LdapAuthenticator.php
@@ -10,6 +10,7 @@
 namespace App\Ldap;
 
 use App\Configuration\LdapConfiguration;
+use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -22,17 +23,19 @@
 
 final class LdapAuthenticator implements AuthenticationEntryPointInterface, InteractiveAuthenticatorInterface
 {
-    public function __construct(private AuthenticatorInterface $authenticator, private LdapConfiguration $configuration)
+    public function __construct(private AuthenticatorInterface $authenticator, private LdapConfiguration $configuration, private LoggerInterface $logger)
     {
     }
 
     public function supports(Request $request): bool
     {
-        if (!class_exists('Laminas\Ldap\Ldap')) {
+        if (!$this->configuration->isActivated()) {
             return false;
         }
 
-        if (!$this->configuration->isActivated()) {
+        if (!class_exists('Laminas\Ldap\Ldap')) {
+            $this->logger->debug('Failed loading LDAP authenticator, missing Laminas dependency');
+
             return false;
         }
 
diff --git a/src/Ldap/LdapCredentialsSubscriber.php b/src/Ldap/LdapCredentialsSubscriber.php
index 6037e5c020..8fdfb7ce94 100644
--- a/src/Ldap/LdapCredentialsSubscriber.php
+++ b/src/Ldap/LdapCredentialsSubscriber.php
@@ -62,12 +62,12 @@ public function onCheckPassport(CheckPassportEvent $event)
             throw new BadCredentialsException('The presented user needs to be a Kimai user.');
         }
 
-        // removing this code allows to upgrade from local to LDAP users
-        // if (!$user->isLdapUser()) {
-        //    return;
-        // }
-
         if (!$this->ldapManager->bind($user->getUserIdentifier(), $presentedPassword)) {
+            // if the login failed and the user is registered with "kimai" auth, simply return:
+            // the FormLogin authenticator will take over and the user can log in via internal database
+            if (!$user->isLdapUser()) {
+                return;
+            }
             throw new BadCredentialsException('The presented password is invalid.');
         }
 


Test patch: