001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.mts.base;
028:
029: import java.io.IOException;
030: import java.lang.reflect.Method;
031: import java.net.InetSocketAddress;
032: import java.net.ServerSocket;
033: import java.net.Socket;
034: import java.net.UnknownHostException;
035: import java.rmi.server.RMISocketFactory;
036:
037: import javax.net.ServerSocketFactory;
038: import javax.net.ssl.SSLServerSocketFactory;
039: import javax.net.ssl.SSLSocketFactory;
040:
041: import org.cougaar.bootstrap.SystemProperties;
042: import org.cougaar.core.component.ServiceBroker;
043: import org.cougaar.util.log.Logger;
044: import org.cougaar.util.log.Logging;
045:
046: import org.cougaar.mts.std.AspectSupportImpl;
047:
048: /**
049: * This is an RMISocketFactory that can wrap {@link ServerSocket}s and
050: * apply Aspect delegates to client {@link Socket}s. It handles SSL as well
051: * as straight RMI, using the CSI classes for the former if they're
052: * available.
053: *
054: * @property org.cougaar.message.transport.server_socket_class
055: * ServerSocketWrapper classname (default is no wrapper).
056: */
057: public class SocketFactory extends RMISocketFactory implements
058: java.io.Serializable {
059:
060: private static transient Logger logger = Logging
061: .getLogger("org.cougaar.mts.base.SocketFactory");
062: // This has to be set very early from outside
063: private static transient SocketControlProvisionService PolicyProvider;
064:
065: static void configureProvider(ServiceBroker sb) {
066: PolicyProvider = (SocketControlProvisionService) sb.getService(
067: sb, SocketControlProvisionService.class, null);
068: }
069:
070: // We're not using this anymore but keep it around for reference.
071: private final static String SSL_INSTRUCTIONS = "\n"
072: + "An exception occurred while trying to create an SSLServerSocket. This\n"
073: + "has probably happened because you have not setup your security\n"
074: + "environment completely. The following checklist should guide you\n"
075: + "through this process.\n"
076: + "\n"
077: + "1. Install jsse (Java Secure Socket Extension). This is a largely\n"
078: + " manual procedure and so is prone to error or omission. Following\n"
079: + " the instructions supplied with the package. In particular, copy the\n"
080: + " three jar files to the jre/lib/ext subdirectory of your java\n"
081: + " installation and edit the jre/lib/security/java.security file to\n"
082: + " add the jsee security provider. The result should resemble this:\n"
083: + " security.provider.1=sun.security.provider.Sun\n"
084: + " security.provider.2=com.sun.rsajca.Provider\n"
085: + " security.provider.3=com.sun.net.ssl.internal.ssl.Provider\n"
086: + "2. Create a keystore. The keystore contains keys and certificates to\n"
087: + " be used for SSL sockets. The full procedure involves the use of a\n"
088: + " Certificate Authority to provide properly signed certificates\n"
089: + " embodying a public key and a chain of certificates back to a\n"
090: + " trusted signer. Until our security infrastructure is completed, the\n"
091: + " following will suffice to enable execution:\n"
092: + " keytool -keystore keystore -alias cougaar -genkey\n"
093: + " keytool -keystore keystore -alias cougaar -selfcert\n"
094: + "3. Make the keystore be used by the key and trust managers. To do\n"
095: + " this, set these properties in the startup scripts:\n"
096: + " -Djavax.net.ssl.trustStore=keystore\n"
097: + " -Djavax.net.ssl.trustStorePassword=password\n"
098: + " -Djavax.net.ssl.keyStore=keystore\n"
099: + " -Djavax.net.ssl.keyStorePassword=password\n"
100: + " Naturally, the passwords should match those used to create the\n"
101: + " keystore.\n";
102:
103: // NAI Linkage
104:
105: private static final String SSL_SOCFAC_CLASS = "org.cougaar.core.security.ssl.KeyRingSSLFactory";
106: private static final String SSL_SERVER_SOCFAC_CLASS = "org.cougaar.core.security.ssl.KeyRingSSLServerFactory";
107:
108: private static final Class[] FORMALS = {};
109: private static final Object[] ACTUALS = {};
110:
111: static SSLSocketFactory getSSLSocketFactory() {
112: Class cls = null;
113: try {
114: cls = Class.forName(SSL_SOCFAC_CLASS);
115: } catch (ClassNotFoundException cnf) {
116: // silently use the default class
117: return (SSLSocketFactory) SSLSocketFactory.getDefault();
118: }
119:
120: try {
121: Method meth = cls.getMethod("getDefault", FORMALS);
122: return (SSLSocketFactory) meth.invoke(cls, ACTUALS);
123: } catch (Exception ex) {
124: if (logger.isErrorEnabled())
125: logger.error("Error getting SSL socket factory: " + ex);
126: return (SSLSocketFactory) SSLSocketFactory.getDefault();
127: }
128: }
129:
130: static ServerSocketFactory getSSLServerSocketFactory() {
131: Class cls = null;
132: try {
133: cls = Class.forName(SSL_SERVER_SOCFAC_CLASS);
134: } catch (ClassNotFoundException cnf) {
135: // silently use the default class
136: return SSLServerSocketFactory.getDefault();
137: }
138:
139: try {
140: Method meth = cls.getMethod("getDefault", FORMALS);
141: return (ServerSocketFactory) meth.invoke(cls, ACTUALS);
142: } catch (Exception ex) {
143: if (logger.isErrorEnabled())
144: logger.error("Error getting socket factory: " + ex);
145: return SSLServerSocketFactory.getDefault();
146: }
147: }
148:
149: private static final String WRAPPER_CLASS_PROP = "org.cougaar.message.transport.server_socket_class";
150:
151: private static Class serverWrapperClass;
152: static {
153: String classname = SystemProperties
154: .getProperty(WRAPPER_CLASS_PROP);
155: if (classname != null) {
156: try {
157: serverWrapperClass = Class.forName(classname);
158: } catch (Exception ex) {
159: System.err.println(ex);
160: }
161: }
162: }
163:
164: // The factory will be serialized along with the MTImpl, and we
165: // definitely don't want to include the AspectSupport when that
166: // happens. Instead, the aspect delegation will be handled by a
167: // special static call.
168: boolean use_ssl, use_aspects;
169: transient SocketControlPolicy policy;
170:
171: public SocketFactory(boolean use_ssl, boolean use_aspects) {
172: this .use_ssl = use_ssl;
173: this .use_aspects = use_aspects;
174: // get the policy from a service
175: }
176:
177: public boolean isMTS() {
178: return use_aspects;
179: }
180:
181: public boolean usesSSL() {
182: return use_ssl;
183: }
184:
185: public Socket createSocket(String host, int port)
186: throws IOException, UnknownHostException {
187: Socket socket = new Socket();
188: InetSocketAddress endpoint = new InetSocketAddress(host, port);
189: if (policy == null && PolicyProvider != null) {
190: policy = PolicyProvider.getPolicy();
191: }
192:
193: if (policy != null) {
194: int timeout = policy.getConnectTimeout(this , host, port);
195: socket.connect(endpoint, timeout);
196: } else {
197: socket.connect(endpoint);
198: }
199:
200: if (use_ssl) {
201: SSLSocketFactory socfac = getSSLSocketFactory();
202: socket = socfac.createSocket(socket, host, port, true);
203: }
204:
205: return use_aspects ? AspectSupportImpl
206: .attachRMISocketAspects(socket) : socket;
207: }
208:
209: public ServerSocket createServerSocket(int port) throws IOException {
210: ServerSocket s = null;
211: if (use_ssl) {
212: ServerSocketFactory factory = getSSLServerSocketFactory();
213: s = factory.createServerSocket(port);
214: } else {
215: s = new ServerSocket(port);
216: }
217: if (serverWrapperClass != null) {
218: try {
219: ServerSocketWrapper wrapper = (ServerSocketWrapper) serverWrapperClass
220: .newInstance();
221: wrapper.setDelegate(s);
222: return wrapper;
223: } catch (Exception ex) {
224: System.err.println(ex);
225: return s;
226: }
227: } else {
228: return s;
229: }
230: }
231:
232: public int hashCode() {
233: if (use_ssl) {
234: if (use_aspects)
235: return 0;
236: return 1;
237: } else {
238: if (use_aspects)
239: return 2;
240: return 3;
241: }
242: }
243:
244: public boolean equals(Object o) {
245: if (this == o)
246: return true;
247: if (o.getClass() == this .getClass()) {
248: SocketFactory that = (SocketFactory) o;
249: return this .use_ssl == that.use_ssl
250: && this .use_aspects == that.use_aspects;
251: }
252: return false;
253: }
254: }
|