Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, May 16, 2012

Secure Password Storage - Lots of don'ts, a few dos, and a concrete Java SE example

Note: this post frequently refers to "encrypting" passwords, a term that usually implies that they could be decrypted. We're really talking about doing a one-way hash. I used the term "encrypt" to make it more accessible to those who are less familiar with cryptography, but "hash" would have been more precise.

The importance of storing passwords securely

As software developers, one of our most important responsibilities is the protection of our users' personal information. Without technical knowledge of our applications, users have no choice but to trust that we're fulfilling this responsibility. Sadly, when it comes to passwords, the software development community has a spotty track record.

While it's impossible to build a 100% secure system, there are fortunately some simple steps we can take to make our users' passwords safe enough to send would-be hackers in search of easier prey.

If you don't want all the background, feel free to skip to the Java SE example below.

The Don'ts

First, let's quickly discuss some of the things you shouldn't do when building an application that requires authentication:
  • Don't store authentication data unless you really have to. This may seem like a cop-out, but before you start building a database of user credentials, consider letting someone else handle it. If you're building a public application, consider using OAuth providers such as Google or Facebook. If you're building an internal enterprise application, consider using any internal authentication services that may already exist, like a corporate LDAP or Kerberos service. Whether it's a public or internal application, your users will appreciate not needing to remember another user ID and password, and it's one less database out there for hackers to attack.
  • If you must store authentication data, for Gosling's sake don't store the passwords in clear text. This should be obvious, but it bears mentioning. Let's at least make the hackers break a sweat.
  • Don't use two-way encryption unless you really need to retrieve the clear-text password. You only need to know their clear-text password if you are using their credentials to interact with an external system on their behalf. Even then, you're better off having the user authenticate with that system directly. To be clear, you do not need to use the user's original clear-text password to perform authentication in your application. I'll go into more detail on this later, but when performing authentication, you will be applying an encryption algorithm to the password the user entered and comparing it to the encrypted password you've stored. 
  • Don't use outdated hashing algorithms like MD5. Honestly, hashing a password with MD5 is virtually useless. Here's an MD5-hashed password:  569a70c2ccd0ac41c9d1637afe8cd932. Go to http://www.md5hacker.com/ and you can decrypt it in seconds.
  • Don't come up with your own encryption scheme. There are a handful of brilliant encryption experts in the world that are capable of outwitting hackers and devising a new encryption algorithm. I am not one of them, and most likely, neither are you. If a hacker gets access to your user database, they can probably get your code too. Unless you've invented the next great successor to PBKDF2 or bcrypt, they will be cackling maniacally as they quickly crack all your users' passwords and publish them on the darknet.

The Dos

Okay, enough lecturing on what not to do. Here are the things you need to focus on:
  • Choose a one-way encryption algorithm. As I mentioned above, once you've encrypted and stored a user's password, you never need to know the real value again. When a user attempts to authenticate, you'll just apply the same algorithm to the password they entered, and compare that to the encrypted password that you stored.
  • Make the encryption as slow as your application can tolerate. Any modern password encryption algorithm should allow you to provide parameters that increase the time needed to encrypt a password (i.e. in PBKDF2, specifying the number of iterations). Why is slow good? Your users won't notice if it takes an extra 100ms to encrypt their password, but a hacker trying a brute-force attack will notice the difference as they run the algorithm billions of times.
  • Pick a well-known algorithm. The National Institute of Standards and Technology (NIST) recommends PBKDF2 for passwords. bcrypt is a popular and established alternative, and scrypt is a relatively new algorithm that has been well-received. All these are popular for a reason: they're good. 

PBKDF2

