You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by mp...@apache.org on 2012/01/06 14:46:52 UTC

svn commit: r1228180 - in /incubator/rave/trunk: ./ rave-components/rave-core/ rave-components/rave-core/src/main/java/org/apache/rave/portal/service/ rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ rave-components/rave-cor...

Author: mpierce
Date: Fri Jan  6 13:46:51 2012
New Revision: 1228180

URL: http://svn.apache.org/viewvc?rev=1228180&view=rev
Log:
(RAVE-134) Committing recaptcha patch contributed by Marijan Milicevic

Added:
    incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/CaptchaService.java
    incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ReCaptchaService.java
Modified:
    incubator/rave/trunk/pom.xml
    incubator/rave/trunk/rave-components/rave-core/pom.xml
    incubator/rave/trunk/rave-components/rave-core/src/test/resources/portal.properties
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/NewAccountController.java
    incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/NewAccountControllerTest.java
    incubator/rave/trunk/rave-portal-resources/src/main/resources/portal.properties
    incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/newaccount.jsp
    incubator/rave/trunk/rave-portal/src/test/resources/portal.properties

Modified: incubator/rave/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/pom.xml?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/pom.xml (original)
+++ incubator/rave/trunk/pom.xml Fri Jan  6 13:46:51 2012
@@ -70,6 +70,7 @@
         <cobertura.version>2.5.1</cobertura.version>
         <org.hamcrest.version>1.1</org.hamcrest.version>
         <tiles.version>2.2.2</tiles.version>
+        <recaptcha4j.version>0.0.7</recaptcha4j.version>
 
         <!-- The location of Rave's H2 file DB. No trailing / -->
         <rave.database.location>/tmp/rave_db</rave.database.location>
@@ -355,6 +356,12 @@
                 <artifactId>tiles-jsp</artifactId>
                 <version>${tiles.version}</version>
             </dependency>
+            <!-- Captcha -->
+            <dependency>
+                <groupId>net.tanesha.recaptcha4j</groupId>
+                <artifactId>recaptcha4j</artifactId>
+                <version>${recaptcha4j.version}</version>
+            </dependency>
 
             <!-- Test -->
             <dependency>

Modified: incubator/rave/trunk/rave-components/rave-core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-core/pom.xml?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-core/pom.xml (original)
+++ incubator/rave/trunk/rave-components/rave-core/pom.xml Fri Jan  6 13:46:51 2012
@@ -137,7 +137,14 @@
             <groupId>com.ibm.icu</groupId>
             <artifactId>icu4j</artifactId>
         </dependency>
-        
+
+        <!--  Captcha -->
+        <dependency>
+            <groupId>net.tanesha.recaptcha4j</groupId>
+            <artifactId>recaptcha4j</artifactId>
+        </dependency>
+
+
         <!-- Test -->
         <dependency>
             <groupId>junit</groupId>

Added: incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/CaptchaService.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/CaptchaService.java?rev=1228180&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/CaptchaService.java (added)
+++ incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/CaptchaService.java Fri Jan  6 13:46:51 2012
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.rave.portal.service;
+
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface CaptchaService {
+
+    /**
+     * Create captcha HTML which can be displayed on the frontend
+     *
+     * @param request HttpServletRequest
+     * @return captcha html
+     */
+    String createHtml(HttpServletRequest request);
+
+    /**
+     * Validate user input
+     *
+     * @param request HttpServletRequest
+     * @return true if captcha service is disabled or user input is valid, false otherwise.
+     */
+    boolean isValid(HttpServletRequest request);
+}

