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     */
020    package org.apache.directory.server.ldap.handlers.extended;
021    
022    
023    import java.security.KeyStore;
024    import java.security.Provider;
025    import java.security.SecureRandom;
026    import java.security.Security;
027    import java.security.cert.CertificateException;
028    import java.security.cert.X509Certificate;
029    import java.util.Collections;
030    import java.util.HashSet;
031    import java.util.Set;
032    
033    import javax.net.ssl.KeyManagerFactory;
034    import javax.net.ssl.SSLContext;
035    import javax.net.ssl.TrustManager;
036    import javax.net.ssl.X509TrustManager;
037    
038    import org.apache.directory.server.core.security.CoreKeyStoreSpi;
039    import org.apache.directory.server.i18n.I18n;
040    import org.apache.directory.server.ldap.ExtendedOperationHandler;
041    import org.apache.directory.server.ldap.LdapServer;
042    import org.apache.directory.server.ldap.LdapSession;
043    import org.apache.directory.shared.ldap.message.ExtendedResponseImpl;
044    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
045    import org.apache.directory.shared.ldap.message.internal.InternalExtendedRequest;
046    import org.apache.directory.shared.ldap.message.internal.InternalExtendedResponse;
047    import org.apache.directory.shared.ldap.message.internal.InternalLdapResult;
048    import org.apache.mina.core.filterchain.IoFilterChain;
049    import org.apache.mina.filter.ssl.SslFilter;
050    
051    import org.slf4j.Logger;
052    import org.slf4j.LoggerFactory;
053    
054    
055    /**
056     * Handler for the StartTLS extended operation.
057     *
058     * @org.apache.xbean.XBean
059     * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a>
060     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
061     * @version $Rev$, $Date$
062     */
063    public class StartTlsHandler implements ExtendedOperationHandler
064    {
065        public static final String EXTENSION_OID = "1.3.6.1.4.1.1466.20037";
066    
067        private static final Set<String> EXTENSION_OIDS;
068        private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class );
069        
070        private SSLContext sslContext;
071    
072        
073        static
074        {
075            Set<String> set = new HashSet<String>( 3 );
076            set.add( EXTENSION_OID );
077            EXTENSION_OIDS = Collections.unmodifiableSet( set );
078        }
079        
080    
081        public void handleExtendedOperation( LdapSession session, InternalExtendedRequest req ) throws Exception
082        {
083            LOG.info( "Handling StartTLS request." );
084            
085            IoFilterChain chain = session.getIoSession().getFilterChain();
086            SslFilter sslFilter = ( SslFilter ) chain.get( "sslFilter" );
087            if( sslFilter == null )
088            {
089                sslFilter = new SslFilter( sslContext );
090                chain.addFirst( "sslFilter", sslFilter );
091            }
092            else
093            {
094                sslFilter.startSsl( session.getIoSession() );
095            }
096            
097            InternalExtendedResponse res = new ExtendedResponseImpl( req.getMessageId() );
098            InternalLdapResult result = res.getLdapResult();
099            result.setResultCode( ResultCodeEnum.SUCCESS );
100            res.setResponseName( EXTENSION_OID );
101            res.setResponse( new byte[ 0 ] );
102    
103            // Send a response.
104            session.getIoSession().setAttribute( SslFilter.DISABLE_ENCRYPTION_ONCE );
105            session.getIoSession().write( res );
106        }
107        
108        
109        class ServerX509TrustManager implements X509TrustManager
110        {
111            public void checkClientTrusted( X509Certificate[] chain, String authType ) throws CertificateException
112            {
113                LOG.debug( "checkClientTrusted() called" );
114            }
115    
116            public void checkServerTrusted( X509Certificate[] chain, String authType ) throws CertificateException
117            {
118                LOG.debug( "checkServerTrusted() called" );
119            }
120    
121            public X509Certificate[] getAcceptedIssuers()
122            {
123                LOG.debug( "getAcceptedIssuers() called" );
124                return new X509Certificate[0];
125            }
126        }
127    
128    
129        public final Set<String> getExtensionOids()
130        {
131            return EXTENSION_OIDS;
132        }
133    
134    
135        public final String getOid()
136        {
137            return EXTENSION_OID;
138        }
139    
140        
141        public void setLdapServer( LdapServer ldapServer )
142        {
143            LOG.debug( "Setting LDAP Service" );
144            Provider provider = Security.getProvider( "SUN" );
145            LOG.debug( "provider = {}", provider );
146            CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( ldapServer.getDirectoryService() );
147            KeyStore keyStore = new KeyStore( coreKeyStoreSpi, provider, "JKS" ) {};
148    
149            try
150            {
151                keyStore.load( null, null );
152            }
153            catch ( Exception e1 )
154            {
155                throw new RuntimeException( I18n.err( I18n.ERR_678 ) );
156            }
157            
158            KeyManagerFactory keyManagerFactory = null;
159            try
160            {
161                keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
162            }
163            catch ( Exception e )
164            {
165                throw new RuntimeException( I18n.err( I18n.ERR_679 ), e );
166            }
167            
168            try
169            {
170                keyManagerFactory.init( keyStore, null );
171            }
172            catch ( Exception e )
173            {
174                throw new RuntimeException( I18n.err( I18n.ERR_680 ), e );
175            }
176            
177            try
178            {
179                sslContext = SSLContext.getInstance( "TLS" );
180            }
181            catch ( Exception e )
182            {
183                throw new RuntimeException( I18n.err( I18n.ERR_681 ), e );
184            }
185            
186            try
187            {
188                sslContext.init( keyManagerFactory.getKeyManagers(), 
189                    new TrustManager[] { new ServerX509TrustManager() }, 
190                    new SecureRandom() );
191            }
192            catch ( Exception e )
193            {
194                throw new RuntimeException( I18n.err( I18n.ERR_682 ), e );
195            }
196        }
197    }