001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.transport.tcp; 018 019import java.io.IOException; 020import java.net.URI; 021import java.net.URISyntaxException; 022import java.net.UnknownHostException; 023import java.security.SecureRandom; 024import java.util.HashMap; 025import java.util.Map; 026 027import javax.net.ServerSocketFactory; 028import javax.net.SocketFactory; 029import javax.net.ssl.KeyManager; 030import javax.net.ssl.SSLServerSocketFactory; 031import javax.net.ssl.SSLSocketFactory; 032import javax.net.ssl.TrustManager; 033 034import org.apache.activemq.broker.SslContext; 035import org.apache.activemq.transport.Transport; 036import org.apache.activemq.transport.TransportServer; 037import org.apache.activemq.util.IOExceptionSupport; 038import org.apache.activemq.util.IntrospectionSupport; 039import org.apache.activemq.util.URISupport; 040import org.apache.activemq.wireformat.WireFormat; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044/** 045 * An implementation of the TcpTransportFactory using SSL. The major 046 * contribution from this class is that it is aware of SslTransportServer and 047 * SslTransport classes. All Transports and TransportServers created from this 048 * factory will have their needClientAuth option set to false. 049 * 050 * @author sepandm@gmail.com (Sepand) 051 * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com (logging improvement modifications) 052 * 053 */ 054public class SslTransportFactory extends TcpTransportFactory { 055 // The log this uses., 056 private static final Logger LOG = LoggerFactory.getLogger(SslTransportFactory.class); 057 058 /** 059 * Overriding to use SslTransportServer and allow for proper reflection. 060 */ 061 public TransportServer doBind(final URI location) throws IOException { 062 try { 063 Map<String, String> options = new HashMap<String, String>(URISupport.parseParameters(location)); 064 065 ServerSocketFactory serverSocketFactory = createServerSocketFactory(); 066 SslTransportServer server = new SslTransportServer(this, location, (SSLServerSocketFactory)serverSocketFactory); 067 server.setWireFormatFactory(createWireFormatFactory(options)); 068 IntrospectionSupport.setProperties(server, options); 069 Map<String, Object> transportOptions = IntrospectionSupport.extractProperties(options, "transport."); 070 server.setTransportOption(transportOptions); 071 server.bind(); 072 073 return server; 074 } catch (URISyntaxException e) { 075 throw IOExceptionSupport.create(e); 076 } 077 } 078 079 /** 080 * Overriding to allow for proper configuration through reflection but delegate to get common 081 * configuration 082 */ 083 @SuppressWarnings("rawtypes") 084 public Transport compositeConfigure(Transport transport, WireFormat format, Map options) { 085 086 SslTransport sslTransport = (SslTransport)transport.narrow(SslTransport.class); 087 IntrospectionSupport.setProperties(sslTransport, options); 088 089 return super.compositeConfigure(transport, format, options); 090 } 091 092 /** 093 * Overriding to use SslTransports. 094 */ 095 protected Transport createTransport(URI location, WireFormat wf) throws UnknownHostException, IOException { 096 URI localLocation = null; 097 String path = location.getPath(); 098 // see if the path is a local URI location 099 if (path != null && path.length() > 0) { 100 int localPortIndex = path.indexOf(':'); 101 try { 102 Integer.parseInt(path.substring(localPortIndex + 1, path.length())); 103 String localString = location.getScheme() + ":/" + path; 104 localLocation = new URI(localString); 105 } catch (Exception e) { 106 LOG.warn("path isn't a valid local location for SslTransport to use", e); 107 } 108 } 109 SocketFactory socketFactory = createSocketFactory(); 110 return new SslTransport(wf, (SSLSocketFactory)socketFactory, location, localLocation, false); 111 } 112 113 /** 114 * Creates a new SSL ServerSocketFactory. The given factory will use 115 * user-provided key and trust managers (if the user provided them). 116 * 117 * @return Newly created (Ssl)ServerSocketFactory. 118 * @throws IOException 119 */ 120 protected ServerSocketFactory createServerSocketFactory() throws IOException { 121 if( SslContext.getCurrentSslContext()!=null ) { 122 SslContext ctx = SslContext.getCurrentSslContext(); 123 try { 124 return ctx.getSSLContext().getServerSocketFactory(); 125 } catch (Exception e) { 126 throw IOExceptionSupport.create(e); 127 } 128 } else { 129 return SSLServerSocketFactory.getDefault(); 130 } 131 } 132 133 /** 134 * Creates a new SSL SocketFactory. The given factory will use user-provided 135 * key and trust managers (if the user provided them). 136 * 137 * @return Newly created (Ssl)SocketFactory. 138 * @throws IOException 139 */ 140 protected SocketFactory createSocketFactory() throws IOException { 141 142 if( SslContext.getCurrentSslContext()!=null ) { 143 SslContext ctx = SslContext.getCurrentSslContext(); 144 try { 145 return ctx.getSSLContext().getSocketFactory(); 146 } catch (Exception e) { 147 throw IOExceptionSupport.create(e); 148 } 149 } else { 150 return SSLSocketFactory.getDefault(); 151 } 152 } 153 154 /** 155 * 156 * @param km 157 * @param tm 158 * @param random 159 * @deprecated "Do not use anymore... using static initializers like this method only allows the JVM to use 1 SSL configuration per broker." 160 * @see org.apache.activemq.broker.SslContext#setCurrentSslContext(SslContext) 161 * @see org.apache.activemq.broker.SslContext#getSSLContext() 162 */ 163 public void setKeyAndTrustManagers(KeyManager[] km, TrustManager[] tm, SecureRandom random) { 164 SslContext ctx = new SslContext(km, tm, random); 165 SslContext.setCurrentSslContext(ctx); 166 } 167 168}