title: How to Integrate JCaptcha in Spring Security
body: <p>Before start answering I know there is ReCaptcha which is simpler and easier, but I can't use that. The production server is not online. So here we go.</p>
  
  <p>I'm using Spring mvc 3 with spring security on maven Project and weblogic as the web server (jetty while developing). I'll be very specific on this one.</p>
  
  <p>Before seeing my configurations and files, I'd like to show you the list of my problems:</p>
  
  <ul>
  <li>I've tried ReCaptcha before JCaptcha with the same coding structure and it works fine.</li>
  <li>logger.debug doesn't appear at all in CaptchaCaptureFilter class and/or CaptchaVerifierFilter class (while it appears in ArtajasaAuthenticationProvider class).</li>
  <li>I can see the captcha image, but whatever the answer is, it always invalid.</li>
  <li><p>With the current state, it doesn't work in jetty nor weblogic, but if I change the custom filter position to the one below, it works only in jetty.</p>
  
  <pre><code>&lt;custom-filter ref="captchaCaptureFilter" position="FIRST"/&gt;
  &lt;custom-filter ref="captchaVerifierFilter" after="FIRST"/&gt;
  </code></pre></li>
  </ul>
  
  <p>Thanks for viewing and many thanks for answering my question.
  Below are the details.</p>
  
  <p>The repository for JCaptcha is this one:</p>
  
  <pre><code>&lt;repository&gt;
          &lt;id&gt;sourceforge-releases&lt;/id&gt;
          &lt;name&gt;Sourceforge Releases&lt;/name&gt;
          &lt;url&gt;https://oss.sonatype.org/content/repositories/sourceforge-releases&lt;/url&gt;
      &lt;/repository&gt;
  
  &lt;dependency&gt;
          &lt;groupId&gt;com.octo.captcha&lt;/groupId&gt;
          &lt;artifactId&gt;jcaptcha-integration-simple-servlet&lt;/artifactId&gt;
          &lt;version&gt;2.0-alpha-1&lt;/version&gt;
      &lt;/dependency&gt;
  </code></pre>
  
  <p>Here are some configuration I made in .xml files:</p>
  
  <p>web.xml</p>
  
  <pre><code>&lt;context-param&gt;
      &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
      &lt;param-value&gt;
          /WEB-INF/applicationContext.xml
          /WEB-INF/spring/spring-security.xml
      &lt;/param-value&gt;
  &lt;/context-param&gt;
   &lt;listener&gt;
      &lt;listener-class&gt;org.springframework.security.web.session.HttpSessionEventPublisher&lt;/listener-class&gt;
  &lt;/listener&gt;
  
  &lt;filter&gt;
      &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
      &lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
  &lt;/filter&gt;
  
  &lt;filter-mapping&gt;
      &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
      &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
      &lt;dispatcher&gt;FORWARD&lt;/dispatcher&gt;
      &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
  &lt;/filter-mapping&gt;
  
  &lt;servlet&gt;
      &lt;servlet-name&gt;jcaptcha&lt;/servlet-name&gt;
      &lt;servlet-class&gt;com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
      &lt;servlet-name&gt;jcaptcha&lt;/servlet-name&gt;
      &lt;url-pattern&gt;/jcaptcha.jpg&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  </code></pre>
  
  <p>spring-security.xml</p>
  
  <pre><code>&lt;http auto-config="true" use-expressions="true"&gt;
      &lt;intercept-url pattern="/resources/**" access="permitAll()" /&gt;
      &lt;intercept-url pattern="/jcaptcha.jpg" access="permitAll()" /&gt;
      &lt;intercept-url pattern="/**" access="isAuthenticated()" /&gt;
  
      &lt;form-login login-page="/session/login/" default-target-url="/"
                  authentication-failure-url="/session/loginfailed/" /&gt;
      &lt;logout logout-success-url="/session/logout/" /&gt;
      &lt;access-denied-handler error-page="/session/403/" /&gt;
  
      &lt;!--JCaptcha Filtering--&gt;
      &lt;custom-filter ref="captchaCaptureFilter" before="FORM_LOGIN_FILTER"/&gt;
      &lt;custom-filter ref="captchaVerifierFilter" after="FORM_LOGIN_FILTER"/&gt;
      &lt;anonymous /&gt;
  &lt;/http&gt;
  
  &lt;!-- For capturing CAPTCHA fields --&gt;
  &lt;beans:bean id="captchaCaptureFilter" class="com.util.CaptchaCaptureFilter" /&gt;
  
  &lt;!-- For verifying CAPTCHA fields --&gt;
  &lt;!-- Private key is assigned by the JCaptcha service --&gt;
  &lt;beans:bean id="captchaVerifierFilter" class="com.util.CaptchaVerifierFilter"
        p:failureUrl="/session/loginfailed/"
        p:captchaCaptureFilter-ref="captchaCaptureFilter"/&gt;
  
  &lt;beans:bean id="customAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"&gt;
      &lt;beans:property name="sessionAuthenticationStrategy" ref="sas"/&gt;
      &lt;beans:property name="authenticationManager" ref="authenticationManager" /&gt;
      &lt;beans:property name="allowSessionCreation" value="true" /&gt;
  &lt;/beans:bean&gt;
  
  &lt;beans:bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"&gt;
      &lt;beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/&gt;
      &lt;beans:property name="maximumSessions" value="1" /&gt;
  &lt;/beans:bean&gt;
  
  &lt;beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /&gt;
  
  &lt;beans:bean id="userService" class="com.service.mybatis.UserManager" /&gt;
  
  &lt;beans:bean id="customAuthenticationProvider" class="com.util.ArtajasaAuthenticationProvider" /&gt;
  &lt;authentication-manager alias="authenticationManager"&gt;
      &lt;authentication-provider ref="customAuthenticationProvider" /&gt;
  &lt;/authentication-manager&gt;
  
  &lt;beans:bean id="accessDeniedHandler" class="com.util.ThouShaltNoPass"&gt;
      &lt;beans:property name="accessDeniedURL" value="/session/403/" /&gt;
  &lt;/beans:bean&gt;
  </code></pre>
  
  <p>And these are the java classes:</p>
  
  <p>ArtajasaAuthenticationProvider.java</p>
  
  <pre><code>public class ArtajasaAuthenticationProvider implements AuthenticationProvider {
  
  @Autowired
  private UserService userService;
  private Logger logger = LoggerFactory.getLogger(ArtajasaAuthenticationProvider.class);
  
  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      String username = String.valueOf(authentication.getPrincipal());
      String password = String.valueOf(authentication.getCredentials());
      logger.debug("Checking authentication for user {}", username);
      if (StringUtils.isBlank(username)
              || StringUtils.isBlank(password)) {
          throw new BadCredentialsException("No Username and/or Password Provided.");
      } else {
          Pengguna user = userService.select(username);
          if (user == null) {
              throw new BadCredentialsException("Invalid Username and/or Password.");
          }
          if (user.getPassword().equals(new PasswordUtil().generateHash(password, user.getSalt()))) {
              List&lt;GrantedAuthority&gt; authorityList = (List&lt;GrantedAuthority&gt;) userService.getAuthorities(user);
              return new UsernamePasswordAuthenticationToken(username, password, authorityList);
          } else {
              throw new BadCredentialsException("Invalid Username and/or Password.");
          }
      }
  }
  
  @Override
  public boolean supports(Class&lt;?&gt; authentication) {
      return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
  }
  }
  </code></pre>
  
  <p>CaptchaCaptureFilter.java</p>
  
  <pre><code>public class CaptchaCaptureFilter extends OncePerRequestFilter {
  
  protected Logger logger = Logger.getLogger(CaptchaCaptureFilter.class);
  private String userCaptchaResponse;
  private HttpServletRequest request;
  
  @Override
  public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                               FilterChain chain) throws IOException, ServletException {
  
      logger.debug("Captcha capture filter");
  
      // Assign values only when user has submitted a Captcha value.
      // Without this condition the values will be reset due to redirection
      // and CaptchaVerifierFilter will enter an infinite loop
      if (req.getParameter("jcaptcha") != null) {
          request = req;
          userCaptchaResponse = req.getParameter("jcaptcha");
      }
  
      logger.debug("userResponse: " + userCaptchaResponse);
  
      // Proceed with the remaining filters
      chain.doFilter(req, res);
  }
  
  public String getUserCaptchaResponse() {
      return userCaptchaResponse;
  }
  
  public void setUserCaptchaResponse(String userCaptchaResponse) {
      this.userCaptchaResponse = userCaptchaResponse;
  }
  
  public HttpServletRequest getRequest() {
      return request;
  }
  
  public void setRequest(HttpServletRequest request) {
      this.request = request;
  }
  }
  </code></pre>
  
  <p>CaptchaVerifierFilter.java</p>
  
  <pre><code>public class CaptchaVerifierFilter extends OncePerRequestFilter {
  
  protected Logger logger = Logger.getLogger(CaptchaVerifierFilter.class);
  private String failureUrl;
  private CaptchaCaptureFilter captchaCaptureFilter;
  
  // Inspired by log output: AbstractAuthenticationProcessingFilter.java:unsuccessfulAuthentication:320)
  // Delegating to authentication failure handlerorg.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@15d4273
  private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
  
  @Override
  public void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                               FilterChain chain) throws IOException, ServletException {
  
      logger.debug("Captcha verifier filter");
      logger.debug("userResponse: " + captchaCaptureFilter.getUserCaptchaResponse());
  
      // Assign values only when user has submitted a Captcha value
      if (captchaCaptureFilter.getUserCaptchaResponse() != null) {
  
          // Send HTTP request to validate user's Captcha
          boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(captchaCaptureFilter.getRequest(), captchaCaptureFilter.getUserCaptchaResponse());
  
          // Check if valid
          if (!captchaPassed) {
              logger.debug("Captcha is invalid!");
  
              // Redirect user to login page
              failureHandler.setDefaultFailureUrl(failureUrl);
              failureHandler.onAuthenticationFailure(req, res, new BadCredentialsException("Captcha invalid! " + captchaCaptureFilter.getRequest() + " " + captchaCaptureFilter.getUserCaptchaResponse()));
  
          } else {
              logger.debug("Captcha is valid!");
          }
  
          // Reset Captcha fields after processing
          // If this method is skipped, everytime we access a page
          // CaptchaVerifierFilter will infinitely send a request to the Google Captcha service!
          resetCaptchaFields();
      }
  
      // Proceed with the remaining filters
      chain.doFilter(req, res);
  }
  
  /**
   * Reset Captcha fields
   */
  public void resetCaptchaFields() {
      captchaCaptureFilter.setUserCaptchaResponse(null);
  }
  
  public String getFailureUrl() {
      return failureUrl;
  }
  
  public void setFailureUrl(String failureUrl) {
      this.failureUrl = failureUrl;
  }
  
  public CaptchaCaptureFilter getCaptchaCaptureFilter() {
      return captchaCaptureFilter;
  }
  
  public void setCaptchaCaptureFilter(CaptchaCaptureFilter captchaCaptureFilter) {
      this.captchaCaptureFilter = captchaCaptureFilter;
  }
  }
  </code></pre>
  
  <p>Last but not least, login.jsp</p>
  
  <pre><code>&lt;%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %&gt;
  
  &lt;form id="login" name="f" action="&lt;c:url value='/j_spring_security_check'/&gt;" method="POST"&gt;
    &lt;div class="container"&gt;
  
      &lt;div class="content"&gt;
          &lt;div class="row"&gt;
              &lt;div class="login-form"&gt;
                  &lt;h3&gt;Login&lt;/h3&gt;
                  &lt;br /&gt;
                    &lt;fieldset&gt;
                         &lt;div class="clearfix"&gt;
                              username: ecr
                              &lt;input type="text" name='j_username' value='&lt;c:if test="${not empty param.login_error}"&gt;&lt;c:out value="${SPRING_SECURITY_LAST_USERNAME}"/&gt;&lt;/c:if&gt;' placeholder="username@artajasa.co.id"&gt;
                         &lt;/div&gt;
                         &lt;div class="clearfix"&gt;
                             password: ecr123
                             &lt;input type="password" name='j_password' placeholder="password"&gt;
                         &lt;/div&gt;
                         &lt;div class="clearfix"&gt;
                             &lt;img src="../../jcaptcha.jpg" /&gt;
                             &lt;br /&gt;
                             &lt;input type="text" name="jcaptcha" placeholder="masukkan captcha" /&gt;
                         &lt;/div&gt;
                         &lt;br /&gt;
                         &lt;button class="btn btn-primary" type="submit"&gt;&lt;i class="icon-lock"&gt;&lt;/i&gt; Sign in&lt;/button&gt;
                     &lt;/fieldset&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
       &lt;br /&gt;
       &lt;c:if test="${not empty error}"&gt;
              &lt;div class="alert alert-error"&gt;
              &lt;button type="button" class="close" data-dismiss="alert"&gt;&lt;i class="icon-remove"&gt;&lt;/i&gt;&lt;/button&gt;
              Login Failed, try again.&lt;br /&gt;
              &lt;c:out value="${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}"/&gt;
              &lt;/div&gt;
            &lt;/c:if&gt;
    &lt;/div&gt;
  </code></pre>
  
  <p></p>