Wednesday, June 06, 2012

Ensure Password Rules for JPasswordField input

Java's standard regular expression classes like Pattern and Matcher only support CharSequence which includes String and StringBuffer but not char[]. And, for security reasons, it is important to never convert a password into a String. It is advisable to keep the password in a char array. So, how do you enforce password rules on a char array. The below code is a sample of how you will need to implement password rules:
      public static boolean isPasswordPatternValid(char[] password) {  
           if (password == null || password.length < 8) {  
                return false;  
           }  
           boolean hasDigit = false;  
           boolean hasLower = false;  
           boolean hasUpper = false;  
           boolean hasSpecial = false;  
           char[] specialChars = new char[] {'~','@','#','$','%','^','&','*','(',')'};  
           for (int i = 0; i < password.length; i++) {  
                if (!hasDigit && Character.isDigit(password[i])) {  
                     hasDigit = true;  
                     continue;  
                }  
                if (!hasLower && Character.isLowerCase(password[i])) {  
                     hasLower = true;  
                     continue;  
                }  
                if (!hasUpper && Character.isUpperCase(password[i])) {  
                     hasUpper = true;  
                     continue;  
                }  
                if (!hasSpecial) {  
                     for (int j = 0; j < specialChars.length; j++) {  
                          if (password[i] == specialChars[j]) {  
                               hasSpecial = true;  
                               break;  
                          }  
                     }  
                }  
           }  
           return true;  
      }  

Tuesday, June 05, 2012

JDialog with Multiple Input Fields

The below code displays password fields in a dialog window. The window is disposed when any of the buttons are clicked. If you want to prevent the dialog from closing if the entries are invalid, you will need to create custom dialog windows. An example of custom dialog is given below:
     

           //STANDARD JDialog code      
           final JPasswordField oldPassword = new JPasswordField();  
           final JPasswordField newPassword = new JPasswordField();  
           final JPasswordField confirmNewPassword = new JPasswordField();  
           final JComponent[] inputs = new JComponent[] {  
                     new JLabel("Old Password:"),  
                     oldPassword,  
                     new JLabel("New Password:"),  
                     newPassword,  
                     new JLabel("Confirm New Password:"),  
                     confirmNewPassword  
           };  
           int result = JOptionPane.showConfirmDialog(null, inputs, "Change Password", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);  
           System.out.println("Old Password:" + new String(oldPassword.getPassword()));  
           System.out.println("New Password:" + new String(newPassword.getPassword()));  
           System.out.println("Confirm New Password:" + new String(confirmNewPassword.getPassword()));  
           if(result == JOptionPane.OK_OPTION){  
                if (!KeyManager.isPasswordPatternValid(oldPassword.getPassword())
                      || !KeyManager.isPasswordPatternValid(newPassword.getPassword())) {  
                     JOptionPane.showMessageDialog (null, KeyManager.passwordPatternRules, "Invalid Password", JOptionPane.ERROR_MESSAGE);  
                     return;  
                }  
                if (!KeyManager.isPasswordReentryMatch(newPassword.getPassword(), confirmNewPassword.getPassword())) {  
                     JOptionPane.showMessageDialog (null, "Passwords do not match!", "Password Mismatch", JOptionPane.ERROR_MESSAGE);  
                     return;  
                }  
                KeyManager.changePassword(oldPassword.getPassword(), newPassword.getPassword());  
                return;  
           } else {  
                return;  
           }  

