/* * Copyright (c) 2001 Matthew Feldt. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided the copyright notice above is * retained. * * THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESSED OR * IMPLIED WARRANTIES. */ /** * PasswordManager.java * * Java Examples In A Nutshell Copyright (c) 2000 David Flanagan * Exercise 6-1: * Write a PasswordManager class that associates usernames with passwords and * has methods for creating and deleting username/password pairs, changing * the password associated with a username, and authenticating a user by verify- * ing a supplied password. PasswordManager should store the usernames and * passwords in a file (or in a database if you've already read Chapter 17, * Database Access with SQL) * * Note, however, that the class should not store the passwords as plain text as * that would allow an intruder who broke into the PasswordManager system to * obtain full access to all passwords. Message digests, such as those used * in Example 6-4, provide exactly this kind of a one-way function. Computing a * message digest for a password is relatively easy, but going in the opposite * direction from digest to password is very difficult or impossible. * * Design the PasswordManager class so that instead of storing the actual pass- * word, it stores only a mesage digest of the password. To verify a user's pass- * word, your class should compute a digest for the supplied password and * compare it to the stored digest. If the digests match, you can assume that the * passwords match also. (There is actually an infinitesimally small chance that * two different passwords will product the same message digest, but you can * disregard that possibility.) * * @author Matthew Feldt * @version 1.0, 03/13/2001 07:27 */ package com.feldt.examples.security; import java.io.*; import java.util.*; import java.security.*; public class PasswordManager { private static final String header = "username:password"; private Properties users; private File passwordFile; /** create a PasswordManager object with the specified password file */ PasswordManager(String filename) throws FileNotFoundException, IOException { users = new Properties(); passwordFile = new File(filename); if (passwordFile.exists() && passwordFile.isFile() && passwordFile.canRead()) { FileInputStream fd = new FileInputStream(passwordFile); users.load(fd); fd.close(); } } /** write the username/password pairs to a file */ public void store() throws FileNotFoundException, IOException { FileOutputStream fd = new FileOutputStream(passwordFile); users.store(fd, header); fd.close(); } /** * returns a string representation of the Properties object that * contains the username/password pairs. */ public String toString() { return users.toString(); } /** return an MD5 digest of the String parameter in */ private String createDigest(String in) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); return new String(md.digest(in.getBytes())); } /** * locate the user specified by username and verify the existing * password against the parameter password. */ public boolean authenticate(String username, String password) throws NoSuchAlgorithmException { String pwd = users.getProperty(username); if (pwd == null) return false; // no such user return pwd.equals(createDigest(password)); } /** create a username/password pair, storing password as an MD5 digest */ public boolean create(String username, String password) throws NoSuchAlgorithmException { if (users.getProperty(username) != null) // user already exists return false; users.setProperty(username, createDigest(password)); return true; } /** * Delete an existing username/password pair specified by the input * parameter username. */ public boolean delete(String username, String password) throws NoSuchAlgorithmException { String pwd = users.getProperty(username); if (pwd == null) return false; // no such user if (! pwd.equals(createDigest(password))) // password doesn't match return false; users.remove(username); return true; } /** * Modify an existing username/password pair specified by the input * parameter username. */ public boolean modify(String username, String password, String newPassword) throws NoSuchAlgorithmException { String pwd = users.getProperty(username); if (pwd == null) return false; // no such user if (! pwd.equals(createDigest(password))) // password doesn't match return false; users.setProperty(username, createDigest(newPassword)); return true; } public static void main(String args[]) { final String USAGE = "java PasswordManager [-a|-c|-d|-m] " + " [newPassword]\n\nwhere options are:\n" + " -a\tauthenticate\n -c\tcreate\n -d\tdelete\n" + " -m\tmodify (requires newPassword)\n"; final String PASSWORD_FILE = "password"; try { switch(args.length) { case 3: if (args[0].equals("-m")) throw new IllegalArgumentException(USAGE); break; case 4: if (! args[0].equals("-m")) throw new IllegalArgumentException(USAGE); break; default: throw new IllegalArgumentException(USAGE); } PasswordManager pwm = new PasswordManager(PASSWORD_FILE); String username = args[1]; String password = args[2]; if (args[0].equals("-a")) { // authenticate an existing user if (pwm.authenticate(username, password)) System.out.println(username + ": authenticated."); else System.out.println(username + ": authentication failed."); } else if (args[0].equals("-c")) { // create a user if (pwm.create(username, password)) { System.out.println(username + ": created."); pwm.store(); } else System.out.println(username + ": creation failed."); } else if (args[0].equals("-d")) { // delete an existing user if (pwm.delete(username, password)) { System.out.println(username + ": deleted."); pwm.store(); } else System.out.println(username + ": deletion failed."); } else if (args[0].equals("-m")) { // modify an existing user String newPassword = args[3]; if (pwm.modify(username, password, newPassword)) { System.out.println(username + ": modified."); pwm.store(); } else System.out.println(username + ": modification failed."); } else { throw new IllegalArgumentException(USAGE); } } catch (NoSuchAlgorithmException e) { System.err.println(e.getMessage()); System.exit(-1); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); System.exit(-1); } catch (FileNotFoundException e) { System.err.println(e.getMessage()); System.exit(-1); } catch (IOException e) { System.err.println(e.getMessage()); System.exit(-1); } } }