All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openhealthtools.ihe.atna.nodeauth.handlers.TLSEnabledSocketHandler Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2006,2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 

* Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.openhealthtools.ihe.atna.nodeauth.handlers; import org.openhealthtools.ihe.atna.nodeauth.NoSecurityDomainException; import org.openhealthtools.ihe.atna.nodeauth.SecurityDomain; import org.openhealthtools.ihe.atna.nodeauth.SecurityDomainManager; import org.openhealthtools.ihe.atna.nodeauth.context.NodeAuthModuleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; import java.net.MalformedURLException; import java.net.Socket; import java.net.SocketException; import java.net.URI; import java.net.URLConnection; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; /** * Implementation of the Node Authentication's SocketHandler * to create of sockets secured using Transport Layer * Security version 1. The TLS-enabled Socket Handler constructs * sockets using a specified keystore, truststore, and cipher suite * via a SecurityDomain. These settings are used to mututally-authenticate * and negotiate the parties involved in the transaction. *

* This handler implements the IHE ITI-19 Node Authentication transaction. *

* To access this handler, use NodeAuthModule.getContext().getSocketHandler(). * * @author Glenn Deen * @author Rick Stevens * @author Sondra Renly * @author Matthew Davis * @see org.openhealthtools.ihe.atna.nodeauth.SocketHandler */ public class TLSEnabledSocketHandler extends AbstractSecureSocketHandler { /** * Logger instance */ private static final Logger logger = LoggerFactory.getLogger(TLSEnabledSocketHandler.class); /** * Default constructor for the TLS-enabled Socket Handler * * @param context The NodeAuth Module Context to use */ public TLSEnabledSocketHandler(NodeAuthModuleContext context) { super(context); } // private void doTunnelHandshake(Socket tunnel, String host, int port)throws IOException // { // OutputStream out = tunnel.getOutputStream(); // String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n" // + "User-Agent: asdf" // + "\r\n\r\n"; // byte b[]; // try { // /* // * We really do want ASCII7 -- the http protocol doesn't change // * with locale. // */ // b = msg.getBytes("ASCII7"); // } catch (UnsupportedEncodingException ignored) { // /* // * If ASCII7 isn't there, something serious is wrong, but // * Paranoia Is Good (tm) // */ // b = msg.getBytes(); // } // out.write(b); // out.flush(); // // /* // * We need to store the reply so we can create a detailed // * error message to the user. // */ // byte reply[] = new byte[200]; // int replyLen = 0; // int newlinesSeen = 0; // boolean headerDone = false; /* Done on first newline */ // // InputStream in = tunnel.getInputStream(); // boolean error = false; // // while (newlinesSeen < 2) { // int i = in.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 && replyLen < reply.length) { // reply[replyLen++] = (byte) i; // } // } // } // // /* // * Converting the byte array to a string is slightly wasteful // * in the case where the connection was successful, but it's // * insignificant compared to the network overhead. // */ // String replyStr; // try { // replyStr = new String(reply, 0, replyLen, "ASCII7"); // } catch (UnsupportedEncodingException ignored) { // replyStr = new String(reply, 0, replyLen); // } // // /* Look for 200 connection established */ // if(replyStr.toLowerCase().indexOf("200 connection established") == -1){ // throw new IOException("Unable to tunnel through " // + host + ":" + port // + ". Proxy returns \"" + replyStr + "\""); // } // // /* tunneling Handshake was successful! */ // } /* (non-Javadoc) * @see org.openhealthtools.ihe.atna.nodeauth.handlers.AbstractSecureSocketHandler#createSecureSocket(java.lang.String, int, org.openhealthtools.ihe.atna.nodeauth.SecurityDomain) */ protected SSLSocket createSecureSocket(String host, int port, SecurityDomain securityDomain, Socket nestedSocket) throws NoSecurityDomainException, NoSuchAlgorithmException, KeyManagementException, UnknownHostException, IOException { if (!CONTEXT.isTLSEnabled()) throw new NoSuchAlgorithmException("TLS has been disabled for ATNA connections via " + SecurityDomainManager.class.getName() + ".setSetTLSEnabled(false)"); SSLContext ctx = null; // Attempt to get an instance of the first support TLS protocol try { ctx = SSLContext.getInstance(securityDomain.getJdkTlsClientProtocols()[0]); } catch (NoSuchAlgorithmException e) { securityDomain.restoreSystemEnvironment(); throw e; } // Initialize the instance for the key and trust stores try { KeyManager[] keyMgrs = securityDomain.getKeyManagers(); TrustManager[] trustMgrs = securityDomain.getTrustManagers(); ctx.init(keyMgrs, trustMgrs, null); } catch (KeyManagementException e) { throw e; } SSLSocketFactory factory = ctx.getSocketFactory(); SSLSocket socket = null; if (logger.isDebugEnabled()) { String[] supportedSuites = factory.getSupportedCipherSuites(); logger.debug("\n\nSupported cipher suites are:"); for (int i = 0; i < supportedSuites.length; i++) { logger.debug("\t" + supportedSuites[i]); } } int retries = 0; Throwable cause = null; // Loop to get a connection or until we've exhausted number of retries while (retries < CONTEXT.getConfig().getSocketRetries()) { try { if (logger.isDebugEnabled()) { logger.debug("Connecting to " + host + " on port " + port + " (timeout: " + CONTEXT.getConfig().getConnectTimeout() + " ms) using factory " + factory.getClass().getName()); } //SocketAddress address = new InetSocketAddress(host,port); if (nestedSocket instanceof Socket) { socket = (SSLSocket) (factory.createSocket(nestedSocket, host, port, true)); } else { socket = (SSLSocket) (factory.createSocket(host, port)); } //socket.connect(address, CONTEXT.getConfig().getConnectTimeout()); // Set amount of time to wait on socket read before timing out socket.setSoTimeout(CONTEXT.getConfig().getSocketTimeout()); socket.setKeepAlive(true); socket.setEnabledProtocols(securityDomain.getJdkTlsClientProtocols()); socket.setEnabledCipherSuites(securityDomain.getCipherSuites()); if (logger.isDebugEnabled()) { logger.debug("\n\nEnabled Cipher suites for connection are: "); String[] suites = socket.getEnabledCipherSuites(); for (int i = 0; i < suites.length; i++) { logger.debug("\t" + suites[i]); } } // Force the TLS handshake at this point so we can catch any authentication errors socket.startHandshake(); break; } catch (SSLHandshakeException e) { logger.error("Handshake failed with server " + host + " on port " + port + " reason " + e.getLocalizedMessage(), e); try { socket.close(); } catch (IOException e1) { logger.error("Error trying to close socket for " + host + " on port " + port + " reason " + e1.getLocalizedMessage(), e1); } //securityDomain.restoreSystemEnvironment(); throw e; } catch (UnknownHostException e) { logger.error("Unable to establish connection to " + host + " on port " + port + " reason " + e.getLocalizedMessage(), e); //securityDomain.restoreSystemEnvironment(); throw e; } catch (SocketException e) { logger.error("Error connecting to " + host + " on port " + port + ". Will retry in " + CONTEXT.getConfig().getSocketRetryWait() / 1000 + " seconds.", e); retries++; cause = e; try { Thread.sleep(CONTEXT.getConfig().getSocketRetryWait()); continue; } catch (InterruptedException ie) { if (logger.isDebugEnabled()) { logger.debug("Sleep awoken early"); } continue; } } catch (IOException e) { logger.error("Error connecting to " + host + " on port " + port + ". Will retry in " + CONTEXT.getConfig().getSocketRetryWait() / 1000 + " seconds." + " reason " + e.getLocalizedMessage(), e); retries++; cause = e; try { Thread.sleep(CONTEXT.getConfig().getSocketRetryWait()); continue; } catch (InterruptedException ie) { if (logger.isDebugEnabled()) { logger.debug("Sleep awoken early"); } continue; } } } // If socket retries exceed maximum allowed, throw an exception if (retries >= CONTEXT.getConfig().getSocketRetries()) { //securityDomain.restoreSystemEnvironment(); logger.error("Secure Socket Connect Retries Exhausted.", cause); throw new ConnectException("Secure socket retries exhausted"); } //securityDomain.restoreSystemEnvironment(); return socket; } /** * TODO: To be removed in the 2009 post-Connectathon Branch */ /* (non-Javadoc) * @see org.openhealthtools.ihe.atna.nodeauth.SocketHandler#getInputStream(java.net.URI, org.openhealthtools.ihe.atna.nodeauth.SecurityDomain) */ public InputStream getInputStream(URI uri, SecurityDomain securityDomain) throws NoSecurityDomainException, MalformedURLException, IOException, NoSuchAlgorithmException { final NodeAuthModuleContext context = NodeAuthModuleContext.getContext(); if (!context.isTLSEnabled() && !context.isNonTLSConnectionsPermitted()) { throw new NoSuchAlgorithmException("TLS has been disabled for ATNA connections"); } boolean tlsURI = uri.getScheme().equalsIgnoreCase("https"); boolean useTLS = tlsURI && context.isTLSEnabled() || !context.isNonTLSConnectionsPermitted(); if (useTLS && null == securityDomain) { throw new NoSecurityDomainException(uri, "Security domain provided is null"); } if (useTLS) { securityDomain.setDomainEnvironment(); } InputStream is = null; try { URLConnection connection = uri.toURL().openConnection(); if (useTLS && !securityDomain.doDomainSpoofCheck()) { ((HttpsURLConnection) connection).setHostnameVerifier((urlHostName, session) -> true); } is = connection.getInputStream(); if (useTLS) { logger.info("Secure connection successfully made using TLS to " + uri.toString()); } else { logger.info("Unsecure connection successfully made to " + uri.toString()); } } catch (IOException e) { if (useTLS) securityDomain.restoreSystemEnvironment(); throw e; } if (useTLS) securityDomain.restoreSystemEnvironment(); return is; } /* * Note that this method always uses the system environment (specifically https.protocols) * in order to derive the HTTPS parameters. As such {@link SecurityDomain#SET_DOMAIN_ENVIRONMENT} must be * set to true if these parameters are not configured via system properties anyway. * * @see org.openhealthtools.ihe.atna.nodeauth.SocketHandler#getInputStream(java.net.URI) */ public InputStream getInputStream(URI uri) throws Exception { boolean tlsURI = uri.getScheme().equalsIgnoreCase("https"); SecurityDomain securityDomain = null; if (tlsURI) { final NodeAuthModuleContext context = NodeAuthModuleContext.getContext(); securityDomain = context.getSecurityDomainManager().getSecurityDomain(uri); } return getInputStream(uri, securityDomain); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy