package at.gv.egovernment.moa.id.util;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.util.Hashtable;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.axis.components.net.BooleanHolder;
import org.apache.axis.components.net.DefaultSocketFactory;
import org.apache.axis.components.net.SecureSocketFactory;
import org.apache.axis.components.net.TransportClientProperties;
import org.apache.axis.components.net.TransportClientPropertiesFactory;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import at.gv.egovernment.moa.logging.Logger;
/**
* Secure socket factory for Axis webs service clients of the MOA-ID component,
* which are the MOA-SP calls from MOA-ID Auth,
* and the MOA-ID Auth calls from MOA-ID Proxy.
*
Use this initialization code:
* // ConnectionParameter connParam = ... get from ConfigurationProvider
* AxisSecureSocketFactory.initialize(connParam);
*
See the Apache Axis documentation on how to configure this class
* as the default secure socket factory to be used by Axis.
*
* This code has been copied from JSSESocketFactory
, the
* method initialize()
has been added.
*
*
* @author Paul Ivancsics
* @version $Id$
*/
public class AxisSecureSocketFactory
extends DefaultSocketFactory implements SecureSocketFactory {
/** Field sslFactory */
private static SSLSocketFactory sslFactory;
/**
* Constructor for AxisSecureSocketFactory.
* @param attributes ???
*/
public AxisSecureSocketFactory(Hashtable attributes) {
super(attributes);
}
/**
* Initializes the factory by setting the connection parameters to be used for
* setting the secure socket factory, and by setting the system property
* axis.socketSecureFactory
.
* @param connParam ConnectionParameter
to derive the
* secure socket factory from
*/
public static void initialize(SSLSocketFactory ssf)
throws IOException, GeneralSecurityException {
Logger.debug("Initialize AxisSecureSocketFactory");
sslFactory = ssf;
}
/**
* creates a secure socket
*
* @param host
* @param port
* @param otherHeaders
* @param useFullURL
*
* @return Socket
* @throws Exception
*/
public Socket create(
String host,
int port,
StringBuffer otherHeaders,
BooleanHolder useFullURL)
throws Exception {
if (port == -1) {
port = 443;
}
TransportClientProperties tcp =
TransportClientPropertiesFactory.create("https");
boolean hostInNonProxyList =
isHostInNonProxyList(host, tcp.getNonProxyHosts());
Socket sslSocket = null;
if (tcp.getProxyHost().length() == 0 || hostInNonProxyList) {
// direct SSL connection
sslSocket = sslFactory.createSocket(host, port);
}
else {
// Default proxy port is 80, even for https
int tunnelPort =
(tcp.getProxyPort().length() != 0)
? Integer.parseInt(tcp.getProxyPort())
: 80;
if (tunnelPort < 0)
tunnelPort = 80;
// Create the regular socket connection to the proxy
Socket tunnel = new Socket(tcp.getProxyHost(), tunnelPort);
// The tunnel handshake method (condensed and made reflexive)
OutputStream tunnelOutputStream = tunnel.getOutputStream();
PrintWriter out =
new PrintWriter(
new BufferedWriter(new OutputStreamWriter(tunnelOutputStream)));
// More secure version... engage later?
// PasswordAuthentication pa =
// Authenticator.requestPasswordAuthentication(
// InetAddress.getByName(tunnelHost),
// tunnelPort, "SOCK", "Proxy","HTTP");
// if(pa == null){
// printDebug("No Authenticator set.");
// }else{
// printDebug("Using Authenticator.");
// tunnelUser = pa.getUserName();
// tunnelPassword = new String(pa.getPassword());
// }
out.print(
"CONNECT "
+ host
+ ":"
+ port
+ " HTTP/1.0\r\n"
+ "User-Agent: AxisClient");
if (tcp.getProxyUser().length() != 0
&& tcp.getProxyPassword().length() != 0) {
// add basic authentication header for the proxy
String encodedPassword =
XMLUtils.base64encode(
(tcp.getProxyUser() + ":" + tcp.getProxyPassword()).getBytes());
out.print("\nProxy-Authorization: Basic " + encodedPassword);
}
out.print("\nContent-Length: 0");
out.print("\nPragma: no-cache");
out.print("\r\n\r\n");
out.flush();
InputStream tunnelInputStream = tunnel.getInputStream();
if (log.isDebugEnabled()) {
log.debug(
Messages.getMessage(
"isNull00",
"tunnelInputStream",
"" + (tunnelInputStream == null)));
}
String replyStr = "";
// Make sure to read all the response from the proxy to prevent SSL negotiation failure
// Response message terminated by two sequential newlines
int newlinesSeen = 0;
boolean headerDone = false; /* Done on first newline */
while (newlinesSeen < 2) {
int i = tunnelInputStream.read();
if (i < 0) {
throw new IOException("Unexpected EOF from proxy");
}
if (i == '\n') {
headerDone = true;
++newlinesSeen;
}
else if (i != '\r') {
newlinesSeen = 0;
if (!headerDone) {
replyStr += String.valueOf((char) i);
}
}
}
if (!replyStr.startsWith("HTTP/1.0 200")
&& !replyStr.startsWith("HTTP/1.1 200")) {
throw new IOException(
Messages.getMessage(
"cantTunnel00",
new String[] { tcp.getProxyHost(), "" + tunnelPort, replyStr }));
}
// End of condensed reflective tunnel handshake method
sslSocket = sslFactory.createSocket(tunnel, host, port, true);
if (log.isDebugEnabled()) {
log.debug(
Messages.getMessage(
"setupTunnel00",
tcp.getProxyHost(),
"" + tunnelPort));
}
}
((SSLSocket) sslSocket).startHandshake();
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage("createdSSL00"));
}
return sslSocket;
}
}