1 /* 2 * Copyright (c) 2002, 2019, 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 26 package sun.net.www.protocol.http.ntlm; 27 28 import java.io.IOException; 29 import java.net.InetAddress; 30 import java.net.PasswordAuthentication; 31 import java.net.UnknownHostException; 32 import java.net.URL; 33 import java.util.Objects; 34 import java.util.Properties; 35 import sun.net.NetProperties; 36 import sun.net.www.HeaderParser; 37 import sun.net.www.protocol.http.AuthenticationInfo; 38 import sun.net.www.protocol.http.AuthScheme; 39 import sun.net.www.protocol.http.HttpURLConnection; 40 import sun.security.action.GetPropertyAction; 41 42 /** 43 * NTLMAuthentication: 44 * 45 * @author Michael McMahon 46 */ 47 48 public class NTLMAuthentication extends AuthenticationInfo { 49 50 private static final long serialVersionUID = 100L; 51 52 private static final NTLMAuthenticationCallback NTLMAuthCallback = 53 NTLMAuthenticationCallback.getNTLMAuthenticationCallback(); 54 55 private String hostname; 56 /* Domain to use if not specified by user */ 57 private static final String defaultDomain; 58 /* Whether cache is enabled for NTLM */ 59 private static final boolean ntlmCache; 60 61 enum TransparentAuth { 62 DISABLED, // disable for all hosts (default) 63 TRUSTED_HOSTS, // use Windows trusted hosts settings 64 ALL_HOSTS // attempt for all hosts 65 } 66 67 private static final TransparentAuth authMode; 68 69 static { 70 Properties props = GetPropertyAction.privilegedGetProperties(); 71 defaultDomain = props.getProperty("http.auth.ntlm.domain", "domain"); 72 String ntlmCacheProp = props.getProperty("jdk.ntlm.cache", "true"); 73 ntlmCache = Boolean.parseBoolean(ntlmCacheProp); 74 String modeProp = java.security.AccessController.doPrivileged( 75 new java.security.PrivilegedAction<String>() { 76 public String run() { 77 return NetProperties.get("jdk.http.ntlm.transparentAuth"); 78 } 79 }); 80 81 if ("trustedHosts".equalsIgnoreCase(modeProp)) 82 authMode = TransparentAuth.TRUSTED_HOSTS; 83 else if ("allHosts".equalsIgnoreCase(modeProp)) 84 authMode = TransparentAuth.ALL_HOSTS; 85 else 86 authMode = TransparentAuth.DISABLED; 87 } 88 init0()89 private void init0() { 90 91 hostname = java.security.AccessController.doPrivileged( 92 new java.security.PrivilegedAction<String>() { 93 public String run() { 94 String localhost; 95 try { 96 localhost = InetAddress.getLocalHost().getHostName().toUpperCase(); 97 } catch (UnknownHostException e) { 98 localhost = "localhost"; 99 } 100 return localhost; 101 } 102 }); 103 int x = hostname.indexOf ('.'); 104 if (x != -1) { 105 hostname = hostname.substring (0, x); 106 } 107 } 108 109 String username; 110 String ntdomain; 111 String password; 112 113 /** 114 * Create a NTLMAuthentication: 115 * Username may be specified as {@literal domain<BACKSLASH>username} 116 * in the application Authenticator. 117 * If this notation is not used, then the domain will be taken 118 * from a system property: "http.auth.ntlm.domain". 119 */ NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw, String authenticatorKey)120 public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw, 121 String authenticatorKey) { 122 super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, 123 AuthScheme.NTLM, 124 url, 125 "", 126 Objects.requireNonNull(authenticatorKey)); 127 init (pw); 128 } 129 init(PasswordAuthentication pw)130 private void init (PasswordAuthentication pw) { 131 this.pw = pw; 132 if (pw != null) { 133 String s = pw.getUserName(); 134 int i = s.indexOf ('\\'); 135 if (i == -1) { 136 username = s; 137 ntdomain = defaultDomain; 138 } else { 139 ntdomain = s.substring (0, i).toUpperCase(); 140 username = s.substring (i+1); 141 } 142 password = new String (pw.getPassword()); 143 } else { 144 /* credentials will be acquired from OS */ 145 username = null; 146 ntdomain = null; 147 password = null; 148 } 149 init0(); 150 } 151 152 /** 153 * Constructor used for proxy entries 154 */ NTLMAuthentication(boolean isProxy, String host, int port, PasswordAuthentication pw, String authenticatorKey)155 public NTLMAuthentication(boolean isProxy, String host, int port, 156 PasswordAuthentication pw, 157 String authenticatorKey) { 158 super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, 159 AuthScheme.NTLM, 160 host, 161 port, 162 "", 163 Objects.requireNonNull(authenticatorKey)); 164 init (pw); 165 } 166 167 @Override useAuthCache()168 protected boolean useAuthCache() { 169 return ntlmCache && super.useAuthCache(); 170 } 171 172 /** 173 * @return true if this authentication supports preemptive authorization 174 */ 175 @Override supportsPreemptiveAuthorization()176 public boolean supportsPreemptiveAuthorization() { 177 return false; 178 } 179 180 /** 181 * @return true if NTLM supported transparently (no password needed, SSO) 182 */ supportsTransparentAuth()183 public static boolean supportsTransparentAuth() { 184 return true; 185 } 186 187 /** 188 * Returns true if the given site is trusted, i.e. we can try 189 * transparent Authentication. 190 */ isTrustedSite(URL url)191 public static boolean isTrustedSite(URL url) { 192 if (NTLMAuthCallback != null) 193 return NTLMAuthCallback.isTrustedSite(url); 194 195 switch (authMode) { 196 case TRUSTED_HOSTS: 197 return isTrustedSite(url.toString()); 198 case ALL_HOSTS: 199 return true; 200 default: 201 return false; 202 } 203 } 204 205 private static final boolean isTrustedSiteAvailable = isTrustedSiteAvailable(); 206 isTrustedSiteAvailable()207 private static native boolean isTrustedSiteAvailable(); 208 isTrustedSite(String url)209 private static boolean isTrustedSite(String url) { 210 if (isTrustedSiteAvailable) 211 return isTrustedSite0(url); 212 return false; 213 } 214 isTrustedSite0(String url)215 private static native boolean isTrustedSite0(String url); 216 217 /** 218 * Not supported. Must use the setHeaders() method 219 */ 220 @Override getHeaderValue(URL url, String method)221 public String getHeaderValue(URL url, String method) { 222 throw new RuntimeException ("getHeaderValue not supported"); 223 } 224 225 /** 226 * Check if the header indicates that the current auth. parameters are stale. 227 * If so, then replace the relevant field with the new value 228 * and return true. Otherwise return false. 229 * returning true means the request can be retried with the same userid/password 230 * returning false means we have to go back to the user to ask for a new 231 * username password. 232 */ 233 @Override isAuthorizationStale(String header)234 public boolean isAuthorizationStale (String header) { 235 return false; /* should not be called for ntlm */ 236 } 237 238 /** 239 * Set header(s) on the given connection. 240 * @param conn The connection to apply the header(s) to 241 * @param p A source of header values for this connection, not used because 242 * HeaderParser converts the fields to lower case, use raw instead 243 * @param raw The raw header field. 244 * @return true if all goes well, false if no headers were set. 245 */ 246 @Override setHeaders(HttpURLConnection conn, HeaderParser p, String raw)247 public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { 248 249 try { 250 NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj(); 251 if (seq == null) { 252 seq = new NTLMAuthSequence (username, password, ntdomain); 253 conn.authObj(seq); 254 } 255 String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null); 256 conn.setAuthenticationProperty(getHeaderName(), response); 257 if (seq.isComplete()) { 258 conn.authObj(null); 259 } 260 return true; 261 } catch (IOException e) { 262 conn.authObj(null); 263 return false; 264 } 265 } 266 } 267