Path: blob/master/src/java.naming/share/classes/javax/naming/ldap/StartTlsRequest.java
41159 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.naming.ldap;2627import java.util.Iterator;28import java.security.AccessController;29import java.security.PrivilegedAction;30import javax.naming.ConfigurationException;31import javax.naming.NamingException;32import com.sun.naming.internal.VersionHelper;33import java.util.ServiceLoader;34import java.util.ServiceConfigurationError;3536/**37* This class implements the LDAPv3 Extended Request for StartTLS as38* defined in39* <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory40* Access Protocol (v3): Extension for Transport Layer Security</a>41*42* The object identifier for StartTLS is 1.3.6.1.4.1.1466.2003743* and no extended request value is defined.44*<p>45* {@code StartTlsRequest}/{@code StartTlsResponse} are used to establish46* a TLS connection over the existing LDAP connection associated with47* the JNDI context on which {@code extendedOperation()} is invoked.48* Typically, a JNDI program uses these classes as follows.49* <blockquote><pre>50* import javax.naming.ldap.*;51*52* // Open an LDAP association53* LdapContext ctx = new InitialLdapContext();54*55* // Perform a StartTLS extended operation56* StartTlsResponse tls =57* (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());58*59* // Open a TLS connection (over the existing LDAP association) and get details60* // of the negotiated TLS session: cipher suite, peer certificate, etc.61* SSLSession session = tls.negotiate();62*63* // ... use ctx to perform protected LDAP operations64*65* // Close the TLS connection (revert back to the underlying LDAP association)66* tls.close();67*68* // ... use ctx to perform unprotected LDAP operations69*70* // Close the LDAP association71* ctx.close;72* </pre></blockquote>73*74* @since 1.475* @see StartTlsResponse76* @author Vincent Ryan77*/78public class StartTlsRequest implements ExtendedRequest {7980// Constant8182/**83* The StartTLS extended request's assigned object identifier84* is 1.3.6.1.4.1.1466.20037.85*/86public static final String OID = "1.3.6.1.4.1.1466.20037";878889// Constructors9091/**92* Constructs a StartTLS extended request.93*/94public StartTlsRequest() {95}969798// ExtendedRequest methods99100/**101* Retrieves the StartTLS request's object identifier string.102*103* @return The object identifier string, "1.3.6.1.4.1.1466.20037".104*/105public String getID() {106return OID;107}108109/**110* Retrieves the StartTLS request's ASN.1 BER encoded value.111* Since the request has no defined value, null is always112* returned.113*114* @return The null value.115*/116public byte[] getEncodedValue() {117return null;118}119120/**121* Creates an extended response object that corresponds to the122* LDAP StartTLS extended request.123* <p>124* The result must be a concrete subclass of StartTlsResponse125* and must have a public zero-argument constructor.126* <p>127* This method locates the implementation class by locating128* configuration files that have the name:129* <blockquote>{@code130* META-INF/services/javax.naming.ldap.StartTlsResponse131* }</blockquote>132* The configuration files and their corresponding implementation classes must133* be accessible to the calling thread's context class loader.134* <p>135* Each configuration file should contain a list of fully-qualified class136* names, one per line. Space and tab characters surrounding each name, as137* well as blank lines, are ignored. The comment character is {@code '#'}138* ({@code 0x23}); on each line all characters following the first comment139* character are ignored. The file must be encoded in UTF-8.140* <p>141* This method will return an instance of the first implementation142* class that it is able to load and instantiate successfully from143* the list of class names collected from the configuration files.144* This method uses the calling thread's context classloader to find the145* configuration files and to load the implementation class.146* <p>147* If no class can be found in this way, this method will use148* an implementation-specific way to locate an implementation.149* If none is found, a NamingException is thrown.150*151* @param id The object identifier of the extended response.152* Its value must be "1.3.6.1.4.1.1466.20037" or null.153* Both values are equivalent.154* @param berValue The possibly null ASN.1 BER encoded value of the155* extended response. This is the raw BER bytes156* including the tag and length of the response value.157* It does not include the response OID.158* Its value is ignored because a Start TLS response159* is not expected to contain any response value.160* @param offset The starting position in berValue of the bytes to use.161* Its value is ignored because a Start TLS response162* is not expected to contain any response value.163* @param length The number of bytes in berValue to use.164* Its value is ignored because a Start TLS response165* is not expected to contain any response value.166* @return The StartTLS extended response object.167* @throws NamingException If a naming exception was encountered168* while creating the StartTLS extended response object.169*/170public ExtendedResponse createExtendedResponse(String id, byte[] berValue,171int offset, int length) throws NamingException {172173// Confirm that the object identifier is correct174if ((id != null) && (!id.equals(OID))) {175throw new ConfigurationException(176"Start TLS received the following response instead of " +177OID + ": " + id);178}179180StartTlsResponse resp = null;181182ServiceLoader<StartTlsResponse> sl = ServiceLoader.load(183StartTlsResponse.class, getContextClassLoader());184Iterator<StartTlsResponse> iter = sl.iterator();185186while (resp == null && privilegedHasNext(iter)) {187resp = iter.next();188}189if (resp != null) {190return resp;191}192try {193VersionHelper helper = VersionHelper.getVersionHelper();194@SuppressWarnings("deprecation")195Object o = helper.loadClass(196"com.sun.jndi.ldap.ext.StartTlsResponseImpl").newInstance();197resp = (StartTlsResponse) o;198199} catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {200throw wrapException(e);201}202203return resp;204}205206/*207* Wrap an exception, thrown while attempting to load the StartTlsResponse208* class, in a configuration exception.209*/210private ConfigurationException wrapException(Exception e) {211ConfigurationException ce = new ConfigurationException(212"Cannot load implementation of javax.naming.ldap.StartTlsResponse");213214ce.setRootCause(e);215return ce;216}217218/*219* Acquire the class loader associated with this thread.220*/221@SuppressWarnings("removal")222private final ClassLoader getContextClassLoader() {223PrivilegedAction<ClassLoader> pa = Thread.currentThread()::getContextClassLoader;224return AccessController.doPrivileged(pa);225}226227@SuppressWarnings("removal")228private static final boolean privilegedHasNext(final Iterator<StartTlsResponse> iter) {229PrivilegedAction<Boolean> pa = iter::hasNext;230return AccessController.doPrivileged(pa);231}232233private static final long serialVersionUID = 4441679576360753397L;234}235236237