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 { |