The following code is custom code that prevents the password entry dialog window from being closed if there are are errors.
          
 
                //CUSTOM JDialog code
  final JPasswordField oldPassword = new JPasswordField();
  final JPasswordField newPassword = new JPasswordField();
  final JPasswordField confirmNewPassword = new JPasswordField();
  final JComponent[] inputs = new JComponent[] {
    new JLabel("Old Password:"),
    oldPassword,
    new JLabel("New Password:"),
    newPassword,
    new JLabel("Confirm New Password:"),
    confirmNewPassword
  };
  final JOptionPane jop = new JOptionPane(inputs,
    JOptionPane.WARNING_MESSAGE,
    JOptionPane.OK_CANCEL_OPTION);
  final JDialog dialog = new JDialog(parentFrame, "Re-Enter Password:");
  dialog.setContentPane(jop);
  dialog.setVisible(true);
  jop.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent e) {
             String prop = e.getPropertyName();
             Object value = jop.getValue();
             if (value == JOptionPane.UNINITIALIZED_VALUE) {
                 return;
             }        
             jop.setValue(JOptionPane.UNINITIALIZED_VALUE);
          if (((Integer)value).intValue() == JOptionPane.CANCEL_OPTION ) {
        dialog.setVisible(false);
        return;
          }
             if (dialog.isVisible() 
              && (e.getSource() == jop)
              && (prop.equals(JOptionPane.VALUE_PROPERTY))) {
              if (!KeyManager.isPasswordPatternValid(oldPassword.getPassword()) 
                || !KeyManager.isPasswordPatternValid(newPassword.getPassword())) {
         JOptionPane.showMessageDialog (null, KeyManager.passwordPatternRules, "Invalid Password", JOptionPane.ERROR_MESSAGE);
         return;
        }
        if (!KeyManager.isPasswordReentryMatch(newPassword.getPassword(), confirmNewPassword.getPassword())) {
         JOptionPane.showMessageDialog (null, "Passwords do not match!", "Password Mismatch", JOptionPane.ERROR_MESSAGE);
         return;
        }
        KeyManager.changePassword(oldPassword.getPassword(), newPassword.getPassword());
        dialog.setVisible(false);
        return;
             }
         }
     });

Wednesday, May 30, 2012

Convert char[] array to byte[] array in Java

I have spent a few hours trying to convert a char[] returned by a JPasswordField into a byte[] that I can encrypt in Java. Here is the conversion code that I finally came up with :
      public void testArrayConversionJapanese() {  
           String hello = new String("こんにちは世界");  
           char[] charArray = hello.toCharArray();  
           byte[] byteArray = new byte[charArray.length*2];  
           for (int i=0; i < charArray.length; i++) {  
                byteArray[i*2] = (byte) ((charArray[i] & 0xFF00) >> 8);  
                byteArray[i*2+1] = (byte) (charArray[i] & 0x00FF);  
           }  
           char[] chars2 = new char[byteArray.length/2];  
           for(int i=0; i < chars2.length; i++) {  
                //bytes must be & with 0x00FF to convert negative values into unsigned positive values  
                chars2[i] = (char) (((byteArray[i*2]&0x00FF) << 8) + (byteArray[i*2+1]&0x00FF));  
           }  
           String hello2 = new String(chars2);  
           assertEquals(hello, hello2);  
      }  
As you can see above, I have used basic array and shift operations for the conversion. This is much more efficient than using java.lang.Character, String and Byte classes to do the conversions.

Tuesday, May 29, 2012

NoClassDefFoundError in Eclipse after upgrade

Sometimes when you open a project for the first time after upgrading your Eclipse IDE, you may find that the project does not run. All the classes and package structure look fine in the Package Explorer but the application fails to run with a NoClassDefFoundError. Even your JUnits fail with the NoClassDefFoundError and the stacktrace usually looks like this:

 Exception in thread "main" java.lang.NoClassDefFoundError: com/vj/test/javatext/TestByteCharConversion  
 Caused by: java.lang.ClassNotFoundException: com.vj.test.javatext.TestByteCharConversion  
  at java.net.URLClassLoader$1.run(URLClassLoader.java:202)  
  at java.security.AccessController.doPrivileged(Native Method)  
  at java.net.URLClassLoader.findClass(URLClassLoader.java:190)  
  at java.lang.ClassLoader.loadClass(ClassLoader.java:307)  
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)  
  at java.lang.ClassLoader.loadClass(ClassLoader.java:248)  
 Could not find the main class: com.vj.test.javatext.TestByteCharConversion. Program will exit.  


The root cause of this could be builders that your project depends upon but are no longer available in the upgraded version of Eclipse. For example, you may have AspectJ code that depends on the AJDT plugin being available in Eclipse. You can confirm this by opening Project -> Properties -> Builders. If you find any "Missing builder" entries, download the appropriate plugins from the Eclipse Marketplace. This should solve your problems. Here is a sample screenshot.


Hope this post helped you. 

Sunday, March 18, 2012

A shout out to Barnes & Noble

B&N, you should allow your customers to buy online and pick up in your stores. I love the experience in your stores and, the prices and choices on your site. Putting the two together you can reduce your shipping costs, generate more traffic for your stores, improve my experience and help you beat the crap out of Amazon.
I am sure you know this already but I am writing this post as one more voice pushing you forward.