Added: incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ReCaptchaService.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ReCaptchaService.java?rev=1228180&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ReCaptchaService.java (added)
+++ incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ReCaptchaService.java Fri Jan  6 13:46:51 2012
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.rave.portal.service.impl;
+
+import net.tanesha.recaptcha.ReCaptcha;
+import net.tanesha.recaptcha.ReCaptchaFactory;
+import net.tanesha.recaptcha.ReCaptchaResponse;
+import org.apache.commons.lang.StringUtils;
+import org.apache.rave.portal.service.CaptchaService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Implementation of ReCaptcha captcha service
+ */
+@Service
+public class ReCaptchaService implements CaptchaService {
+
+    @SuppressWarnings("unused")
+    private static Logger log = LoggerFactory.getLogger(ReCaptchaService.class);
+
+    public static final String PARAM_CAPTCHA_RESPONSE = "recaptcha_response_field";
+    public static final String PARAM_CAPTCHA_CHALLENGE = "recaptcha_challenge_field";
+
+
+    private String invalidConfigurationMessage;
+    private boolean captchaEnabled;
+    private String publicKey;
+    private boolean createNoScript;
+    private String privateKey;
+
+
+    @Autowired
+    public ReCaptchaService(@Value("${portal.captcha.enabled}") boolean captchaEnabled,
+                            @Value("${portal.captcha.key.public}") String publicKey,
+                            @Value("${portal.captcha.key.private}") String privateKey,
+                            @Value("${portal.captcha.usenoscript}") boolean createNoScript,
+                            @Value("${portal.captcha.invalid.configuration}") String invalidConfigurationMessage
+    ) {
+        this.captchaEnabled = captchaEnabled;
+        this.publicKey = publicKey;
+        this.createNoScript = createNoScript;
+        this.privateKey = privateKey;
+        this.invalidConfigurationMessage = invalidConfigurationMessage;
+    }
+
+    @Override
+    public boolean isValid(HttpServletRequest request) {
+        log.debug("ReCaptcha enabled:  {}", captchaEnabled);
+        if (!captchaEnabled) {
+            return true;
+        }
+        if (StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey)) {
+            log.error("ReCaptcha service is enabled, however, private or public keys are not defined.");
+            return true;
+        }
+
+        boolean secure = request.isSecure();
+        ReCaptcha captcha;
+        if (secure) {
+            captcha = ReCaptchaFactory.newSecureReCaptcha(publicKey, privateKey, createNoScript);
+        } else {
+            captcha = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, createNoScript);
+        }
+        String response = request.getParameter(PARAM_CAPTCHA_RESPONSE);
+        String challenge = request.getParameter(PARAM_CAPTCHA_CHALLENGE);
+        String remoteAddress = request.getRemoteAddr();
+        // validate:
+        ReCaptchaResponse captchaResponse = captcha.checkAnswer(remoteAddress, challenge, response);
+        boolean valid = captchaResponse.isValid();
+        if (valid) {
+            return true;
+        }
+        log.warn("Invalid captcha response:  {}", captchaResponse.getErrorMessage());
+        return false;
+
+    }
+
+    @Override
+    public String createHtml(HttpServletRequest request) {
+        if (captchaEnabled) {
+            if (StringUtils.isBlank(privateKey) || StringUtils.isBlank(publicKey)) {
+                return invalidConfigurationMessage;
+            }
+            boolean secure = request.isSecure();
+
+            ReCaptcha captcha;
+            if (secure) {
+                captcha = ReCaptchaFactory.newSecureReCaptcha(publicKey, privateKey, createNoScript);
+            } else {
+                captcha = ReCaptchaFactory.newReCaptcha(publicKey, privateKey, createNoScript);
+            }
+
+            return captcha.createRecaptchaHtml(null, null);
+        }
+        return "";
+    }
+}

Modified: incubator/rave/trunk/rave-components/rave-core/src/test/resources/portal.properties
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-core/src/test/resources/portal.properties?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-core/src/test/resources/portal.properties (original)
+++ incubator/rave/trunk/rave-components/rave-core/src/test/resources/portal.properties Fri Jan  6 13:46:51 2012
@@ -37,4 +37,10 @@ portal.openjpa.RuntimeUnenhancedClasses=
 portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
-provider.wookie.wookieApiKey=TEST
\ No newline at end of file
+provider.wookie.wookieApiKey=TEST
+# captcha settings
+portal.captcha.enabled=false
+portal.captcha.key.private=
+portal.captcha.key.public=
+portal.captcha.usenoscript=false
+portal.captcha.invalid.configuration=<label class="error">ReCaptcha service is not properly configured.</label>
\ No newline at end of file

Modified: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/NewAccountController.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/NewAccountController.java?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/NewAccountController.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/NewAccountController.java Fri Jan  6 13:46:51 2012
@@ -20,6 +20,7 @@
 package org.apache.rave.portal.web.controller;
 
 import org.apache.rave.portal.model.NewUser;
+import org.apache.rave.portal.service.CaptchaService;
 import org.apache.rave.portal.service.NewAccountService;
 import org.apache.rave.portal.web.util.ModelKeys;
 import org.apache.rave.portal.web.util.ViewNames;
