KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > knowgate > jcifs > http > NtlmHttpURLConnection


1 /* jcifs smb client library in Java
2  * Copyright (C) 2002 "Michael B. Allen" <jcifs at samba dot org>
3  * "Eric Glass" <jcifs at samba dot org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package com.knowgate.jcifs.http;
21
22 import java.io.InputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25
26 import java.net.Authenticator JavaDoc;
27 import java.net.HttpURLConnection JavaDoc;
28 import java.net.PasswordAuthentication JavaDoc;
29 import java.net.ProtocolException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.net.URLDecoder JavaDoc;
32
33 import java.security.Permission JavaDoc;
34
35 import java.util.ArrayList JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Map JavaDoc;
41
42 import com.knowgate.jcifs.Config;
43
44 import com.knowgate.jcifs.ntlmssp.NtlmFlags;
45 import com.knowgate.jcifs.ntlmssp.NtlmMessage;
46 import com.knowgate.jcifs.ntlmssp.Type1Message;
47 import com.knowgate.jcifs.ntlmssp.Type2Message;
48 import com.knowgate.jcifs.ntlmssp.Type3Message;
49
50 import com.knowgate.misc.Base64Decoder;
51 import com.knowgate.misc.Base64Encoder;
52
53
54 /**
55  * Wraps an <code>HttpURLConnection</code> to provide NTLM authentication
56  * services.
57  *
58  * Please read <a HREF="../../../httpclient.html">Using jCIFS NTLM Authentication for HTTP Connections</a>.
59  * @version 0.9.1
60  */

