NTLMAuthentication.java revision 12816:1de2065763c1
1/* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.net.www.protocol.http.ntlm; 27 28import com.sun.security.ntlm.Client; 29import com.sun.security.ntlm.NTLMException; 30import java.io.IOException; 31import java.net.InetAddress; 32import java.net.PasswordAuthentication; 33import java.net.UnknownHostException; 34import java.net.URL; 35import java.security.GeneralSecurityException; 36import java.util.Base64; 37 38import sun.net.www.HeaderParser; 39import sun.net.www.protocol.http.AuthenticationInfo; 40import sun.net.www.protocol.http.AuthScheme; 41import sun.net.www.protocol.http.HttpURLConnection; 42 43/** 44 * NTLMAuthentication: 45 * 46 * @author Michael McMahon 47 */ 48 49/* 50 * NTLM authentication is nominally based on the framework defined in RFC2617, 51 * but differs from the standard (Basic & Digest) schemes as follows: 52 * 53 * 1. A complete authentication requires three request/response transactions 54 * as shown below: 55 * REQ -------------------------------> 56 * <---- 401 (signalling NTLM) -------- 57 * 58 * REQ (with type1 NTLM msg) ---------> 59 * <---- 401 (with type 2 NTLM msg) --- 60 * 61 * REQ (with type3 NTLM msg) ---------> 62 * <---- OK --------------------------- 63 * 64 * 2. The scope of the authentication is the TCP connection (which must be kept-alive) 65 * after the type2 response is received. This means that NTLM does not work end-to-end 66 * through a proxy, rather between client and proxy, or between client and server (with no proxy) 67 */ 68 69public class NTLMAuthentication extends AuthenticationInfo { 70 private static final long serialVersionUID = 170L; 71 72 private static final NTLMAuthenticationCallback NTLMAuthCallback = 73 NTLMAuthenticationCallback.getNTLMAuthenticationCallback(); 74 75 private String hostname; 76 private static String defaultDomain; /* Domain to use if not specified by user */ 77 78 static { 79 defaultDomain = java.security.AccessController.doPrivileged( 80 new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", "")); 81 }; 82 83 public static boolean supportsTransparentAuth () { 84 return false; 85 } 86 87 /** 88 * Returns true if the given site is trusted, i.e. we can try 89 * transparent Authentication. 90 */ 91 public static boolean isTrustedSite(URL url) { 92 return NTLMAuthCallback.isTrustedSite(url); 93 } 94 95 private void init0() { 96 97 hostname = java.security.AccessController.doPrivileged( 98 new java.security.PrivilegedAction<>() { 99 public String run() { 100 String localhost; 101 try { 102 localhost = InetAddress.getLocalHost().getHostName(); 103 } catch (UnknownHostException e) { 104 localhost = "localhost"; 105 } 106 return localhost; 107 } 108 }); 109 }; 110 111 PasswordAuthentication pw; 112 113 Client client; 114 /** 115 * Create a NTLMAuthentication: 116 * Username may be specified as {@literal domain<BACKSLASH>username} 117 * in the application Authenticator. 118 * If this notation is not used, then the domain will be taken 119 * from a system property: "http.auth.ntlm.domain". 120 */ 121 public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) { 122 super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, 123 AuthScheme.NTLM, 124 url, 125 ""); 126 init (pw); 127 } 128 129 private void init (PasswordAuthentication pw) { 130 String username; 131 String ntdomain; 132 char[] password; 133 this.pw = pw; 134 String s = pw.getUserName(); 135 int i = s.indexOf ('\\'); 136 if (i == -1) { 137 username = s; 138 ntdomain = defaultDomain; 139 } else { 140 ntdomain = s.substring (0, i).toUpperCase(); 141 username = s.substring (i+1); 142 } 143 password = pw.getPassword(); 144 init0(); 145 try { 146 String version = java.security.AccessController.doPrivileged( 147 new sun.security.action.GetPropertyAction("ntlm.version")); 148 client = new Client(version, hostname, username, ntdomain, password); 149 } catch (NTLMException ne) { 150 try { 151 client = new Client(null, hostname, username, ntdomain, password); 152 } catch (NTLMException ne2) { 153 // Will never happen 154 throw new AssertionError("Really?"); 155 } 156 } 157 } 158 159 /** 160 * Constructor used for proxy entries 161 */ 162 public NTLMAuthentication(boolean isProxy, String host, int port, 163 PasswordAuthentication pw) { 164 super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, 165 AuthScheme.NTLM, 166 host, 167 port, 168 ""); 169 init (pw); 170 } 171 172 /** 173 * @return true if this authentication supports preemptive authorization 174 */ 175 @Override 176 public boolean supportsPreemptiveAuthorization() { 177 return false; 178 } 179 180 /** 181 * Not supported. Must use the setHeaders() method 182 */ 183 @Override 184 public String getHeaderValue(URL url, String method) { 185 throw new RuntimeException ("getHeaderValue not supported"); 186 } 187 188 /** 189 * Check if the header indicates that the current auth. parameters are stale. 190 * If so, then replace the relevant field with the new value 191 * and return true. Otherwise return false. 192 * returning true means the request can be retried with the same userid/password 193 * returning false means we have to go back to the user to ask for a new 194 * username password. 195 */ 196 @Override 197 public boolean isAuthorizationStale (String header) { 198 return false; /* should not be called for ntlm */ 199 } 200 201 /** 202 * Set header(s) on the given connection. 203 * @param conn The connection to apply the header(s) to 204 * @param p A source of header values for this connection, not used because 205 * HeaderParser converts the fields to lower case, use raw instead 206 * @param raw The raw header field. 207 * @return true if all goes well, false if no headers were set. 208 */ 209 @Override 210 public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { 211 212 try { 213 String response; 214 if (raw.length() < 6) { /* NTLM<sp> */ 215 response = buildType1Msg (); 216 } else { 217 String msg = raw.substring (5); /* skip NTLM<sp> */ 218 response = buildType3Msg (msg); 219 } 220 conn.setAuthenticationProperty(getHeaderName(), response); 221 return true; 222 } catch (IOException e) { 223 return false; 224 } catch (GeneralSecurityException e) { 225 return false; 226 } 227 } 228 229 private String buildType1Msg () { 230 byte[] msg = client.type1(); 231 String result = "NTLM " + Base64.getEncoder().encodeToString(msg); 232 return result; 233 } 234 235 private String buildType3Msg (String challenge) throws GeneralSecurityException, 236 IOException { 237 /* First decode the type2 message to get the server nonce */ 238 /* nonce is located at type2[24] for 8 bytes */ 239 240 byte[] type2 = Base64.getDecoder().decode(challenge); 241 byte[] nonce = new byte[8]; 242 new java.util.Random().nextBytes(nonce); 243 byte[] msg = client.type3(type2, nonce); 244 String result = "NTLM " + Base64.getEncoder().encodeToString(msg); 245 return result; 246 } 247} 248 249