Showing posts with label jsf. Show all posts
Showing posts with label jsf. Show all posts

Tuesday, December 29, 2009

Credit card validator in JSF

If you have a JSF page with credit card information you might want to validate the credit card number the user is entering. Different credit card companies (VISA,Master & Amex) have credit card numbers that follow different validation rules. All major credit cards will satisfy a Cyclic Redundancy Check (CRC) called Luhn Algorithm.

Luhn Algorithm

Step1: Sum all odd digits of the credit card number
Step2: Take each even digit multiply it by 2 if the result is greater than 9 subtract 9 from it then add it to the Sum of Step1
Step3: If sum is divisible by 10 then CRC passed else failed

To implement this lets do the following
1.In your JSP page which has the credit card form add the validator to the the card number input text field


<h:inputText label="Credit Card Number:"
id="inpCCnumber" required="true"
value="#{backing_ccbean.cardNumber}">
<f:validator validatorId="CreditCardValidator"/>
</h:inputText>




As you can see the custom credit card validator is called CreditCardValidator. The value is stored in the backing_ccbean. Assume there is a drop down list from which the user selects the card type(Visa,Master or Amex) and this value is stored in the same backing bean backing_ccbean in the attribute cardType, however this value will be set to the model object only after the validation phase so we need to directly bind to the component



<h:selectOneListBox label="Credit card type" value="#{backing_ccbean.cardType}"
binding="#{backing_requestscope.cardTypeChoice}">
<f:selectItem itemValue="1" itemLabel="Visa" />
<f:selectItem itemValue="2" itemLabel="Master Card" />
<f:selectItem itemValue="3" itemLabel="American Express" />
</h:selectOneListBox>




backing_requestscope.cardTypeChoice maps to a javax.faces.component.html.HtmlSelectOneListBox this way we get the users selection in the validation phase of the JSF life cycle.

2. The next step would be to define CreditCardValidator in faces-config.xml. Add the following XML element to your faces-config


<validator>
<validator-id>CreditCardValidator</validator-id>
<validator-class>validators.MyCreditCardValidator</validator-class>
</validator>


The XML element is simple there is an ID and a Class we have called it MyCreditCardValidator.

3. Now let us write the java class MyCreditCardValidator in the package validators





package validators;

public class MyCreditCardValidator implements javax.faces.validator.Validator{


public void validate(FacesContext ctx,UIComponent component,Object value) throws ValidatorException{
String ccnum=(String)value;
// get the card type form the binding object instead of the model object
HtmlSelectOneListBox cardChoiceComp= (HtmlSelectOneListBox) context.getApplication().createValueBinding("#{backing_requestscope.cardTypeChoice}").getValue(context);
int cardType = ((Integer)cardChoiceComp.getValue()).intValue();

boolean validCard = validateCard(ccnum,cardType);

if (validCard==false) throw new ValidatorException(new FacesMessage(" Invalid credit card format!!!!"));

}

private boolean validateCard(String ccnum,int cardType){
// visa cards always start with 4 and are either 13 or 16 digits in length
final int VISA=1;
// master cards are 16 digits in length and the first 2 digits range from 51 to 55
final int MASTER=2;
// Amex cards are 15 digits in length and the first 2 digits range from 34 to 37
final int AMEX=3;
switch(type) {
case VISA:
if ((ccnum.length() != 13 && ccnum.length() != 16) ||
Integer.parseInt(ccnum.substring(0,1))!=4)
return false;
break;
case MASTER:
if (ccnum.length() != 16 ||
Integer.parseInt(ccnum.substring(0,2)) <> 55)
return false;
break;
case AMEX:
if (ccnum.length() != 15 ||
(Integer.parseInt(ccnum.substring(0,2)) != 34 &&
Integer.parseInt(ccnum.substring(0,2))) != 37))
return false;
break;
}

// luhn validate
char[] charArr = ccnum.toCharArray();
int[] num = new int[charArr.length];
int total =0;
for(int i=0;i -1; i--){
if (alternate){ // multiply each even digit by 2 then add it to total
num[i] *=2;
if (num[i] > 9) num[i] -=9;
}
total +=num[i];
alternate = !alternate;

}
if (total % 10 != 0) return false;

return true;

}


}





In the MyCreditCardValidator class the most important thing to notice is how the value of card type is got since the validate method is called in the validation phase of a JSF life cycle the model objects are not set with the value hence the only way to get the value of a component other than the component that is being validated is thru the component binding.

Tuesday, April 21, 2009

Protecting your pages using servlet filtering