Before I give show you some concrete code, let's talk a little about why PBKDF2 is a good choice for encrypting passwords:
  • Recommended by the NIST. Section 5.3 of Special Publication 800-132 recommends PBKDF2 for encrypting passwords. Security officials will love that.
  • Adjustable key stretching to defeat brute force attacks. The basic idea of key stretching is that after you apply your hashing algorithm to the password, you then continue to apply the same algorithm to the result many times (the iteration count). If hackers are trying to crack your passwords, this greatly increases the time it takes to try the billions of possible passwords. As mentioned previously, the slower, the better. PBKDF2 lets you specify the number of iterations to apply, allowing you to make it as slow as you like.
  • A required salt to defeat rainbow table attacks and prevent collisions with other users. A salt is a randomly generated sequence of bits that is unique to each user and is added to the user's password as part of the hashing. This prevents rainbow table attacks by making a precomputed list of results unfeasible. And since each user gets their own salt, even if two users have the same password, the encrypted values will be different. There is a lot of conflicting information out there on whether the salts should be stored someplace separate from the encrypted passwords. Since the key stretching in PBKDF2 already protects us from brute-force attacks, I feel it is unnecessary to try to hide the salt. Section 3.1 of NIST SP 800-132 also defines salt as a "non-secret binary value," so that's what I go with.
  • Part of Java SE 6. No additional libraries necessary. This is particularly attractive to those working in environments with restrictive open-source policies.

Finally, a concrete example

Okay, here's some code to encrypt passwords using PBKDF2. Only Java SE 6 is required.
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class PasswordEncryptionService {

 public boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt)
   throws NoSuchAlgorithmException, InvalidKeySpecException {
  // Encrypt the clear-text password using the same salt that was used to
  // encrypt the original password
  byte[] encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);

  // Authentication succeeds if encrypted password that the user entered
  // is equal to the stored hash
  return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
 }

 public byte[] getEncryptedPassword(String password, byte[] salt)
   throws NoSuchAlgorithmException, InvalidKeySpecException {
  // PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST
  // specifically names SHA-1 as an acceptable hashing algorithm for PBKDF2
  String algorithm = "PBKDF2WithHmacSHA1";
  // SHA-1 generates 160 bit hashes, so that's what makes sense here
  int derivedKeyLength = 160;
  // Pick an iteration count that works for you. The NIST recommends at
  // least 1,000 iterations:
  // http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
  // iOS 4.x reportedly uses 10,000:
  // http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/
  int iterations = 20000;

  KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);

  SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);

  return f.generateSecret(spec).getEncoded();
 }

 public byte[] generateSalt() throws NoSuchAlgorithmException {
  // VERY important to use SecureRandom instead of just Random
  SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

  // Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
  byte[] salt = new byte[8];
  random.nextBytes(salt);

  return salt;
 }
}

The flow goes something like this:
  1. When adding a new user, call generateSalt(), then getEncryptedPassword(), and store both the encrypted password and the salt. Do not store the clear-text password. Don't worry about keeping the salt in a separate table or location from the encrypted password; as discussed above, the salt is non-secret.
  2. When authenticating a user, retrieve the previously encrypted password and salt from the database, then send those and the clear-text password they entered to authenticate(). If it returns true, authentication succeeded.
  3. When a user changes their password, it's safe to reuse their old salt; you can just call getEncryptedPassword() with the old salt.
Easy enough, right? If you're building or maintaining an application that violates any of the "don'ts" above, then please do your users a favor and use something like PBKDF2 or bcrypt. Help them, Obi-Wan Developer, you're their only hope.

References

Monday, January 16, 2012

JSF and the "immediate" Attribute - Command Components

The immediate attribute in JSF is commonly misunderstood. If you don't believe me, check out Stack Overflow. Part of the confusion is likely due to immediate being available on both input (i.e.. <h:inputText />) and command (i.e. <h:commandButton />) components, each of which affects the JSF lifecycle differently.

Here is the standard JSF lifecycle:


For the purposes of this article, I'll assume you are familiar with the basics of the JSF lifecycle. If you need an introduction or a memory refresher, check out the Java EE 6 Tutorial - The Lifecycle of a JavaServer Faces Application.

Note: the code examples in this article are for JSF 2 (Java EE 6), but the principals are the same for JSF 1.2 (Java EE 5).

immediate=true on Command components

In the standard JSF lifecycle, the action attribute on an Command component is evaluated in the Invoke Application phase. For example, say we have a User entity/bean:

public class User implements Serializable {

 @NotBlank
 @Length(max = 50)
 private String firstName;

 @NotBlank
 @Length(max = 50)
 private String lastName;

