001: /*
002: * @(#)NTLMAuthentication.java 1.5 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package sun.net.www.protocol.http;
028:
029: import java.util.Arrays;
030: import java.util.StringTokenizer;
031: import java.util.Random;
032:
033: import sun.net.www.HeaderParser;
034:
035: import java.io.*;
036: import javax.crypto.*;
037: import javax.crypto.spec.*;
038: import java.security.*;
039: import java.net.*;
040:
041: /**
042: * NTLMAuthentication:
043: *
044: * @author Michael McMahon
045: */
046:
047: class NTLMAuthentication extends AuthenticationInfo {
048:
049: static char NTLM_AUTH = 'N';
050: static boolean supported;
051: private String hostname;
052: private static String defaultDomain; /* Domain to use if not specified by user */
053:
054: static {
055:
056: defaultDomain = (String) java.security.AccessController
057: .doPrivileged(new java.security.PrivilegedAction() {
058: public Object run() {
059: String prop = System.getProperty("os.name");
060: supported = (prop.toUpperCase()
061: .startsWith("WINDOWS"));
062: if (!supported)
063: return null;
064: String s = System
065: .getProperty("http.auth.ntlm.domain");
066: if (s == null)
067: return "domain";
068: return s;
069: }
070: });
071: };
072:
073: private void init0() {
074:
075: hostname = (String) java.security.AccessController
076: .doPrivileged(new java.security.PrivilegedAction() {
077: public Object run() {
078: String localhost;
079: try {
080: localhost = InetAddress.getLocalHost()
081: .getHostName().toUpperCase();
082: } catch (UnknownHostException e) {
083: localhost = "localhost";
084: }
085: return localhost;
086: }
087: });
088: int x = hostname.indexOf('.');
089: if (x != -1) {
090: hostname = hostname.substring(0, x);
091: }
092: }
093:
094: PasswordAuthentication pw;
095: String username;
096: String ntdomain;
097: String password;
098:
099: /**
100: * Create a NTLMAuthentication:
101: * Username may be specified as domain<BACKSLASH>username in the application Authenticator.
102: * If this notation is not used, then the domain will be taken
103: * from a system property: "http.auth.ntlm.domain".
104: */
105: public NTLMAuthentication(boolean isProxy, URL url,
106: PasswordAuthentication pw) {
107: super (isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
108: NTLM_AUTH, url, "");
109: init(pw);
110: }
111:
112: private void init(PasswordAuthentication pw) {
113: this .pw = pw;
114: String s = pw.getUserName();
115: int i = s.indexOf('\\');
116: if (i == -1) {
117: username = s;
118: ntdomain = defaultDomain;
119: } else {
120: ntdomain = s.substring(0, i).toUpperCase();
121: username = s.substring(i + 1);
122: }
123: password = new String(pw.getPassword());
124: init0();
125: }
126:
127: /**
128: * Constructor used for proxy entries
129: */
130: public NTLMAuthentication(boolean isProxy, String host, int port,
131: PasswordAuthentication pw) {
132: super (isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
133: NTLM_AUTH, host, port, "");
134: init(pw);
135: }
136:
137: /**
138: * @return true if this authentication supports preemptive authorization
139: */
140: boolean supportsPreemptiveAuthorization() {
141: return false;
142: }
143:
144: /**
145: * @return true if this NTLM supported on this platform
146: */
147: static boolean isSupported() {
148: return supported;
149: }
150:
151: /**
152: * @return the name of the HTTP header this authentication wants set
153: */
154: String getHeaderName() {
155: if (type == SERVER_AUTHENTICATION) {
156: return "Authorization";
157: } else {
158: return "Proxy-authorization";
159: }
160: }
161:
162: /**
163: * Not supported. Must use the setHeaders() method
164: */
165: String getHeaderValue(URL url, String method) {
166: throw new RuntimeException("getHeaderValue not supported");
167: }
168:
169: /**
170: * Check if the header indicates that the current auth. parameters are stale.
171: * If so, then replace the relevant field with the new value
172: * and return true. Otherwise return false.
173: * returning true means the request can be retried with the same userid/password
174: * returning false means we have to go back to the user to ask for a new
175: * username password.
176: */
177: boolean isAuthorizationStale(String header) {
178: return false; /* should not be called for ntlm */
179: }
180:
181: /**
182: * Set header(s) on the given connection.
183: * @param conn The connection to apply the header(s) to
184: * @param p A source of header values for this connection, not used because
185: * HeaderParser converts the fields to lower case, use raw instead
186: * @param raw The raw header field.
187: * @return true if all goes well, false if no headers were set.
188: */
189: synchronized boolean setHeaders(HttpURLConnection conn,
190: HeaderParser p, String raw) {
191:
192: try {
193: if (!supported)
194: return false;
195: NTLMAuthSequence seq = (NTLMAuthSequence) conn.authObj;
196: if (seq == null) {
197: seq = new NTLMAuthSequence(username, password, ntdomain);
198: conn.authObj = seq;
199: }
200: String response = "NTLM "
201: + seq.getAuthHeader(raw.length() > 6 ? raw
202: .substring(5) : null);
203: conn.setAuthenticationProperty(getHeaderName(), response);
204: return true;
205: } catch (IOException e) {
206: return false;
207: }
208: }
209:
210: /* This is a no-op for NTLM, because there is no authentication information
211: * provided by the server to the client
212: */
213: public void checkResponse(String header, String method, URL url)
214: throws IOException {
215: }
216: }
|