At long last I have been able to set up a form signature for a Java/JSP application. The application I developed uses the Faces framework, and I set up a custom tag to handle the functionality. I am including the important Java classes here. The first Java class is the most important since it contains the functions that generate the signature components. I have documented the code in the javadoc comments.
FormSignatureValidator.java
-
package com.threeleaf.jsf.components.formsignature;
-
-
import java.security.MessageDigest;
-
import java.text.SimpleDateFormat;
-
import java.util.Calendar;
-
import java.util.Date;
-
-
import javax.faces.application.FacesMessage;
-
import javax.faces.component.UIComponent;
-
import javax.faces.context.FacesContext;
-
import javax.faces.validator.Validator;
-
import javax.faces.validator.ValidatorException;
-
import javax.servlet.ServletContext;
-
-
import org.apache.log4j.Logger;
-
-
import com.threeleaf.agentguidedselling.model.StringEncrypter;
-
import com.threeleaf.agentguidedselling.model.StringEncrypter.EncryptionException;
-
-
/**
-
* Add a "random" but verifiable form field in Faces to prevent many kinds of
-
* scripted spam attacks. The idea is to tie a browser session to a web address
-
* during a given timeframe. The goal is to make sure that 1) no generated
-
* script will be valid for more than an hour 2) robots to different machines
-
* cannot be spawned. The technique can be worked around, but the hope is that
-
* spammers will not find it worth their while to do so. If stronger prevention
-
* is needed, then captchas can be used.
-
*
-
* @author John A. Marsh
-
*
-
*/
-
public class FormSignatureValidator implements Validator {
-
private Logger logger = Logger.getLogger(this.getClass().getName());
-
-
/*
-
* Generates the variable to be used in the form signature input tag. The
-
* value changes every hour. It is assumed
-
* that no single form will ever take an hour to fill out and submit. Every
-
* hour, the length of the random variable will change. The object is to
-
* twart script robots. It is not perfect, but it works well without
-
* requiring captchas.
-
*
-
* @param optional calendar object with which to calculate the field.
-
* Overloaded to default to the current time.
-
*
-
* @return a reproducable "random" string to be used as a form field name.
-
*
-
* @author John A. Marsh
-
*
-
*/
-
// The filed name will change once an hour
-
// We want to have the string be between 7 and 14 characters in a
-
// reproducably "random" manner
-
int stringLength = 7 + fieldName.length() % 7;
-
fieldName = md5(fieldName);
-
/*
-
* We want the first character to begin with a letter, not a number, to
-
* guarantee browser and language compatibilty We want to start as close
-
* to the beginning as possible. It is highly improbably that one of the
-
* hex letters would not be found closer to the beginning than the first
-
* calculation, but it is there just in case.
-
*/
-
int firstCharacter = 31 - stringLength;
-
if (fieldName.indexOf("a")> -1)
-
if (fieldName.indexOf("b")> -1)
-
if (fieldName.indexOf("c")> -1)
-
if (fieldName.indexOf("d")> -1)
-
if (fieldName.indexOf("e")> -1)
-
if (fieldName.indexOf("f")> -1)
-
fieldName = fieldName.substring(firstCharacter, firstCharacter + stringLength);
-
return fieldName;
-
}
-
-
return formSignatureID(now);
-
}
-
-
/*
-
* Create a form signature. This is basically a timestamp. The time in
-
* milliseconds is hashed and then paired with the encrypted value. On the
-
* other side, the time is unencrypted and compared with the hashed value.
-
*
-
* @param seed Optional "password" for the form
-
*
-
* @return the generated key
-
*
-
* @trows EncryptionException
-
*
-
* @author John A. Marsh
-
*
-
*/
-
Logger logger = Logger.getLogger("FormSignatureValidator.formSignatureGenerate(\"" + seed + "\")");
-
StringEncrypter encrypter = new StringEncrypter("DES", seed);
-
if(logger.isDebugEnabled()) {
-
logger.debug("Time in milliseconds: " + millitime);
-
logger.debug("md5(millitime): " + md5(millitime));
-
logger.debug("encrypter.encrypt(millitime): " + encrypter.encrypt(millitime));
-
}
-
return md5(millitime) + encrypter.encrypt(millitime);
-
}
-
-
ServletContext context = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
-
Logger logger = Logger.getLogger("FormSignatureValidator.formSignatureGenerate()");
-
logger.debug("Generated seed: " + seed);
-
try {
-
return formSignatureGenerate(seed);
-
} catch (EncryptionException e) {
-
return "error";
-
}
-
}
-
-
try {
-
md.update(string.getBytes());
-
byte[] digest = md.digest();
-
return hexString;
-
e.printStackTrace();
-
return null;
-
}
-
}
-
-
static private String[] HEX = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
-
-
int nValue = (int) byValue + 128;
-
return HEX[nValue / 16] + HEX[nValue % 16];
-
}
-
-
String hexed = "";
-
for (int i = 0; i <bytes.length; i++) {
-
hexed += hexify(bytes[i]);
-
}
-
return hexed;
-
}
-
-
}
The following code is used to render the custom tag in Faces.
FormSignatureRenderer.java
-
package com.threeleaf.jsf.components.formsignature;
-
-
import java.io.IOException;
-
import java.util.Map;
-
-
import javax.faces.component.UIComponent;
-
import javax.faces.component.UIInput;
-
import javax.faces.context.FacesContext;
-
import javax.faces.context.ResponseWriter;
-
import javax.faces.render.Renderer;
-
-
/**
-
* Dictates how the HTML element is to be rendered.
-
* The form signature is a hidden field in a form. Its name and
-
* value are auto generated using the formulas in FormSignatureValidator.
-
*
-
* @author John A. Marsh
-
* @see FormSignatureValidator
-
*
-
*/
-
-
public FormSignatureRenderer() {
-
super();
-
}
-
-
/* (non-Javadoc)
-
*
-
* This method is responsible for taking any parameters that were passed in from a form post and setting the value on the component.
-
*
-
* @see javax.faces.render.Renderer#decode(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
-
*/
-
public void decode(FacesContext context, UIComponent component) {
-
-
assertValidInput(context, component);
-
-
if (component instanceof UIInput) {
-
UIInput input = (UIInput) component;
-
if (null != newValue) {
-
input.setSubmittedValue(newValue);
-
}
-
}
-
}
-
-
/* (non-Javadoc)
-
* @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext, javax.faces.component.UIComponent)
-
*/
-
public void encodeEnd(FacesContext context, UIComponent component)
-
assertValidInput(context, component);
-
String formSignature = "";
-
-
ResponseWriter writer = context.getResponseWriter();
-
writer.startElement("input", component);
-
writer.writeAttribute("type", "hidden", null);
-
writer.writeAttribute("id", component.getParent().getId() + ":" + id, "id");
-
writer.writeAttribute("name", id, "id");
-
formSignature = FormSignatureValidator.formSignatureGenerate();
-
writer.writeAttribute("value", formSignature, "value");
-
writer.endElement("input");
-
}
-
-
/**
-
* Verify that the context and the component are not null.
-
* Every Faces Renderer component should do this.
-
*
-
* @author John A. Marsh
-
* @param context
-
* @param component
-
*
-
*/
-
private void assertValidInput(FacesContext context, UIComponent component) {
-
if (context == null) {
-
} else if (component == null) {
-
}
-
}
-
}
FormSignatureTag.java
-
package com.threeleaf.jsf.components.formsignature;
-
-
import javax.faces.component.UIComponent;
-
import javax.faces.context.FacesContext;
-
import javax.faces.webapp.UIComponentTag;
-
-
/**
-
* Code to create the form signature tag
-
*
-
* @author John A. Marsh
-
*
-
*/
-
public class FormSignatureTag extends UIComponentTag {
-
-
-
/* (non-Javadoc)
-
* @see javax.faces.webapp.UIComponentTag#getComponentType()
-
*/
-
return FORM_SIGNATURE_COMPONENT_TYPE;
-
}
-
/* (non-Javadoc)
-
* @see javax.faces.webapp.UIComponentTag#getRendererType()
-
*/
-
// TODO Auto-generated method stub
-
return FORM_SIGNATURE_RENDER_TYPE;
-
}
-
-
protected void setProperties(UIComponent component) {
-
FacesContext context = FacesContext.getCurrentInstance();
-
super.setProperties(component);
-
/*if (null != value) {
-
if (isValueReference(value)) {
-
ValueBinding vb = context.getApplication().createValueBinding(
-
value);
-
component.setValueBinding("value", vb);
-
} else {
-
((UIInput) component).setValue(value);
-
}
-
}*/
-
}
-
}
UIFormSignature.java
-
package com.threeleaf.jsf.components.formsignature;
-
-
import javax.faces.component.UIInput;
-
-
/**
-
* Sets up the user interface compontent for the form signature.
-
*
-
* @author John A. Marsh
-
*/
-
public class UIFormSignature extends UIInput {
-
-
/**
-
* Adding the validator directly to the component, so it does not need to be specified separately.
-
*/
-
public UIFormSignature() {
-
super();
-
addValidator(new FormSignatureValidator());
-
}
-
-
return FORM_SIGNATURE_FAMILY;
-
}
-
}
