001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.ldap.handlers.extended; 021 022 023import java.security.Provider; 024import java.security.SecureRandom; 025import java.security.Security; 026import java.util.Collections; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Set; 030 031import javax.net.ssl.SSLContext; 032import javax.net.ssl.TrustManager; 033 034import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest; 035import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse; 036import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponseImpl; 037import org.apache.directory.api.ldap.model.message.ExtendedRequest; 038import org.apache.directory.api.ldap.model.message.ExtendedResponse; 039import org.apache.directory.api.ldap.model.message.LdapResult; 040import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 041import org.apache.directory.ldap.client.api.NoVerificationTrustManager; 042import org.apache.directory.server.i18n.I18n; 043import org.apache.directory.server.ldap.ExtendedOperationHandler; 044import org.apache.directory.server.ldap.LdapServer; 045import org.apache.directory.server.ldap.LdapSession; 046import org.apache.directory.server.protocol.shared.transport.TcpTransport; 047import org.apache.directory.server.protocol.shared.transport.Transport; 048import org.apache.mina.core.filterchain.IoFilterChain; 049import org.apache.mina.filter.ssl.SslFilter; 050import org.slf4j.Logger; 051import org.slf4j.LoggerFactory; 052 053 054/** 055 * Handler for the StartTLS extended operation. 056 * 057 * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a> 058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 059 */ 060public class StartTlsHandler implements ExtendedOperationHandler<ExtendedRequest, ExtendedResponse> 061{ 062 public static final String EXTENSION_OID = StartTlsRequest.EXTENSION_OID; 063 064 private static final Set<String> EXTENSION_OIDS; 065 private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class ); 066 067 /** The SSL Context instance */ 068 private SSLContext sslContext; 069 070 /** The list of enabled ciphers */ 071 private List<String> cipherSuite; 072 073 /** The list of enabled protocols */ 074 private List<String> enabledProtocols; 075 076 /** The 'needClientAuth' SSL flag */ 077 private boolean needClientAuth; 078 079 /** The 'wantClientAuth' SSL flag */ 080 private boolean wantClientAuth; 081 082 static 083 { 084 Set<String> set = new HashSet<>( 3 ); 085 set.add( EXTENSION_OID ); 086 EXTENSION_OIDS = Collections.unmodifiableSet( set ); 087 } 088 089 090 /** 091 * {@inheritDoc} 092 */ 093 public void handleExtendedOperation( LdapSession session, ExtendedRequest req ) throws Exception 094 { 095 LOG.info( "Handling StartTLS request." ); 096 097 IoFilterChain chain = session.getIoSession().getFilterChain(); 098 SslFilter sslFilter = ( SslFilter ) chain.get( "sslFilter" ); 099 100 if ( sslFilter == null ) 101 { 102 sslFilter = new SslFilter( sslContext, false ); 103 104 // Set the cipher suite 105 if ( ( cipherSuite != null ) && !cipherSuite.isEmpty() ) 106 { 107 sslFilter.setEnabledCipherSuites( cipherSuite.toArray( new String[cipherSuite.size()] ) ); 108 } 109 110 // Set the enabled protocols, default to no SSLV3 111 if ( ( enabledProtocols != null ) && !enabledProtocols.isEmpty() ) 112 { 113 sslFilter.setEnabledProtocols( enabledProtocols.toArray( new String[enabledProtocols.size()] ) ); 114 } 115 else 116 { 117 // default to TLS only 118 sslFilter.setEnabledProtocols( new String[]{ "TLSv1", "TLSv1.1", "TLSv1.2" } ); 119 } 120 121 // Set the remaining SSL flags 122 sslFilter.setNeedClientAuth( needClientAuth ); 123 sslFilter.setWantClientAuth( wantClientAuth ); 124 125 chain.addFirst( "sslFilter", sslFilter ); 126 } 127 else 128 { 129 // Be sure we disable SSLV3 130 sslFilter.setEnabledProtocols( new String[] 131 { "TLSv1", "TLSv1.1", "TLSv1.2" } ); 132 sslFilter.startSsl( session.getIoSession() ); 133 } 134 135 StartTlsResponse res = new StartTlsResponseImpl( req.getMessageId() ); 136 LdapResult result = res.getLdapResult(); 137 result.setResultCode( ResultCodeEnum.SUCCESS ); 138 res.setResponseName( EXTENSION_OID ); 139 140 // Send a response. 141 session.getIoSession().setAttribute( SslFilter.DISABLE_ENCRYPTION_ONCE ); 142 session.getIoSession().write( res ); 143 } 144 145 146 /** 147 * {@inheritDoc} 148 */ 149 public final Set<String> getExtensionOids() 150 { 151 return EXTENSION_OIDS; 152 } 153 154 155 /** 156 * {@inheritDoc} 157 */ 158 public final String getOid() 159 { 160 return EXTENSION_OID; 161 } 162 163 164 /** 165 * {@inheritDoc} 166 */ 167 public void setLdapServer( LdapServer ldapServer ) 168 { 169 LOG.debug( "Setting LDAP Service" ); 170 Provider provider = Security.getProvider( "SUN" ); 171 LOG.debug( "provider = {}", provider ); 172 173 try 174 { 175 sslContext = SSLContext.getInstance( "TLS" ); 176 } 177 catch ( Exception e ) 178 { 179 throw new RuntimeException( I18n.err( I18n.ERR_681 ), e ); 180 } 181 182 try 183 { 184 sslContext.init( ldapServer.getKeyManagerFactory().getKeyManagers(), new TrustManager[] 185 { new NoVerificationTrustManager() }, new SecureRandom() ); 186 } 187 catch ( Exception e ) 188 { 189 throw new RuntimeException( I18n.err( I18n.ERR_682 ), e ); 190 } 191 192 // Get the transport 193 Transport[] transports = ldapServer.getTransports(); 194 195 // Check for any SSL parameter 196 for ( Transport transport : transports ) 197 { 198 if ( transport instanceof TcpTransport ) 199 { 200 TcpTransport tcpTransport = ( TcpTransport ) transport; 201 202 cipherSuite = tcpTransport.getCipherSuite(); 203 enabledProtocols = tcpTransport.getEnabledProtocols(); 204 needClientAuth = tcpTransport.isNeedClientAuth(); 205 wantClientAuth = tcpTransport.isWantClientAuth(); 206 207 break; 208 } 209 } 210 } 211}