19 April 2015

Spring Security Login With Recaptcha

A few months ago I was asked to create a login with ReCaptcha using spring security core and recaptcha plugins. At that time I made a plugin for solving the requirement Spring Security Plugin Recaptcha. Today I want to share another idea to accomplish this.

Assuming the application has ReCaptcha and spring security core the first thing to do is add the ReCaptcha widget our loginview, usually auth.gsp.

	
<p>
	<label for='username'><g:message code="springSecurity.login.username.label"/>:</label>
	<input type='text' class='text_' name='j_username' id='username'/>
</p>

<p>
	<label for='password'><g:message code="springSecurity.login.password.label"/>:</label>
	<input type='password' class='text_' name='j_password' id='password'/>
</p>

<p>
	<recaptcha:ifEnabled>
		<recaptcha:recaptcha  theme="clean"/>
		<recaptcha:ifFailed>CAPTCHA Failed</recaptcha:ifFailed>
		</recaptcha:ifEnabled>
</p>

Then generate a filter (AuthFilter.groovy) to override the 'authenticationProcessingFilter' bean (this filter subclasses the plugin's RequestHolderAuthenticationFilter to Maintain its functionality). You can name this filter as you like and put it under /src/groovy folder.


import com.megatome.grails.RecaptchaService
import grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException

import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.web.context.request.RequestContextHolder

import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class AuthFilter extends RequestHolderAuthenticationFilter {
	private String recaptcha_response
	private String recaptcha_challenge
	private String remoteAddr
	private String failureUrl

	RecaptchaService recaptchaService

	private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler()

	@Override
	Authentication attemptAuthentication(HttpServletRequest request, 	HttpServletResponse response) throws AuthenticationException {
			def session = RequestContextHolder.currentRequestAttributes().getSession()

			recaptcha_response = request.getParameter("recaptcha_response_field")
			recaptcha_challenge = request.getParameter("recaptcha_challenge_field")
			remoteAddr = request.getRemoteAddr()

			Map params = ["recaptcha_response_field": recaptcha_response, "recaptcha_challenge_field": recaptcha_challenge]

			// Check if valid
			if (!recaptchaService.verifyAnswer(session, remoteAddr, params)) {
				// Redirect user to login page
				failureHandler.setDefaultFailureUrl(failureUrl)
				failureHandler.onAuthenticationFailure(request, response, new BadCredentialsException("Captcha invalid!"))
				return
			}

			super.attemptAuthentication(request, response)
	}

	public void setFailureUrl(String failureUrl) {
		this.failureUrl = failureUrl
	}
}

Finally, we will register this bean in our resources.groovy as follows:


beans = {
	authenticationProcessingFilter (AuthFilter) {
		def conf = SpringSecurityUtils.securityConfig
		authenticationManager = ref('authenticationManager')
		failureUrl = conf.failureHandler. defaultFailureUrl
		recaptchaService = ref('recaptchaService')
		storeLastUsername  = conf.apf.storeLastUsername
  }
}

Once done, we can use our ReCaptcha widget as part of our authentication process.

I hope this has been helpful.