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; 032 033import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest; 034import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse; 035import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponseImpl; 036import org.apache.directory.api.ldap.model.message.ExtendedRequest; 037import org.apache.directory.api.ldap.model.message.ExtendedResponse; 038import org.apache.directory.api.ldap.model.message.LdapResult; 039import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 040import org.apache.directory.server.i18n.I18n; 041import org.apache.directory.server.ldap.ExtendedOperationHandler; 042import org.apache.directory.server.ldap.LdapServer; 043import org.apache.directory.server.ldap.LdapSession; 044import org.apache.directory.server.protocol.shared.transport.TcpTransport; 045import org.apache.directory.server.protocol.shared.transport.Transport; 046import org.apache.mina.core.filterchain.IoFilterChain; 047import org.apache.mina.filter.ssl.SslFilter; 048import org.slf4j.Logger; 049import org.slf4j.LoggerFactory; 050 051 052/** 053 * Handler for the StartTLS extended operation. 054 * 055 * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a> 056 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 057 */ 058public class StartTlsHandler implements ExtendedOperationHandler<ExtendedRequest, ExtendedResponse> 059{ 060 public static final String EXTENSION_OID = StartTlsRequest.EXTENSION_OID; 061 062 private static final Set<String> EXTENSION_OIDS; 063 private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class ); 064 065 /** The SSL Context instance */ 066 private SSLContext sslContext; 067 068 /** The list of enabled ciphers */ 069 private List<String> cipherSuite; 070 071 /** The list of enabled protocols */ 072 private List<String> enabledProtocols; 073 074 /** The 'needClientAuth' SSL flag */ 075 private boolean needClientAuth; 076 077 /** The 'wantClientAuth' SSL flag */ 078 private boolean wantClientAuth; 079 080 static 081 { 082 Set<String> set = new HashSet<>( 3 ); 083 set.add( EXTENSION_OID ); 084 EXTENSION_OIDS = Collections.unmodifiableSet( set ); 085 } 086 087 088 /** 089 * {@inheritDoc} 090 */ 091 public void handleExtendedOperation( LdapSession session, ExtendedRequest req ) throws Exception 092 { 093 LOG.info( "Handling StartTLS request." ); 094 095 IoFilterChain chain = session.getIoSession().getFilterChain(); 096 SslFilter sslFilter = ( SslFilter ) chain.get( "sslFilter" ); 097 098 if ( sslFilter == null ) 099 { 100 sslFilter = new SslFilter( sslContext ); 101 102 // Set the cipher suite 103 if ( ( cipherSuite != null ) && !cipherSuite.isEmpty() ) 104 { 105 sslFilter.setEnabledCipherSuites( cipherSuite.toArray( new String[cipherSuite.size()] ) ); 106 } 107 108 // Set the enabled protocols, default to no SSLV3 109 if ( ( enabledProtocols != null ) && !enabledProtocols.isEmpty() ) 110 { 111 sslFilter.setEnabledProtocols( enabledProtocols.toArray( new String[enabledProtocols.size()] ) ); 112 } 113 else 114 { 115 // default to TLS only 116 sslFilter.setEnabledProtocols( new String[]{ "TLSv1", "TLSv1.1", "TLSv1.2" } ); 117 } 118 119 // Set the remaining SSL flags 120 sslFilter.setNeedClientAuth( needClientAuth ); 121 sslFilter.setWantClientAuth( wantClientAuth ); 122 123 StartTlsFilter startTlsFilter = new StartTlsFilter(); 124 chain.addFirst( "startTls", startTlsFilter ); 125 chain.addFirst( "sslFilter", sslFilter ); 126 } 127 128 StartTlsResponse res = new StartTlsResponseImpl( req.getMessageId() ); 129 LdapResult result = res.getLdapResult(); 130 result.setResultCode( ResultCodeEnum.SUCCESS ); 131 res.setResponseName( EXTENSION_OID ); 132 133 // Send a response. 134 session.getIoSession().write( res ); 135 } 136 137 138 /** 139 * {@inheritDoc} 140 */ 141 public final Set<String> getExtensionOids() 142 { 143 return EXTENSION_OIDS; 144 } 145 146 147 /** 148 * {@inheritDoc} 149 */ 150 public final String getOid() 151 { 152 return EXTENSION_OID; 153 } 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 public void setLdapServer( LdapServer ldapServer ) 160 { 161 LOG.debug( "Setting LDAP Service" ); 162 Provider provider = Security.getProvider( "SUN" ); 163 LOG.debug( "provider = {}", provider ); 164 165 try 166 { 167 sslContext = SSLContext.getInstance( "TLS" ); 168 } 169 catch ( Exception e ) 170 { 171 throw new RuntimeException( I18n.err( I18n.ERR_681 ), e ); 172 } 173 174 try 175 { 176 sslContext.init( ldapServer.getKeyManagerFactory().getKeyManagers(), 177 ldapServer.getTrustManagers(), new SecureRandom() ); 178 } 179 catch ( Exception e ) 180 { 181 throw new RuntimeException( I18n.err( I18n.ERR_682 ), e ); 182 } 183 184 // Get the transport 185 Transport[] transports = ldapServer.getTransports(); 186 187 // Check for any SSL parameter 188 for ( Transport transport : transports ) 189 { 190 if ( transport instanceof TcpTransport ) 191 { 192 TcpTransport tcpTransport = ( TcpTransport ) transport; 193 194 cipherSuite = tcpTransport.getCipherSuite(); 195 enabledProtocols = tcpTransport.getEnabledProtocols(); 196 needClientAuth = tcpTransport.isNeedClientAuth(); 197 wantClientAuth = tcpTransport.isWantClientAuth(); 198 199 break; 200 } 201 } 202 } 203}