001package org.apache.activemq.transport.auto.nio; 002 003import java.io.IOException; 004import java.net.Socket; 005import java.net.URI; 006import java.net.URISyntaxException; 007import java.nio.ByteBuffer; 008import java.util.HashMap; 009import java.util.Set; 010import java.util.concurrent.ExecutorService; 011import java.util.concurrent.Executors; 012import java.util.concurrent.Future; 013 014import javax.net.ServerSocketFactory; 015import javax.net.ssl.SSLContext; 016import javax.net.ssl.SSLEngine; 017 018import org.apache.activemq.broker.BrokerService; 019import org.apache.activemq.broker.BrokerServiceAware; 020import org.apache.activemq.transport.Transport; 021import org.apache.activemq.transport.auto.AutoTcpTransportServer; 022import org.apache.activemq.transport.nio.AutoInitNioSSLTransport; 023import org.apache.activemq.transport.nio.NIOSSLTransport; 024import org.apache.activemq.transport.tcp.TcpTransport; 025import org.apache.activemq.transport.tcp.TcpTransport.InitBuffer; 026import org.apache.activemq.transport.tcp.TcpTransportFactory; 027import org.apache.activemq.transport.tcp.TcpTransportServer; 028import org.apache.activemq.util.IntrospectionSupport; 029import org.apache.activemq.wireformat.WireFormat; 030 031/** 032 * Licensed to the Apache Software Foundation (ASF) under one or more 033 * contributor license agreements. See the NOTICE file distributed with 034 * this work for additional information regarding copyright ownership. 035 * The ASF licenses this file to You under the Apache License, Version 2.0 036 * (the "License"); you may not use this file except in compliance with 037 * the License. You may obtain a copy of the License at 038 * 039 * http://www.apache.org/licenses/LICENSE-2.0 040 * 041 * Unless required by applicable law or agreed to in writing, software 042 * distributed under the License is distributed on an "AS IS" BASIS, 043 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 044 * See the License for the specific language governing permissions and 045 * limitations under the License. 046 */ 047public class AutoNIOSSLTransportServer extends AutoTcpTransportServer { 048 049 private SSLContext context; 050 051 public AutoNIOSSLTransportServer(SSLContext context, TcpTransportFactory transportFactory, URI location, ServerSocketFactory serverSocketFactory, 052 BrokerService brokerService, Set<String> enabledProtocols) throws IOException, URISyntaxException { 053 super(transportFactory, location, serverSocketFactory, brokerService, enabledProtocols); 054 055 this.context = context; 056 } 057 058 private boolean needClientAuth; 059 private boolean wantClientAuth; 060 061 protected Transport createTransport(Socket socket, WireFormat format, SSLEngine engine, 062 InitBuffer initBuffer, ByteBuffer inputBuffer, TcpTransportFactory detectedFactory) throws IOException { 063 NIOSSLTransport transport = new NIOSSLTransport(format, socket, engine, initBuffer, inputBuffer); 064 if (context != null) { 065 transport.setSslContext(context); 066 } 067 068 transport.setNeedClientAuth(needClientAuth); 069 transport.setWantClientAuth(wantClientAuth); 070 071 072 return transport; 073 } 074 075 @Override 076 protected TcpTransport createTransport(Socket socket, WireFormat format) throws IOException { 077 throw new UnsupportedOperationException("method not supported"); 078 } 079 080 @Override 081 public boolean isSslServer() { 082 return true; 083 } 084 085 public boolean isNeedClientAuth() { 086 return this.needClientAuth; 087 } 088 089 public void setNeedClientAuth(boolean value) { 090 this.needClientAuth = value; 091 } 092 093 public boolean isWantClientAuth() { 094 return this.wantClientAuth; 095 } 096 097 public void setWantClientAuth(boolean value) { 098 this.wantClientAuth = value; 099 } 100 101 102 @Override 103 protected TransportInfo configureTransport(final TcpTransportServer server, final Socket socket) throws Exception { 104 ExecutorService executor = Executors.newSingleThreadExecutor(); 105 106 //The SSLEngine needs to be initialized and handshake done to get the first command and detect the format 107 //The wireformat doesn't need properties set here because we aren't using this format during the SSL handshake 108 final AutoInitNioSSLTransport in = new AutoInitNioSSLTransport(wireFormatFactory.createWireFormat(), socket); 109 if (context != null) { 110 in.setSslContext(context); 111 } 112 //We need to set the transport options on the init transport so that the SSL options are set 113 if (transportOptions != null) { 114 //Clone the map because we will need to set the options later on the actual transport 115 IntrospectionSupport.setProperties(in, new HashMap<>(transportOptions)); 116 } 117 in.start(); 118 SSLEngine engine = in.getSslSession(); 119 120 Future<?> future = executor.submit(new Runnable() { 121 @Override 122 public void run() { 123 //Wait for handshake to finish initializing 124 do { 125 in.serviceRead(); 126 } while(in.getReadSize().get() < 8); 127 } 128 }); 129 130 waitForProtocolDetectionFinish(future, in.getReadSize()); 131 in.stop(); 132 133 initBuffer = new InitBuffer(in.getReadSize().get(), ByteBuffer.allocate(in.getReadData().length)); 134 initBuffer.buffer.put(in.getReadData()); 135 136 ProtocolInfo protocolInfo = detectProtocol(in.getReadData()); 137 138 if (protocolInfo.detectedTransportFactory instanceof BrokerServiceAware) { 139 ((BrokerServiceAware) protocolInfo.detectedTransportFactory).setBrokerService(brokerService); 140 } 141 142 WireFormat format = protocolInfo.detectedWireFormatFactory.createWireFormat(); 143 Transport transport = createTransport(socket, format, engine, initBuffer, in.getInputBuffer(), protocolInfo.detectedTransportFactory); 144 145 return new TransportInfo(format, transport, protocolInfo.detectedTransportFactory); 146 } 147 148} 149 150