Announcement Announcement Module
Collapse
No announcement yet.
Integrating JCaptcha with authentication Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Integrating JCaptcha with authentication

    I have an application using both authentication (working in a similar way as that outlined in Bart van Riel's article) and captcha via JCaptcha (implemented separately, using a channelProcessingFilter, similar to that described in Spring framework + Acegi Security captcha layer + JCaptcha integration).

    So far so good (apart from the fact that the JCaptcha stuff results in regular server crashes and core dumps on my Windows Vista machine!).

    However, the authentication and captcha components are entirely separate, with one page for the login form, and a different one for the captcha form. They each have different filters for identifiying resources that need the appropriate captcha or login, different contexts for the httpSessionContextIntegrationFilter (actually I have to set the context property to CaptchaSecurityContextImpl) , different entry points etc.

    What I really want to do is have captcha and login combined, so that I can specify if a resource requires both of these, then the user gets a single form with both captcha and login details that they need to complete in order to access the resource.

    What would be the best way to do this?

    *By the way, I did get it half working by placing captchaValidationProcessingFilter & channelProcessingFilter before the authenticationProcessingFilter, making the JCaptcha form also contain the login detail fields, and getting the user to submit to j_acegi_security_check (i.e. the normal authentication URL) with the user's answer to the captcha image set in j_captcha_response. This worked, except a) on successful login & captcha it did not redirect the user to the page they originally asked for (presumably because the filter that is responsible for redirecting the user to the login form had not been invoked) and b) if login was ok but captcha failed, it did not return the captcha/login page again. In both cases, the user was returned to the base URL of the app.
    Last edited by jcavell; May 29th, 2007, 11:46 AM.

  • #2
    Integrating the JCaptcha with Acegi security using the filter chain is a bit complex. Also there is problem in having the captcha validation field along with other form fields.

    A more simpler approach is to integrate JCaptcha at the controller level, without using Acegi Security, if that approach works for you.

    URL Mapping
    Code:
    <bean id=urlMapping class="...">
      <!-- Controller which produces the captcha image -->
      <entry key="captchaImage.do">
         <ref bean="captchaImageController"/>
      </entry>
    
      <!-- Controller which handles the form containing captcha as just 
             another field -->
      <entry key="/captchaForm.do>
        <ref bean="captchaFormController"/>
      </entry> 
    </bean>
    
    <!-- Controller producing the captcha image -->
    <bean id="captchaImageController" class="MyCaptchaImageController>
      <property name="captchaService" ref="captchaService"/>
    </bean>  
    
    <!-- Captcha Service -->
    <bean id="capthcaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService"/>
    
    <!-- Form controller to handle the form submissions containing the captcha
          image along with other information -->
    <bean id="captchaFormController" class="MyCapthaFormController">
       <property name="captchaService" ref="captchaService"/>
    
       <!-- The view containing captcha image and validation field -->
       <property name="formView" value="/catchaForm"/>
    
       <!-- The view shown *if* user entered correct captcha id and captcha
               validation is successful -->
       <property name="successView" value="/captchaProtected"/>
       <property name="commandClass" value="CaptchaFormBean"/>
    </bean>
    MyCaptchaImageController
    Code:
    public class MyCaptchaImageController extends AbstractController {
        public ModelAndView handleRequestInternal(HttpServletRequest request,
                                                                   HttpServletResponse response)
            throws Exception {
    
            String captchaId = request.getSession().getId();
            BufferedImage challenge = captchaService
                .getImageChallengeForID(captchaId, request.getLocale());
    
            ByteArrayOutputStream bstream = new ByteArrayOutputStream();
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bstream);
            encoder.encode(challenge);
    
            byte[] img = bstream.toByteArray();
    
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
    
            OutputStream out = response.getOutputStream();
            out.write(img);
            out.flush();
            out.close();
    
            return null;
        }
    MyCaptchaFormController
    Code:
    public class MyCaptchaFormController extends SimpleFormController {
        protected ModelAndView onSubmit(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Object command, BindException errors)
            throws Exception {
       
            // ... Do the form submit actions here ....
       }
    
       protected void onBindAndValidate(HttpServletRequest request,
                                         Object command,
                                         BindException errors) throws Exception {
            validateCaptcha(request, command, errors);
        }
    
       /**
         * Validate the captcha response
         */
        protected void validateCaptcha(HttpServletRequest request,
                                       Object command,
                                       BindException errors) throws Exception {
            String captchaId = request.getSession().getId();
            String response  = ((CaptchaFormBean) command).getCaptchaResponse();
    
            if (LOG.isDebugEnabled()) {
                LOG.debug("Validating captcha response: '" + response + "'");
            }
            boolean okay = false;
            if (StringUtils.isNotBlank(response)) {
                try {
                    okay = captchaService.validateResponseForID(captchaId,
                                                                response);
                } catch (CaptchaServiceException ex) {
                    LOG.error("Captcha exception: " + ex);
                }            
            }
            if (!okay) {
                errors.rejectValue("captchaResponse",
                                   "err.invalid.captcha.entry"
                                   "Invalid Entry");
            }
        }
    }
    This way, I find it a lot simpler to integrate the JCaptcha. Since the captcha validation is handled at the controller level, it is much easier to provide nicer error messages etc.

    -- suresh --

    Comment


    • #3
      Thanks sureshpw, that helped me a lot.

      Comment


      • #4
        can you post CaptchaFormBean?

        a have a problem with ((CaptchaFormBean) command).getCaptchaResponse();

        Comment


        • #5
          Spring and JCaptcha

          Chk this out
          http://springkbase.blogspot.com/2009...-jcaptcha.html

          Comment

          Working...
          X