View Javadoc

1   // ========================================================================
2   // Copyright (c) 1998-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.http.security;
15  
16  import java.io.IOException;
17  import java.util.Arrays;
18  
19  import org.eclipse.jetty.util.log.Log;
20  
21  /* ------------------------------------------------------------ */
22  /**
23   * Password utility class.
24   * 
25   * This utility class gets a password or pass phrase either by:
26   * 
27   * <PRE>
28   *  + Password is set as a system property.
29   *  + The password is prompted for and read from standard input
30   *  + A program is run to get the password.
31   * </pre>
32   * 
33   * Passwords that begin with OBF: are de obfuscated. Passwords can be obfuscated
34   * by run org.eclipse.util.Password as a main class. Obfuscated password are
35   * required if a system needs to recover the full password (eg. so that it may
36   * be passed to another system). They are not secure, but prevent casual
37   * observation.
38   * <p>
39   * Passwords that begin with CRYPT: are oneway encrypted with UnixCrypt. The
40   * real password cannot be retrieved, but comparisons can be made to other
41   * passwords. A Crypt can be generated by running org.eclipse.util.UnixCrypt as
42   * a main class, passing password and then the username. Checksum passwords are
43   * a secure(ish) way to store passwords that only need to be checked rather than
44   * recovered. Note that it is not strong security - specially if simple
45   * passwords are used.
46   * 
47   * 
48   */
49  public class Password extends Credential
50  {
51      private static final long serialVersionUID = 5062906681431569445L;
52  
53      public static final String __OBFUSCATE = "OBF:";
54  
55      private String _pw;
56  
57      /* ------------------------------------------------------------ */
58      /**
59       * Constructor.
60       * 
61       * @param password The String password.
62       */
63      public Password(String password)
64      {
65          _pw = password;
66  
67          // expand password
68          while (_pw != null && _pw.startsWith(__OBFUSCATE))
69              _pw = deobfuscate(_pw);
70      }
71  
72      /* ------------------------------------------------------------ */
73      @Override
74      public String toString()
75      {
76          return _pw;
77      }
78  
79      /* ------------------------------------------------------------ */
80      public String toStarString()
81      {
82          return "*****************************************************".substring(0, _pw.length());
83      }
84  
85      /* ------------------------------------------------------------ */
86      @Override
87      public boolean check(Object credentials)
88      {
89          if (this == credentials) return true;
90  
91          if (credentials instanceof Password) return credentials.equals(_pw);
92  
93          if (credentials instanceof String) return credentials.equals(_pw);
94  
95          if (credentials instanceof char[]) return Arrays.equals(_pw.toCharArray(), (char[]) credentials);
96  
97          if (credentials instanceof Credential) return ((Credential) credentials).check(_pw);
98  
99          return false;
100     }
101 
102     /* ------------------------------------------------------------ */
103     @Override
104     public boolean equals(Object o)
105     {
106         if (this == o) 
107             return true;
108 
109         if (null == o) 
110             return false;
111 
112         if (o instanceof Password)
113         {
114             Password p = (Password) o;
115             //noinspection StringEquality
116             return p._pw == _pw || (null != _pw && _pw.equals(p._pw));
117         }
118 
119         if (o instanceof String) 
120             return o.equals(_pw);
121 
122         return false;
123     }
124 
125     /* ------------------------------------------------------------ */
126     @Override
127     public int hashCode()
128     {
129         return null == _pw ? super.hashCode() : _pw.hashCode();
130     }
131 
132     /* ------------------------------------------------------------ */
133     public static String obfuscate(String s)
134     {
135         StringBuilder buf = new StringBuilder();
136         byte[] b = s.getBytes();
137 
138         buf.append(__OBFUSCATE);
139         for (int i = 0; i < b.length; i++)
140         {
141             byte b1 = b[i];
142             byte b2 = b[s.length() - (i + 1)];
143             int i1 = 127 + b1 + b2;
144             int i2 = 127 + b1 - b2;
145             int i0 = i1 * 256 + i2;
146             String x = Integer.toString(i0, 36);
147 
148             switch (x.length())
149             {
150                 case 1:
151                     buf.append('0');
152                 case 2:
153                     buf.append('0');
154                 case 3:
155                     buf.append('0');
156                 default:
157                     buf.append(x);
158             }
159         }
160         return buf.toString();
161 
162     }
163 
164     /* ------------------------------------------------------------ */
165     public static String deobfuscate(String s)
166     {
167         if (s.startsWith(__OBFUSCATE)) s = s.substring(4);
168 
169         byte[] b = new byte[s.length() / 2];
170         int l = 0;
171         for (int i = 0; i < s.length(); i += 4)
172         {
173             String x = s.substring(i, i + 4);
174             int i0 = Integer.parseInt(x, 36);
175             int i1 = (i0 / 256);
176             int i2 = (i0 % 256);
177             b[l++] = (byte) ((i1 + i2 - 254) / 2);
178         }
179 
180         return new String(b, 0, l);
181     }
182 
183     /* ------------------------------------------------------------ */
184     /**
185      * Get a password. A password is obtained by trying
186      * <UL>
187      * <LI>Calling <Code>System.getProperty(realm,dft)</Code>
188      * <LI>Prompting for a password
189      * <LI>Using promptDft if nothing was entered.
190      * </UL>
191      * 
192      * @param realm The realm name for the password, used as a SystemProperty
193      *                name.
194      * @param dft The default password.
195      * @param promptDft The default to use if prompting for the password.
196      * @return Password
197      */
198     public static Password getPassword(String realm, String dft, String promptDft)
199     {
200         String passwd = System.getProperty(realm, dft);
201         if (passwd == null || passwd.length() == 0)
202         {
203             try
204             {
205                 System.out.print(realm + ((promptDft != null && promptDft.length() > 0) ? " [dft]" : "") + " : ");
206                 System.out.flush();
207                 byte[] buf = new byte[512];
208                 int len = System.in.read(buf);
209                 if (len > 0) passwd = new String(buf, 0, len).trim();
210             }
211             catch (IOException e)
212             {
213                 Log.warn(Log.EXCEPTION, e);
214             }
215             if (passwd == null || passwd.length() == 0) passwd = promptDft;
216         }
217         return new Password(passwd);
218     }
219 
220     /* ------------------------------------------------------------ */
221     /**
222      * @param arg
223      */
224     public static void main(String[] arg)
225     {
226         if (arg.length != 1 && arg.length != 2)
227         {
228             System.err.println("Usage - java org.eclipse.jetty.security.Password [<user>] <password>");
229             System.err.println("If the password is ?, the user will be prompted for the password");
230             System.exit(1);
231         }
232         String p = arg[arg.length == 1 ? 0 : 1];
233         Password pw = new Password(p);
234         System.err.println(pw.toString());
235         System.err.println(obfuscate(pw.toString()));
236         System.err.println(Credential.MD5.digest(p));
237         if (arg.length == 2) System.err.println(Credential.Crypt.crypt(arg[0], pw.toString()));
238     }
239 }