Source Code Cross Referenced for NTLMAuthentication.java in  » 6.0-JDK-Platform » solaris » sun » net » www » protocol » http » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Platform » solaris » sun.net.www.protocol.http 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004:         *
005:         * This code is free software; you can redistribute it and/or modify it
006:         * under the terms of the GNU General Public License version 2 only, as
007:         * published by the Free Software Foundation.  Sun designates this
008:         * particular file as subject to the "Classpath" exception as provided
009:         * by Sun in the LICENSE file that accompanied this code.
010:         *
011:         * This code is distributed in the hope that it will be useful, but WITHOUT
012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014:         * version 2 for more details (a copy is included in the LICENSE file that
015:         * accompanied this code).
016:         *
017:         * You should have received a copy of the GNU General Public License version
018:         * 2 along with this work; if not, write to the Free Software Foundation,
019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020:         *
021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022:         * CA 95054 USA or visit www.sun.com if you need additional information or
023:         * have any questions.
024:         */
025:
026:        package sun.net.www.protocol.http;
027:
028:        import java.util.Arrays;
029:        import java.util.StringTokenizer;
030:        import java.util.Random;
031:
032:        import sun.net.www.HeaderParser;
033:
034:        import java.io.*;
035:        import javax.crypto.*;
036:        import javax.crypto.spec.*;
037:        import java.security.*;
038:        import java.net.*;
039:
040:        /**
041:         * NTLMAuthentication: 
042:         *
043:         * @author Michael McMahon
044:         */
045:
046:        /*
047:         * NTLM authentication is nominally based on the framework defined in RFC2617,
048:         * but differs from the standard (Basic & Digest) schemes as follows:
049:         *
050:         * 1. A complete authentication requires three request/response transactions
051:         *    as shown below:
052:         *            REQ ------------------------------->
053:         *            <---- 401 (signalling NTLM) --------
054:         *
055:         *            REQ (with type1 NTLM msg) --------->
056:         *            <---- 401 (with type 2 NTLM msg) ---
057:         *
058:         *            REQ (with type3 NTLM msg) --------->
059:         *            <---- OK ---------------------------
060:         *
061:         * 2. The scope of the authentication is the TCP connection (which must be kept-alive)
062:         *    after the type2 response is received. This means that NTLM does not work end-to-end
063:         *    through a proxy, rather between client and proxy, or between client and server (with no proxy)
064:         */
065:
066:        class NTLMAuthentication extends AuthenticationInfo {
067:
068:            static char NTLM_AUTH = 'N';
069:
070:            private byte[] type1;
071:            private byte[] type3;
072:
073:            private SecretKeyFactory fac;
074:            private Cipher cipher;
075:            private MessageDigest md4;
076:            private String hostname;
077:            private static String defaultDomain; /* Domain to use if not specified by user */
078:
079:            static {
080:                defaultDomain = (String) java.security.AccessController
081:                        .doPrivileged(new java.security.PrivilegedAction() {
082:                            public Object run() {
083:                                String s = System
084:                                        .getProperty("http.auth.ntlm.domain");
085:                                if (s == null)
086:                                    return "domain";
087:                                return s;
088:                            }
089:                        });
090:            };
091:
092:            static boolean supportsTransparentAuth() {
093:                return false;
094:            }
095:
096:            private void init0() {
097:                type1 = new byte[256];
098:                type3 = new byte[256];
099:                System.arraycopy(new byte[] { 'N', 'T', 'L', 'M', 'S', 'S',
100:                        'P', 0, 1 }, 0, type1, 0, 9);
101:                type1[12] = (byte) 3;
102:                type1[13] = (byte) 0xb2;
103:                type1[28] = (byte) 0x20;
104:                System.arraycopy(new byte[] { 'N', 'T', 'L', 'M', 'S', 'S',
105:                        'P', 0, 3 }, 0, type3, 0, 9);
106:                type3[12] = (byte) 0x18;
107:                type3[14] = (byte) 0x18;
108:                type3[20] = (byte) 0x18;
109:                type3[22] = (byte) 0x18;
110:                type3[32] = (byte) 0x40;
111:                type3[60] = (byte) 1;
112:                type3[61] = (byte) 0x82;
113:
114:                try {
115:                    hostname = (String) java.security.AccessController
116:                            .doPrivileged(new java.security.PrivilegedAction() {
117:                                public Object run() {
118:                                    String localhost;
119:                                    try {
120:                                        localhost = InetAddress.getLocalHost()
121:                                                .getHostName().toUpperCase();
122:                                    } catch (UnknownHostException e) {
123:                                        localhost = "localhost";
124:                                    }
125:                                    return localhost;
126:                                }
127:                            });
128:                    int x = hostname.indexOf('.');
129:                    if (x != -1) {
130:                        hostname = hostname.substring(0, x);
131:                    }
132:                    fac = SecretKeyFactory.getInstance("DES");
133:                    cipher = Cipher.getInstance("DES/ECB/NoPadding");
134:                    md4 = sun.security.provider.MD4.getInstance();
135:                } catch (NoSuchPaddingException e) {
136:                    assert false;
137:                } catch (NoSuchAlgorithmException e) {
138:                    assert false;
139:                }
140:            };
141:
142:            PasswordAuthentication pw;
143:            String username;
144:            String ntdomain;
145:            String password;
146:
147:            /**
148:             * Create a NTLMAuthentication:
149:             * Username may be specified as domain<BACKSLASH>username in the application Authenticator. 
150:             * If this notation is not used, then the domain will be taken 
151:             * from a system property: "http.auth.ntlm.domain".
152:             */
153:            public NTLMAuthentication(boolean isProxy, URL url,
154:                    PasswordAuthentication pw) {
155:                super (isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
156:                        NTLM_AUTH, url, "");
157:                init(pw);
158:            }
159:
160:            private void init(PasswordAuthentication pw) {
161:                this .pw = pw;
162:                String s = pw.getUserName();
163:                int i = s.indexOf('\\');
164:                if (i == -1) {
165:                    username = s;
166:                    ntdomain = defaultDomain;
167:                } else {
168:                    ntdomain = s.substring(0, i).toUpperCase();
169:                    username = s.substring(i + 1);
170:                }
171:                password = new String(pw.getPassword());
172:                init0();
173:            }
174:
175:            /** 
176:             * Constructor used for proxy entries
177:             */
178:            public NTLMAuthentication(boolean isProxy, String host, int port,
179:                    PasswordAuthentication pw) {
180:                super (isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
181:                        NTLM_AUTH, host, port, "");
182:                init(pw);
183:            }
184:
185:            /**
186:             * @return true if this authentication supports preemptive authorization
187:             */
188:            boolean supportsPreemptiveAuthorization() {
189:                return false;
190:            }
191:
192:            /**
193:             * @return the name of the HTTP header this authentication wants set
194:             */
195:            String getHeaderName() {
196:                if (type == SERVER_AUTHENTICATION) {
197:                    return "Authorization";
198:                } else {
199:                    return "Proxy-authorization";
200:                }
201:            }
202:
203:            /**
204:             * Not supported. Must use the setHeaders() method
205:             */
206:            String getHeaderValue(URL url, String method) {
207:                throw new RuntimeException("getHeaderValue not supported");
208:            }
209:
210:            /**
211:             * Check if the header indicates that the current auth. parameters are stale.
212:             * If so, then replace the relevant field with the new value
213:             * and return true. Otherwise return false.
214:             * returning true means the request can be retried with the same userid/password
215:             * returning false means we have to go back to the user to ask for a new
216:             * username password.
217:             */
218:            boolean isAuthorizationStale(String header) {
219:                return false; /* should not be called for ntlm */
220:            }
221:
222:            /**
223:             * Set header(s) on the given connection.
224:             * @param conn The connection to apply the header(s) to
225:             * @param p A source of header values for this connection, not used because
226:             * 		HeaderParser converts the fields to lower case, use raw instead
227:             * @param raw The raw header field.
228:             * @return true if all goes well, false if no headers were set.
229:             */
230:            synchronized boolean setHeaders(HttpURLConnection conn,
231:                    HeaderParser p, String raw) {
232:
233:                try {
234:                    String response;
235:                    if (raw.length() < 6) { /* NTLM<sp> */
236:                        response = buildType1Msg();
237:                    } else {
238:                        String msg = raw.substring(5); /* skip NTLM<sp> */
239:                        response = buildType3Msg(msg);
240:                    }
241:                    conn.setAuthenticationProperty(getHeaderName(), response);
242:                    return true;
243:                } catch (IOException e) {
244:                    return false;
245:                } catch (GeneralSecurityException e) {
246:                    return false;
247:                }
248:            }
249:
250:            /* This is a no-op for NTLM, because there is no authentication information
251:             * provided by the server to the client
252:             */
253:            public void checkResponse(String header, String method, URL url)
254:                    throws IOException {
255:            }
256:
257:            private void copybytes(byte[] dest, int destpos, String src,
258:                    String enc) {
259:                try {
260:                    byte[] x = src.getBytes(enc);
261:                    System.arraycopy(x, 0, dest, destpos, x.length);
262:                } catch (UnsupportedEncodingException e) {
263:                    assert false;
264:                }
265:            }
266:
267:            private String buildType1Msg() {
268:                int dlen = ntdomain.length();
269:                type1[16] = (byte) (dlen % 256);
270:                type1[17] = (byte) (dlen / 256);
271:                type1[18] = type1[16];
272:                type1[19] = type1[17];
273:
274:                int hlen = hostname.length();
275:                type1[24] = (byte) (hlen % 256);
276:                type1[25] = (byte) (hlen / 256);
277:                type1[26] = type1[24];
278:                type1[27] = type1[25];
279:
280:                copybytes(type1, 32, hostname, "ISO8859_1");
281:                copybytes(type1, hlen + 32, ntdomain, "ISO8859_1");
282:                type1[20] = (byte) ((hlen + 32) % 256);
283:                type1[21] = (byte) ((hlen + 32) / 256);
284:
285:                byte[] msg = new byte[32 + hlen + dlen];
286:                System.arraycopy(type1, 0, msg, 0, 32 + hlen + dlen);
287:                String result = "NTLM " + (new B64Encoder()).encode(msg);
288:                return result;
289:            }
290:
291:            /* Convert a 7 byte array to an 8 byte array (for a des key with parity)
292:             * input starts at offset off
293:             */
294:            private byte[] makeDesKey(byte[] input, int off) {
295:                int[] in = new int[input.length];
296:                for (int i = 0; i < in.length; i++) {
297:                    in[i] = input[i] < 0 ? input[i] + 256 : input[i];
298:                }
299:                byte[] out = new byte[8];
300:                out[0] = (byte) in[off + 0];
301:                out[1] = (byte) (((in[off + 0] << 7) & 0xFF) | (in[off + 1] >> 1));
302:                out[2] = (byte) (((in[off + 1] << 6) & 0xFF) | (in[off + 2] >> 2));
303:                out[3] = (byte) (((in[off + 2] << 5) & 0xFF) | (in[off + 3] >> 3));
304:                out[4] = (byte) (((in[off + 3] << 4) & 0xFF) | (in[off + 4] >> 4));
305:                out[5] = (byte) (((in[off + 4] << 3) & 0xFF) | (in[off + 5] >> 5));
306:                out[6] = (byte) (((in[off + 5] << 2) & 0xFF) | (in[off + 6] >> 6));
307:                out[7] = (byte) ((in[off + 6] << 1) & 0xFF);
308:                return out;
309:            }
310:
311:            private byte[] calcLMHash() throws GeneralSecurityException {
312:                byte[] magic = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
313:                byte[] pwb = password.toUpperCase().getBytes();
314:                byte[] pwb1 = new byte[14];
315:                int len = password.length();
316:                if (len > 14)
317:                    len = 14;
318:                System.arraycopy(pwb, 0, pwb1, 0, len); /* Zero padded */
319:
320:                DESKeySpec dks1 = new DESKeySpec(makeDesKey(pwb1, 0));
321:                DESKeySpec dks2 = new DESKeySpec(makeDesKey(pwb1, 7));
322:
323:                SecretKey key1 = fac.generateSecret(dks1);
324:                SecretKey key2 = fac.generateSecret(dks2);
325:                cipher.init(Cipher.ENCRYPT_MODE, key1);
326:                byte[] out1 = cipher.doFinal(magic, 0, 8);
327:                cipher.init(Cipher.ENCRYPT_MODE, key2);
328:                byte[] out2 = cipher.doFinal(magic, 0, 8);
329:
330:                byte[] result = new byte[21];
331:                System.arraycopy(out1, 0, result, 0, 8);
332:                System.arraycopy(out2, 0, result, 8, 8);
333:                return result;
334:            }
335:
336:            private byte[] calcNTHash() throws GeneralSecurityException {
337:                byte[] pw = null;
338:                try {
339:                    pw = password.getBytes("UnicodeLittleUnmarked");
340:                } catch (UnsupportedEncodingException e) {
341:                    assert false;
342:                }
343:                byte[] out = md4.digest(pw);
344:                byte[] result = new byte[21];
345:                System.arraycopy(out, 0, result, 0, 16);
346:                return result;
347:            }
348:
349:            /* key is a 21 byte array. Split it into 3 7 byte chunks,
350:             * Convert each to 8 byte DES keys, encrypt the text arg with
351:             * each key and return the three results in a sequential []
352:             */
353:            private byte[] calcResponse(byte[] key, byte[] text)
354:                    throws GeneralSecurityException {
355:                assert key.length == 21;
356:                DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
357:                DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
358:                DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
359:                SecretKey key1 = fac.generateSecret(dks1);
360:                SecretKey key2 = fac.generateSecret(dks2);
361:                SecretKey key3 = fac.generateSecret(dks3);
362:                cipher.init(Cipher.ENCRYPT_MODE, key1);
363:                byte[] out1 = cipher.doFinal(text, 0, 8);
364:                cipher.init(Cipher.ENCRYPT_MODE, key2);
365:                byte[] out2 = cipher.doFinal(text, 0, 8);
366:                cipher.init(Cipher.ENCRYPT_MODE, key3);
367:                byte[] out3 = cipher.doFinal(text, 0, 8);
368:                byte[] result = new byte[24];
369:                System.arraycopy(out1, 0, result, 0, 8);
370:                System.arraycopy(out2, 0, result, 8, 8);
371:                System.arraycopy(out3, 0, result, 16, 8);
372:                return result;
373:            }
374:
375:            private String buildType3Msg(String challenge)
376:                    throws GeneralSecurityException, IOException {
377:                /* First decode the type2 message to get the server nonce */
378:                /* nonce is located at type2[24] for 8 bytes */
379:
380:                byte[] type2 = (new sun.misc.BASE64Decoder())
381:                        .decodeBuffer(challenge);
382:                byte[] nonce = new byte[8];
383:                System.arraycopy(type2, 24, nonce, 0, 8);
384:
385:                int ulen = username.length() * 2;
386:                type3[36] = type3[38] = (byte) (ulen % 256);
387:                type3[37] = type3[39] = (byte) (ulen / 256);
388:                int dlen = ntdomain.length() * 2;
389:                type3[28] = type3[30] = (byte) (dlen % 256);
390:                type3[29] = type3[31] = (byte) (dlen / 256);
391:                int hlen = hostname.length() * 2;
392:                type3[44] = type3[46] = (byte) (hlen % 256);
393:                type3[45] = type3[47] = (byte) (hlen / 256);
394:
395:                int l = 64;
396:                copybytes(type3, l, ntdomain, "UnicodeLittleUnmarked");
397:                type3[32] = (byte) (l % 256);
398:                type3[33] = (byte) (l / 256);
399:                l += dlen;
400:                copybytes(type3, l, username, "UnicodeLittleUnmarked");
401:                type3[40] = (byte) (l % 256);
402:                type3[41] = (byte) (l / 256);
403:                l += ulen;
404:                copybytes(type3, l, hostname, "UnicodeLittleUnmarked");
405:                type3[48] = (byte) (l % 256);
406:                type3[49] = (byte) (l / 256);
407:                l += hlen;
408:
409:                byte[] lmhash = calcLMHash();
410:                byte[] lmresponse = calcResponse(lmhash, nonce);
411:                byte[] nthash = calcNTHash();
412:                byte[] ntresponse = calcResponse(nthash, nonce);
413:                System.arraycopy(lmresponse, 0, type3, l, 24);
414:                type3[16] = (byte) (l % 256);
415:                type3[17] = (byte) (l / 256);
416:                l += 24;
417:                System.arraycopy(ntresponse, 0, type3, l, 24);
418:                type3[24] = (byte) (l % 256);
419:                type3[25] = (byte) (l / 256);
420:                l += 24;
421:                type3[56] = (byte) (l % 256);
422:                type3[57] = (byte) (l / 256);
423:
424:                byte[] msg = new byte[l];
425:                System.arraycopy(type3, 0, msg, 0, l);
426:                String result = "NTLM " + (new B64Encoder()).encode(msg);
427:                return result;
428:            }
429:
430:        }
431:
432:        class B64Encoder extends sun.misc.BASE64Encoder {
433:            /* to force it to to the entire encoding in one line */
434:            protected int bytesPerLine() {
435:                return 1024;
436:            }
437:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.