title: Adding Captcha to Symfony2 Login Page
body: <p>I am new to Symfony2 but read about it very much.
  First of all, I am using symfony 2.1.7. And FOSUserBundle for user settings. I have already override fos_user-login template, with username and password. But I want to add a captcha for log in. I have seen GregwarCaptchaBundle, and according to document, new field should be added to FormType. And my question comes: Where is the symfony or FOSUserBundle login form type, that i can add this new field, or override it? There exists ChangePasswordFormType, ProfileFormType... etc. but no LoginFOrmType. May be it is so obvious but i did not get the point, Any help is welcomed please<br>
  <strong>QUESTION IS EDITED WITH A SOLUTION SOMEHOW</strong><br>
  Take a look at the comments below that Patt helped me.
  I have created a new form type with <code>_username</code>, <code>_password</code> and <code>captcha</code> fields. When naming for username and password begins with an underscore is enough for 'login_check' routing and Symfony authentication. However Symfony uses a listener for login process.
  Which is <code>UsernamePasswordFormAuthenticationListener</code>class. Although i've added captcha field in the Form type, it is always ignored during login process.(It is rendered on the page, but the field is never validated, it is simply ignored.)</p>
  
  <pre><code>public function buildForm(FormBuilderInterface $builder, array $options)
  {
      $builder
          -&gt;add('_username', 'email', array('label' =&gt; 'form.username', 'translation_domain' =&gt; 'FOSUserBundle')) // TODO: user can login with email by inhibit the user to enter username
          -&gt;add('_password', 'password', array(
          'label' =&gt; 'form.current_password',
          'translation_domain' =&gt; 'FOSUserBundle',
          'mapped' =&gt; false,
          'constraints' =&gt; new UserPassword()))
          -&gt;add('captcha', 'captcha');
  }
  </code></pre>
  
  <p>As i mentioned above <code>UsernamePasswordFormAuthenticationListener</code> class gets the form input values and then redirects you:</p>
  
  <pre><code>public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
  {
      parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
          'username_parameter' =&gt; '_username',
          'password_parameter' =&gt; '_password',
          'csrf_parameter'     =&gt; '_csrf_token',
          'captcha'           =&gt; 'captcha',
          'intention'          =&gt; 'authenticate',
          'post_only'          =&gt; true,
      ), $options), $logger, $dispatcher);
  
      $this-&gt;csrfProvider = $csrfProvider;
  }
  </code></pre>
  
  <p>captcha field is added.</p>
  
  <pre><code>protected function attemptAuthentication(Request $request)
  {
      if ($this-&gt;options['post_only'] &amp;&amp; 'post' !== strtolower($request-&gt;getMethod())) {
          if (null !== $this-&gt;logger) {
              $this-&gt;logger-&gt;debug(sprintf('Authentication method not supported: %s.', $request-&gt;getMethod()));
          }
  
          return null;
      }
  
      if (null !== $this-&gt;csrfProvider) {
          $csrfToken = $request-&gt;get($this-&gt;options['csrf_parameter'], null, true);
  
          if (false === $this-&gt;csrfProvider-&gt;isCsrfTokenValid($this-&gt;options['intention'], $csrfToken)) {
              throw new InvalidCsrfTokenException('Invalid CSRF token.');
          }
      }
  
     // check here the captcha value
      $userCaptcha = $request-&gt;get($this-&gt;options['captcha'], null, true);
      $dummy = $request-&gt;getSession()-&gt;get('gcb_captcha');
      $sessionCaptcha = $dummy['phrase'];
     // if captcha is not correct, throw exception
      if ($userCaptcha !== $sessionCaptcha) {
          throw new BadCredentialsException('Captcha is invalid');
      }
  
      $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 UsernamePasswordToken($username, $password, $this-&gt;providerKey));
  }
  </code></pre>
  
  <p>Now, i have captcha on login screen.
  Playing with symfony code is not a good way, i know. If i find out some way to override and call my own function, i'll post it.<br>
  <strong>ANOTHER USEFUL ANSWER</strong>  </p>
  
  <p>I found another answer that might be useful
  [link]<a href="https://stackoverflow.com/questions/8406001/is-there-any-sort-of-pre-login-event-or-similar?answertab=active#tab-top">Is there any sort of &quot;pre login&quot; event or similar?</a></p>
  
  <p>Following this solution, I have simply override <code>UsernamePasswordFormAuthenticationListener</code>class and override security listener <code>security.authentication.listener.form.class</code> parameter. Here goes the code:  </p>
  
  <pre><code>namespace TCAT\StaffBundle\Listener;
  
  use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener as BaseListener; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  
  
      class StaffLoginFormListener extends BaseListener
      {
          private $csrfProvider;
  
          /**
           * {@inheritdoc}
           */
          public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options
  = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
          {
              parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
                  'username_parameter' =&gt; '_username',
                  'password_parameter' =&gt; '_password',
                  'csrf_parameter'     =&gt; '_csrf_token',
                  'captcha'           =&gt; 'captcha',
                  'intention'          =&gt; 'authenticate',
                  'post_only'          =&gt; true,
              ), $options), $logger, $dispatcher);
  
              $this-&gt;csrfProvider = $csrfProvider;
          }
  
          /**
           * {@inheritdoc}
           */
          protected function attemptAuthentication(Request $request)
          {
              if ($this-&gt;options['post_only'] &amp;&amp; 'post' !== strtolower($request-&gt;getMethod())) {
                  if (null !== $this-&gt;logger) {
                      $this-&gt;logger-&gt;debug(sprintf('Authentication method not supported: %s.', $request-&gt;getMethod()));
                  }
  
                  return null;
              }
  
              if (null !== $this-&gt;csrfProvider) {
                  $csrfToken = $request-&gt;get($this-&gt;options['csrf_parameter'], null, true);
  
                  if (false === $this-&gt;csrfProvider-&gt;isCsrfTokenValid($this-&gt;options['intention'], $csrfToken)) {
                      throw new InvalidCsrfTokenException('Invalid CSRF token.');
                  }
              }
  
              // throw new BadCredentialsException('Bad credentials');
              $userCaptcha = $request-&gt;get($this-&gt;options['captcha'], null, true);
              $dummy = $request-&gt;getSession()-&gt;get('gcb_captcha');
              $sessionCaptcha = $dummy['phrase'];
  
              if ($userCaptcha !== $sessionCaptcha) {
                  throw new BadCredentialsException('Captcha is invalid');
              }
  
              $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 UsernamePasswordToken($username, $password, $this-&gt;providerKey));
          }
  
  
  
      }
  </code></pre>
  
  <p>and add <code>security.authentication.listener.form.class:      TCAT\StaffBundle\Listener\StaffLoginFormListener</code> line to the app/config/paramaters.yml
  BTW i can check my captcha value. I hope it all work for you.</p>