View Javadoc

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