 /* Snip constructors, getters/setters, a nice toString() method, etc */
}

And a UserManager to serve as our managed bean:

@SessionScoped
@ManagedBean
public class UserManager {
 private User newUser;

 /* Snip some general page logic... */

 public String addUser() {
  //Snip logic to persist newUser

  FacesContext.getCurrentInstance().addMessage(null,
    new FacesMessage("User " + newUser.toString() + " added"));

  return "/home.xhtml";
 }

And a basic Facelets page, newUser.xhtml, to render the view:

<h:form>
 <h:panelGrid columns="2">

  <h:outputText value="First Name: " />
  <h:panelGroup>
   <h:inputText id="firstName"
    value="#{userManager.newUser.firstName}" />
   <h:message for="firstName" />
  </h:panelGroup>

  <h:outputText value="Last Name: " />
  <h:panelGroup>
   <h:inputText id="lastName" value="#{userManager.newUser.lastName}" />
   <h:message for="lastName" />
  </h:panelGroup>

 </h:panelGrid>

 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
</h:form>

Which all combine to produce this lovely form:


When the user clicks on the Add User button, #{userManager.addUser} will be called in the Invoke Application phase; this makes sense, because we want the input fields to be validated, converted, and applied to newUser before it is persisted.

Now let's add a "cancel" button to the page, in case the user changes his/her mind. We'll add another <h:commandButton /> to the page:

<h:form>
 <!-- Snip Input components --> 

 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
 <h:commandButton value="Cancel" action="#{userManager.cancel()}" />
</h:form>

And the cancel() method to UserManager:

public String cancel() {
 newUser = new User();

 FacesContext.getCurrentInstance().addMessage(null,
   new FacesMessage("Cancelled new user"));

 return "/home.xhtml";
}

Looks good, right? But when we actually try to use the cancel button, we get errors complaining that first and last name are required:

This is because #{userManager.cancel} isn't called until the Invoke Application phase, which occurs after the Process Validations phase; since we didn't enter a first and last name, the validations failed before #{userManager.cancel} is called, and the response is rendered after the Process Validations phase.

We certainly don't want to require the end user to enter a valid user before cancelling! Fortunately, JSF provides the immediate attribute on Command components. When immediate is set to true on an Command component, the action is invoked in the Apply Request Values phase:


This is perfect for our Cancel use case. If we add immediate=true to the Cancel , #{userManager.cancel} will be called in the Apply Request Values phase, before any validation occurs.


<h:form>  
 <!-- Snip Input components -->

 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
 <h:commandButton value="Cancel" action="#{userManager.cancel()}" immediate="true" />
</h:form>

So now when we click cancel, #{userManager.cancel} is called in the Apply Request Values phase, and we are directed back to the home page with the expected cancellation message; no validation errors!



What about Input components?

Input components have the immediate attribute as well, which also moves all their logic into the Apply Request Values phase. However, the behavior is slightly different from Command components, especially depending on whether or not the validation on the Input component succeeds. My next article will address immediate=true on Input components. For now, here's a preview of how the JSF lifecycle is affected:





Thursday, October 13, 2011

Replacement for s:decorate in Seam 3

I've been doing a gap analysis for our migration from Seam 2 to Seam 3, and I was dismayed to find that the <s:decorate> tag is gone! In Seam 2, you create a template like this:

<ui:composition  xmlns="http://www.w3.org/1999/xhtml"
                 xmlns:ui="http://java.sun.com/jsf/facelets"
                 xmlns:h="http://java.sun.com/jsf/html"
                 xmlns:f="http://java.sun.com/jsf/core"
                 xmlns:s="http://jboss.com/products/seam/taglib">

    <div class="prop">
        <s:label styleClass="nameEdit #{invalid?'errors':''}">
            <s:span styleClass="required"
               rendered="#{required}">*</s:span>
            <ui:insert name="label"/>
        </s:label>

        <span class="value #{invalid?'errors':''}">
            <s:validateAll>
                <ui:insert/>
            </s:validateAll>
        </span>

