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.ldap.ExtendedOperationHandler;
040 import org.apache.directory.server.ldap.LdapServer;
041 import org.apache.directory.server.ldap.LdapSession;
042 import org.apache.directory.shared.ldap.message.InternalExtendedRequest;
043 import org.apache.directory.shared.ldap.message.InternalExtendedResponse;
044 import org.apache.directory.shared.ldap.message.ExtendedResponseImpl;
045 import org.apache.directory.shared.ldap.message.InternalLdapResult;
046 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
047 import org.apache.mina.core.filterchain.IoFilterChain;
048 import org.apache.mina.filter.ssl.SslFilter;
049
050 import org.slf4j.Logger;
051 import org.slf4j.LoggerFactory;
052
053
054 /**
055 * Handler for the StartTLS extended operation.
056 *
057 * @org.apache.xbean.XBean
058 * @see <a href="http://www.ietf.org/rfc/rfc2830.txt">RFC 2830</a>
059 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
060 * @version $Rev$, $Date$
061 */
062 public class StartTlsHandler implements ExtendedOperationHandler
063 {
064 public static final String EXTENSION_OID = "1.3.6.1.4.1.1466.20037";
065
066 private static final Set<String> EXTENSION_OIDS;
067 private static final Logger LOG = LoggerFactory.getLogger( StartTlsHandler.class );
068
069 private SSLContext sslContext;
070
071
072 static
073 {
074 Set<String> set = new HashSet<String>( 3 );
075 set.add( EXTENSION_OID );
076 EXTENSION_OIDS = Collections.unmodifiableSet( set );
077 }
078
079
080 public void handleExtendedOperation( LdapSession session, InternalExtendedRequest req ) throws Exception
081 {
082 LOG.info( "Handling StartTLS request." );
083
084 IoFilterChain chain = session.getIoSession().getFilterChain();
085 SslFilter sslFilter = ( SslFilter ) chain.get( "sslFilter" );
086 if( sslFilter == null )
087 {
088 sslFilter = new SslFilter( sslContext );
089 chain.addFirst( "sslFilter", sslFilter );
090 }
091 else
092 {
093 sslFilter.startSsl( session.getIoSession() );
094 }
095
096 InternalExtendedResponse res = new ExtendedResponseImpl( req.getMessageId() );
097 InternalLdapResult result = res.getLdapResult();
098 result.setResultCode( ResultCodeEnum.SUCCESS );
099 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( LdapServer ldapServer )
141 {
142 LOG.debug( "Setting LDAP Service" );
143 Provider provider = Security.getProvider( "SUN" );
144 LOG.debug( "provider = {}", provider );
145 CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( ldapServer.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( KeyManagerFactory.getDefaultAlgorithm() );
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 }