src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java

Print this page




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 
  28 import java.io.IOException;
  29 import java.io.UnsupportedEncodingException;
  30 import java.net.InetAddress;
  31 import java.net.PasswordAuthentication;
  32 import java.net.UnknownHostException;
  33 import java.net.URL;
  34 import java.security.GeneralSecurityException;
  35 import java.security.MessageDigest;
  36 import java.security.NoSuchAlgorithmException;
  37 import javax.crypto.Cipher;
  38 import javax.crypto.NoSuchPaddingException;
  39 import javax.crypto.SecretKey;
  40 import javax.crypto.SecretKeyFactory;
  41 import javax.crypto.spec.DESKeySpec;
  42 
  43 import sun.net.www.HeaderParser;



  44 
  45 /**
  46  * NTLMAuthentication:
  47  *
  48  * @author Michael McMahon
  49  */
  50 
  51 /*
  52  * NTLM authentication is nominally based on the framework defined in RFC2617,
  53  * but differs from the standard (Basic & Digest) schemes as follows:
  54  *
  55  * 1. A complete authentication requires three request/response transactions
  56  *    as shown below:
  57  *            REQ ------------------------------->
  58  *            <---- 401 (signalling NTLM) --------
  59  *
  60  *            REQ (with type1 NTLM msg) --------->
  61  *            <---- 401 (with type 2 NTLM msg) ---
  62  *
  63  *            REQ (with type3 NTLM msg) --------->
  64  *            <---- OK ---------------------------
  65  *
  66  * 2. The scope of the authentication is the TCP connection (which must be kept-alive)
  67  *    after the type2 response is received. This means that NTLM does not work end-to-end
  68  *    through a proxy, rather between client and proxy, or between client and server (with no proxy)
  69  */
  70 
  71 class NTLMAuthentication extends AuthenticationInfo {
  72     private static final long serialVersionUID = -2403849171106437142L;
  73 
  74     private byte[] type1;
  75     private byte[] type3;
  76 
  77     private SecretKeyFactory fac;
  78     private Cipher cipher;
  79     private MessageDigest md4;
  80     private String hostname;
  81     private static String defaultDomain; /* Domain to use if not specified by user */
  82 
  83     static {
  84         defaultDomain = java.security.AccessController.doPrivileged(
  85             new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
  86                                                       "domain"));
  87     };
  88 
  89     static boolean supportsTransparentAuth () {
  90         return false;
  91     }
  92 
  93     private void init0() {
  94         type1 = new byte[256];
  95         type3 = new byte[256];
  96         System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9);
  97         type1[12] = (byte) 3;
  98         type1[13] = (byte) 0xb2;
  99         type1[28] = (byte) 0x20;
 100         System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,3}, 0, type3, 0, 9);
 101         type3[12] = (byte) 0x18;
 102         type3[14] = (byte) 0x18;
 103         type3[20] = (byte) 0x18;
 104         type3[22] = (byte) 0x18;
 105         type3[32] = (byte) 0x40;
 106         type3[60] = (byte) 1;
 107         type3[61] = (byte) 0x82;
 108 
 109         try {


 166         password = new String (pw.getPassword());
 167         init0();
 168     }
 169 
 170    /**
 171     * Constructor used for proxy entries
 172     */
 173     public NTLMAuthentication(boolean isProxy, String host, int port,
 174                                 PasswordAuthentication pw) {
 175         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
 176                 AuthScheme.NTLM,
 177                 host,
 178                 port,
 179                 "");
 180         init (pw);
 181     }
 182 
 183     /**
 184      * @return true if this authentication supports preemptive authorization
 185      */
 186     boolean supportsPreemptiveAuthorization() {

 187         return false;
 188     }
 189 
 190     /**
 191      * @return the name of the HTTP header this authentication wants set
 192      */
 193     String getHeaderName() {
 194         if (type == SERVER_AUTHENTICATION) {
 195             return "Authorization";
 196         } else {
 197             return "Proxy-authorization";
 198         }
 199     }
 200 
 201     /**
 202      * Not supported. Must use the setHeaders() method
 203      */
 204     String getHeaderValue(URL url, String method) {

 205         throw new RuntimeException ("getHeaderValue not supported");
 206     }
 207 
 208     /**
 209      * Check if the header indicates that the current auth. parameters are stale.
 210      * If so, then replace the relevant field with the new value
 211      * and return true. Otherwise return false.
 212      * returning true means the request can be retried with the same userid/password
 213      * returning false means we have to go back to the user to ask for a new
 214      * username password.
 215      */
 216     boolean isAuthorizationStale (String header) {

 217         return false; /* should not be called for ntlm */
 218     }
 219 
 220     /**
 221      * Set header(s) on the given connection.
 222      * @param conn The connection to apply the header(s) to
 223      * @param p A source of header values for this connection, not used because
 224      *          HeaderParser converts the fields to lower case, use raw instead
 225      * @param raw The raw header field.
 226      * @return true if all goes well, false if no headers were set.
 227      */
 228     synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {

 229 
 230         try {
 231             String response;
 232             if (raw.length() < 6) { /* NTLM<sp> */
 233                 response = buildType1Msg ();
 234             } else {
 235                 String msg = raw.substring (5); /* skip NTLM<sp> */
 236                 response = buildType3Msg (msg);
 237             }
 238             conn.setAuthenticationProperty(getHeaderName(), response);
 239             return true;
 240         } catch (IOException e) {
 241             return false;
 242         } catch (GeneralSecurityException e) {
 243             return false;
 244         }
 245     }
 246 
 247     private void copybytes (byte[] dest, int destpos, String src, String enc) {
 248         try {




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.net.www.protocol.http.ntlm;
  27 
  28 import java.io.IOException;
  29 import java.io.UnsupportedEncodingException;
  30 import java.net.InetAddress;
  31 import java.net.PasswordAuthentication;
  32 import java.net.UnknownHostException;
  33 import java.net.URL;
  34 import java.security.GeneralSecurityException;
  35 import java.security.MessageDigest;
  36 import java.security.NoSuchAlgorithmException;
  37 import javax.crypto.Cipher;
  38 import javax.crypto.NoSuchPaddingException;
  39 import javax.crypto.SecretKey;
  40 import javax.crypto.SecretKeyFactory;
  41 import javax.crypto.spec.DESKeySpec;
  42 
  43 import sun.net.www.HeaderParser;
  44 import sun.net.www.protocol.http.AuthenticationInfo;
  45 import sun.net.www.protocol.http.AuthScheme;
  46 import sun.net.www.protocol.http.HttpURLConnection;
  47 
  48 /**
  49  * NTLMAuthentication:
  50  *
  51  * @author Michael McMahon
  52  */
  53 
  54 /*
  55  * NTLM authentication is nominally based on the framework defined in RFC2617,
  56  * but differs from the standard (Basic & Digest) schemes as follows:
  57  *
  58  * 1. A complete authentication requires three request/response transactions
  59  *    as shown below:
  60  *            REQ ------------------------------->
  61  *            <---- 401 (signalling NTLM) --------
  62  *
  63  *            REQ (with type1 NTLM msg) --------->
  64  *            <---- 401 (with type 2 NTLM msg) ---
  65  *
  66  *            REQ (with type3 NTLM msg) --------->
  67  *            <---- OK ---------------------------
  68  *
  69  * 2. The scope of the authentication is the TCP connection (which must be kept-alive)
  70  *    after the type2 response is received. This means that NTLM does not work end-to-end
  71  *    through a proxy, rather between client and proxy, or between client and server (with no proxy)
  72  */
  73 
  74 public class NTLMAuthentication extends AuthenticationInfo {
  75     private static final long serialVersionUID = -2403849171106437142L;
  76 
  77     private byte[] type1;
  78     private byte[] type3;
  79 
  80     private SecretKeyFactory fac;
  81     private Cipher cipher;
  82     private MessageDigest md4;
  83     private String hostname;
  84     private static String defaultDomain; /* Domain to use if not specified by user */
  85 
  86     static {
  87         defaultDomain = java.security.AccessController.doPrivileged(
  88             new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
  89                                                       "domain"));
  90     };
  91 
  92     public static boolean supportsTransparentAuth () {
  93         return false;
  94     }
  95 
  96     private void init0() {
  97         type1 = new byte[256];
  98         type3 = new byte[256];
  99         System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9);
 100         type1[12] = (byte) 3;
 101         type1[13] = (byte) 0xb2;
 102         type1[28] = (byte) 0x20;
 103         System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,3}, 0, type3, 0, 9);
 104         type3[12] = (byte) 0x18;
 105         type3[14] = (byte) 0x18;
 106         type3[20] = (byte) 0x18;
 107         type3[22] = (byte) 0x18;
 108         type3[32] = (byte) 0x40;
 109         type3[60] = (byte) 1;
 110         type3[61] = (byte) 0x82;
 111 
 112         try {


 169         password = new String (pw.getPassword());
 170         init0();
 171     }
 172 
 173    /**
 174     * Constructor used for proxy entries
 175     */
 176     public NTLMAuthentication(boolean isProxy, String host, int port,
 177                                 PasswordAuthentication pw) {
 178         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
 179                 AuthScheme.NTLM,
 180                 host,
 181                 port,
 182                 "");
 183         init (pw);
 184     }
 185 
 186     /**
 187      * @return true if this authentication supports preemptive authorization
 188      */
 189     @Override
 190     public boolean supportsPreemptiveAuthorization() {
 191         return false;
 192     }
 193 
 194     /**











 195      * Not supported. Must use the setHeaders() method
 196      */
 197     @Override
 198     public String getHeaderValue(URL url, String method) {
 199         throw new RuntimeException ("getHeaderValue not supported");
 200     }
 201 
 202     /**
 203      * Check if the header indicates that the current auth. parameters are stale.
 204      * If so, then replace the relevant field with the new value
 205      * and return true. Otherwise return false.
 206      * returning true means the request can be retried with the same userid/password
 207      * returning false means we have to go back to the user to ask for a new
 208      * username password.
 209      */
 210     @Override
 211     public boolean isAuthorizationStale (String header) {
 212         return false; /* should not be called for ntlm */
 213     }
 214 
 215     /**
 216      * Set header(s) on the given connection.
 217      * @param conn The connection to apply the header(s) to
 218      * @param p A source of header values for this connection, not used because
 219      *          HeaderParser converts the fields to lower case, use raw instead
 220      * @param raw The raw header field.
 221      * @return true if all goes well, false if no headers were set.
 222      */
 223     @Override
 224     public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
 225 
 226         try {
 227             String response;
 228             if (raw.length() < 6) { /* NTLM<sp> */
 229                 response = buildType1Msg ();
 230             } else {
 231                 String msg = raw.substring (5); /* skip NTLM<sp> */
 232                 response = buildType3Msg (msg);
 233             }
 234             conn.setAuthenticationProperty(getHeaderName(), response);
 235             return true;
 236         } catch (IOException e) {
 237             return false;
 238         } catch (GeneralSecurityException e) {
 239             return false;
 240         }
 241     }
 242 
 243     private void copybytes (byte[] dest, int destpos, String src, String enc) {
 244         try {