View Javadoc

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