You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by ug...@apache.org on 2005/05/18 16:43:06 UTC

svn commit: r170759 - in /cocoon/branches/BRANCH_2_1_X/src/blocks/forms: java/org/apache/cocoon/forms/formmodel/CaptchaField.java java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java samples/resources/forms-field-styling.xsl

Author: ugo
Date: Wed May 18 07:43:05 2005
New Revision: 170759

URL: http://svn.apache.org/viewcvs?rev=170759&view=rev
Log:
Use random string for session attribute name instead of field id, as suggested by Vadim

Modified:
    cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/formmodel/CaptchaField.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java
    cocoon/branches/BRANCH_2_1_X/src/blocks/forms/samples/resources/forms-field-styling.xsl

Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/formmodel/CaptchaField.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/formmodel/CaptchaField.java?rev=170759&r1=170758&r2=170759&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/formmodel/CaptchaField.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/formmodel/CaptchaField.java Wed May 18 07:43:05 2005
@@ -15,22 +15,25 @@
  */
 package org.apache.cocoon.forms.formmodel;
 
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.Locale;
 import java.util.Map;
 
+import org.apache.avalon.framework.CascadingRuntimeException;
 import org.apache.avalon.framework.context.Context;
 import org.apache.cocoon.components.ContextHelper;
 import org.apache.cocoon.environment.ObjectModelHelper;
 import org.apache.cocoon.environment.Session;
 import org.apache.cocoon.forms.Constants;
-import org.apache.cocoon.xml.XMLUtils;
+import org.apache.cocoon.xml.AttributesImpl;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
 
 /**
  * A {@link Field} for CAPTCHA validation. Upon generation, a secret random string is stored
- * in a session attribute having the same name as the field's ID, for use by a 
+ * in a session attribute having a randomly generated name, for use by a 
  * {@link org.apache.cocoon.forms.validation.impl.CaptchaValidator}.
  * <br>
  * Usage sample:
@@ -49,33 +52,68 @@
  */
 public class CaptchaField extends Field {
 
-    private static final String IMAGE_EL = "captcha-image";
     public static final String SESSION_ATTR_PREFIX = "captcha-";
+
+    private static final String IMAGE_EL = "captcha-image";
     private static final String SECRET_CHARS = "abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
     private static final int SECRET_LENGTH = 7;
+    private static final int SESSION_ATTR_NAME_LENGTH = 6;
+    
     private Context avalonContext;
+
+    /**
+     * Random number generator used to create session attribute name.
+     */
+    protected static SecureRandom random;
+
+    static {
+        try {
+            random = SecureRandom.getInstance("SHA1PRNG");
+        } catch(java.security.NoSuchAlgorithmException nsae) {
+            // Maybe we are on IBM's SDK
+            try {
+                random = SecureRandom.getInstance("IBMSecureRandom");
+            } catch (NoSuchAlgorithmException e) {
+                throw new CascadingRuntimeException("No random number generator available", e);
+            }
+        }
+        random.setSeed(System.currentTimeMillis());
+    }
+
+    public CaptchaField(FieldDefinition fieldDefinition, Context avalonContext) {
+        super(fieldDefinition);
+        this.avalonContext = avalonContext;
+    }
     
     private String generateSecret() {
         StringBuffer secret = new StringBuffer(SECRET_LENGTH);
         for (int n = 0 ; n < SECRET_LENGTH ; n++) {
-            int randomnumber = (int) Math.floor(SECRET_CHARS.length() * Math.random());
+            int randomnumber = random.nextInt(SECRET_CHARS.length());
             secret.append(SECRET_CHARS.charAt(randomnumber)); 
         }
         return secret.toString();
     }
 
-    public CaptchaField(FieldDefinition fieldDefinition, Context avalonContext) {
-        super(fieldDefinition);
-        this.avalonContext = avalonContext;
-    }
-
     public void generateItemSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
         super.generateItemSaxFragment(contentHandler, locale);
-        contentHandler.startElement(Constants.INSTANCE_NS, IMAGE_EL, Constants.INSTANCE_PREFIX_COLON + IMAGE_EL, XMLUtils.EMPTY_ATTRIBUTES);
-        contentHandler.endElement(Constants.INSTANCE_NS, IMAGE_EL, Constants.INSTANCE_PREFIX_COLON + IMAGE_EL);
+        byte[] bytes = new byte[SESSION_ATTR_NAME_LENGTH];
+        char[] result = new char[bytes.length * 2];
+        random.nextBytes(bytes);
+        for (int i = 0; i < SESSION_ATTR_NAME_LENGTH; i++) {
+            byte ch = bytes[i];
+            result[2 * i] = Character.forDigit(Math.abs(ch >> 4), 16);
+            result[2 * i + 1] = Character.forDigit(Math.abs(ch & 0x0f), 16);
+        }
+        String id = new String(result);
         Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
         Session session = ObjectModelHelper.getRequest(objectModel).getSession(true);
-        session.setAttribute(SESSION_ATTR_PREFIX + getId(), generateSecret());
+        String secret = generateSecret();
+        session.setAttribute(SESSION_ATTR_PREFIX + id, secret);
+        this.setAttribute("secret", secret);
+        AttributesImpl attrs = new AttributesImpl();
+        attrs.addAttribute("", "id", "id", "PCDATA", id);
+        contentHandler.startElement(Constants.INSTANCE_NS, IMAGE_EL, Constants.INSTANCE_PREFIX_COLON + IMAGE_EL, attrs);
+        contentHandler.endElement(Constants.INSTANCE_NS, IMAGE_EL, Constants.INSTANCE_PREFIX_COLON + IMAGE_EL);
     }
     
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java?rev=170759&r1=170758&r2=170759&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidator.java Wed May 18 07:43:05 2005
@@ -15,13 +15,6 @@
  */
 package org.apache.cocoon.forms.validation.impl;
 
