blob: 118eee6abe487f89cd26f49476a7d9aab0363c8e [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.naming.ldap;
27
28import java.util.Iterator;
29import java.security.AccessController;
30import java.security.PrivilegedAction;
31import javax.naming.ConfigurationException;
32import javax.naming.NamingException;
33import com.sun.naming.internal.VersionHelper;
34import java.util.ServiceLoader;
35import java.util.ServiceConfigurationError;
36
37/**
38 * This class implements the LDAPv3 Extended Request for StartTLS as
39 * defined in
40 * <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
41 * Access Protocol (v3): Extension for Transport Layer Security</a>
42 *
43 * The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
44 * and no extended request value is defined.
45 *<p>
46 * <tt>StartTlsRequest</tt>/<tt>StartTlsResponse</tt> are used to establish
47 * a TLS connection over the existing LDAP connection associated with
48 * the JNDI context on which <tt>extendedOperation()</tt> is invoked.
49 * Typically, a JNDI program uses these classes as follows.
50 * <blockquote><pre>
51 * import javax.naming.ldap.*;
52 *
53 * // Open an LDAP association
54 * LdapContext ctx = new InitialLdapContext();
55 *
56 * // Perform a StartTLS extended operation
57 * StartTlsResponse tls =
58 * (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
59 *
60 * // Open a TLS connection (over the existing LDAP association) and get details
61 * // of the negotiated TLS session: cipher suite, peer certificate, etc.
62 * SSLSession session = tls.negotiate();
63 *
64 * // ... use ctx to perform protected LDAP operations
65 *
66 * // Close the TLS connection (revert back to the underlying LDAP association)
67 * tls.close();
68 *
69 * // ... use ctx to perform unprotected LDAP operations
70 *
71 * // Close the LDAP association
72 * ctx.close;
73 * </pre></blockquote>
74 *
75 * @since 1.4
76 * @see StartTlsResponse
77 * @author Vincent Ryan
78 */
79public class StartTlsRequest implements ExtendedRequest {
80
81 // Constant
82
83 /**
84 * The StartTLS extended request's assigned object identifier
85 * is 1.3.6.1.4.1.1466.20037.
86 */
87 public static final String OID = "1.3.6.1.4.1.1466.20037";
88
89
90 // Constructors
91
92 /**
93 * Constructs a StartTLS extended request.
94 */
95 public StartTlsRequest() {
96 }
97
98
99 // ExtendedRequest methods
100
101 /**
102 * Retrieves the StartTLS request's object identifier string.
103 *
104 * @return The object identifier string, "1.3.6.1.4.1.1466.20037".
105 */
106 public String getID() {
107 return OID;
108 }
109
110 /**
111 * Retrieves the StartTLS request's ASN.1 BER encoded value.
112 * Since the request has no defined value, null is always
113 * returned.
114 *
115 * @return The null value.
116 */
117 public byte[] getEncodedValue() {
118 return null;
119 }
120
121 /**
122 * Creates an extended response object that corresponds to the
123 * LDAP StartTLS extended request.
124 * <p>
125 * The result must be a concrete subclass of StartTlsResponse
126 * and must have a public zero-argument constructor.
127 * <p>
128 * This method locates the implementation class by locating
129 * configuration files that have the name:
130 * <blockquote><tt>
131 * META-INF/services/javax.naming.ldap.StartTlsResponse
132 * </tt></blockquote>
133 * The configuration files and their corresponding implementation classes must
134 * be accessible to the calling thread's context class loader.
135 * <p>
136 * Each configuration file should contain a list of fully-qualified class
137 * names, one per line. Space and tab characters surrounding each name, as
138 * well as blank lines, are ignored. The comment character is <tt>'#'</tt>
139 * (<tt>0x23</tt>); on each line all characters following the first comment
140 * character are ignored. The file must be encoded in UTF-8.
141 * <p>
142 * This method will return an instance of the first implementation
143 * class that it is able to load and instantiate successfully from
144 * the list of class names collected from the configuration files.
145 * This method uses the calling thread's context classloader to find the
146 * configuration files and to load the implementation class.
147 * <p>
148 * If no class can be found in this way, this method will use
149 * an implementation-specific way to locate an implementation.
150 * If none is found, a NamingException is thrown.
151 *
152 * @param id The object identifier of the extended response.
153 * Its value must be "1.3.6.1.4.1.1466.20037" or null.
154 * Both values are equivalent.
155 * @param berValue The possibly null ASN.1 BER encoded value of the
156 * extended response. This is the raw BER bytes
157 * including the tag and length of the response value.
158 * It does not include the response OID.
159 * Its value is ignored because a Start TLS response
160 * is not expected to contain any response value.
161 * @param offset The starting position in berValue of the bytes to use.
162 * Its value is ignored because a Start TLS response
163 * is not expected to contain any response value.
164 * @param length The number of bytes in berValue to use.
165 * Its value is ignored because a Start TLS response
166 * is not expected to contain any response value.
167 * @return The StartTLS extended response object.
168 * @exception NamingException If a naming exception was encountered
169 * while creating the StartTLS extended response object.
170 */
171 public ExtendedResponse createExtendedResponse(String id, byte[] berValue,
172 int offset, int length) throws NamingException {
173
174 // Confirm that the object identifier is correct
175 if ((id != null) && (!id.equals(OID))) {
176 throw new ConfigurationException(
177 "Start TLS received the following response instead of " +
178 OID + ": " + id);
179 }
180
181 StartTlsResponse resp = null;
182
183 ServiceLoader<StartTlsResponse> sl = ServiceLoader.load(
184 StartTlsResponse.class, getContextClassLoader());
185 Iterator<StartTlsResponse> iter = sl.iterator();
186
187 while (resp == null && privilegedHasNext(iter)) {
188 resp = iter.next();
189 }
190 if (resp != null) {
191 return resp;
192 }
193 try {
194 VersionHelper helper = VersionHelper.getVersionHelper();
195 Class clas = helper.loadClass(
196 "com.sun.jndi.ldap.ext.StartTlsResponseImpl");
197
198 resp = (StartTlsResponse) clas.newInstance();
199
200 } catch (IllegalAccessException e) {
201 throw wrapException(e);
202
203 } catch (InstantiationException e) {
204 throw wrapException(e);
205
206 } catch (ClassNotFoundException e) {
207 throw wrapException(e);
208 }
209
210 return resp;
211 }
212
213 /*
214 * Wrap an exception, thrown while attempting to load the StartTlsResponse
215 * class, in a configuration exception.
216 */
217 private ConfigurationException wrapException(Exception e) {
218 ConfigurationException ce = new ConfigurationException(
219 "Cannot load implementation of javax.naming.ldap.StartTlsResponse");
220
221 ce.setRootCause(e);
222 return ce;
223 }
224
225 /*
226 * Acquire the class loader associated with this thread.
227 */
228 private final ClassLoader getContextClassLoader() {
229 return (ClassLoader) AccessController.doPrivileged(
230 new PrivilegedAction() {
231 public Object run() {
232 return Thread.currentThread().getContextClassLoader();
233 }
234 }
235 );
236 }
237
238 private final static boolean privilegedHasNext(final Iterator iter) {
239 Boolean answer = (Boolean) AccessController.doPrivileged(
240 new PrivilegedAction() {
241 public Object run() {
242 return Boolean.valueOf(iter.hasNext());
243 }
244 });
245 return answer.booleanValue();
246 }
247
248 private static final long serialVersionUID = 4441679576360753397L;
249}