        <span class="error">
            <h:graphicImage value="/img/error.gif" 
                rendered="#{invalid}" styleClass="errors"/>
        </span>
    </div>
</ui:composition>

And then reference it using <s:decorate>

<s:decorate template="edit.xhtml">
  <ui:define name="label">Country:</ui:define>
  <h:inputText value="#{location.country}" required="true"/>
</s:decorate>

And now required fields are noted with an asterisk (*), all fields are automatically validated, and when they have errors, a special style is applied and the error message appears to the right of the field:


Note: this is all documented in Section 33.1.13 of the Seam 2 reference.

Pretty slick! I definitely need this functionality when I migrate to Seam 3, but the <s:decorate> tag is gone, and I had a hard time finding a replacement.

Replacing with UIInputContainer

Fortunately, a close replacement actually exists in Seam 3's Faces module... it just isn't described as such! Seam Faces provides a component called UIInputContainer. When this is combined with a JSF 2 composite component, you can get the same functionality.

First, create your composite component. I created mine at WebContent/resources/orr/decorate.xhtml:

<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface componentType="org.jboss.seam.faces.InputContainer" />

<composite:implementation>
 <div>
  <h:outputLabel id="label" value="#{cc.attrs.label}:"
   styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">

   <h:outputText styleClass="required" rendered="#{cc.attrs.required}"
    value="*" />

  </h:outputLabel>

  <!-- h:panelGroup is a workaround for a JSF bug, see http://java.net/jira/browse/JAVASERVERFACES-1991  -->
  <h:panelGroup styleClass="value #{invalid?'errors':''}" >
   <composite:insertChildren />
  </h:panelGroup>

  <h:message id="message" errorClass="invalid message"
   rendered="#{cc.attrs.invalid}" />
 </div>
</composite:implementation>
</html>

Since I put the composite component in WebContent/resources/orr/decorate.xhtml, the namespace is http://java.sun.com/jsf/composite/orr and the tag name is decorate.

Now use this new tag in your Facelets page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:o="http://java.sun.com/jsf/composite/orr">



<o:decorate label="Country:">
    <h:inputText value="#{location.country}" required="true"/>
</o:decorate>

And that's it! This will generate roughly the same output and behavior as Seam 2's <s:decorate> tag. So all along, there was a pretty good replacement, but either this wasn't made clear anywhere, or my Google skills aren't quite as good as I think. I imagine this would be documented in JBoss's Seam 2 to Seam 3 migration guide, if such a thing existed...

Friday, October 7, 2011

Creating a JSF 1.2 Custom Converter with Attributes

Custom converters are a very important part of many JSF applications. Writing and using a basic converter is quite simple if it has no attributes:

<h:outputText value="#{somePhoneNumber}" 
  converter="myPhoneNumberConverter" />

However, things get a little trickier when you need to provide attributes to your converter. For example, Facelets includes a date/time converter:

<h:outputText value="#{someDate}">
  <f:convertDateTime type="both" dateStyle="short"/>
</h:outputText>

While there are many resources out there on creating basic custom converters, I had difficulty finding a good explanation of how to create custom converters with attributes. Here are the steps I followed:

Note: I built this using Seam 2.2 on JBoss EAP 5.1, but this should work for any JSF 1.2 application using Facelets.

The USAPhoneNumber class

We'll be creating a converter for a class called USAPhoneNumber. There's nothing special about this class, just a POJO with an attribute for each "part" of a US phone number.

package org.orr.customconverter;

import java.io.Serializable;

public class USAPhoneNumber implements Serializable {
 private static final long serialVersionUID = 1L;

 private String areaCode;
 private String prefix;
 private String lineNumber;
 private String extension;

 public USAPhoneNumber(String areaCode, String prefix, String lineNumber,
   String extension) {
  super();
  this.areaCode = areaCode;
  this.prefix = prefix;
  this.lineNumber = lineNumber;
  this.extension = extension;
 }

 public USAPhoneNumber(String areaCode, String prefix, String lineNumber) {
  super();
  this.areaCode = areaCode;
  this.prefix = prefix;
  this.lineNumber = lineNumber;
 }

 public String getAreaCode() {
  return areaCode;
 }

