Add reCaptcha as default implementation
Add support for enabling and disabling captcha
This commit is contained in:
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.controller;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
import com.octo.captcha.service.image.ImageCaptchaService;
|
||||
|
||||
import com.sun.image.codec.jpeg.JPEGCodec;
|
||||
import com.sun.image.codec.jpeg.JPEGImageEncoder;
|
||||
|
||||
public class CaptchaController
|
||||
implements Controller, InitializingBean
|
||||
{
|
||||
private ImageCaptchaService captchaService;
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
byte[] captchaChallengeAsJpeg;
|
||||
// the output stream to render the captcha image as jpeg into
|
||||
final ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
// get the session id that will identify the generated captcha.
|
||||
//the same id must be used to validate the response, the session id is a good candidate!
|
||||
final String captchaId = request.getSession().getId();
|
||||
|
||||
// call the ImageCaptchaService getChallenge method
|
||||
final BufferedImage challenge = captchaService.getImageChallengeForID(captchaId,request.getLocale());
|
||||
|
||||
// a jpeg encoder
|
||||
final JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
|
||||
jpegEncoder.encode(challenge);
|
||||
|
||||
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
|
||||
|
||||
// flush it in the response
|
||||
response.setHeader("Cache-Control", "no-store");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
response.setContentType("image/jpeg");
|
||||
final ServletOutputStream responseOutputStream = response.getOutputStream();
|
||||
responseOutputStream.write(captchaChallengeAsJpeg);
|
||||
responseOutputStream.flush();
|
||||
responseOutputStream.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Set captcha service
|
||||
* @param captchaService The captchaService to set.
|
||||
*/
|
||||
public void setCaptchaService(ImageCaptchaService captchaService) {
|
||||
this.captchaService = captchaService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet()
|
||||
throws Exception
|
||||
{
|
||||
if(captchaService == null){
|
||||
throw new RuntimeException("captcha service wasn`t set!");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.controller;
|
||||
|
||||
import com.octo.captcha.service.CaptchaServiceException;
|
||||
import com.octo.captcha.service.image.ImageCaptchaService;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.servlet.mvc.SimpleFormController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Convenient superclass for form controller implementations which need
|
||||
* CAPTCHA support.
|
||||
*/
|
||||
public class CaptchaFormController extends SimpleFormController {
|
||||
/**
|
||||
* Default paramter name for CAPTCHA response in <code>{@link HttpServletRequest}</code>
|
||||
*/
|
||||
private static final String DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME = "j_captcha_response";
|
||||
|
||||
protected ImageCaptchaService captchaService;
|
||||
protected String captchaResponseParameterName = DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME;
|
||||
|
||||
/**
|
||||
* Delegates request to CAPTCHA validation, subclasses which overrides this
|
||||
* method must manually call <code>{@link #validateCaptcha(HttpServletRequest,BindException)}</code>
|
||||
* or explicitly call super method.
|
||||
*
|
||||
* @see #validateCaptcha(HttpServletRequest,BindException)
|
||||
* @see org.springframework.web.servlet.mvc.BaseCommandController#onBindAndValidate(javax.servlet.http.HttpServletRequest,java.lang.Object,org.springframework.validation.BindException)
|
||||
*/
|
||||
@Override
|
||||
protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors) throws Exception {
|
||||
validateCaptcha(request, errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate CAPTCHA response, if response isn`t valid creates new error object
|
||||
* and put him to errors holder.
|
||||
*
|
||||
* @param request current servlet request
|
||||
* @param errors errors holder
|
||||
*/
|
||||
protected void validateCaptcha(HttpServletRequest request, BindException errors) {
|
||||
boolean isResponseCorrect = false;
|
||||
|
||||
//remenber that we need an id to validate!
|
||||
String captchaId = request.getSession().getId();
|
||||
//retrieve the response
|
||||
String response = request.getParameter(captchaResponseParameterName);
|
||||
//validate response
|
||||
try {
|
||||
if (response != null) {
|
||||
isResponseCorrect =
|
||||
captchaService.validateResponseForID(captchaId, response);
|
||||
}
|
||||
} catch (CaptchaServiceException e) {
|
||||
//should not happen, may be thrown if the id is not valid
|
||||
}
|
||||
|
||||
if (!isResponseCorrect) {
|
||||
//prepare object error, captcha response isn`t valid
|
||||
// String objectName = "Captcha";
|
||||
// String[] codes = {"invalid"};
|
||||
// Object[] arguments = {};
|
||||
// String defaultMessage = "Wrong control text!";
|
||||
// ObjectError oe = new ObjectError(objectName, codes, arguments, defaultMessage);
|
||||
//
|
||||
// errors.addError(oe);
|
||||
errors.rejectValue("captcha", Messages.CAPTCHA_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set captcha service
|
||||
*
|
||||
* @param captchaService the captchaService to set.
|
||||
*/
|
||||
public void setCaptchaService(ImageCaptchaService captchaService) {
|
||||
this.captchaService = captchaService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set paramter name for CAPTCHA response in <code>{@link HttpServletRequest}</code>
|
||||
*
|
||||
* @param captchaResponseParameterName the captchaResponseParameterName to set.
|
||||
*/
|
||||
public void setCaptchaResponseParameterName(String captchaResponseParameterName) {
|
||||
this.captchaResponseParameterName = captchaResponseParameterName;
|
||||
}
|
||||
}
|
||||
|
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.controller;
|
||||
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.service.UserService;
|
||||
import com.wisemapping.view.UserBean;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class UserController
|
||||
extends CaptchaFormController {
|
||||
|
||||
//~ Instance fields ......................................................................................
|
||||
|
||||
private boolean emailConfirmEnabled;
|
||||
private UserService userService;
|
||||
|
||||
//~ Methods ..............................................................................................
|
||||
|
||||
|
||||
public boolean isEmailConfirmEnabled() {
|
||||
return emailConfirmEnabled;
|
||||
}
|
||||
|
||||
public void setEmailConfirmEnabled(boolean emailConfirmEnabled) {
|
||||
this.emailConfirmEnabled = emailConfirmEnabled;
|
||||
}
|
||||
|
||||
public ModelAndView onSubmit(Object command) throws WiseMappingException {
|
||||
final UserBean userBean = ((UserBean) command);
|
||||
|
||||
if (userBean != null) {
|
||||
final User user = new User();
|
||||
// trim() the email email in order to remove spaces
|
||||
user.setEmail(userBean.getEmail().trim());
|
||||
user.setUsername(userBean.getUsername());
|
||||
user.setFirstname(userBean.getFirstname());
|
||||
user.setLastname(userBean.getLastname());
|
||||
user.setPassword(userBean.getPassword());
|
||||
userService.createUser(user,emailConfirmEnabled);
|
||||
}
|
||||
|
||||
final Map<String,Object> model = new HashMap<String,Object>();
|
||||
model.put("confirmByEmail",emailConfirmEnabled);
|
||||
return new ModelAndView(getSuccessView(),model);
|
||||
}
|
||||
|
||||
public void setUserService(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.wisemapping.controller;
|
||||
|
||||
import com.wisemapping.model.User;
|
||||
import com.wisemapping.service.UserService;
|
||||
import com.wisemapping.view.UserBean;
|
||||
import com.wisemapping.exceptions.WiseMappingException;
|
||||
import net.tanesha.recaptcha.ReCaptcha;
|
||||
import net.tanesha.recaptcha.ReCaptchaResponse;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class UserRegistrationController
|
||||
extends BaseSimpleFormController {
|
||||
|
||||
//~ Instance fields ......................................................................................
|
||||
|
||||
private boolean emailConfirmEnabled;
|
||||
private UserService userService;
|
||||
private ReCaptcha captchaService;
|
||||
private boolean captchaEnabled;
|
||||
|
||||
//~ Methods ..............................................................................................
|
||||
|
||||
|
||||
public boolean isEmailConfirmEnabled() {
|
||||
return emailConfirmEnabled;
|
||||
}
|
||||
|
||||
public void setEmailConfirmEnabled(boolean emailConfirmEnabled) {
|
||||
this.emailConfirmEnabled = emailConfirmEnabled;
|
||||
}
|
||||
|
||||
public ModelAndView onSubmit(@Nullable Object command) throws WiseMappingException {
|
||||
final UserBean userBean = ((UserBean) command);
|
||||
|
||||
if (userBean != null) {
|
||||
final User user = new User();
|
||||
// trim() the email email in order to remove spaces
|
||||
user.setEmail(userBean.getEmail().trim());
|
||||
user.setUsername(userBean.getUsername());
|
||||
user.setFirstname(userBean.getFirstname());
|
||||
user.setLastname(userBean.getLastname());
|
||||
user.setPassword(userBean.getPassword());
|
||||
userService.createUser(user, emailConfirmEnabled);
|
||||
}
|
||||
|
||||
final Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("confirmByEmail", emailConfirmEnabled);
|
||||
return new ModelAndView(getSuccessView(), model);
|
||||
}
|
||||
|
||||
public void setUserService(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
public void setCaptchaService(@NotNull final ReCaptcha captchaService) {
|
||||
this.captchaService = captchaService;
|
||||
}
|
||||
|
||||
public ReCaptcha getCaptchaService() {
|
||||
return captchaService;
|
||||
}
|
||||
|
||||
public boolean isCaptchaEnabled() {
|
||||
return captchaEnabled;
|
||||
}
|
||||
|
||||
public void setCaptchaEnabled(boolean captchaEnabled) {
|
||||
this.captchaEnabled = captchaEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors) throws Exception {
|
||||
|
||||
super.onBindAndValidate(request, command, errors);
|
||||
// If captcha is enabled, generate it ...
|
||||
if (isCaptchaEnabled()) {
|
||||
|
||||
final String challenge = request.getParameter("recaptcha_challenge_field");
|
||||
final String uresponse = request.getParameter("recaptcha_response_field");
|
||||
|
||||
final String remoteAddr = request.getRemoteAddr();
|
||||
final ReCaptchaResponse reCaptchaResponse = captchaService.checkAnswer(remoteAddr, challenge, uresponse);
|
||||
if (!reCaptchaResponse.isValid()) {
|
||||
errors.rejectValue("captcha", Messages.CAPTCHA_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException bindException) throws Exception {
|
||||
final ModelAndView modelAndView = super.showForm(request, response, bindException);
|
||||
|
||||
// If captcha is enabled, generate it ...
|
||||
if (isCaptchaEnabled()) {
|
||||
final Properties prop = new Properties();
|
||||
prop.put("theme", "white");
|
||||
final String captchaHtml = captchaService.createRecaptchaHtml(null, prop);
|
||||
request.setAttribute("captchaHtml", captchaHtml);
|
||||
request.setAttribute("captchaEnabled", true);
|
||||
}
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
@@ -107,12 +107,12 @@ public class User
|
||||
|
||||
final User user = (User) o;
|
||||
|
||||
if (!getEmail().equals(user.getEmail())) return false;
|
||||
final String email = getEmail();
|
||||
if (email != null ? !email.equals(user.getEmail()) : user.getEmail() != null) return false;
|
||||
if (firstname != null ? !firstname.equals(user.firstname) : user.firstname != null) return false;
|
||||
if (lastname != null ? !lastname.equals(user.lastname) : user.lastname != null) return false;
|
||||
if (username != null ? !username.equals(user.username) : user.username != null) return false;
|
||||
return !(username != null ? !username.equals(user.username) : user.username != null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
@@ -120,7 +120,7 @@ public class User
|
||||
result = (firstname != null ? firstname.hashCode() : 0);
|
||||
result = 29 * result + (lastname != null ? lastname.hashCode() : 0);
|
||||
result = 29 * result + (password != null ? password.hashCode() : 0);
|
||||
result = 29 * result + getEmail().hashCode();
|
||||
result = 29 * result + (getEmail() != null ? getEmail().hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,9 @@ import com.wisemapping.controller.Messages;
|
||||
import com.wisemapping.service.UserService;
|
||||
import com.wisemapping.view.UserBean;
|
||||
import com.wisemapping.model.Constants;
|
||||
import net.tanesha.recaptcha.ReCaptcha;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.ValidationUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -30,12 +33,14 @@ public class UserValidator
|
||||
implements Validator {
|
||||
|
||||
private UserService userService;
|
||||
private ReCaptcha captchaService;
|
||||
|
||||
|
||||
public boolean supports(final Class clazz) {
|
||||
return clazz.equals(UserBean.class);
|
||||
}
|
||||
|
||||
public void validate(Object obj, Errors errors) {
|
||||
public void validate(@Nullable Object obj, @NotNull Errors errors) {
|
||||
UserBean user = (UserBean) obj;
|
||||
if (user == null) {
|
||||
errors.rejectValue("user", "error.not-specified");
|
||||
@@ -65,30 +70,30 @@ public class UserValidator
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", Messages.FIELD_REQUIRED);
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "retypePassword", Messages.FIELD_REQUIRED);
|
||||
ValidatorUtils.rejectIfExceeded(errors,
|
||||
"firstname",
|
||||
"The firstname must have less than "+ Constants.MAX_USER_FIRSTNAME_LENGTH + " characters.",
|
||||
user.getFirstname(),
|
||||
Constants.MAX_USER_FIRSTNAME_LENGTH);
|
||||
"firstname",
|
||||
"The firstname must have less than " + Constants.MAX_USER_FIRSTNAME_LENGTH + " characters.",
|
||||
user.getFirstname(),
|
||||
Constants.MAX_USER_FIRSTNAME_LENGTH);
|
||||
ValidatorUtils.rejectIfExceeded(errors,
|
||||
"lastname",
|
||||
"The lastname must have less than "+ Constants.MAX_USER_LASTNAME_LENGTH + " characters.",
|
||||
user.getLastname(),
|
||||
Constants.MAX_USER_LASTNAME_LENGTH);
|
||||
"lastname",
|
||||
"The lastname must have less than " + Constants.MAX_USER_LASTNAME_LENGTH + " characters.",
|
||||
user.getLastname(),
|
||||
Constants.MAX_USER_LASTNAME_LENGTH);
|
||||
ValidatorUtils.rejectIfExceeded(errors,
|
||||
"username",
|
||||
"The username must have less than "+ Constants.MAX_USER_USERNAME_LENGTH + " characters.",
|
||||
username,
|
||||
Constants.MAX_USER_USERNAME_LENGTH);
|
||||
"username",
|
||||
"The username must have less than " + Constants.MAX_USER_USERNAME_LENGTH + " characters.",
|
||||
username,
|
||||
Constants.MAX_USER_USERNAME_LENGTH);
|
||||
ValidatorUtils.rejectIfExceeded(errors,
|
||||
"password",
|
||||
"The password must have less than "+ Constants.MAX_USER_PASSWORD_LENGTH + " characters.",
|
||||
user.getPassword(),
|
||||
Constants.MAX_USER_PASSWORD_LENGTH);
|
||||
"password",
|
||||
"The password must have less than " + Constants.MAX_USER_PASSWORD_LENGTH + " characters.",
|
||||
user.getPassword(),
|
||||
Constants.MAX_USER_PASSWORD_LENGTH);
|
||||
ValidatorUtils.rejectIfExceeded(errors,
|
||||
"retypePassword",
|
||||
"The retypePassword must have less than "+ Constants.MAX_USER_PASSWORD_LENGTH + " characters.",
|
||||
user.getRetypePassword(),
|
||||
Constants.MAX_USER_PASSWORD_LENGTH);
|
||||
"retypePassword",
|
||||
"The retypePassword must have less than " + Constants.MAX_USER_PASSWORD_LENGTH + " characters.",
|
||||
user.getRetypePassword(),
|
||||
Constants.MAX_USER_PASSWORD_LENGTH);
|
||||
|
||||
final String password = user.getPassword();
|
||||
if (password != null && !password.equals(user.getRetypePassword())) {
|
||||
@@ -100,4 +105,12 @@ public class UserValidator
|
||||
public void setUserService(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
public void setCaptchaService(@NotNull final ReCaptcha captchaService) {
|
||||
this.captchaService = captchaService;
|
||||
}
|
||||
|
||||
public ReCaptcha getCaptchaService() {
|
||||
return captchaService;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user