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