@@ -35,6 +36,7 @@ import org.springframework.web.bind.anno
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
+import javax.servlet.http.HttpServletRequest;
 
 @Controller
 public class NewAccountController {
@@ -42,40 +44,53 @@ public class NewAccountController {
 
     private final NewAccountService newAccountService;
     private final NewAccountValidator newAccountValidator;
+    private final CaptchaService captchaService;
 
 
     @Autowired
-    public NewAccountController(NewAccountService newAccountService, NewAccountValidator newAccountValidator) {
+    public NewAccountController(NewAccountService newAccountService, NewAccountValidator newAccountValidator, CaptchaService captchaService) {
         this.newAccountService = newAccountService;
+        this.captchaService = captchaService;
         this.newAccountValidator = newAccountValidator;
     }
 
     @RequestMapping(value = "/newaccount.jsp")
-    public void setUpForm(ModelMap model) {
+    public void setUpForm(ModelMap model, HttpServletRequest request) {
         logger.debug("Initializing form");
+        model.addAttribute("captchaHtml", captchaService.createHtml(request));
         model.addAttribute(ModelKeys.NEW_USER, new NewUser());
     }
 
     @RequestMapping(value = {"/newaccount", "/newacount/*"}, method = RequestMethod.POST)
-    public String create(@ModelAttribute NewUser newUser, BindingResult results, Model model) {
+    public String create(@ModelAttribute NewUser newUser, BindingResult results, Model model, HttpServletRequest request) {
         logger.debug("Creating a new user account");
         model.addAttribute(ModelKeys.NEW_USER, newUser);
 
         newAccountValidator.validate(newUser, results);
         if (results.hasErrors()) {
             logger.info("newaccount.jsp: shows validation errors");
+            initializeCaptcha(model, request);
             return ViewNames.NEW_ACCOUNT;
         }
 
         //Now attempt to create the account.
         try {
             logger.debug("newaccount.jsp: passed form validation");
-            newAccountService.createNewAccount(newUser);
-            return ViewNames.REDIRECT;
+
+            if (captchaService.isValid(request)) {
+                newAccountService.createNewAccount(newUser);
+                return ViewNames.REDIRECT;
+            } else {
+                logger.debug("newaccount.jsp: failed  captcha validation");
+                results.reject("Captcha validation failed", "Unable to create account, captcha validation failed");
+                initializeCaptcha(model, request);
+                return ViewNames.NEW_ACCOUNT;
+            }
         } catch (org.springframework.dao.IncorrectResultSizeDataAccessException ex) {
             //This exception is thrown if the account already exists.
             logger.info("Account creation failed: ", ex);
             results.reject("Account already exists", "Unable to create account");
+            initializeCaptcha(model, request);
             return ViewNames.NEW_ACCOUNT;
 
         } catch (Exception ex) {
@@ -86,8 +101,13 @@ public class NewAccountController {
                 logger.error("Account creation failed: {}", ex.getMessage());
             }
             results.reject("Unable to create account:" + ex.getMessage(), "Unable to create account");
+            initializeCaptcha(model, request);
             return ViewNames.NEW_ACCOUNT;
         }
 
     }
+
+    private void initializeCaptcha(Model model, HttpServletRequest request) {
+        model.addAttribute("captchaHtml", captchaService.createHtml(request));
+    }
 }
\ No newline at end of file

Modified: incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/NewAccountControllerTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/NewAccountControllerTest.java?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/NewAccountControllerTest.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/NewAccountControllerTest.java Fri Jan  6 13:46:51 2012
@@ -24,21 +24,27 @@ import java.util.List;
 
 import org.apache.rave.portal.model.NewUser;
 import org.apache.rave.portal.model.User;
+import org.apache.rave.portal.service.CaptchaService;
 import org.apache.rave.portal.service.NewAccountService;
 import org.apache.rave.portal.service.UserService;
+import org.apache.rave.portal.service.impl.ReCaptchaService;
 import org.apache.rave.portal.web.util.ModelKeys;
 import org.apache.rave.portal.web.util.ViewNames;
 import org.apache.rave.portal.web.validator.NewAccountValidator;
 
+import org.easymock.EasyMock;
 import org.hamcrest.CoreMatchers;
 import org.junit.Before;
 import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.ui.Model;
 import org.springframework.ui.ModelMap;
 import org.springframework.validation.BindingResult;
 import org.springframework.validation.Errors;
 import org.springframework.validation.ObjectError;
 
+import javax.servlet.http.HttpServletRequest;
+
 import static org.easymock.EasyMock.*;
 import static org.junit.Assert.assertThat;
 
@@ -52,27 +58,31 @@ public class NewAccountControllerTest {
 	private NewAccountController newAccountController;
 	private NewAccountService newAccountService;
 	private NewAccountValidator newAccountValidator;
+	private CaptchaService captchaService;
+    private MockHttpServletRequest request;
 	private UserService userService;
 	
 	@Before
 	public void setup() {
 		newAccountService = createNiceMock(NewAccountService.class);
 		userService = createNiceMock(UserService.class);
+        request = new MockHttpServletRequest();
 		newAccountValidator = new NewAccountValidator(userService);
-		newAccountController = new NewAccountController(newAccountService, newAccountValidator);
+		captchaService = new ReCaptchaService(false, null, null, false, "error message");
+		newAccountController = new NewAccountController(newAccountService, newAccountValidator, captchaService);
 	}
 	
 	@Test
 	public void setUpForm_ShouldAddAttributeForNewUser() {
 		final ModelMap model = new ModelMap();
 		String newUser = new String(ModelKeys.NEW_USER);
-		newAccountController.setUpForm(model);
+		newAccountController.setUpForm(model, request);
 		
 		//assert that the model is not null
 		assertThat(model, CoreMatchers.notNullValue());
 		
-		//assert that the model size is one
-		assertThat(model.size(), CoreMatchers.equalTo(1));
+		//assert that the model size is two
+		assertThat(model.size(), CoreMatchers.equalTo(2));
 		
 		//assert that the model does contain an attribute associated with newUser after setUpForm() is called
 		assertThat(model.containsAttribute(newUser), CoreMatchers.equalTo(true)); 
@@ -101,8 +111,9 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+
+        replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -130,15 +141,16 @@ public class NewAccountControllerTest {
 		existingUser.setPassword(password);
 		
 		errorList.add(error);
-		
+
+
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
 		
 		expect(userService.getUserByUsername(username)).andReturn(existingUser).anyTimes();
 		replay(userService);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -166,8 +178,9 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		replay(model);
+
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -195,8 +208,8 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(2));
@@ -224,8 +237,9 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+
+        replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -252,8 +266,8 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -280,8 +294,8 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -308,8 +322,8 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+        replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(1));
@@ -338,8 +352,9 @@ public class NewAccountControllerTest {
 		expect(errors.hasErrors()).andReturn(true).anyTimes();		
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
-		
-		String result = new String(newAccountController.create(newUser, errors, model));
+
+        replay(model);
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(3));
@@ -367,7 +382,7 @@ public class NewAccountControllerTest {
 		expect(errors.getAllErrors()).andReturn(errorList).anyTimes();
 		replay(errors);
 		
-		String result = new String(newAccountController.create(newUser, errors, model));
+		String result = new String(newAccountController.create(newUser, errors, model, request));
 		errorList = errors.getAllErrors();
 
 		assertThat(errorList.size(), CoreMatchers.equalTo(0));

Modified: incubator/rave/trunk/rave-portal-resources/src/main/resources/portal.properties
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/resources/portal.properties?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/resources/portal.properties (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/resources/portal.properties Fri Jan  6 13:46:51 2012
@@ -51,4 +51,10 @@ portal.openjpa.RuntimeUnenhancedClasses=
 portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
-provider.wookie.wookieApiKey=TEST
\ No newline at end of file
+provider.wookie.wookieApiKey=TEST
+# captcha settings
+portal.captcha.enabled=false
+portal.captcha.key.private=
+portal.captcha.key.public=
+portal.captcha.usenoscript=false
+portal.captcha.invalid.configuration=<label class="error">ReCaptcha service is not properly configured.</label>
\ No newline at end of file

Modified: incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/newaccount.jsp
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/newaccount.jsp?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/newaccount.jsp (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/newaccount.jsp Fri Jan  6 13:46:51 2012
@@ -1,21 +1,21 @@
 <%--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  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.
-  --%>
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+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.
+--%>
 <%@ page language="java" trimDirectiveWhitespaces="true" %>
 <%@ include file="/WEB-INF/jsp/includes/taglibs.jsp" %>
 <fmt:setBundle basename="messages"/>
@@ -54,9 +54,7 @@
 
                     <p>
                         <label for="emailField"><fmt:message key="page.general.email"/></label>
-                        <spring:bind path="email">
-                            <input type="email" name="email" id="emailField" required="required"/>
-                        </spring:bind>
+                        <form:input id="emailField" path="email" required="required" />
                         <form:errors path="email" cssClass="error"/>
                     </p>
 
@@ -80,6 +78,7 @@
                         </form:select>
                     </p>
                 </fieldset>
+                <fieldset>${captchaHtml}</fieldset>
                 <fieldset>
                     <fmt:message key="page.newaccount.button" var="submitButtonText"/>
                     <input type="submit" value="${submitButtonText}"/>

Modified: incubator/rave/trunk/rave-portal/src/test/resources/portal.properties
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/test/resources/portal.properties?rev=1228180&r1=1228179&r2=1228180&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal/src/test/resources/portal.properties (original)
+++ incubator/rave/trunk/rave-portal/src/test/resources/portal.properties Fri Jan  6 13:46:51 2012
@@ -50,4 +50,10 @@ portal.openjpa.RuntimeUnenhancedClasses=
 portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
-provider.wookie.wookieApiKey=TEST
\ No newline at end of file
+provider.wookie.wookieApiKey=TEST
+# captcha settings
+portal.captcha.enabled=false
+portal.captcha.key.private=
+portal.captcha.key.public=
+portal.captcha.usenoscript=false
+portal.captcha.invalid.configuration=<label class="error">ReCaptcha service is not properly configured.</label>
\ No newline at end of file