View Javadoc

1   /*
2    * $Id: IBMSslAdapterServerSocketFactory.java 7963 2007-08-21 08:53:15Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.management.agents;
12  
13  import org.mule.umo.security.provider.AutoDiscoverySecurityProviderFactory;
14  import org.mule.umo.security.provider.SecurityProviderFactory;
15  import org.mule.umo.security.provider.SecurityProviderInfo;
16  import org.mule.util.FileUtils;
17  import org.mule.util.IOUtils;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.InetAddress;
24  import java.net.ServerSocket;
25  import java.security.KeyStore;
26  import java.security.Security;
27  import java.security.UnrecoverableKeyException;
28  
29  import javax.net.ssl.KeyManagerFactory;
30  import javax.net.ssl.SSLContext;
31  import javax.net.ssl.SSLServerSocket;
32  import javax.net.ssl.SSLServerSocketFactory;
33  import javax.net.ssl.TrustManagerFactory;
34  
35  import mx4j.log.Log;
36  import mx4j.log.Logger;
37  import mx4j.tools.adaptor.ssl.SSLAdaptorServerSocketFactoryMBean;
38  
39  /**
40   * This MBean creates SSLServerSocket instances.
41   * <p>
42   * It can be configured to use a specific keystore and SSL protocol version to create
43   * SSLServerSockets that will use the keystore information to encrypt data. <br>
44   * <p/> A keystore can be created with this command:
45   * 
46   * <pre>
47   *  keytool -genkey -v -keystore store.key -storepass storepwd -keypass keypwd -dname &quot;CN=Simone Bordet, OU=Project Administrator, O=MX4J, L=Torino, S=TO, C=IT&quot; -validity 365
48   * </pre>
49   * 
50   * or with this minimal command (that will prompt you for further information):
51   * 
52   * <pre>
53   *  keytool -genkey -keystore store.key
54   * </pre>
55   * 
56   * <p/> A keystore may contains more than one entry, but only the first entry will be
57   * used for encryption, no matter which is the alias for that entry. <p/> Following
58   * the first example of generation of the keystore, this MBean must be instantiated
59   * and then setup by invoking the following methods:
60   * <ul>
61   * <li> {@link #setKeyStoreName}("store.key");
62   * <li> {@link #setKeyStorePassword}("storepwd");
63   * <li> {@link #setKeyManagerPassword}("keypwd");
64   * </ul>
65   * before {@link #createServerSocket} is called.
66   */
67  public class IBMSslAdapterServerSocketFactory implements SSLAdaptorServerSocketFactoryMBean
68  {
69  
70      // it will always be IBM, anyway
71      private SecurityProviderFactory spFactory = new AutoDiscoverySecurityProviderFactory();
72      private SecurityProviderInfo spInfo = spFactory.getSecurityProviderInfo();
73  
74      private String m_keyStoreType = "JKS";
75      private String m_trustStoreType = "JKS";
76      private String m_keyStoreName;
77      private String m_trustStoreName;
78      private String m_keyStorePassword;
79      private String m_trustStorePassword;
80      private String m_keyManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
81      // the same?
82      private String m_trustManagerAlgorithm = spInfo.getKeyManagerAlgorithm();
83      private String m_keyManagerPassword;
84      // IMPORTANT Sun-specific version works with TLS protocol,
85      // but fails in Internet Explorer and IBM-specific provider.
86      // SSL works fine though
87      private String m_sslProtocol = "SSL";
88  
89      public IBMSslAdapterServerSocketFactory()
90      {
91          Security.addProvider(spFactory.getProvider());
92      }
93  
94      public void setKeyStoreType(String keyStoreType)
95      {
96          if (keyStoreType == null || keyStoreType.trim().length() == 0)
97          {
98              throw new IllegalArgumentException("Invalid KeyStore type");
99          }
100         m_keyStoreType = keyStoreType;
101     }
102 
103     public void setTrustStoreType(String trustStoreType)
104     {
105         if (trustStoreType == null || trustStoreType.trim().length() == 0)
106         {
107             throw new IllegalArgumentException("Invalid TrustStore type");
108         }
109         m_trustStoreType = trustStoreType;
110     }
111 
112     public void setKeyStoreName(String name)
113     {
114         if (name == null || name.trim().length() == 0)
115         {
116             throw new IllegalArgumentException("Invalid KeyStore name");
117         }
118         m_keyStoreName = name;
119     }
120 
121     public void setTrustStoreName(String name)
122     {
123         if (name == null || name.trim().length() == 0)
124         {
125             throw new IllegalArgumentException("Invalid TrustStore name");
126         }
127         m_trustStoreName = name;
128     }
129 
130     public void setKeyStorePassword(String password)
131     {
132         if (password == null || password.trim().length() == 0)
133         {
134             throw new IllegalArgumentException("Invalid KeyStore password");
135         }
136         m_keyStorePassword = password;
137     }
138 
139     public void setTrustStorePassword(String password)
140     {
141         if (password == null || password.trim().length() == 0)
142         {
143             throw new IllegalArgumentException("Invalid TrustStore password");
144         }
145         m_trustStorePassword = password;
146     }
147 
148     public void setKeyManagerAlgorithm(String algorithm)
149     {
150         if (algorithm == null || algorithm.trim().length() == 0)
151         {
152             throw new IllegalArgumentException("Invalid KeyManager algorithm");
153         }
154         m_keyManagerAlgorithm = algorithm;
155     }
156 
157     public void setTrustManagerAlgorithm(String algorithm)
158     {
159         if (algorithm == null || algorithm.trim().length() == 0)
160         {
161             throw new IllegalArgumentException("Invalid TrustManager algorithm");
162         }
163         m_trustManagerAlgorithm = algorithm;
164     }
165 
166     public void setKeyManagerPassword(String password)
167     {
168         if (password == null || password.trim().length() == 0)
169         {
170             throw new IllegalArgumentException("Invalid KeyManager password");
171         }
172         m_keyManagerPassword = password;
173     }
174 
175     public void setSSLProtocol(String protocol)
176     {
177         if (protocol == null || protocol.trim().length() == 0)
178         {
179             throw new IllegalArgumentException("Invalid SSL protocol");
180         }
181         m_sslProtocol = protocol;
182     }
183 
184     /**
185      * Returns a SSLServerSocket on the given port.
186      */
187     public ServerSocket createServerSocket(int port, int backlog, String host) throws IOException
188     {
189         if (m_keyStoreName == null)
190         {
191             throw new IOException("KeyStore file name cannot be null");
192         }
193         if (m_keyStorePassword == null)
194         {
195             throw new IOException("KeyStore password cannot be null");
196         }
197 
198         Logger logger = getLogger();
199         if (logger.isEnabledFor(Logger.TRACE))
200         {
201             logger.trace("Creating SSLServerSocket");
202             logger.trace("\tKeyStore " + m_keyStoreName + ", type " + m_keyStoreType);
203             logger.trace("\tKeyManager algorithm is " + m_keyManagerAlgorithm);
204             logger.trace("\tTrustStore " + m_trustStoreName + ", type " + m_trustStoreType);
205             logger.trace("\tTrustManager algorithm is " + m_trustManagerAlgorithm);
206             logger.trace("\tSSL protocol version is " + m_sslProtocol);
207         }
208 
209         try
210         {
211             KeyStore keystore = KeyStore.getInstance(m_keyStoreType);
212             InputStream keyStoreStream = IOUtils.getResourceAsStream(m_keyStoreName, getClass());
213             // Must check for nullity, otherwise a new empty keystore is created by
214             // KeyStore.load
215             if (keyStoreStream == null)
216             {
217                 // Let's look at the file system, maybe that the name provided is in
218                 // fact a file path
219                 File fle = FileUtils.newFile(m_keyStoreName);
220                 if (fle.exists()) keyStoreStream = new FileInputStream(fle);
221             }
222             if (keyStoreStream == null) throw new IOException("Cannot find KeyStore " + m_keyStoreName);
223             keystore.load(keyStoreStream, m_keyStorePassword.toCharArray());
224             try
225             {
226                 keyStoreStream.close();
227             }
228             catch (IOException x)
229             {
230                 // ignore
231             }
232 
233             KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(m_keyManagerAlgorithm);
234             // Use the keystore password as default if not given
235             keyFactory.init(keystore, m_keyManagerPassword == null
236                             ? m_keyStorePassword.toCharArray() : m_keyManagerPassword.toCharArray());
237 
238             TrustManagerFactory trustFactory = null;
239             if (m_trustStoreName != null)
240             {
241                 // User specified a trust store, retrieve it
242 
243                 if (m_trustStorePassword == null)
244                 {
245                     throw new IOException("TrustStore password cannot be null");
246                 }
247 
248                 KeyStore trustStore = KeyStore.getInstance(m_trustStoreType);
249                 InputStream trustStoreStream = IOUtils.getResourceAsStream(m_trustStoreName, getClass());
250                 // Check for nullity
251                 if (trustStoreStream == null)
252                 {
253                     throw new IOException("Cannot find TrustStore " + m_trustStoreName);
254                 }
255                 trustStore.load(trustStoreStream, m_trustStorePassword.toCharArray());
256 
257                 trustFactory = TrustManagerFactory.getInstance(m_trustManagerAlgorithm);
258                 trustFactory.init(trustStore);
259             }
260 
261             SSLContext context = SSLContext.getInstance(m_sslProtocol);
262             // Below call does not handle TrustManagers, needed when server must
263             // authenticate clients.
264             context.init(keyFactory.getKeyManagers(), trustFactory == null
265                             ? null : trustFactory.getTrustManagers(), null);
266 
267             SSLServerSocketFactory ssf = context.getServerSocketFactory();
268             SSLServerSocket serverSocket = (SSLServerSocket)ssf.createServerSocket(port, backlog,
269                 InetAddress.getByName(host));
270 
271             return serverSocket;
272         }
273         catch (IOException x)
274         {
275             logger.error("", x);
276             throw x;
277         }
278         catch (UnrecoverableKeyException x)
279         {
280             // Wrong password for the key
281             logger.error("Probably a bad key password", x);
282             throw new IOException("Probably a bad key password: " + x.toString());
283         }
284         catch (Exception x)
285         {
286             logger.error("Unexpected exception", x);
287             throw new IOException(x.toString());
288         }
289     }
290 
291     private Logger getLogger()
292     {
293         return Log.getLogger(getClass().getName());
294     }
295 }