title: symfony2 login_check and custom authentication provider
body: <p>I have the following code files from my project that works perfectly relating to custom authentication provider, and I can intercept the request in the authenticate(TokenInterface $token), I've put echo "it worked"; exit; to print the message on the screen to let me know that it entered authenticate() in the file AuthProvider.php.</p>
  
  <p>But the problem rises when I try to change the <strong>login_path:/login</strong> to <strong>login_path:/user/login</strong> and <strong>check_path:/login_check</strong> to <strong>check_path:/user/login_check</strong> and also modify the routing.yml to let UserBundle to have the prefix /user, then the code will work but it will not enter the <strong>authenticate()</strong>, but it will print <strong>"The presented password is invalid"</strong> instead of <strong>"Bad credentials"</strong>, how can I change the login_check &amp; check_path to other values otherthan login &amp; login_check respectively and to let my custom authentication provider works with the new settings?</p>
  
  <p><strong>// app/config/security.yml</strong></p>
  
  <pre><code>security:
      factories:
          - "%kernel.root_dir%/../src/FD/UserBundle/Resources/config/security_factories.yml"
  
      firewalls:
          checkpoint:
              pattern: ^/
              user: true
              form_login:
                  login_path: /login
                  check_path: /login_check
              logout:
                  path:   /logout
                  target: /
              anonymous: ~
  
      encoders:
          FD\UserBundle\Entity\User: sha512
  
      role_hierarchy:
          ROLE_ADMIN:       ROLE_USER
          ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
  
      providers:
           user_provider:
               id: user_provider_service
  
      access_control:
          - { path: ^/_internal, role: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
          - { path: ^/user/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
          - { path: ^/event/new, roles: ROLE_ADMIN }
          - { path: ^/hello, roles: ROLE_USER }
  </code></pre>
  
  <p><strong>// app/config/config.yml</strong></p>
  
  <pre><code>imports:
      - { resource: parameters.ini }
      - { resource: security.yml }
      - { resource: @UserBundle/Resources/config/services.yml }
  
  framework:
      #esi:             ~
      translator:      { fallback: %locale% }
      secret:          %secret%
      charset:         UTF-8
      router:          { resource: "%kernel.root_dir%/config/routing.yml" }
      form:            true
      csrf_protection: false
      validation: { enabled: true }
      #validation:      { enable_annotations: true }
      templating:      { engines: ['twig'] } #assets_version: SomeVersionScheme
      session:
          default_locale: %locale%
          auto_start:     true
  
  # Twig Configuration
  twig:
      debug:            %kernel.debug%
      strict_variables: %kernel.debug%
  
  # Assetic Configuration
  assetic:
      debug:          %kernel.debug%
      use_controller: false
      # java: /usr/bin/java
      filters:
          cssrewrite: ~
          # closure:
          #     jar: %kernel.root_dir%/java/compiler.jar
          # yui_css:
          #     jar: %kernel.root_dir%/java/yuicompressor-2.4.2.jar
  
  # Doctrine Configuration
  doctrine:
      dbal:
          default_connection:    default
          connections:
              default:      
                  driver:   %database_driver%
                  host:     %database_host%
                  port:     %database_port%
                  dbname:   %database_name%
                  user:     %database_user%
                  password: %database_password%
                  charset:  UTF8
                  mapping_types:
                      enum: string
                      set: string
                      blob: object
      orm:
          auto_generate_proxy_classes: %kernel.debug%    
          default_entity_manager:         default # The first defined is used if not set
          entity_managers:
              default:      
                  # The name of a DBAL connection (the one marked as default is used if not set)
                  connection: ~
                  mappings: # Required
                      FDHelloBundle: ~
                      UserBundle: { type: annotation }
  
        # mappings:
          #   FDHelloBundle: { type: yml, dir: Resources/config/doctrine/metadata/orm }         
  
  # Swiftmailer Configuration
  swiftmailer:
      transport: %mailer_transport%
      host:      %mailer_host%
      username:  %mailer_user%
      password:  %mailer_password%
  
  jms_security_extra:
      secure_controllers:  true
      secure_all_services: false
  
  services:
      fd_hello.twig.extension.debug:
          class:        Twig_Extension_Debug
          tags:
               - { name: 'twig.extension' }
  
      user_provider_service:
          class: FD\UserBundle\Security\User\UserProvider
  </code></pre>
  
  <p><strong>// app/config/routing.yml</strong></p>
  
  <pre><code>FDHelloBundle:
      resource: "@FDHelloBundle/Resources/config/routing.yml"
      prefix:   /
  
  FDUserBundle:
      resource: "@UserBundle/Controller"
      prefix:   /user
      type: annotation
  </code></pre>
  
  <p><strong>// src/FD/UserBundle/Controller/LoginController.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\Controller;
  
  use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  use Symfony\Component\Security\Core\SecurityContext;
  
  class LoginController extends Controller
  {
      /**
       * @Route("login", name="login")
       */
      public function loginAction()
      {
          $request = $this-&gt;getRequest();
          $session = $request-&gt;getSession();
  
          // get the login error if there is one
          $error = $session-&gt;get(SecurityContext::AUTHENTICATION_ERROR);
          $session-&gt;remove(SecurityContext::AUTHENTICATION_ERROR);
  
          return $this-&gt;render('UserBundle:Login:login.html.twig', array(
              // last username entered by the user
              'last_username' =&gt; $session-&gt;get(SecurityContext::LAST_USERNAME),
              'error'         =&gt; $error,
          ));
      }
  
      /**
       * @Route("login_check", name="login_check")
       */
      public function loginCheckAction()
      {
  
      }
  
      /**
       * @Route("logout", name="logout")
       */
      public function logoutAction()
      {
  
      }
  }
  </code></pre>
  
  <p><strong>// src/FD/UserBundle/DependencyInjection/Security/Factory/UserFactory.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\DependencyInjection\Security\Factory;
  
  use Symfony\Component\DependencyInjection\ContainerBuilder;
  use Symfony\Component\DependencyInjection\Reference;
  use Symfony\Component\DependencyInjection\DefinitionDecorator;
  use Symfony\Component\Config\Definition\Builder\NodeDefinition;
  use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
  
  class UserFactory implements SecurityFactoryInterface
  {
      public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
      {
          $providerId = 'security.authentication.provider.user.'.$id;
          $container
              -&gt;setDefinition($providerId, new DefinitionDecorator('user.security.authentication.provider'))
              -&gt;replaceArgument(0, new Reference($userProvider))
          ;
          $listenerId = 'security.authentication.listener.user.'.$id;
          $listener = $container-&gt;setDefinition($listenerId, new DefinitionDecorator('user.security.authentication.listener'));
  
          return array($providerId, $listenerId, $defaultEntryPoint);
      }
  
      public function getPosition()
      {
          return 'pre_auth';
      }
  
      public function getKey()
      {
          return 'user';
      }
  
      public function addConfiguration(NodeDefinition $node)
      {}
  }
  </code></pre>
  
  <p><strong>// FD/UserBundle/Resources/config/services.yml</strong></p>
  
  <pre><code>services:
      user.security.authentication.provider:
          class:  FD\UserBundle\Security\Authentication\Provider\AuthProvider
          arguments: ['', %kernel.cache_dir%/security/nonces]
  
      user.security.authentication.listener:
          class:  FD\UserBundle\Security\Firewall\AuthListener
  </code></pre>
  
  <p><strong>// FD/UserBundle/Resources/config/security_factories.yml</strong></p>
  
  <pre><code>services:
      security.authentication.factory.user:
          class:  FD\UserBundle\DependencyInjection\Security\Factory\UserFactory
          tags:
              - { name: security.listener.factory }
  </code></pre>
  
  <p><strong>// FD/UserBundle/Security/Authentication/Provider/AuthProvider.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\Security\Authentication\Provider;
  
  use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
  use Symfony\Component\Security\Core\User\UserProviderInterface;
  use Symfony\Component\Security\Core\Exception\AuthenticationException;
  use Symfony\Component\Security\Core\Exception\NonceExpiredException;
  use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  
  use FD\UserBundle\Security\Authentication\Token\UserToken;
  
  class AuthProvider implements AuthenticationProviderInterface
  {
      private $userProvider;
      private $cacheDir;
  
      public function __construct(UserProviderInterface $userProvider, $cacheDir)
      {
          $this-&gt;userProvider = $userProvider;
          $this-&gt;cacheDir     = $cacheDir;
      }
  
      public function authenticate(TokenInterface $token)
      {
  //        $user = $this-&gt;userProvider-&gt;loadUserByUsername($token-&gt;getUsername());
  //        $userToken = new UserToken();
  //        $userToken-&gt;setUser($user);
  echo "it worked"; exit;
          $newToken = new UserToken($token-&gt;getUser(), $token-&gt;getCredentials(), "user", array("ROLE_ADMIN"));
          $username = $newToken-&gt;getUser();
          if (empty($username)) {
              throw new BadCredentialsException('Bad credentials :)');
          }
          return $newToken;
  
  //        if ($user &amp;&amp; $this-&gt;validateDigest($token-&gt;digest, $token-&gt;nonce, $token-&gt;created, $user-&gt;getPassword())) {
  //            $authenticatedToken = new UserToken($user-&gt;getRoles());
  //            $authenticatedToken-&gt;setUser($user);
  //
  //            return $authenticatedToken;
  //        }
      }
  
      public function supports(TokenInterface $token)
      {
          return $token instanceof UserToken;
      }
  }
  </code></pre>
  
  <p><strong>// FD/UserBundle/Security/Authenticaion/Token/UserToken.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\Security\Authentication\Token;
  
  use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
  
  /**
   * UsernamePasswordToken implements a username and password token.
   *
   */
  
  class UserToken extends AbstractToken
  {
      private $credentials;
      private $providerKey;
  
      /**
       * Constructor.
       *
       * @param string $user        The username (like a nickname, email address, etc.)
       * @param string $credentials This usually is the password of the user
       * @param string $providerKey The provider key
       * @param array  $roles       An array of roles
       *
       * @throws \InvalidArgumentException
       */
      public function __construct($user, $credentials, $providerKey, array $roles = array())
      {
          parent::__construct($roles);
  
          if (empty($providerKey)) {
              throw new \InvalidArgumentException('$providerKey must not be empty.');
          }
  
          $this-&gt;setUser($user);
          $this-&gt;credentials = $credentials;
          $this-&gt;providerKey = $providerKey;
  
          parent::setAuthenticated(count($roles) &gt; 0);
      }
  
      /**
       * {@inheritdoc}
       */
      public function setAuthenticated($isAuthenticated)
      {
          if ($isAuthenticated) {
              throw new \LogicException('Cannot set this token to trusted after instantiation.');
          }
  
          parent::setAuthenticated(false);
      }
  
      public function getCredentials()
      {
          return $this-&gt;credentials;
      }
  
      public function getProviderKey()
      {
          return $this-&gt;providerKey;
      }
  
      /**
       * {@inheritdoc}
       */
      public function eraseCredentials()
      {
          parent::eraseCredentials();
  
          $this-&gt;credentials = null;
      }
  
      public function serialize()
      {
          return serialize(array($this-&gt;credentials, $this-&gt;providerKey, parent::serialize()));
      }
  
      public function unserialize($str)
      {
          list($this-&gt;credentials, $this-&gt;providerKey, $parentStr) = unserialize($str);
          parent::unserialize($parentStr);
      }
  }
  </code></pre>
  
  <p><strong>// FD/UserBundle/Security/Firewall/AuthListener.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\Security\Firewall;
  
  use Symfony\Component\HttpFoundation\Response;
  use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  use Symfony\Component\Security\Http\Firewall\ListenerInterface;
  use Symfony\Component\Security\Core\Exception\AuthenticationException;
  use Symfony\Component\Security\Core\SecurityContextInterface;
  use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
  use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
  use Symfony\Component\HttpFoundation\Request;
  use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
  use Symfony\Component\Security\Http\HttpUtils;
  
  
  use FD\UserBundle\Security\Authentication\Token\UserToken;
  
  class AuthListener extends AbstractAuthenticationListener
  {
      protected $securityContext;
      protected $authenticationManager;
      protected $httpUtils;
  
      public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager,
                                  SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $options = array())
      {
          parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, "user", array_merge(array(
              'username_parameter' =&gt; '_username',
              'password_parameter' =&gt; '_password',
              'intention' =&gt; 'authenticate',
              'post_only' =&gt; true,
          ), $options));
      }
  
      /**
       * Performs authentication.
       *
       * @param  Request $request A Request instance
       *
       * @return TokenInterface The authenticated token, or null if full authentication is not possible
       *
       * @throws AuthenticationException if the authentication fails
       */
      protected function attemptAuthentication(Request $request)
      {
  
          $username = trim($request-&gt;get($this-&gt;options['username_parameter'], null, true));
          $password = $request-&gt;get($this-&gt;options['password_parameter'], null, true);
  
          //$request-&gt;getSession()-&gt;set(SecurityContextInterface::LAST_USERNAME, $username);
  
          return $this-&gt;authenticationManager-&gt;authenticate(new UserToken($username, $password, $this-&gt;providerKey));
  
      }
  
      public function getHttpUtils()
      {
          return $this-&gt;httpUtils;
      }
  
      public function setHttpUtils($httpUtils)
      {
          $this-&gt;httpUtils = $httpUtils;
      }
  }
  </code></pre>
  
  <p><strong>// src/FD/UserBundle/Security/User/UserProvider.php</strong></p>
  
  <pre><code>namespace FD\UserBundle\Security\User;
  
  use Symfony\Component\Security\Core\User\UserProviderInterface;
  use Symfony\Component\Security\Core\User\UserInterface;
  use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
  use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
  
  use FD\UserBundle\Entity\User;
  
  class UserProvider implements UserProviderInterface
  {
      public function loadUserByUsername($username)
      {
          // make a call to your webservice here
          // $userData = ...
          // pretend it returns an array on success, false if there is no user
          $user = new User();
          $user-&gt;setUsername($username);
          $user-&gt;setPassword("1234");
          $user-&gt;setRoles(array("ROLE_ADMIN"));
  
          return $user;
  
  //        if ($userData) {
  //            // $password = '...';
  //            // ...
  //
  //            return new WebserviceUser($username, $password, $salt, $roles)
  //        } else {
  //            throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
  //        }
      }
  
      public function refreshUser(UserInterface $user)
      {
          if (!$user instanceof User) {
              throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
          }
  
          return $this-&gt;loadUserByUsername($user-&gt;getUsername());
      }
  
      public function supportsClass($class)
      {
          return $class === 'FD\UserBundle\Entity\User';
      }
  }
  </code></pre>