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.KeyStore;
24  import java.security.Provider;
25  import java.security.SecureRandom;
26  import java.security.Security;
27  import java.security.cert.CertificateException;
28  import java.security.cert.X509Certificate;
29  import java.util.Collections;
30  import java.util.HashSet;
31  import java.util.Set;
32  
33  import javax.net.ssl.KeyManagerFactory;
34  import javax.net.ssl.SSLContext;
35  import javax.net.ssl.TrustManager;
36  import javax.net.ssl.X509TrustManager;
37  
38  import org.apache.directory.server.core.security.CoreKeyStoreSpi;
39  import org.apache.directory.server.ldap.ExtendedOperationHandler;
40  import org.apache.directory.server.ldap.LdapService;
41  import org.apache.directory.server.ldap.LdapSession;
42  import org.apache.directory.shared.ldap.message.ExtendedRequest;
43  import org.apache.directory.shared.ldap.message.ExtendedResponse;
44  import org.apache.directory.shared.ldap.message.ExtendedResponseImpl;
45  import org.apache.directory.shared.ldap.message.LdapResult;
46  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
47  import org.apache.mina.common.IoFilterChain;
48  import org.apache.mina.filter.SSLFilter;
49  
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  
54  /**
55   * Handler for the StartTLS extended operation.
56   *
57   * @org.apache.xbean.XBean
58   * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a>
59   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
60   * @version $Rev$, $Date$
61   */
62  public class StartTlsHandler implements ExtendedOperationHandler
63  {
64      public static final String EXTENSION_OID = "1.3.6.1.4.1.1466.20037";
65  
66      private static final Set<String> EXTENSION_OIDS;
67      private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class );
68      
69      private SSLContext sslContext;
70  
71      
72      static
73      {
74          Set<String> set = new HashSet<String>( 3 );
75          set.add( EXTENSION_OID );
76          EXTENSION_OIDS = Collections.unmodifiableSet( set );
77      }
78      
79  
80      public void handleExtendedOperation( LdapSession session, ExtendedRequest req ) throws Exception
81      {
82          LOG.info( "Handling StartTLS request." );
83          
84          IoFilterChain chain = session.getIoSession().getFilterChain();
85          SSLFilter sslFilter = ( SSLFilter ) chain.get( "sslFilter" );
86          if( sslFilter == null )
87          {
88              sslFilter = new SSLFilter( sslContext );
89              chain.addFirst( "sslFilter", sslFilter );
90          }
91          else
92          {
93              sslFilter.startSSL( session.getIoSession() );
94          }
95          
96          ExtendedResponse res = new ExtendedResponseImpl( req.getMessageId() );
97          LdapResult result = res.getLdapResult();
98          result.setResultCode( ResultCodeEnum.SUCCESS );
99          res.setResponseName( EXTENSION_OID );
100         res.setResponse( new byte[ 0 ] );
101 
102         // Send a response.
103         session.getIoSession().setAttribute( SSLFilter.DISABLE_ENCRYPTION_ONCE );
104         session.getIoSession().write( res );
105     }
106     
107     
108     class ServerX509TrustManager implements X509TrustManager
109     {
110         public void checkClientTrusted( X509Certificate[] chain, String authType ) throws CertificateException
111         {
112             LOG.debug( "checkClientTrusted() called" );
113         }
114 
115         public void checkServerTrusted( X509Certificate[] chain, String authType ) throws CertificateException
116         {
117             LOG.debug( "checkServerTrusted() called" );
118         }
119 
120         public X509Certificate[] getAcceptedIssuers()
121         {
122             LOG.debug( "getAcceptedIssuers() called" );
123             return new X509Certificate[0];
124         }
125     }
126 
127 
128     public final Set<String> getExtensionOids()
129     {
130         return EXTENSION_OIDS;
131     }
132 
133 
134     public final String getOid()
135     {
136         return EXTENSION_OID;
137     }
138 
139     
140     public void setLdapServer( LdapService ldapService )
141     {
142         LOG.debug( "Setting LDAP Service" );
143         Provider provider = Security.getProvider( "SUN" );
144         LOG.debug( "provider = {}", provider );
145         CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( ldapService.getDirectoryService() );
146         KeyStore keyStore = new KeyStore( coreKeyStoreSpi, provider, "JKS" ) {};
147 
148         try
149         {
150             keyStore.load( null, null );
151         }
152         catch ( Exception e1 )
153         {
154             throw new RuntimeException( "Failed on keystore load which should never really happen." );
155         }
156         
157         KeyManagerFactory keyManagerFactory = null;
158         try
159         {
160             keyManagerFactory = KeyManagerFactory.getInstance( "SunX509" );
161         }
162         catch ( Exception e )
163         {
164             throw new RuntimeException( "Failed to create KeyManagerFactory", e );
165         }
166         
167         try
168         {
169             keyManagerFactory.init( keyStore, null );
170         }
171         catch ( Exception e )
172         {
173             throw new RuntimeException( "Failed to initialize KeyManagerFactory", e );
174         }
175         
176         try
177         {
178             sslContext = SSLContext.getInstance( "TLS" );
179         }
180         catch ( Exception e )
181         {
182             throw new RuntimeException( "Failed to create SSLContext", e );
183         }
184         
185         try
186         {
187             sslContext.init( keyManagerFactory.getKeyManagers(), 
188                 new TrustManager[] { new ServerX509TrustManager() }, 
189                 new SecureRandom() );
190         }
191         catch ( Exception e )
192         {
193             throw new RuntimeException( "Failed to initialize SSLContext", e );
194         }
195     }
196 }