Source Code Cross Referenced for StartTlsResponseImpl.java in  » 6.0-JDK-Modules-com.sun » jndi » com » sun » jndi » ldap » ext » 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 Modules com.sun » jndi » com.sun.jndi.ldap.ext 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2000-2003 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 com.sun.jndi.ldap.ext;
027:
028:        import java.io.InputStream;
029:        import java.io.OutputStream;
030:        import java.io.BufferedInputStream;
031:        import java.io.BufferedOutputStream;
032:        import java.io.IOException;
033:
034:        import java.net.Socket;
035:
036:        import java.util.Collection;
037:        import java.util.Iterator;
038:        import java.util.List;
039:
040:        import java.security.Principal;
041:        import java.security.cert.X509Certificate;
042:        import java.security.cert.CertificateException;
043:        import javax.security.auth.kerberos.KerberosPrincipal;
044:
045:        import javax.net.ssl.SSLSession;
046:        import javax.net.ssl.SSLSocket;
047:        import javax.net.ssl.SSLSocketFactory;
048:        import javax.net.ssl.SSLPeerUnverifiedException;
049:        import javax.net.ssl.SSLContext;
050:        import javax.net.ssl.HostnameVerifier;
051:        import sun.security.util.HostnameChecker;
052:
053:        import javax.naming.*;
054:        import javax.naming.ldap.*;
055:        import com.sun.jndi.ldap.Connection;
056:
057:        /**
058:         * This class implements the LDAPv3 Extended Response for StartTLS as
059:         * defined in
060:         * <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
061:         * Access Protocol (v3): Extension for Transport Layer Security</a>
062:         *
063:         * The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
064:         * and no extended response value is defined.
065:         *
066:         *<p>
067:         * The Start TLS extended request and response are used to establish
068:         * a TLS connection over the existing LDAP connection associated with
069:         * the JNDI context on which <tt>extendedOperation()</tt> is invoked.
070:         *
071:         * @see StartTlsRequest
072:         * @author Vincent Ryan
073:         */
074:        final public class StartTlsResponseImpl extends StartTlsResponse {
075:
076:            private static final boolean debug = false;
077:
078:            /*
079:             * The dNSName type in a subjectAltName extension of an X.509 certificate
080:             */
081:            private static final int DNSNAME_TYPE = 2;
082:
083:            /*
084:             * The server's hostname.
085:             */
086:            private transient String hostname = null;
087:
088:            /*
089:             * The LDAP socket.
090:             */
091:            private transient Connection ldapConnection = null;
092:
093:            /*
094:             * The original input stream.
095:             */
096:            private transient InputStream originalInputStream = null;
097:
098:            /*
099:             * The original output stream.
100:             */
101:            private transient OutputStream originalOutputStream = null;
102:
103:            /*
104:             * The SSL socket.
105:             */
106:            private transient SSLSocket sslSocket = null;
107:
108:            /*
109:             * The SSL socket factories.
110:             */
111:            private transient SSLSocketFactory defaultFactory = null;
112:            private transient SSLSocketFactory currentFactory = null;
113:
114:            /*
115:             * The list of cipher suites to be enabled.
116:             */
117:            private transient String[] suites = null;
118:
119:            /*
120:             * The hostname verifier callback.
121:             */
122:            private transient HostnameVerifier verifier = null;
123:
124:            /*
125:             * The flag to indicate that the TLS connection is closed.
126:             */
127:            private transient boolean isClosed = true;
128:
129:            private static final long serialVersionUID = -1126624615143411328L;
130:
131:            // public no-arg constructor required by JDK's Service Provider API.
132:
133:            public StartTlsResponseImpl() {
134:            }
135:
136:            /**
137:             * Overrides the default list of cipher suites enabled for use on the
138:             * TLS connection. The cipher suites must have already been listed by
139:             * <tt>SSLSocketFactory.getSupportedCipherSuites()</tt> as being supported.
140:             * Even if a suite has been enabled, it still might not be used because
141:             * the peer does not support it, or because the requisite certificates
142:             * (and private keys) are not available.
143:             *
144:             * @param suites The non-null list of names of all the cipher suites to
145:             * enable.
146:             * @see #negotiate
147:             */
148:            public void setEnabledCipherSuites(String[] suites) {
149:                this .suites = suites;
150:            }
151:
152:            /**
153:             * Overrides the default hostname verifier used by <tt>negotiate()</tt>
154:             * after the TLS handshake has completed. If
155:             * <tt>setHostnameVerifier()</tt> has not been called before
156:             * <tt>negotiate()</tt> is invoked, <tt>negotiate()</tt>
157:             * will perform a simple case ignore match. If called after
158:             * <tt>negotiate()</tt>, this method does not do anything.
159:             *
160:             * @param verifier The non-null hostname verifier callback.
161:             * @see #negotiate
162:             */
163:            public void setHostnameVerifier(HostnameVerifier verifier) {
164:                this .verifier = verifier;
165:            }
166:
167:            /**
168:             * Negotiates a TLS session using the default SSL socket factory.
169:             * <p>
170:             * This method is equivalent to <tt>negotiate(null)</tt>.
171:             *
172:             * @return The negotiated SSL session
173:             * @throw IOException If an IO error was encountered while establishing
174:             * the TLS session.
175:             * @see #setEnabledCipherSuites
176:             * @see #setHostnameVerifier
177:             */
178:            public SSLSession negotiate() throws IOException {
179:
180:                return negotiate(null);
181:            }
182:
183:            /**
184:             * Negotiates a TLS session using an SSL socket factory.
185:             * <p>
186:             * Creates an SSL socket using the supplied SSL socket factory and
187:             * attaches it to the existing connection. Performs the TLS handshake
188:             * and returns the negotiated session information.
189:             * <p>
190:             * If cipher suites have been set via <tt>setEnabledCipherSuites</tt>
191:             * then they are enabled before the TLS handshake begins.
192:             * <p>
193:             * Hostname verification is performed after the TLS handshake completes.
194:             * The default check performs a case insensitive match of the server's
195:             * hostname against that in the server's certificate. The server's
196:             * hostname is extracted from the subjectAltName in the server's
197:             * certificate (if present). Otherwise the value of the common name
198:             * attribute of the subject name is used. If a callback has
199:             * been set via <tt>setHostnameVerifier</tt> then that verifier is used if
200:             * the default check fails.
201:             * <p>
202:             * If an error occurs then the SSL socket is closed and an IOException
203:             * is thrown. The underlying connection remains intact.
204:             *
205:             * @param factory The possibly null SSL socket factory to use.
206:             * If null, the default SSL socket factory is used.
207:             * @return The negotiated SSL session
208:             * @throw IOException If an IO error was encountered while establishing
209:             * the TLS session.
210:             * @see #setEnabledCipherSuites
211:             * @see #setHostnameVerifier
212:             */
213:            public SSLSession negotiate(SSLSocketFactory factory)
214:                    throws IOException {
215:
216:                if (isClosed && sslSocket != null) {
217:                    throw new IOException("TLS connection is closed.");
218:                }
219:
220:                if (factory == null) {
221:                    factory = getDefaultFactory();
222:                }
223:
224:                if (debug) {
225:                    System.out.println("StartTLS: About to start handshake");
226:                }
227:
228:                SSLSession sslSession = startHandshake(factory).getSession();
229:
230:                if (debug) {
231:                    System.out.println("StartTLS: Completed handshake");
232:                }
233:
234:                SSLPeerUnverifiedException verifExcep = null;
235:                try {
236:                    if (verify(hostname, sslSession)) {
237:                        isClosed = false;
238:                        return sslSession;
239:                    }
240:                } catch (SSLPeerUnverifiedException e) {
241:                    // Save to return the cause
242:                    verifExcep = e;
243:                }
244:                if ((verifier != null) && verifier.verify(hostname, sslSession)) {
245:                    isClosed = false;
246:                    return sslSession;
247:                }
248:
249:                // Verification failed
250:                close();
251:                sslSession.invalidate();
252:                if (verifExcep == null) {
253:                    verifExcep = new SSLPeerUnverifiedException(
254:                            "hostname of the server '" + hostname
255:                                    + "' does not match the hostname in the "
256:                                    + "server's certificate.");
257:                }
258:                throw verifExcep;
259:            }
260:
261:            /**
262:             * Closes the TLS connection gracefully and reverts back to the underlying
263:             * connection.
264:             *
265:             * @throw IOException If an IO error was encountered while closing the
266:             * TLS connection
267:             */
268:            public void close() throws IOException {
269:
270:                if (isClosed) {
271:                    return;
272:                }
273:
274:                if (debug) {
275:                    System.out.println("StartTLS: replacing SSL "
276:                            + "streams with originals");
277:                }
278:
279:                // Replace SSL streams with the original streams
280:                ldapConnection.replaceStreams(originalInputStream,
281:                        originalOutputStream);
282:
283:                if (debug) {
284:                    System.out.println("StartTLS: closing SSL Socket");
285:                }
286:                sslSocket.close();
287:
288:                isClosed = true;
289:            }
290:
291:            /**
292:             * Sets the connection for TLS to use. The TLS connection will be attached
293:             * to this connection.
294:             *
295:             * @param ldapConnection The non-null connection to use.
296:             * @param hostname The server's hostname. If null, the hostname used to
297:             * open the connection will be used instead. 
298:             */
299:            public void setConnection(Connection ldapConnection, String hostname) {
300:                this .ldapConnection = ldapConnection;
301:                this .hostname = (hostname != null) ? hostname
302:                        : ldapConnection.host;
303:                originalInputStream = ldapConnection.inStream;
304:                originalOutputStream = ldapConnection.outStream;
305:            }
306:
307:            /*
308:             * Returns the default SSL socket factory.
309:             *
310:             * @return The default SSL socket factory.
311:             * @throw IOException If TLS is not supported.
312:             */
313:            private SSLSocketFactory getDefaultFactory() throws IOException {
314:
315:                if (defaultFactory != null) {
316:                    return defaultFactory;
317:                }
318:
319:                return (defaultFactory = (SSLSocketFactory) SSLSocketFactory
320:                        .getDefault());
321:            }
322:
323:            /*
324:             * Start the TLS handshake and manipulate the input and output streams.
325:             *
326:             * @param factory The SSL socket factory to use.
327:             * @return The SSL socket.
328:             * @throw IOException If an exception occurred while performing the
329:             * TLS handshake.
330:             */
331:            private SSLSocket startHandshake(SSLSocketFactory factory)
332:                    throws IOException {
333:
334:                if (ldapConnection == null) {
335:                    throw new IllegalStateException(
336:                            "LDAP connection has not been set."
337:                                    + " TLS requires an existing LDAP connection.");
338:                }
339:
340:                if (factory != currentFactory) {
341:                    // Create SSL socket layered over the existing connection
342:                    sslSocket = (SSLSocket) factory.createSocket(
343:                            ldapConnection.sock, ldapConnection.host,
344:                            ldapConnection.port, false);
345:                    currentFactory = factory;
346:
347:                    if (debug) {
348:                        System.out.println("StartTLS: Created socket : "
349:                                + sslSocket);
350:                    }
351:                }
352:
353:                if (suites != null) {
354:                    sslSocket.setEnabledCipherSuites(suites);
355:                    if (debug) {
356:                        System.out.println("StartTLS: Enabled cipher suites");
357:                    }
358:                }
359:
360:                // Connection must be quite for handshake to proceed
361:
362:                try {
363:                    if (debug) {
364:                        System.out
365:                                .println("StartTLS: Calling sslSocket.startHandshake");
366:                    }
367:                    sslSocket.startHandshake();
368:                    if (debug) {
369:                        System.out
370:                                .println("StartTLS: + Finished sslSocket.startHandshake");
371:                    }
372:
373:                    // Replace original streams with the new SSL streams
374:                    ldapConnection.replaceStreams(sslSocket.getInputStream(),
375:                            sslSocket.getOutputStream());
376:                    if (debug) {
377:                        System.out.println("StartTLS: Replaced IO Streams");
378:                    }
379:
380:                } catch (IOException e) {
381:                    if (debug) {
382:                        System.out
383:                                .println("StartTLS: Got IO error during handshake");
384:                        e.printStackTrace();
385:                    }
386:
387:                    sslSocket.close();
388:                    isClosed = true;
389:                    throw e; // pass up exception
390:                }
391:
392:                return sslSocket;
393:            }
394:
395:            /*
396:             * Verifies that the hostname in the server's certificate matches the
397:             * hostname of the server. 
398:             * The server's first certificate is examined. If it has a subjectAltName
399:             * that contains a dNSName then that is used as the server's hostname.
400:             * The server's hostname may contain a wildcard for its left-most name part.
401:             * Otherwise, if the certificate has no subjectAltName then the value of
402:             * the common name attribute of the subject name is used.
403:             *
404:             * @param hostname The hostname of the server.
405:             * @param session the SSLSession used on the connection to host.
406:             * @return true if the hostname is verified, false otherwise.
407:             */
408:
409:            private boolean verify(String hostname, SSLSession session)
410:                    throws SSLPeerUnverifiedException {
411:
412:                java.security.cert.Certificate[] certs = null;
413:
414:                // if IPv6 strip off the "[]"
415:                if (hostname != null && hostname.startsWith("[")
416:                        && hostname.endsWith("]")) {
417:                    hostname = hostname.substring(1, hostname.length() - 1);
418:                }
419:                try {
420:                    HostnameChecker checker = HostnameChecker
421:                            .getInstance(HostnameChecker.TYPE_LDAP);
422:                    Principal principal = getPeerPrincipal(session);
423:                    if (principal instanceof  KerberosPrincipal) {
424:                        if (!checker.match(hostname,
425:                                (KerberosPrincipal) principal)) {
426:                            throw new SSLPeerUnverifiedException(
427:                                    "hostname of the kerberos principal:"
428:                                            + principal
429:                                            + " does not match the hostname:"
430:                                            + hostname);
431:                        }
432:                    } else {
433:
434:                        // get the subject's certificate
435:                        certs = session.getPeerCertificates();
436:                        X509Certificate peerCert;
437:                        if (certs[0] instanceof  java.security.cert.X509Certificate) {
438:                            peerCert = (java.security.cert.X509Certificate) certs[0];
439:                        } else {
440:                            throw new SSLPeerUnverifiedException(
441:                                    "Received a non X509Certificate from the server");
442:                        }
443:                        checker.match(hostname, peerCert);
444:                    }
445:
446:                    // no exception means verification passed
447:                    return true;
448:                } catch (SSLPeerUnverifiedException e) {
449:
450:                    /*
451:                     * The application may enable an anonymous SSL cipher suite, and
452:                     * hostname verification is not done for anonymous ciphers
453:                     */
454:                    String cipher = session.getCipherSuite();
455:                    if (cipher != null && (cipher.indexOf("_anon_") != -1)) {
456:                        return true;
457:                    }
458:                    throw e;
459:                } catch (CertificateException e) {
460:
461:                    /*
462:                     * Pass up the cause of the failure
463:                     */
464:                    throw (SSLPeerUnverifiedException) new SSLPeerUnverifiedException(
465:                            "hostname of the server '" + hostname
466:                                    + "' does not match the hostname in the "
467:                                    + "server's certificate.").initCause(e);
468:                }
469:            }
470:
471:            /*
472:             * Get the peer principal from the session
473:             */
474:            private static Principal getPeerPrincipal(SSLSession session)
475:                    throws SSLPeerUnverifiedException {
476:                Principal principal;
477:                try {
478:                    principal = session.getPeerPrincipal();
479:                } catch (AbstractMethodError e) {
480:                    // if the JSSE provider does not support it, return null, since
481:                    // we need it only for Kerberos.
482:                    principal = null;
483:                }
484:                return principal;
485:            }
486:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.