1 /* 2 * Copyright (c) 2002, 2016, 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 isTrustedSite(String url)205 static native boolean isTrustedSite(String url); 206 207 /** 208 * Not supported. Must use the setHeaders() method 209 */ 210 @Override getHeaderValue(URL url, String method)211 public String getHeaderValue(URL url, String method) { 212 throw new RuntimeException ("getHeaderValue not supported"); 213 } 214 215 /** 216 * Check if the header indicates that the current auth. parameters are stale. 217 * If so, then replace the relevant field with the new value 218 * and return true. Otherwise return false. 219 * returning true means the request can be retried with the same userid/password 220 * returning false means we have to go back to the user to ask for a new 221 * username password. 222 */ 223 @Override isAuthorizationStale(String header)224 public boolean isAuthorizationStale (String header) { 225 return false; /* should not be called for ntlm */ 226 } 227 228 /** 229 * Set header(s) on the given connection. 230 * @param conn The connection to apply the header(s) to 231 * @param p A source of header values for this connection, not used because 232 * HeaderParser converts the fields to lower case, use raw instead 233 * @param raw The raw header field. 234 * @return true if all goes well, false if no headers were set. 235 */ 236 @Override setHeaders(HttpURLConnection conn, HeaderParser p, String raw)237 public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { 238 239 try { 240 NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj(); 241 if (seq == null) { 242 seq = new NTLMAuthSequence (username, password, ntdomain); 243 conn.authObj(seq); 244 } 245 String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null); 246 conn.setAuthenticationProperty(getHeaderName(), response); 247 if (seq.isComplete()) { 248 conn.authObj(null); 249 } 250 return true; 251 } catch (IOException e) { 252 conn.authObj(null); 253 return false; 254 } 255 } 256 } 257