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