 public String getPrefix() {
  return prefix;
 }

 public String getLineNumber() {
  return lineNumber;
 }

 public String getExtension() {
  return extension;
 }

 @Override
 public String toString() {
  String tmp = areaCode + "-" + prefix + "-" + lineNumber;
  if (extension != null && extension.length() > 0)
   tmp += " x" + extension;

  return tmp;
 }
}


Create a Converter class

First we'll create an implementation of javax.faces.convert.Converter. We might want the ability to convert it into a few different styles, such as 212-555-7456, (212) 555-7456, 212 555 7456, etc. To support this, we are creating an attribute called style, which will accept values like parentheses, dashes, and spaces.

package org.orr.customconverter;

import java.io.Serializable;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

public class PhoneNumberConverter implements Converter, Serializable {
 private static final long serialVersionUID = 1L;

 private String style;

 private static final Style DEFAULT_STYLE = Style.DASHES;

 private enum Style {
  DASHES, SPACES, PARENTHESES
 };

 public Object getAsObject(FacesContext context, UIComponent component,
   String stringValue) {

  if (stringValue == null || stringValue.trim().length() == 0)
   return null;

  // We COULD try to read in the value based on the style, but in this
  // case, it's easiest to just strip out all non-numeric characters and
  // require that the number be greater than 10 digits, with any digits
  // past 10 becoming the extension
  String rawNumber = stringValue.replaceAll("[^0-9]", "");

  USAPhoneNumber number = null;

  if (rawNumber.length() < 10)
   throw new ConverterException(new FacesMessage(
     "Phone number must have at least 10 numeric characters"));
  else if (rawNumber.length() == 10)
   number = new USAPhoneNumber(rawNumber.substring(0, 3),
     rawNumber.substring(3, 6), rawNumber.substring(6));
  else
   number = new USAPhoneNumber(rawNumber.substring(0, 3),
     rawNumber.substring(3, 6), rawNumber.substring(6, 10),
     rawNumber.substring(10));

  return number;
 }

 public String getAsString(FacesContext context, UIComponent component,
   Object value) {
  USAPhoneNumber number = (USAPhoneNumber) value;

  if (number == null)
   return "";

  String stringValue = null;

  Style styleEnum = style == null ? DEFAULT_STYLE : Style.valueOf(style
    .toUpperCase());

  switch (styleEnum) {
  case DASHES:
   stringValue = number.getAreaCode() + "-" + number.getPrefix() + "-"
     + number.getLineNumber() + getFormattedExtension(number);
   break;
  case SPACES:
   stringValue = number.getAreaCode() + " " + number.getPrefix() + " "
     + number.getLineNumber() + getFormattedExtension(number);
   break;
  case PARENTHESES:
   stringValue = "(" + number.getAreaCode() + ") "
     + number.getPrefix() + "-" + number.getLineNumber()
     + getFormattedExtension(number);
   break;
  default:
   throw new ConverterException(new FacesMessage("Unsupported style: "
     + style));
  }

  return stringValue;
 }

 private String getFormattedExtension(USAPhoneNumber number) {
  if (number.getExtension() == null)
   return "";
  else
   return " x" + number.getExtension();
 }

 public String getStyle() {
  return style;
 }

