title: Symfony 4. Authorization through LDAP. How to custom AuthenticationProvider?
body: <p>First, sorry for my english and english google-translate :)</p>
  <p>In russian: <a href="https://ru.stackoverflow.com/questions/1031596/symfony-4-%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D1%87%D0%B5%D1%80%D0%B5%D0%B7-ldap-%D0%9A%D0%B0%D0%BA-%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B8%D1%82%D1%8C-%D0%BA%D0%B0%D1%81%D1%82%D0%BE%D0%BC%D0%BD%D1%8B%D0%B9-authenticationprovid">https://ru.stackoverflow.com/questions/1031596/symfony-4-Авторизация-через-ldap-Как-подключить-кастомный-authenticationprovid</a></p>
  <p>My problem, that my LDAP server make authorize exclusively on dn received from Entry after search. That is, it searches by username:</p>
  <pre><code>$query: (samAccountName=AIvanov)
  </code></pre>
  <p>but authorizes only on the dn attribute:</p>
  <pre><code>$dn: CN=Ivanov Alxey,OU=Staff,OU=Users,OU=Company,DC=company,DC=local
  </code></pre>
  <p>And if there is a way how to use the configuration to specify a way to transfer from the custom UserProvider to the native LdapBindAuthenticationProvider data that you need to use not username from the token but take username from the object of this custom user:</p>
  <pre><code>$user-&gt;getUsername()
  </code></pre>
  <p>who will return this damn name and surname, I will be grateful.
  Because otherwise only the creation of CustomLdapBindAuthenticationProvider with which I came here.</p>
  <p>Used a manual: <a href="https://symfony.com/doc/current/security/custom_authentication_provider.html" rel="nofollow noreferrer">https://symfony.com/doc/current/security/custom_authentication_provider.html</a></p>
  <p>And I stopped on the fact that I don`t know what is the relation between my factory and the firewall, and I have an error in calling this factory of mine.</p>
  <p>So, following this manual, I created a custom authentication provider. I tried to inherit from native Ldap ... but its ldap property is private, so I just copied the entire Ldap to myself and renamed it to CustomLdapBindAuthenticationProvider. Changed there this one line because of which the whole fuss. Then I created his own factory by inheriting it from native FormLoginLdapFactory</p>
  <pre><code>class CustomFormLoginLdapFactory extends FormLoginLdapFactory {
      protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId) {
      $provider = 'security.authentication.provider.ldap_bind.'.$id;
      $definition = $container
          //-&gt;setDefinition($provider, new ChildDefinition('security.authentication.provider.ldap_bind'))
          -&gt;setDefinition($provider, new ChildDefinition(CustomLdapBindAuthenticationProvider::class))
          -&gt;replaceArgument(0, new Reference($userProviderId))
          -&gt;replaceArgument(1, new Reference('security.user_checker.'.$id))
          -&gt;replaceArgument(2, $id)
          -&gt;replaceArgument(3, new Reference($config['service']))
          -&gt;replaceArgument(4, $config['dn_string']);
      if (!empty($config['query_string'])) {
          $definition-&gt;addMethodCall('setQueryString', [$config['query_string']]);
      }
      
      return $provider;
  }
  </code></pre>
  <p>I included the service as indicated in the manual</p>
  <pre><code>App\Security\Authentication\Provider\CustomLdapBindAuthenticationProvider:
      arguments:
          $userProvider: '@Symfony\Component\Security\Core\User\UserProviderInterface'
          $ldap: '@Symfony\Component\Ldap\Ldap'
          $dnString: '{username}'
  </code></pre>
  <p>and so also tried (I have exactly the ChainUserProvider object passed in the first argument)</p>
  <pre><code>App\Security\Authentication\Provider\CustomLdapBindAuthenticationProvider:
      arguments:
          $userProvider: '@Symfony\Component\Security\Core\User\ChainUserProvider'
          $ldap: '@Symfony\Component\Ldap\Ldap'
          $dnString: '{username}'
  </code></pre>
  <p>And finally, I inserted a new method into the kernel (src/Kernel.php), I also took it from the manual:</p>
  <pre><code>public function build(ContainerBuilder $container)
  {
      $extension = $container-&gt;getExtension('security');
      $extension-&gt;addSecurityListenerFactory(new CustomFormLoginLdapFactory());
  }
  </code></pre>
  <p>but what to write in the firewalls block is not obvious to me and there are no instructions in the training manual.
  As a result, the original form_login_ldap does not work. an attempt to replace form_login_ldap with something similar similar, such as custom_form_login_ldap was unsuccessful, the symfony says that there can only be the original name in this part of the config.</p>
  <pre><code>firewalls:
      dev:
          pattern: ^/(_(profiler|wdt)|css|images|js)/
          security: false
      main:
          anonymous: true
          provider: chain_provider
          #http_basic: ~
          form_login_ldap:
              login_path: /login
              check_path: /login
              csrf_token_generator: security.csrf.token_manager
              service: 'Symfony\Component\Ldap\Ldap'
              dn_string: 'cn={username},OU=Staff,OU=Users,OU=Company,DC=company,DC=local'
  </code></pre>
  <p>when I run with this config:</p>
  <pre><code>Service &quot;security.authentication.provider.ldap_bind.main&quot;: The argument &quot;0&quot; doesn't exist. (1/1) OutOfBoundsException
  
  Service &quot;security.authentication.provider.ldap_bind.main&quot;: The argument &quot;0&quot; doesn't exist. in Definition.php line 275 at Definition-&gt;replaceArgument(0, object(Reference))in ResolveChildDefinitionsPass.php line 163 at ResolveChildDefinitionsPass-&gt;doResolveDefinition(object(ChildDefinition))in ResolveChildDefinitionsPass.php line 62 at ResolveChildDefinitionsPass-&gt;resolveDefinition(object(ChildDefinition))in ResolveChildDefinitionsPass.php line 43 at ResolveChildDefinitionsPass-&gt;processValue(object(ChildDefinition), true)in AbstractRecursivePass.php line 82
  </code></pre>
  <p>So, how to link the factory to the firewall section?</p>