-import java.util.Map;
-
-import org.apache.avalon.framework.context.Context;
-import org.apache.cocoon.components.ContextHelper;
-import org.apache.cocoon.environment.ObjectModelHelper;
-import org.apache.cocoon.environment.Session;
-import org.apache.cocoon.forms.formmodel.CaptchaField;
 import org.apache.cocoon.forms.formmodel.Widget;
 import org.apache.cocoon.forms.validation.ValidationError;
 import org.apache.cocoon.forms.validation.ValidationErrorAware;
@@ -37,27 +30,14 @@
  */
 public class CaptchaValidator implements WidgetValidator {
 
-    private final Context avalonContext;
     private static final String VALIDATION_MESSAGE_KEY = "validation.captcha.mismatch"; 
-                                                          
-    public CaptchaValidator(Context avalonContext) {
-        this.avalonContext = avalonContext;
-    }
 
     public boolean validate(Widget widget) {
         if (! (widget instanceof ValidationErrorAware)) {
             // Invalid widget type
             throw new IllegalArgumentException("Widget '" + widget.getRequestParameterName() + "' is not ValidationErrorAware");
         }
-        Map objectModel = ContextHelper.getObjectModel(this.avalonContext);
-        Session session = ObjectModelHelper.getRequest(objectModel).getSession(false);
-        if (session == null) {
-            throw new RuntimeException("No session associated with request.");
-        }
-        if (session.getAttribute(CaptchaField.SESSION_ATTR_PREFIX + widget.getId()) == null) {
-            throw new RuntimeException("No CAPTCHA attribute associated with widget " + widget.getId());
-        }
-        boolean result = widget.getValue() != null && widget.getValue().equals(session.getAttribute(CaptchaField.SESSION_ATTR_PREFIX + widget.getId()));
+        boolean result = widget.getValue() != null && widget.getValue().equals(widget.getAttribute("secret"));
         if (! result) {
             ((ValidationErrorAware) widget).setValidationError(new ValidationError(VALIDATION_MESSAGE_KEY));
         }

Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java?rev=170759&r1=170758&r2=170759&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java (original)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/forms/java/org/apache/cocoon/forms/validation/impl/CaptchaValidatorBuilder.java Wed May 18 07:43:05 2005
@@ -15,9 +15,6 @@
  */
 package org.apache.cocoon.forms.validation.impl;
 
-import org.apache.avalon.framework.context.Context;
-import org.apache.avalon.framework.context.ContextException;
-import org.apache.avalon.framework.context.Contextualizable;
 import org.apache.avalon.framework.thread.ThreadSafe;
 import org.apache.cocoon.forms.formmodel.WidgetDefinition;
 import org.apache.cocoon.forms.validation.WidgetValidator;
@@ -31,18 +28,11 @@
  * @see org.apache.cocoon.forms.validation.impl.CaptchaValidator
  * @version $Id$
  */
-public class CaptchaValidatorBuilder implements WidgetValidatorBuilder, Contextualizable, ThreadSafe {
-    
-    private Context avalonContext;
-
-    public void contextualize(Context context) throws ContextException {
-        System.err.println("CaptchaValidatorBuilder.contextualize(" + context + ")");
-        this.avalonContext = context;
-    }
+public class CaptchaValidatorBuilder implements WidgetValidatorBuilder, ThreadSafe {
 
     public WidgetValidator build(Element validationRuleElement,
             WidgetDefinition definition) throws Exception {
-        return new CaptchaValidator(avalonContext);
+        return new CaptchaValidator();
     }
 
 }

Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/forms/samples/resources/forms-field-styling.xsl
URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/forms/samples/resources/forms-field-styling.xsl?rev=170759&r1=170758&r2=170759&view=diff
==============================================================================
--- cocoon/branches/BRANCH_2_1_X/src/blocks/forms/samples/resources/forms-field-styling.xsl (original)
+++ cocoon/branches/BRANCH_2_1_X/src/blocks/forms/samples/resources/forms-field-styling.xsl Wed May 18 07:43:05 2005
@@ -49,7 +49,7 @@
       +-->
   <xsl:template match="fi:field">
     <xsl:if test="fi:captcha-image">
-      <img src="captcha-{@id}.jpg" style="vertical-align:middle"/>
+      <img src="captcha-{fi:captcha-image/@id}.jpg" style="vertical-align:middle"/>
       <xsl:text> </xsl:text>
     </xsl:if>
     <input name="{@id}" id="{@id}" value="{fi:value}" title="{fi:hint}" type="text">