View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.server.ldap.handlers.extended;
21  
22  
23  import java.security.Provider;
24  import java.security.SecureRandom;
25  import java.security.Security;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Set;
30  
31  import javax.net.ssl.SSLContext;
32  import javax.net.ssl.TrustManager;
33  
34  import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
35  import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse;
36  import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponseImpl;
37  import org.apache.directory.api.ldap.model.message.ExtendedRequest;
38  import org.apache.directory.api.ldap.model.message.ExtendedResponse;
39  import org.apache.directory.api.ldap.model.message.LdapResult;
40  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
41  import org.apache.directory.ldap.client.api.NoVerificationTrustManager;
42  import org.apache.directory.server.i18n.I18n;
43  import org.apache.directory.server.ldap.ExtendedOperationHandler;
44  import org.apache.directory.server.ldap.LdapServer;
45  import org.apache.directory.server.ldap.LdapSession;
46  import org.apache.directory.server.protocol.shared.transport.TcpTransport;
47  import org.apache.directory.server.protocol.shared.transport.Transport;
48  import org.apache.mina.core.filterchain.IoFilterChain;
49  import org.apache.mina.filter.ssl.SslFilter;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  
54  /**
55   * Handler for the StartTLS extended operation.
56   *
57   * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a>
58   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
59   */
60  public class StartTlsHandler implements ExtendedOperationHandler<ExtendedRequest, ExtendedResponse>
61  {
62      public static final String EXTENSION_OID = StartTlsRequest.EXTENSION_OID;
63  
64      private static final Set<String> EXTENSION_OIDS;
65      private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class );
66  
67      /** The SSL Context instance */
68      private SSLContext sslContext;
69  
70      /** The list of enabled ciphers */
71      private List<String> cipherSuite;
72  
73      /** The list of enabled protocols */
74      private List<String> enabledProtocols;
75  
76      /** The 'needClientAuth' SSL flag */
77      private boolean needClientAuth;
78  
79      /** The 'wantClientAuth' SSL flag */
80      private boolean wantClientAuth;
81  
82      static
83      {
84          Set<String> set = new HashSet<>( 3 );
85          set.add( EXTENSION_OID );
86          EXTENSION_OIDS = Collections.unmodifiableSet( set );
87      }
88  
89  
90      /**
91       * {@inheritDoc}
92       */
93      public void handleExtendedOperation( LdapSession session, ExtendedRequest req ) throws Exception
94      {
95          LOG.info( "Handling StartTLS request." );
96  
97          IoFilterChain chain = session.getIoSession().getFilterChain();
98          SslFilter sslFilter = ( SslFilter ) chain.get( "sslFilter" );
99  
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./../../org/apache/directory/server/protocol/shared/transport/TcpTransport.html#TcpTransport">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 }