1

I am developing a standalone application to test a website using Selenium Webdriver. The application will use a JavaFX, or Swing, UI to allow a user to load a test suite file and select which tests to run and which browser to run them in. The UI will also capture data used by the tests, such as usernames and passwords.

I am planning on using JUnitCore to run the selected test classes but I will need to pass data from the UI to the test classes. For most of the data I can do this using System.setProperty(prop, value). However I will also need to pass admin, and other, passwords for the website to the tests

What would be the best way to pass the password(s) to the tests?

What would be the security concerns when using System.setProperty to store passwords? Should I instead encrypt the data and store it in a file and have the tests read the file and decrypt the data? This would obviously increase the amount of processing required to set up each test

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
tom dude
  • 13
  • 2

1 Answers1

0
  • If the user who runs the UI knows the passwords, then I don't really see your security concerns. Who are you defending from?
  • If the user who runs the UI does not know the passwords (and the passwords should be stored in the testcases themselves), then you're in a pickle - encrypting is good, but you have to store the password for decrypting somehow ... endless circle, there's no safe space. Even if the storing is safe, the weak points are definitely the transfer to browser (which will be done as plain string encapsulated in JSON no matter what) and the automated typing into the browser itself. Seriously, if you don't trust the machines the tests are run on, don't store the passwords.

However, for the first case (when the user has to type in the password into the UI), to minimize the possibility of threat and also for maximum convenience, I'd do this:

  1. create a singleton class PasswordHolder
  2. a PasswordHolder would remember the passwords (given to them by JPasswordField) in a Map<String, char[]> or Map<String, Password> where key is some password identifier and value is the password itself
  3. once a password would be accessed via getPassword() method, it's contents would get nullified

A quick sample implementation (for further improvement as I hope I won't forget to include anything important ... but it could happen). I think it kinda speaks for itself:

public class PasswordHolder {

    private static PasswordHolder instance = null; 
    private final Map<String, Password> map = new HashMap<String, Password>();

    private PasswordHolder() {
        // nothing to do
    }

    public static PasswordHolder getInstance() {
        if (instance == null) {
            instance = new PasswordHolder();
        }
        return instance;
    }

    public void addPassword(String name, char[] pass) {
        if (map.containsKey(name)) {
            // throw some sort of Exception("Duplicate password name, man.")
        }
        map.put(name, new Password(pass));
    }

    public Password getPassword(String name) {
        return map.get(name);
    }

}

As the most convenient thing, I wrote Password to be a CharSequence so is useful with sendKeys(CharSequence keys). Unfortunately, sendKeys() uses toString(), so you have to make a String out of the password anyway (which is considered a bad practice).

public class Password implements CharSequence {

    private final char[] pass;
    private final BitSet nulled;

    Password(char[] pass) {
        this.pass = pass;
        nulled = new BitSet(pass.length);
    }

    private void nullify(int start, int end) {
        for (int i = start; i < end; i++) {
            pass[i] = '\0';
        }
        nulled.set(start, end);
    }

    @Override
    public int length() {
        return pass.length;
    }

    @Override
    public char charAt(int index) {
        if (nulled.get(index)) {
            // throw some Exception("That character has already been read!")
        }
        char ret = pass[index];
        pass[index] = '\0';
        nulled.set(index);
        return ret;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        if (nulled.get(start, end).cardinality() > 0) {
            // throw some Exception("Some of the characters has already been read!")
        }
        Password subPass = new Password(Arrays.copyOfRange(pass, start, end)); 
        nullify(start, end);
        return subPass;
    }

    @Override
    public String toString() {
        if (nulled.cardinality() > 0) {
            // throw some Exception("Some of the characters has already been read!")
        }
        String str = new String(pass);
        nullify(0, pass.length);
        return str;
    }

}
Community
  • 1
  • 1
Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
  • Also, I'd love to see (and get my hands on) the UI for tests ;) – Petr Janeček May 31 '12 at 12:17
  • Many thanks for your help. The user who runs the program will know the passwords so I see your point about who would I be defending them from. This is for my own academic interest but if I develop something which could be generally useful, rather than for just a specific site, I'll share it. – tom dude May 31 '12 at 12:57
  • That's what I thought and that's what I counted on when I wrote those classes. In any case, try to make the password as short-lived as possible, try avoid using String, add simple encryption if you feel like it (it's a nice exercise, too!). There's a new `Password` implementation, too. – Petr Janeček May 31 '12 at 14:28