61 public class NtlmHttpURLConnection extends HttpURLConnection JavaDoc {
62
63     private static final int MAX_REDIRECTS =
64             Integer.parseInt(System.getProperty("http.maxRedirects", "20"));
65
66     private static final int LM_COMPATIBILITY =
67             Config.getInt("jcifs.smb.lmCompatibility", 0);
68
69     private static final String JavaDoc DEFAULT_DOMAIN;
70
71     private HttpURLConnection JavaDoc connection;
72
73     private Map JavaDoc requestProperties;
74
75     private Map JavaDoc headerFields;
76
77     private String JavaDoc authProperty;
78
79     private String JavaDoc method;
80
81     static {
82         String JavaDoc domain = System.getProperty("http.auth.ntlm.domain");
83         if (domain == null) domain = Type3Message.getDefaultDomain();
84         DEFAULT_DOMAIN = domain;
85     }
86
87     public NtlmHttpURLConnection(HttpURLConnection JavaDoc connection) {
88         super(connection.getURL());
89         this.connection = connection;
90         requestProperties = new HashMap JavaDoc();
91     }
92
93     public void connect() throws IOException JavaDoc {
94         if (connected) return;
95         doConnect();
96         connected = true;
97     }
98
99     public URL JavaDoc getURL() {
100         return connection.getURL();
101     }
102
103     public int getContentLength() {
104         try {
105             connect();
106         } catch (IOException JavaDoc ex) { }
107         return connection.getContentLength();
108     }
109
110     public String JavaDoc getContentType() {
111         try {
112             connect();
113         } catch (IOException JavaDoc ex) { }
114         return connection.getContentType();
115     }
116
117     public String JavaDoc getContentEncoding() {
118         try {
119             connect();
120         } catch (IOException JavaDoc ex) { }
121         return connection.getContentEncoding();
122     }
123
124     public long getExpiration() {
125         try {
126             connect();
127         } catch (IOException JavaDoc ex) { }
128         return connection.getExpiration();
129     }
130
131     public long getDate() {
132         try {
133             connect();
134         } catch (IOException JavaDoc ex) { }
135         return connection.getDate();
136     }
137
138     public long getLastModified() {
139         try {
140             connect();
141         } catch (IOException JavaDoc ex) { }
142         return connection.getLastModified();
143     }
144
145     public String JavaDoc getHeaderField(String JavaDoc header) {
146         try {
147             connect();
148         } catch (IOException JavaDoc ex) { }
149         return connection.getHeaderField(header);
150     }
151
152     private synchronized Map JavaDoc getHeaderFields0() {
153         if (headerFields != null) return headerFields;
154         Map JavaDoc map = new HashMap JavaDoc();
155         String JavaDoc key = connection.getHeaderFieldKey(0);
156         String JavaDoc value = connection.getHeaderField(0);
157         for (int i = 1; key != null || value != null; i++) {
158             List JavaDoc values = (List JavaDoc) map.get(key);
159             if (values == null) {
160                 values = new ArrayList JavaDoc();
161                 map.put(key, values);
162             }
163             values.add(value);
164             key = connection.getHeaderFieldKey(i);
165             value = connection.getHeaderField(i);
166         }
167         Iterator JavaDoc entries = map.entrySet().iterator();
168         while (entries.hasNext()) {
169             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
170             entry.setValue(Collections.unmodifiableList((List JavaDoc)
171                     entry.getValue()));
172         }
173         return (headerFields = Collections.unmodifiableMap(map));
174     }
175
176     public Map JavaDoc getHeaderFields() {
177         synchronized (this) {
178             if (headerFields != null) return headerFields;
179         }
180         try {
181             connect();
182         } catch (IOException JavaDoc ex) { }
183         return getHeaderFields0();
184     }
185
186     public int getHeaderFieldInt(String JavaDoc header, int def) {
187         try {
188             connect();
189         } catch (IOException JavaDoc ex) { }
190         return connection.getHeaderFieldInt(header, def);
191     }
192
193     public long getHeaderFieldDate(String JavaDoc header, long def) {
194         try {
195             connect();
196         } catch (IOException JavaDoc ex) { }
197         return connection.getHeaderFieldDate(header, def);
198     }
199
200     public String JavaDoc getHeaderFieldKey(int index) {
201         try {
202             connect();
203         } catch (IOException JavaDoc ex) { }
204         return connection.getHeaderFieldKey(index);
205     }
206
207     public String JavaDoc getHeaderField(int index) {
208         try {
209             connect();
210         } catch (IOException JavaDoc ex) { }
211         return connection.getHeaderField(index);
212     }
213
214     public Object JavaDoc getContent() throws IOException JavaDoc {
215         try {
216             connect();
217         } catch (IOException JavaDoc ex) { }
218         return connection.getContent();
219     }
220
221     public Object JavaDoc getContent(Class JavaDoc[] classes) throws IOException JavaDoc {
222         try {
223             connect();
224         } catch (IOException JavaDoc ex) { }
225         return connection.getContent(classes);
226     }
227
228     public Permission JavaDoc getPermission() throws IOException JavaDoc {
229         return connection.getPermission();
230     }
231
232     public InputStream JavaDoc getInputStream() throws IOException JavaDoc {
233         try {
234             connect();
235         } catch (IOException JavaDoc ex) { }
236         return connection.getInputStream();
237     }
238
239     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
240         try {
241             connect();
242         } catch (IOException JavaDoc ex) { }
243         return connection.getOutputStream();
244     }
245
246     public String JavaDoc toString() {
247         return connection.toString();
248     }
249
250     public void setDoInput(boolean doInput) {
251         connection.setDoInput(doInput);
252         this.doInput = doInput;
253     }
254
255     public boolean getDoInput() {
256         return connection.getDoInput();
257     }
258
259     public void setDoOutput(boolean doOutput) {
260         connection.setDoOutput(doOutput);
261         this.doOutput = doOutput;
262     }
263
264     public boolean getDoOutput() {
265         return connection.getDoOutput();
266     }
267
268     public void setAllowUserInteraction(boolean allowUserInteraction) {
269         connection.setAllowUserInteraction(allowUserInteraction);
270         this.allowUserInteraction = allowUserInteraction;
271     }
272
273     public boolean getAllowUserInteraction() {
274         return connection.getAllowUserInteraction();
275     }
276
277     public void setUseCaches(boolean useCaches) {
278         connection.setUseCaches(useCaches);
279         this.useCaches = useCaches;
280     }
281
282     public boolean getUseCaches() {
283         return connection.getUseCaches();
284     }
285
286     public void setIfModifiedSince(long ifModifiedSince) {
287         connection.setIfModifiedSince(ifModifiedSince);
288         this.ifModifiedSince = ifModifiedSince;
289     }
290
291     public long getIfModifiedSince() {
292         return connection.getIfModifiedSince();
293     }
294
295     public boolean getDefaultUseCaches() {
296         return connection.getDefaultUseCaches();
297     }
298
299     public void setDefaultUseCaches(boolean defaultUseCaches) {
300         connection.setDefaultUseCaches(defaultUseCaches);
301     }
302
303     public void setRequestProperty(String JavaDoc key, String JavaDoc value) {
304         if (key == null) throw new NullPointerException JavaDoc();
305         List JavaDoc values = new ArrayList JavaDoc();
306         values.add(value);
307         boolean found = false;
308         synchronized (requestProperties) {
309             Iterator JavaDoc entries = requestProperties.entrySet().iterator();
310             while (entries.hasNext()) {
311                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
312                 if (key.equalsIgnoreCase((String JavaDoc) entry.getKey())) {
313                     entry.setValue(value);
314                     found = true;
315                     break;
316                 }
317             }
318             if (!found) requestProperties.put(key, values);
319         }
320         connection.setRequestProperty(key, value);
321     }
322
323     public void addRequestProperty(String JavaDoc key, String JavaDoc value) {
324         if (key == null) throw new NullPointerException JavaDoc();
325         List JavaDoc values = null;
326         synchronized (requestProperties) {
327             Iterator JavaDoc entries = requestProperties.entrySet().iterator();
328             while (entries.hasNext()) {
329                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
330                 if (key.equalsIgnoreCase((String JavaDoc) entry.getKey())) {
331                     values = (List JavaDoc) entry.getValue();
332                     values.add(value);
333                     break;
334                 }
335             }
336             if (values == null) {
337                 values = new ArrayList JavaDoc();
338                 values.add(value);
339                 requestProperties.put(key, values);
340             }
341         }
342         // 1.3-compatible.
343
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
344         Iterator JavaDoc propertyValues = values.iterator();
345         while (propertyValues.hasNext()) {
346             buffer.append(propertyValues.next());
347             if (propertyValues.hasNext()) {
348                 buffer.append(", ");
349             }
350         }
351         connection.setRequestProperty(key, buffer.toString());
352     }
353
354     public String JavaDoc getRequestProperty(String JavaDoc key) {
355         return connection.getRequestProperty(key);
356     }
357
358     public Map JavaDoc getRequestProperties() {
359         Map JavaDoc map = new HashMap JavaDoc();
360         synchronized (requestProperties) {
361             Iterator JavaDoc entries = requestProperties.entrySet().iterator();
362             while (entries.hasNext()) {
363                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
364                 map.put(entry.getKey(),
365                         Collections.unmodifiableList((List JavaDoc) entry.getValue()));
366             }
367         }
368         return Collections.unmodifiableMap(map);
369     }
370
371     public void setInstanceFollowRedirects(boolean instanceFollowRedirects) {
372         connection.setInstanceFollowRedirects(instanceFollowRedirects);
373     }
374
375     public boolean getInstanceFollowRedirects() {
376         return connection.getInstanceFollowRedirects();
377     }
378
379     public void setRequestMethod(String JavaDoc requestMethod)
380             throws ProtocolException JavaDoc {
381         connection.setRequestMethod(requestMethod);
382     }
383
384     public String JavaDoc getRequestMethod() {
385         return connection.getRequestMethod();
386     }
387
388     public int getResponseCode() throws IOException JavaDoc {
389         return connection.getResponseCode();
390     }
391
392     public String JavaDoc getResponseMessage() throws IOException JavaDoc {
393         return connection.getResponseMessage();
394     }
395
396     public void disconnect() {
397         connection.disconnect();
398         connected = false;
399     }
400
401     public boolean usingProxy() {
402         return connection.usingProxy();
403     }
404
405     public InputStream JavaDoc getErrorStream() {
406         return connection.getErrorStream();
407     }
408
409     private int parseResponseCode() throws IOException JavaDoc {
410         try {
411             String JavaDoc response = connection.getHeaderField(0);
412             int index = response.indexOf(' ');
413             while (response.charAt(index) == ' ') index++;
414             return Integer.parseInt(response.substring(index, index + 3));
415         } catch (Exception JavaDoc ex) {
416             throw new IOException JavaDoc(ex.getMessage());
417         }
418     }
419
420     private synchronized void doConnect() throws IOException JavaDoc {
421         connection.connect();
422         int response = parseResponseCode();
423         if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
424             return;
425         }
426         Type1Message type1 = (Type1Message) attemptNegotiation(response);
427         if (type1 == null) return; // no NTLM
428
int attempt = 0;
429         while (attempt < MAX_REDIRECTS) {
430             connection.setRequestProperty(authProperty, method + ' ' + Base64Encoder.encode(type1.toByteArray()));
431             connection.connect(); // send type 1
432
response = parseResponseCode();
433             if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
434                 return;
435             }
436             Type3Message type3 = (Type3Message) attemptNegotiation(response);
437             if (type3 == null) return;
438             connection.setRequestProperty(authProperty, method + ' ' + Base64Encoder.encode(type3.toByteArray()));
439             connection.connect(); // send type 3
440
response = parseResponseCode();
441             if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
442                 return;
443             }
444             attempt++;
445             if (attempt < MAX_REDIRECTS) reconnect();
446         }
447         throw new IOException JavaDoc("Unable to negotiate NTLM authentication.");
448     }
449
450     private NtlmMessage attemptNegotiation(int response) throws IOException JavaDoc {
451         authProperty = null;
452         method = null;
453         InputStream JavaDoc errorStream = connection.getErrorStream();
454         if (errorStream != null && errorStream.available() != 0) {
455             int count;
456             byte[] buf = new byte[1024];
457             while ((count = errorStream.read(buf, 0, 1024)) != -1);
458         }
459         String JavaDoc authHeader;
460         if (response == HTTP_UNAUTHORIZED) {
461             authHeader = "WWW-Authenticate";
462             authProperty = "Authorization";
463         } else {
464             authHeader = "Proxy-Authenticate";
465             authProperty = "Proxy-Authorization";
466         }
467         String JavaDoc authorization = null;
468         List JavaDoc methods = (List JavaDoc) getHeaderFields0().get(authHeader);
469         if (methods == null) return null;
470         Iterator JavaDoc iterator = methods.iterator();
471         while (iterator.hasNext()) {
472             String JavaDoc authMethod = (String JavaDoc) iterator.next();
473             if (authMethod.startsWith("NTLM")) {
474                 if (authMethod.length() == 4) {
475                     method = "NTLM";
476                     break;
477                 }
478                 if (authMethod.indexOf(' ') != 4) continue;
479                 method = "NTLM";
480                 authorization = authMethod.substring(5).trim();
481                 break;
482             } else if (authMethod.startsWith("Negotiate")) {
483                 if (authMethod.length() == 9) {
484                     method = "Negotiate";
485                     break;
486                 }
487                 if (authMethod.indexOf(' ') != 9) continue;
488                 method = "Negotiate";
489                 authorization = authMethod.substring(10).trim();
490                 break;
491             }
492         }
493         if (method == null) return null;
494         NtlmMessage message = (authorization != null) ?
495                 new Type2Message(Base64Decoder.decodeToBytes(authorization)) : null;
496         reconnect();
497         if (message == null) {
498             message = new Type1Message();
499             if (LM_COMPATIBILITY > 2) {
500                 message.setFlag(NtlmFlags.NTLMSSP_REQUEST_TARGET, true);
501             }
502         } else {
503             String JavaDoc domain = DEFAULT_DOMAIN;
504             String JavaDoc user = Type3Message.getDefaultUser();
505             String JavaDoc password = Type3Message.getDefaultPassword();
506             String JavaDoc userInfo = url.getUserInfo();
507             if (userInfo != null) {
508                 userInfo = URLDecoder.decode(userInfo);
509                 int index = userInfo.indexOf(':');
510                 user = (index != -1) ? userInfo.substring(0, index) : userInfo;
511                 if (index != -1) password = userInfo.substring(index + 1);
512                 index = user.indexOf('\\');
513                 if (index == -1) index = user.indexOf('/');
514                 domain = (index != -1) ? user.substring(0, index) : domain;
515                 user = (index != -1) ? user.substring(index + 1) : user;
516             }
517             if (user == null) {
518                 try {
519                     URL JavaDoc url = getURL();
520                     String JavaDoc protocol = url.getProtocol();
521                     int port = url.getPort();
522                     if (port == -1) {
523                         port = "https".equalsIgnoreCase(protocol) ? 443 : 80;
524                     }
525                     PasswordAuthentication JavaDoc auth =
526                             Authenticator.requestPasswordAuthentication(null,
527                                     port, protocol, "", method);
528                     if (auth != null) {
529                         user = auth.getUserName();
530                         password = new String JavaDoc(auth.getPassword());
531                     }
532                 } catch (Exception JavaDoc ex) { }
533             }
534             Type2Message type2 = (Type2Message) message;
535             message = new Type3Message(type2, password, domain, user,
536                     Type3Message.getDefaultWorkstation());
537         }
538         return message;
539     }
540
541     private void reconnect() throws IOException JavaDoc {
542         connection = (HttpURLConnection JavaDoc) connection.getURL().openConnection();
543         headerFields = null;
544         synchronized (requestProperties) {
545             Iterator JavaDoc properties = requestProperties.entrySet().iterator();
546             while (properties.hasNext()) {
547                 Map.Entry JavaDoc property = (Map.Entry JavaDoc) properties.next();
548                 String JavaDoc key = (String JavaDoc) property.getKey();
549                 StringBuffer JavaDoc value = new StringBuffer JavaDoc();
550                 Iterator JavaDoc values = ((List JavaDoc) property.getValue()).iterator();
551                 while (values.hasNext()) {
552                     value.append(values.next());
553                     if (values.hasNext()) value.append(", ");
554                 }
555                 connection.setRequestProperty(key, value.toString());
556             }
557         }
558         connection.setAllowUserInteraction(allowUserInteraction);
559         connection.setDoInput(doInput);
560         connection.setDoOutput(doOutput);
561         connection.setIfModifiedSince(ifModifiedSince);
562         connection.setUseCaches(useCaches);
563     }
564 }
565
Popular Tags