001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.security;
007:
008: import java.io.BufferedReader;
009: import java.io.IOException;
010: import java.io.InputStreamReader;
011: import java.security.MessageDigest;
012: import java.security.NoSuchAlgorithmException;
013: import java.security.SecureRandom;
014: import java.sql.Connection;
015: import java.sql.PreparedStatement;
016: import java.sql.ResultSet;
017: import java.sql.SQLException;
018: import java.util.Date;
019:
020: import org.jasig.portal.RDBMServices;
021:
022: /**
023: * <p>A utility class that demonstrates changing and locking md5 passwords in
024: * the UP_PERSON_DIR table. The program accepts two optional flags <code>-c</code>
025: * causes the user to be created if he/she doesn't exist. The <code>-l</code>
026: * flag causes the specified user's account to be locked.</p>
027: *
028: * @author Andrew Newman, newman@yale.edu
029: * @version $Revision: 35498 $
030: */
031: public class Md5Passwd {
032:
033: static private final String SELECTSTMT = "SELECT COUNT(*) FROM UP_PERSON_DIR WHERE USER_NAME = ?";
034: static private final String UPDATESTMT = "UPDATE UP_PERSON_DIR SET ENCRPTD_PSWD = ? WHERE USER_NAME = ?";
035: static private final String INSERTSTMT = "INSERT INTO UP_PERSON_DIR (USER_NAME, ENCRPTD_PSWD) "
036: + "VALUES (?, ?)";
037:
038: public Md5Passwd(String user, boolean create, boolean lock)
039: throws IOException, NoSuchAlgorithmException, SQLException {
040: byte[] hash, rnd = new byte[8], fin = new byte[24];
041: Long date = new Long((new Date()).getTime());
042: SecureRandom r = new SecureRandom((date.toString()).getBytes());
043: MessageDigest md = MessageDigest.getInstance("MD5");
044: Connection conn;
045: PreparedStatement stmt;
046: ResultSet rset;
047: String spass;
048: int cnt = 0;
049:
050: // Make sure user is specified correctly
051: if (user == null || user.trim().length() <= 0) {
052: System.out
053: .println("You did not specify a valid user name. Please try again.");
054: System.exit(0);
055: }
056:
057: // Check to see if the user exists
058:
059: conn = RDBMServices.getConnection();
060: stmt = conn.prepareStatement(SELECTSTMT);
061: stmt.setString(1, user);
062: rset = stmt.executeQuery();
063: if (rset.next())
064: cnt = rset.getInt(1);
065: rset.close();
066: stmt.close();
067: if (cnt < 1 && create == false) {
068: System.out.println("No such user: " + user);
069: RDBMServices.releaseConnection(conn);
070: return;
071: }
072:
073: // Create a password for this user
074: if (lock == false) {
075: r.nextBytes(rnd);
076: md.update(rnd);
077: System.out.print("Enter Password for " + user + ": ");
078: System.out.flush(); // Needed for prompt to appear when running from Ant.
079: BufferedReader d = new BufferedReader(
080: new InputStreamReader(System.in));
081: spass = d.readLine();
082: hash = md.digest(spass.getBytes());
083: System.arraycopy(rnd, 0, fin, 0, 8);
084: System.arraycopy(hash, 0, fin, 8, 16);
085: } else
086: fin = "*LCK*".getBytes();
087:
088: // Commit it to the database
089: if (cnt < 1) {
090: stmt = conn.prepareStatement(INSERTSTMT);
091: stmt.setString(1, user);
092: stmt.setString(2, "(MD5)" + encode(fin));
093: stmt.executeUpdate();
094: } else {
095: stmt = conn.prepareStatement(UPDATESTMT);
096: stmt.setString(1, "(MD5)" + encode(fin));
097: stmt.setString(2, user);
098: stmt.executeUpdate();
099: }
100: stmt.close();
101: RDBMServices.releaseConnection(conn);
102: System.out.println("Password Updated...");
103: return;
104: }
105:
106: public static void main(String[] args) throws IOException,
107: NoSuchAlgorithmException, SQLException {
108:
109: if (args.length == 1 && args[0].charAt(0) != '-')
110: new Md5Passwd(args[0], false, false);
111: else if (args.length == 2 && args[0].equals("-c")
112: && args[1].charAt(0) != '-')
113: new Md5Passwd(args[1], true, false);
114: else if (args.length == 2 && args[0].equals("-l")
115: && args[1].charAt(0) != '-')
116: new Md5Passwd(args[1], false, true);
117: else {
118: System.err.println("Usage \"Md5Passwd [-c| -l] <user>\"");
119: return;
120: }
121: }
122:
123: //
124: // This was originally Jonathan B. Knudsen's Example from his book
125: // Java Cryptography published by O'Reilly Associates (1st Edition 1998)
126: //
127:
128: private static String encode(byte[] raw) {
129: StringBuffer encoded = new StringBuffer();
130: for (int i = 0; i < raw.length; i += 3) {
131: encoded.append(encodeBlock(raw, i));
132: }
133: return encoded.toString();
134: }
135:
136: private static char[] encodeBlock(byte[] raw, int offset) {
137: int block = 0;
138: int slack = raw.length - offset - 1;
139: int end = (slack >= 2) ? 2 : slack;
140: for (int i = 0; i <= end; i++) {
141: byte b = raw[offset + i];
142: int neuter = (b < 0) ? b + 256 : b;
143: block += neuter << (8 * (2 - i));
144: }
145: char[] base64 = new char[4];
146: for (int i = 0; i < 4; i++) {
147: int sixbit = (block >>> (6 * (3 - i))) & 0x3f;
148: base64[i] = getChar(sixbit);
149: }
150: if (slack < 1)
151: base64[2] = '=';
152: if (slack < 2)
153: base64[3] = '=';
154: return base64;
155: }
156:
157: private static char getChar(int sixBit) {
158: if (sixBit >= 0 && sixBit <= 25)
159: return (char) ('A' + sixBit);
160: if (sixBit >= 26 && sixBit <= 51)
161: return (char) ('a' + (sixBit - 26));
162: if (sixBit >= 52 && sixBit <= 61)
163: return (char) ('0' + (sixBit - 52));
164: if (sixBit == 62)
165: return '+';
166: if (sixBit == 63)
167: return '/';
168: return '?';
169: }
170: }
|