001: // ========================================================================
002: // Copyright 1998-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.security;
016:
017: import java.io.IOException;
018:
019: import org.mortbay.log.Log;
020:
021: /* ------------------------------------------------------------ */
022: /** Password utility class.
023: *
024: * This utility class gets a password or pass phrase either by:<PRE>
025: * + Password is set as a system property.
026: * + The password is prompted for and read from standard input
027: * + A program is run to get the password.
028: * </pre>
029: * Passwords that begin with OBF: are de obfuscated.
030: * Passwords can be obfuscated by run org.mortbay.util.Password as a
031: * main class. Obfuscated password are required if a system needs
032: * to recover the full password (eg. so that it may be passed to another
033: * system). They are not secure, but prevent casual observation.
034: * <p>
035: * Passwords that begin with CRYPT: are oneway encrypted with
036: * UnixCrypt. The real password cannot be retrieved, but comparisons
037: * can be made to other passwords. A Crypt can be generated by running
038: * org.mortbay.util.UnixCrypt as a main class, passing password and
039: * then the username. Checksum passwords are a secure(ish) way to
040: * store passwords that only need to be checked rather
041: * than recovered. Note that it is not strong security - specially if
042: * simple passwords are used.
043: *
044: * @author Greg Wilkins (gregw)
045: */
046: public class Password extends Credential {
047: public static final String __OBFUSCATE = "OBF:";
048:
049: private String _pw;
050:
051: /* ------------------------------------------------------------ */
052: /** Constructor.
053: * @param password The String password.
054: */
055: public Password(String password) {
056: _pw = password;
057:
058: // expand password
059: while (_pw != null && _pw.startsWith(__OBFUSCATE))
060: _pw = deobfuscate(_pw);
061: }
062:
063: /* ------------------------------------------------------------ */
064: public String toString() {
065: return _pw;
066: }
067:
068: /* ------------------------------------------------------------ */
069: public String toStarString() {
070: return "*****************************************************"
071: .substring(0, _pw.length());
072: }
073:
074: /* ------------------------------------------------------------ */
075: public boolean check(Object credentials) {
076: if (this == credentials)
077: return true;
078:
079: if (credentials instanceof Password)
080: return credentials.equals(_pw);
081:
082: if (credentials instanceof String)
083: return credentials.equals(_pw);
084:
085: if (credentials instanceof Credential)
086: return ((Credential) credentials).check(_pw);
087:
088: return false;
089: }
090:
091: /* ------------------------------------------------------------ */
092: public boolean equals(Object o) {
093: if (this == o)
094: return true;
095:
096: if (null == o)
097: return false;
098:
099: if (o instanceof Password) {
100: Password p = (Password) o;
101: return p._pw == _pw || (null != _pw && _pw.equals(p._pw));
102: }
103:
104: if (o instanceof String)
105: return o.equals(_pw);
106:
107: return false;
108: }
109:
110: /* ------------------------------------------------------------ */
111: public int hashCode() {
112: return null == _pw ? super .hashCode() : _pw.hashCode();
113: }
114:
115: /* ------------------------------------------------------------ */
116: public static String obfuscate(String s) {
117: StringBuffer buf = new StringBuffer();
118: byte[] b = s.getBytes();
119:
120: synchronized (buf) {
121: buf.append(__OBFUSCATE);
122: for (int i = 0; i < b.length; i++) {
123: byte b1 = b[i];
124: byte b2 = b[s.length() - (i + 1)];
125: int i1 = 127 + b1 + b2;
126: int i2 = 127 + b1 - b2;
127: int i0 = i1 * 256 + i2;
128: String x = Integer.toString(i0, 36);
129:
130: switch (x.length()) {
131: case 1:
132: buf.append('0');
133: case 2:
134: buf.append('0');
135: case 3:
136: buf.append('0');
137: default:
138: buf.append(x);
139: }
140: }
141: return buf.toString();
142: }
143: }
144:
145: /* ------------------------------------------------------------ */
146: public static String deobfuscate(String s) {
147: if (s.startsWith(__OBFUSCATE))
148: s = s.substring(4);
149:
150: byte[] b = new byte[s.length() / 2];
151: int l = 0;
152: for (int i = 0; i < s.length(); i += 4) {
153: String x = s.substring(i, i + 4);
154: int i0 = Integer.parseInt(x, 36);
155: int i1 = (i0 / 256);
156: int i2 = (i0 % 256);
157: b[l++] = (byte) ((i1 + i2 - 254) / 2);
158: }
159:
160: return new String(b, 0, l);
161: }
162:
163: /* ------------------------------------------------------------ */
164: /** Get a password.
165: * A password is obtained by trying <UL>
166: * <LI>Calling <Code>System.getProperty(realm,dft)</Code>
167: * <LI>Prompting for a password
168: * <LI>Using promptDft if nothing was entered.
169: * </UL>
170: * @param realm The realm name for the password, used as a SystemProperty name.
171: * @param dft The default password.
172: * @param promptDft The default to use if prompting for the password.
173: * @return Password
174: */
175: public static Password getPassword(String realm, String dft,
176: String promptDft) {
177: String passwd = System.getProperty(realm, dft);
178: if (passwd == null || passwd.length() == 0) {
179: try {
180: System.out
181: .print(realm
182: + ((promptDft != null && promptDft
183: .length() > 0) ? " [dft]" : "")
184: + " : ");
185: System.out.flush();
186: byte[] buf = new byte[512];
187: int len = System.in.read(buf);
188: if (len > 0)
189: passwd = new String(buf, 0, len).trim();
190: } catch (IOException e) {
191: Log.warn(Log.EXCEPTION, e);
192: }
193: if (passwd == null || passwd.length() == 0)
194: passwd = promptDft;
195: }
196: return new Password(passwd);
197: }
198:
199: /* ------------------------------------------------------------ */
200: /**
201: * @param arg
202: */
203: public static void main(String[] arg) {
204: if (arg.length != 1 && arg.length != 2) {
205: System.err
206: .println("Usage - java org.mortbay.jetty.security.Password [<user>] <password>");
207: System.err
208: .println("If the password is ?, the user will be prompted for the password");
209: System.exit(1);
210: }
211: String p = arg[arg.length == 1 ? 0 : 1];
212: Password pw = "?".equals(p) ? new Password(p) : new Password(p);
213: System.err.println(pw.toString());
214: System.err.println(obfuscate(pw.toString()));
215: System.err.println(Credential.MD5.digest(p));
216: if (arg.length == 2)
217: System.err.println(Credential.Crypt.crypt(arg[0], pw
218: .toString()));
219: }
220: }
|