View Javadoc

1   /*
2    * $Id: SslMessageReceiver.java 22981 2011-09-19 13:18:55Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.ssl;
12  
13  import org.mule.api.MuleMessage;
14  import org.mule.api.construct.FlowConstruct;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.lifecycle.CreateException;
17  import org.mule.api.transport.Connector;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.transport.AbstractMessageReceiver;
20  import org.mule.transport.ConnectException;
21  import org.mule.transport.tcp.TcpMessageReceiver;
22  import org.mule.util.StringUtils;
23  
24  import java.io.IOException;
25  import java.net.Socket;
26  import java.security.cert.Certificate;
27  import java.util.concurrent.CountDownLatch;
28  import java.util.concurrent.TimeUnit;
29  
30  import javax.net.ssl.HandshakeCompletedEvent;
31  import javax.net.ssl.HandshakeCompletedListener;
32  import javax.net.ssl.SSLPeerUnverifiedException;
33  import javax.net.ssl.SSLSocket;
34  import javax.resource.spi.work.Work;
35  
36  
37  public class SslMessageReceiver extends TcpMessageReceiver implements HandshakeCompletedListener
38  {
39  
40      // We must wait for handshake to complete before sending message, as the callback
41      // sets important properties. The wait period is arbitrary, but the two threads
42      // are approximately synchronized (handshake completes before/at same time as
43      // message is received) so value should not be critical
44      private CountDownLatch handshakeComplete = new CountDownLatch(1);
45  
46      private Certificate[] peerCertificateChain;
47      private Certificate[] localCertificateChain;
48  
49      public SslMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint)
50              throws CreateException
51      {
52          super(connector, flowConstruct, endpoint);
53      }
54  
55      @Override
56      protected void doConnect() throws ConnectException
57      {
58          checkKeyStore();
59          super.doConnect();
60      }
61  
62      protected void checkKeyStore() throws ConnectException
63      {
64          SslConnector sslConnector = (SslConnector) connector;
65          String keyStore = sslConnector.getKeyStore();
66          if (StringUtils.isBlank(keyStore))
67          {
68              throw new ConnectException(CoreMessages.objectIsNull("tls-key-store"), this);
69          }
70      }
71  
72      @Override
73      protected Work createWork(Socket socket) throws IOException
74      {
75          return new SslWorker(socket, this);
76      }
77  
78      private void preRoute(MuleMessage message) throws Exception
79      {
80          long sslHandshakeTimeout = ((SslConnector) getConnector()).getSslHandshakeTimeout();
81          boolean rc = handshakeComplete.await(sslHandshakeTimeout, TimeUnit.MILLISECONDS);
82          if (rc == false)
83          {
84              throw new IllegalStateException("Handshake did not complete");
85          }
86  
87          if (peerCertificateChain != null)
88          {
89              message.setOutboundProperty(SslConnector.PEER_CERTIFICATES, peerCertificateChain);
90          }
91          if (localCertificateChain != null)
92          {
93              message.setOutboundProperty(SslConnector.LOCAL_CERTIFICATES, localCertificateChain);
94          }
95      }
96  
97      public void handshakeCompleted(HandshakeCompletedEvent event)
98      {
99          try
100         {
101             localCertificateChain = event.getLocalCertificates();
102             try
103             {
104                 peerCertificateChain = event.getPeerCertificates();
105             }
106             catch (SSLPeerUnverifiedException e)
107             {
108                 logger.debug("Cannot get peer certificate chain: "+ e.getMessage());
109             }
110         }
111         finally
112         {
113             handshakeComplete.countDown();
114         }
115     }
116 
117     protected class SslWorker extends TcpWorker
118     {
119         public SslWorker(Socket socket, AbstractMessageReceiver receiver) throws IOException
120         {
121             super(socket, receiver);
122             ((SSLSocket) socket).addHandshakeCompletedListener(SslMessageReceiver.this);
123         }
124 
125         @Override
126         protected void preRouteMuleMessage(MuleMessage message) throws Exception
127         {
128             super.preRouteMuleMessage(message);
129 
130             preRoute(message);
131         }
132 
133         @Override
134         protected void shutdownSocket() throws IOException
135         {
136             // SSL Sockets don't support shutdownSocket
137         }
138     }
139 
140 }