001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.extensions;
028
029
030
031 import org.opends.messages.MessageBuilder;
032 import org.opends.server.admin.std.server.StartTLSExtendedOperationHandlerCfg;
033 import org.opends.server.api.ClientConnection;
034 import org.opends.server.api.ExtendedOperationHandler;
035 import org.opends.server.config.ConfigException;
036 import org.opends.server.core.DirectoryServer;
037 import org.opends.server.core.ExtendedOperation;
038 import org.opends.server.loggers.debug.DebugTracer;
039 import org.opends.server.types.DebugLogLevel;
040 import org.opends.server.types.DirectoryException;
041 import org.opends.server.types.DisconnectReason;
042 import org.opends.server.types.InitializationException;
043 import org.opends.server.types.ResultCode;
044
045 import static org.opends.server.loggers.ErrorLogger.*;
046 import static org.opends.server.loggers.debug.DebugLogger.*;
047 import static org.opends.messages.ExtensionMessages.*;
048 import static org.opends.server.util.ServerConstants.*;
049 import static org.opends.server.util.StaticUtils.*;
050
051
052
053 /**
054 * This class provides an implementation of the StartTLS extended operation as
055 * defined in RFC 2830. It can enable the TLS connection security provider on
056 * an established connection upon receiving an appropriate request from a
057 * client.
058 */
059 public class StartTLSExtendedOperation
060 extends ExtendedOperationHandler<StartTLSExtendedOperationHandlerCfg>
061 {
062 /**
063 * The tracer object for the debug logger.
064 */
065 private static final DebugTracer TRACER = getTracer();
066
067
068
069 /**
070 * Create an instance of this StartTLS extended operation handler. All
071 * initialization should be performed in the
072 * <CODE>initializeExtendedOperationHandler</CODE> method.
073 */
074 public StartTLSExtendedOperation()
075 {
076 super();
077 }
078
079
080 /**
081 * Initializes this extended operation handler based on the information in the
082 * provided configuration entry. It should also register itself with the
083 * Directory Server for the particular kinds of extended operations that it
084 * will process.
085 *
086 * @param config The configuration that contains the information
087 * to use to initialize this extended operation handler.
088 *
089 * @throws ConfigException If an unrecoverable problem arises in the
090 * process of performing the initialization.
091 *
092 * @throws InitializationException If a problem occurs during initialization
093 * that is not related to the server
094 * configuration.
095 */
096 public void initializeExtendedOperationHandler(
097 StartTLSExtendedOperationHandlerCfg config)
098 throws ConfigException, InitializationException
099 {
100 // FIXME -- Are there any configurable options that we should support?
101 DirectoryServer.registerSupportedExtension(OID_START_TLS_REQUEST, this);
102
103 registerControlsAndFeatures();
104 }
105
106
107
108 /**
109 * Performs any finalization that may be necessary for this extended
110 * operation handler. By default, no finalization is performed.
111 */
112 public void finalizeExtendedOperationHandler()
113 {
114 DirectoryServer.deregisterSupportedExtension(OID_START_TLS_REQUEST);
115
116 deregisterControlsAndFeatures();
117 }
118
119
120
121 /**
122 * Processes the provided extended operation.
123 *
124 * @param operation The extended operation to be processed.
125 */
126 public void processExtendedOperation(ExtendedOperation operation)
127 {
128 // We should always include the StartTLS OID in the response (the same OID
129 // is used for both the request and the response), so make sure that it will
130 // happen.
131 operation.setResponseOID(OID_START_TLS_REQUEST);
132
133
134 // Get the reference to the client connection. If there is none, then fail.
135 ClientConnection clientConnection = operation.getClientConnection();
136 if (clientConnection == null)
137 {
138 operation.setResultCode(ResultCode.UNAVAILABLE);
139
140
141 operation.appendErrorMessage(ERR_STARTTLS_NO_CLIENT_CONNECTION.get());
142 return;
143 }
144
145
146 // Make sure that the client connection is capable of enabling TLS. If not,
147 // then fail.
148 TLSCapableConnection tlsCapableConnection;
149 if (clientConnection instanceof TLSCapableConnection)
150 {
151 tlsCapableConnection = (TLSCapableConnection) clientConnection;
152 }
153 else
154 {
155 operation.setResultCode(ResultCode.UNAVAILABLE);
156
157
158 operation.appendErrorMessage(ERR_STARTTLS_NOT_TLS_CAPABLE.get());
159 return;
160 }
161
162 MessageBuilder unavailableReason = new MessageBuilder();
163 if (! tlsCapableConnection.tlsProtectionAvailable(unavailableReason))
164 {
165 operation.setResultCode(ResultCode.UNAVAILABLE);
166 operation.setErrorMessage(unavailableReason);
167 return;
168 }
169
170
171 // Actually enable TLS protection on the client connection. This may fail,
172 // but if it does then the connection will be closed so we'll just need to
173 // log it.
174 try
175 {
176 tlsCapableConnection.enableTLSConnectionSecurityProvider();
177 }
178 catch (DirectoryException de)
179 {
180 if (debugEnabled())
181 {
182 TRACER.debugCaught(DebugLogLevel.ERROR, de);
183 }
184
185 logError(ERR_STARTTLS_ERROR_ON_ENABLE.get(getExceptionMessage(de)));
186 }
187
188
189 // TLS was successfully enabled on the client connection, but we need to
190 // send the response in the clear.
191 operation.setResultCode(ResultCode.SUCCESS);
192
193 try
194 {
195 tlsCapableConnection.sendClearResponse(operation);
196 operation.setResponseSent();
197 }
198 catch (Exception e)
199 {
200 if (debugEnabled())
201 {
202 TRACER.debugCaught(DebugLogLevel.ERROR, e);
203 }
204
205 logError(ERR_STARTTLS_ERROR_SENDING_CLEAR_RESPONSE.get(
206 getExceptionMessage(e)));
207
208 clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM, false,
209 ERR_STARTTLS_ERROR_SENDING_CLEAR_RESPONSE.get(
210 getExceptionMessage(e)));
211 }
212 }
213 }
214