At some point in your web application development you will need to restrict access to certain pages based on login. In other words if a user goes to a protected page without logging in he/she needs to be redirected to the login page and thus enforcing security. This can be achieved using servlet filters. A servlet filter gets executed first before any JSP page is rendered and so we can check for a value of a session variable in this filter. The value is set in the login action so if a user skips login this value will not be set and so the servlet filter will throw them back to the login page. With this basic idea the implementation will be as follows.

Step1 Create a java class which implements javax.servlet.Filter


class SecurityCheckFilter implements Filter {
{
private final static String FILTER_APPLIED = "_security_filter_applied";
private List nonRestrictedPages;

/**
* This method returns true if the page is not restricted like the landing page
*/
public boolean isNonRestrictedPage(String page){
Iterator it = nonRestrictedPages.iterator();
boolean result = false;
while (it.hasNext()) {
String nonrestrictedPage = (String)it.next();
if (page.endsWith(nonrestrictedPage)) {
result = true;
break;
}
}
return result;
}

public void init(FilterConfig conf) throws ServletException {
nonRestrictedPages = new ArrayList();
// index.jsp is the landing page of the application
// and needs no logging in
nonRestrictedPages.add("index.jsp");
}
/**
* This method gets called for every jsp page before the page gets rendered
*/
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hreq = (HttpServletRequest)request;
HttpServletResponse hres = (HttpServletResponse)response;
HttpSession session = hreq.getSession();
String requestedSession = hreq.getRequestedSessionId();
String currentWebSession = hreq.getSession().getId();
String currentpage = hreq.getPathTranslated();

// if currentpage is null or is not a jsp page don't do any filtering
if (currentpage == null || !(currentpage.endsWith(".jsp")) ) {
if (chain != null) chain.doFilter(request, response);
return;
}

// if the page is restricted and this filter is not
// already applied do this block
if ((isNonRestrictedPage(currentpage)==false) &&
(request.getAttribute(FILTER_APPLIED) == null){

request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//If the session bean is not null get the session bean property username.
String user=null;
// This LoggedInBean is has the login information
if(((LoggedInBean)session.getAttribute("backing_loggedin_bean"))!=null) {
user = ((LoggedInBean)session.getAttribute("backing_loggedin_bean")).getUserName();
}
// if the user is not set and the current page is not
// the login page then redirect back to login page
if (user==null && (!currentpage.endsWith("login.jsp")))
{
hres.sendRedirect("login.jsp");
return;
}
}

//deliver request to next filter
if (chain!=null)
chain.doFilter(request, response);

}
}


Step2 Register your custom servlet filter class in the web.xml



<filter>
<filter-name>Security Page Filter</filter-name>
<filter-class>SecurityCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Security Page Filter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

Saturday, February 21, 2009

Catch All exception page for a JSF web application

If your application wants to display a generic error page if an internal exception occurs in your web application then all you have to do is register an action listener in your faces config, under the application as follows

<faces-config>
<application>
<default-render-kit-id>oracle.adf.core</default-render-kit-id>
<action-listener>
view.faces.GlobalActionListener
</action-listener>
</application>
<navigation-rule>
<navigation-case>
<from-outcome>exceptionNavigation</from-outcome>
<to-view-id>/global_exception.html</to-view-id>
<redirect>
</redirect>
</navigation-case>
</navigation-rule>
</faces-config>



Once you have configured your faces config with the action listener you create your java class called GlobalActionListener



import com.sun.faces.application.ActionListenerImpl;
import javax.faces.application.Application;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.servlet.http.HttpSession;

public class GlobalActionListener extends ActionListenerImpl implements ActionListener{
public GlobalActionListener() {
super();
}
public void processAction(ActionEvent event){
try{
super.processAction(event);
}catch(Throwable exception){
//This part of the code is reached if any of your pages throw an exception and if it is not handled
FacesContext fc = FacesContext.getCurrentInstance();
Application app = fc.getApplication();
// goto this error page
NavigationHandler nhandler = app.getNavigationHandler();
nhandler.handleNavigation(fc, null, "exceptionNavigation");
// invalidate the session
ExternalContext ectx = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession)ectx.getSession(false);
session.invalidate();
fc.renderResponse();
}
}
}

Our GlobalActionListener implements the interface ActionListener and implements processAction method. It also extends the default Implementation from sun's class ActionListenerImpl. All that we have to do is call the base class's process Action and if an exception is throw catch that and redirect it to an exception page. In addition to redirecting to the exception page we also invalidate the http session.

The NavigationHandler class navigates to the exception page defined in faces config.