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