 public void setStyle(String style) {
  this.style = style;
 }
}

If you've written a JSF converter before, this will look pretty familiar. However, there are a few things to note:
  1. You must implement java.io.Serializable. After the RENDER RESPONSE phase, JSF serializes the view; in the RENDER RESPONSE phase, it deserializes it. If your converter does not implement Serializable, the attribute(s) (style in this example) will be lost.
  2. You must not make your converter a Seam component. Seam provides some handy annotations to save some of the configuration overhead in creating a converter (see section 33.2 in the Seam reference for details). However, if you are using the same converter with different attribute values on the same page, Seam will reuse the same instance with the same attribute values on the entire page. Note: this might be avoidable by using the STATELESS scope, but I haven't tried it.

Create taglib.xml

Now we need to create a Facelets tag library definition. We'll call it orr-taglib.xml and put it in WebContent/META-INF:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">

<facelet-taglib>
 <namespace>http://jerryorr.blogspot.com/customConverterTaglib</namespace>
 <tag>
  <tag-name>convertPhoneNumber</tag-name>
  <converter>
   <converter-id>orr.convertPhoneNumber</converter-id>
  </converter>
 </tag>
</facelet-taglib>

We also need to register the taglib in web.xml:

<context-param>
 <param-name>facelets.LIBRARIES</param-name>
 <param-value>/META-INF/orr-taglib.xml</param-value>
</context-param>

Register converter in faces-config.xml

Next, we need to register our converter in faces-config.xml. Note: this is one of those steps that Seam can save for us, but since we aren't making this a Seam component, we need to register the converter manually.

<converter>
  <converter-id>orr.convertPhoneNumber</converter-id>
  <converter-class>org.orr.customconverter.PhoneNumberConverter</converter-class>
 </converter>

Create a TLD

Finally, we'll create a tag library descriptor. This step is not strictly necessary, but Eclipse will use it for autocomplete.

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
 <tlib-version>2.0</tlib-version>
 <short-name>n</short-name>
 <uri>http://jerryorr.blogspot.com/customConverterTaglib</uri>

 <tag>
  <description>Converts a USAPhoneNumber.</description>
  <name>convertPhoneNumber</name>
  <tag-class>org.orr.customconverter.PhoneNumberConverter</tag-class>
  <body-content>JSP</body-content>
  <attribute>
   <description>Style to display the phone number. Valid values include parentheses, dashes, spaces</description>
   <name>style</name>
   <rtexprvalue>true</rtexprvalue>
   <deferred-value>
    <type>java.lang.String</type>
   </deferred-value>
  </attribute>
 </tag>
</taglib>

Using the converter

Now we can use our phone number converter! We'll create a simple Seam component to interact with:

package org.orr.customconverter;

import java.io.Serializable;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.international.StatusMessage.Severity;
import org.jboss.seam.international.StatusMessages;

@Name("updatePhoneNumberAction")
@Scope(ScopeType.SESSION)
public class UpdatePhoneNumberAction implements Serializable {
 private static final long serialVersionUID = 1L;

 private USAPhoneNumber phoneNumber = new USAPhoneNumber("212", "555",
   "3456");

 @In
 StatusMessages statusMessages;

 public USAPhoneNumber getPhoneNumber() {
  return phoneNumber;
 }

 public void setPhoneNumber(USAPhoneNumber phoneNumber) {
  this.phoneNumber = phoneNumber;
 }

 public void update() {
  statusMessages.add(Severity.INFO, "Phone number updated: "
    + phoneNumber);
 }
}

And a simple Facelets view to interact with it:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:o="http://jerryorr.blogspot.com/customConverterTaglib"
 contentType="text/html">

 <h:messages />

 <h:form>
  <h:panelGrid columns="2" border="1">
   <h:outputText value="Style" style="font-weight: bold" />
   <h:outputText value="Output" style="font-weight: bold" />

   <h:outputText value="(default)" />
   <h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
    <o:convertPhoneNumber />
   </h:outputText>

   <h:outputText value="parentheses" />
   <h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
    <o:convertPhoneNumber style="parentheses" />
   </h:outputText>

   <h:outputText value="spaces" />
   <h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
    <o:convertPhoneNumber style="spaces" />
   </h:outputText>

   <h:outputText value="dashes" />
   <h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
    <o:convertPhoneNumber style="dashes" />
   </h:outputText>
  </h:panelGrid>

  <p>
   Phone Number:
   <h:inputText value="#{updatePhoneNumberAction.phoneNumber}">
    <o:convertPhoneNumber style="spaces" />
   </h:inputText>
   <h:commandButton action="#{updatePhoneNumberAction.update()}"
    value="Update" />
  </p>
 </h:form>
</f:view>

When we first load the page, we can see our converter in action:


And since we have our converter on the inputText component, we can see it converter back to a USAPhoneNumber when we add an extension:


Hopefully, all of this will be a lot easier in future versions of JSF. For those of us stuck on JSF 1.2, though, creating our own converters with attributes can come in handy!