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 }