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