/*
* IRClib -- A Java Internet Relay Chat library -- class SSLIRCConnection
* Copyright (C) 2002 - 2006 Christoph Schwering <schwering@gmail.com>
*
* This library and the accompanying materials are made available under the
* terms of the
* - GNU Lesser General Public License,
* - Apache License, Version 2.0 and
* - Eclipse Public License v1.0.
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY.
*/
package org.schwering.irc.lib;
import com.sun.net.ssl.SSLContext;
import com.sun.net.ssl.TrustManager;
import com.sun.net.ssl.internal.ssl.Provider;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.net.SocketException;
import java.security.Security;
import java.util.Vector;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/**
* The SSL extension of the <code>IRCConnection</code> class.
* <p>
* Note that this class is <b>deprecated</b>. The SSL supporting classes moved
* to <code>org.schwering.irc.lib.ssl</code> since IRClib 1.10.
* <p>
* The IRC server you want to connect to must accept SSL connections.
* Otherwise you cannot connect to it with an instance of
* <code>SSLIRCConnection</code>. IRC servers which accept SSL connections are
* really very rare, because SSL means a high load for the server.
* <p>
* The following sample code tries to establish an IRC connection to an
* IRC server which must support SSL. Differences to the code which
* demonstrates the use of of the {@link org.schwering.irc.lib.IRCConnection}
* class are printed in bold font:
* <p>
* <hr /><pre>
* /*
* * The following code of a class which imports org.schwering.irc.lib.*
* * prepares an SSL IRC connection and then tries to establish the
* * connection. The server is "irc.somenetwork.com", the ports are
* * the default SSL port (443) and the port used on most SSL IRC servers
* * (994). No password is used (null). The nickname is "Foo" and
* * the realname is "Mr. Foobar". The username "foobar".
* * Because of setDaemon(true), the JVM exits even if this thread is
* * running.
* * By setting an instance of SSLDefaultTrustManager as TrustManager
* * (which is also done implicitely by the SSLIRCConnection class if no
* * TrustManager is set until the connect method is invoked), the
* * X509Certificate is accepted automatically. Of course, you can write
* * your own TrustManager. For example, you could write a class which
* * extends SSLDefaultTrustManager and overrides its checkServerTrusted
* * method. In the new checkServerTrusted method, you could ask the user
* * to accept or reject the certificate.
* * An instance of the class MyListener which must implement
* * IRCActionListener is set as event-listener for the connection.
* * The connection is told to parse out mIRC color codes and to enable
* * automatic PING? PONG! replies.
* */
* <b>SSL</b>IRCConnection conn = new <b>SSL</b>IRCConnection(
* "irc.somenetwork.com",
* new int[] { 443, 994 },
* null,
* "Foo",
* "Mr. Foobar",
* "foo@bar.com"
* );
*
* conn.addIRCEventListener(new MyListener());
* <b>conn.addTrustManager(new SSLDefaultTrustManager());</b>
* conn.setDaemon(true);
* conn.setColors(false);
* conn.setPong(true);
*
* try {
* conn.connect(); // Try to connect!!! Don't forget this!!!
* } catch (IOException ioexc) {
* ioexc.printStackTrace();
* }
* </pre><hr />
* <p>
* The serverpassword isn't needed in most cases. You can give
* <code>null</code> or <code>""</code> instead as done in this example.
* <p>
* <code>TrustManager</code>s can be added and removed until the
* <code>connect</code> method is invoked. If no <code>TrustManager</code>s are
* set until then, an {@link org.schwering.irc.lib.SSLDefaultTrustManager} is
* set automatically. It accepts all X509 certificates.
* @deprecated This class has been replaced with
* <code>org.schwering.irc.lib.ssl.SSLDefaultTrustManager</code>.
* @author Christoph Schwering <schwering@gmail.com>
* @version 1.33
* @see IRCConnection
* @see SSLDefaultTrustManager
* @see com.sun.net.ssl.TrustManager
*/
public class SSLIRCConnection extends IRCConnection {
/**
* The list of <code>TrustManager</code>s. <code>TrustManager</code>s can be
* added with the <code>addTrustManager</code> method and removed with the
* <code>removeTrustManager</code> method. If no <code>TrustManager</code>
* is included, the <code>getTrustManagers</code> method sets an instance of
* <code>SSLDefaultTrustManager</code> as only <code>TrustManager</code>.
*/
private Vector trustManagers = new Vector(1);
// ------------------------------
/**
* Creates a new IRC connection with secure sockets (SSL).<br />
* The difference to the other constructor is, that it transmits the ports in
* an <code>int[]</code>. Thus, also ports like 994, 6000 and 6697 can be
* selected.<br /><br />
* The constructor prepares a new IRC connection with secure sockets which
* can be really started by invoking the <code>connect</code> method. Before
* invoking it, you should set the <code>IRCEventListener</code>, optionally
* the <code>TrustManager</code>, if you don't want to use the
* <code>SSLDefaultTrustManager</code> which accepts the X509 certificate
* automatically, and other settings.<br />
* Note that you do not need to set a password to connect to the large public
* IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
* connection, use <code>""</code> or <code>null</code> for the password
* argument in the constructor.
* @param host The hostname of the server we want to connect to.
* @param ports The portrange to which we want to connect.
* @param pass The password of the IRC server. If your server isn't
* secured by a password (that's normal), use
* <code>null</code> or <code>""</code>.
* @param nick The nickname for the connection. Is used to register the
* connection.
* @param username The username. Is used to register the connection.
* @param realname The realname. Is used to register the connection.
* @throws IllegalArgumentException If the <code>host</code> or
* <code>ports</code> is <code>null</code> or
* <code>ports</code>' length is
* <code>0</code>.
* @see #connect()
*/
public SSLIRCConnection(String host, int[] ports, String pass, String nick,
String username, String realname) {
super(host, ports, pass, nick, username, realname);
}
// ------------------------------
/**
* Creates a new IRC connection with secure sockets (SSL).<br />
* The difference to the other constructor is, that it transmits the ports as
* two <code>int</code>s. Thus, only a portrange from port <code>x</code> to
* port <code>y</code> like from port 6000 to 6010 can be selected.<br />
* <br />
* The constructor prepares a new IRC connection with secure sockets which
* can be really started by invoking the <code>connect</code> method. Before
* invoking it, you should set the <code>IRCEventListener</code>, optionally
* the <code>TrustManager</code>, if you don't want to use the
* <code>SSLDefaultTrustManager</code> which accepts the X509 certificate
* automatically, and other settings.<br />
* Note that you do not need to set a password to connect to the large public
* IRC networks like QuakeNet, EFNet etc. To use no password in your IRC
* connection, use <code>""</code> or <code>null</code> for the password
* argument in the constructor.
* @param host The hostname of the server we want to connect to.
* @param portMin The beginning of the port range we are going to connect
* to.
* @param portMax The ending of the port range we are going to connect to.
* @param pass The password of the IRC server. If your server isn't
* secured by a password (that's normal), use
* <code>null</code> or <code>""</code>.
* @param nick The nickname for the connection. Is used to register the
* connection.
* @param username The username. Is used to register the connection.
* @param realname The realname. Is used to register the connection.
* @throws IllegalArgumentException If the <code>host</code> is
* <code>null</code>.
* @see #connect()
*/
public SSLIRCConnection(String host, int portMin, int portMax, String pass,
String nick, String username, String realname) {
super(host, portMin, portMax, pass, nick, username, realname);
}
// ------------------------------
/**
* Establish a connection to the server.<br />
* This method must be invoked to start a connection; the constructor doesn't
* do that!<br />
* It tries all set ports until one is open. If all ports fail it throws an
* <code>IOException</code>. If anything SSL related fails (for example
* conflicts with the algorithms or during the handshaking), a
* <code>SSLException</code> is thrown. <br />
* You can invoke <code>connect</code> only one time.
* @throws IOException If an I/O error occurs.
* @throws SSLException If anything with the secure sockets fails.
* @throws SocketException If the <code>connect</code> method was already
* invoked.
* @see #isConnected()
* @see #doQuit()
* @see #doQuit(String)
* @see #close()
*/
public void connect() throws IOException {
if (level != 0) // otherwise disconnected or connect
throw new SocketException("Socket closed or already open ("+ level +")");
IOException exception = null;
SSLSocketFactory sf = null;
SSLSocket s = null;
for (int i = 0; i < ports.length && s == null; i++) {
try {
if (sf == null)
sf = getSocketFactory();
s = (SSLSocket)sf.createSocket(host, ports[i]);
s.startHandshake();
exception = null;
} catch (IOException exc) {
if (s != null)
s.close();
s = null;
exception = exc;
}
}
if (exception != null)
throw exception; // connection wasn't successful at any port
prepare(s);
}
// ------------------------------
/**
* Creates a new <code>SSLSocketFactory</code> on whose base a new
* <code>SSLSocket</code> can be created. This method is used by the
* <code>connect</code> method. If a <code>NoSuchAlgorithmException</code>,
* <code>KeyManagementException</code>, or any other exception is thrown,
* it's catched a <code>SSLException</code> is thrown. This
* <code>SSLException</code> contains all information about the exception
* which was really thrown.<br /><br />
* If there are now <code>TrustManager</code>s set at the moment, an instance
* of <code>SSLDefultTrustManager</code> is set automatically.
* @throws SSLException If any exception is thrown. It contains all the thrown
* exception's information.
* @return A new <code>SSLSocketFactory on which base a new
* <code>SSLSocket</code> can be created.
*/
private SSLSocketFactory getSocketFactory() throws SSLException {
if (trustManagers.size() == 0)
addTrustManager(new SSLDefaultTrustManager());
try {
Security.addProvider(new Provider());
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, getTrustManagers(), null);
SSLSocketFactory socketFactory = context.getSocketFactory();
return socketFactory;
} catch (Exception exc) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exc.printStackTrace(pw);
pw.close();
throw new SSLException("Exception while preparing "+
"the SSLSocket:\n---\n"+ sw.toString() + "---");
}
}
// ------------------------------
/**
* Adds a new <code>TrustManager</code>. <br />
* Please remind that we're talking here about
* <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the
* <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
* @param trustManager The <code>TrustManager</code> object which is to add.
* @see #removeTrustManager(TrustManager)
* @see #getTrustManagers()
*/
public void addTrustManager(TrustManager trustManager) {
trustManagers.add(trustManager);
}
// ------------------------------
/**
* Removes one <code>TrustManager</code>.<br />
* Please remind that we're talking here about
* <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the
* <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
* @param trustManager The <code>TrustManager</code> object which is to
* remove.
* @return <code>true</code> if a <code>TrustManager</code> was removed.
* @see #addTrustManager(TrustManager)
* @see #getTrustManagers()
*/
public boolean removeTrustManager(TrustManager trustManager) {
return trustManagers.remove(trustManager);
}
// ------------------------------
/**
* Returns the set <code>TrustManager</code>s. The default
* <code>TrustManager</code> is an instance of
* <code>SSLDefaultTrustManager</code>, which is set when you invoke the
* <code>connect</code> method without having set another
* <code>TrustManager</code>.<br />
* Please remind that we're talking here about
* <code>com.sun.net.ssl.TrustManager</code>s of the JSSE API and not the
* <code>javax.net.ssl.TrustManager</code>s of the Java 1.4 API!
* @return The set <code>TrustManager</code>s.
* @see #addTrustManager(TrustManager)
* @see #removeTrustManager(TrustManager)
*/
public TrustManager[] getTrustManagers() {
TrustManager[] tm = new TrustManager[trustManagers.size()];
trustManagers.copyInto(tm);
return tm;
}
}