view src/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java @ 972:5ee36654b383

simplify AbstractHttpConnection
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 15 Oct 2016 22:42:05 -0600
parents d82eb99e8df6
children 39154cfa58e4
line wrap: on
line source

//
//  ========================================================================
//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.server.ssl;

import java.io.IOException;
import java.nio.channels.SocketChannel;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.Buffers.Type;
import org.eclipse.jetty.io.BuffersFactory;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.SslConnection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;

/* ------------------------------------------------------------ */
/**
 * SslSelectChannelConnector.
 *
 * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
 */
public class SslSelectChannelConnector extends SelectChannelConnector
{
	private final SslContextFactory _sslContextFactory;
	private Buffers _sslBuffers;

	/* ------------------------------------------------------------ */
	public SslSelectChannelConnector(Server server,int port)
	{
		this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH),server,port);
		setSoLingerTime(30000);
	}

	/* ------------------------------------------------------------ */
	/** Construct with explicit SslContextFactory.
	 * The SslContextFactory passed is added via {@link #addBean(Object)} so that 
	 * it's lifecycle may be managed with {@link AggregateLifeCycle}.
	 * @param sslContextFactory
	 */
	public SslSelectChannelConnector(SslContextFactory sslContextFactory,Server server,int port)
	{
		super(server,port);
		_sslContextFactory = sslContextFactory;
		addBean(_sslContextFactory);
		setUseDirectBuffers(false);
		setSoLingerTime(30000);
	}

	/* ------------------------------------------------------------ */
	/**
	 * Allow the Listener a chance to customise the request. before the server
	 * does its stuff. <br>
	 * This allows the required attributes to be set for SSL requests. <br>
	 * The requirements of the Servlet specs are:
	 * <ul>
	 * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
	 * String (since Servlet Spec 3.0).</li>
	 * <li> an attribute named "javax.servlet.request.cipher_suite" of type
	 * String.</li>
	 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
	 * <li> an attribute named "javax.servlet.request.X509Certificate" of type
	 * java.security.cert.X509Certificate[]. This is an array of objects of type
	 * X509Certificate, the order of this array is defined as being in ascending
	 * order of trust. The first certificate in the chain is the one set by the
	 * client, the next is the one used to authenticate the first, and so on.
	 * </li>
	 * </ul>
	 *
	 * @param endpoint
	 *                The Socket the request arrived on.
	 * @param request
	 *                HttpRequest to be customised.
	 */
	@Override
	public void customize(EndPoint endpoint, Request request) throws IOException
	{
		request.setScheme(HttpSchemes.HTTPS);
		super.customize(endpoint,request);

		SslConnection.SslEndPoint sslEndpoint=(SslConnection.SslEndPoint)endpoint;
		SSLEngine sslEngine=sslEndpoint.getSslEngine();
		SSLSession sslSession=sslEngine.getSession();

		SslCertificates.customize(sslSession,endpoint,request);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @return True if SSL re-negotiation is allowed (default false)
	 * @deprecated
	 */
	@Deprecated
	public boolean isAllowRenegotiate()
	{
		return _sslContextFactory.isAllowRenegotiate();
	}

	/* ------------------------------------------------------------ */
	/**
	 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
	 * a vulnerability in SSL/TLS with re-negotiation.  If your JVM
	 * does not have CVE-2009-3555 fixed, then re-negotiation should
	 * not be allowed.  CVE-2009-3555 was fixed in Sun java 1.6 with a ban
	 * of renegotiate in u19 and with RFC5746 in u22.
	 * @param allowRenegotiate true if re-negotiation is allowed (default false)
	 * @deprecated
	 */
	@Deprecated
	public void setAllowRenegotiate(boolean allowRenegotiate)
	{
		_sslContextFactory.setAllowRenegotiate(allowRenegotiate);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
	 * @deprecated
	 */
	@Deprecated
	public String[] getExcludeCipherSuites()
	{
		return _sslContextFactory.getExcludeCipherSuites();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
	 * @deprecated
	 */
	@Deprecated
	public void setExcludeCipherSuites(String[] cipherSuites)
	{
		_sslContextFactory.setExcludeCipherSuites(cipherSuites);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
	 * @deprecated
	 */
	@Deprecated
	public String[] getIncludeCipherSuites()
	{
		return _sslContextFactory.getIncludeCipherSuites();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
	 * @deprecated
	 */
	@Deprecated
	public void setIncludeCipherSuites(String[] cipherSuites)
	{
		_sslContextFactory.setIncludeCipherSuites(cipherSuites);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setPassword(String password)
	{
		_sslContextFactory.setKeyStorePassword(password);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setTrustPassword(String password)
	{
		_sslContextFactory.setTrustStorePassword(password);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setKeyPassword(String password)
	{
		_sslContextFactory.setKeyManagerPassword(password);
	}

	/* ------------------------------------------------------------ */
	/**
	 * Unsupported.
	 *
	 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
	 * @deprecated
	 */
	@Deprecated
	public String getAlgorithm()
	{
		throw new UnsupportedOperationException();
	}

	/* ------------------------------------------------------------ */
	/**
	 * Unsupported.
	 *
	 * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past)
	 * @deprecated
	 */
	@Deprecated
	public void setAlgorithm(String algorithm)
	{
		throw new UnsupportedOperationException();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
	 * @deprecated
	 */
	@Deprecated
	public String getProtocol()
	{
		return _sslContextFactory.getProtocol();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setProtocol(String protocol)
	{
		_sslContextFactory.setProtocol(protocol);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setKeystore(String keystore)
	{
		_sslContextFactory.setKeyStorePath(keystore);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
	 * @deprecated
	 */
	@Deprecated
	public String getKeystore()
	{
		return _sslContextFactory.getKeyStorePath();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
	 * @deprecated
	 */
	@Deprecated
	public String getKeystoreType()
	{
		return _sslContextFactory.getKeyStoreType();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
	 * @deprecated
	 */
	@Deprecated
	public boolean getNeedClientAuth()
	{
		return _sslContextFactory.getNeedClientAuth();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
	 * @deprecated
	 */
	@Deprecated
	public boolean getWantClientAuth()
	{
		return _sslContextFactory.getWantClientAuth();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean)
	 * @deprecated
	 */
	@Deprecated
	public void setNeedClientAuth(boolean needClientAuth)
	{
		_sslContextFactory.setNeedClientAuth(needClientAuth);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean)
	 * @deprecated
	 */
	@Deprecated
	public void setWantClientAuth(boolean wantClientAuth)
	{
		_sslContextFactory.setWantClientAuth(wantClientAuth);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setKeystoreType(String keystoreType)
	{
		_sslContextFactory.setKeyStoreType(keystoreType);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
	 * @deprecated
	 */
	@Deprecated
	public String getProvider()
	{
		return _sslContextFactory.getProvider();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
	 * @deprecated
	 */
	@Deprecated
	public String getSecureRandomAlgorithm()
	{
		return _sslContextFactory.getSecureRandomAlgorithm();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
	 * @deprecated
	 */
	@Deprecated
	public String getSslKeyManagerFactoryAlgorithm()
	{
		return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
	 * @deprecated
	 */
	@Deprecated
	public String getSslTrustManagerFactoryAlgorithm()
	{
		return _sslContextFactory.getTrustManagerFactoryAlgorithm();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
	 * @deprecated
	 */
	@Deprecated
	public String getTruststore()
	{
		return _sslContextFactory.getTrustStore();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
	 * @deprecated
	 */
	@Deprecated
	public String getTruststoreType()
	{
		return _sslContextFactory.getTrustStoreType();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setProvider(String provider)
	{
		_sslContextFactory.setProvider(provider);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setSecureRandomAlgorithm(String algorithm)
	{
		_sslContextFactory.setSecureRandomAlgorithm(algorithm);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setSslKeyManagerFactoryAlgorithm(String algorithm)
	{
		_sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setSslTrustManagerFactoryAlgorithm(String algorithm)
	{
		_sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setTruststore(String truststore)
	{
		_sslContextFactory.setTrustStore(truststore);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
	 * @deprecated
	 */
	@Deprecated
	public void setTruststoreType(String truststoreType)
	{
		_sslContextFactory.setTrustStoreType(truststoreType);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
	 * @deprecated
	 */
	@Deprecated
	public void setSslContext(SSLContext sslContext)
	{
		_sslContextFactory.setSslContext(sslContext);
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
	 * @deprecated
	 */
	@Deprecated
	public SSLContext getSslContext()
	{
		return _sslContextFactory.getSslContext();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslContextFactory()
	 */
	public SslContextFactory getSslContextFactory()
	{
		return _sslContextFactory;
	}

	/* ------------------------------------------------------------ */
	/**
	 * By default, we're confidential, given we speak SSL. But, if we've been
	 * told about an confidential port, and said port is not our port, then
	 * we're not. This allows separation of listeners providing INTEGRAL versus
	 * CONFIDENTIAL constraints, such as one SSL listener configured to require
	 * client certs providing CONFIDENTIAL, whereas another SSL listener not
	 * requiring client certs providing mere INTEGRAL constraints.
	 */
	@Override
	public boolean isConfidential()
	{
		return true;
	}

	@Override
	public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
	{
		try
		{
			SSLEngine engine = createSSLEngine(channel);
			SslConnection connection = new SslConnection(engine, endpoint);
			AsyncConnection delegate = super.newConnection(channel, connection.getSslEndPoint());
			connection.getSslEndPoint().setConnection(delegate);
			connection.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate());
			return connection;
		}
		catch (IOException e)
		{
			throw new RuntimeIOException(e);
		}
	}

	/* ------------------------------------------------------------ */
	/**
	 * @param channel A channel which if passed is used as to extract remote
	 * host and port for the purposes of SSL session caching
	 * @return A SSLEngine for a new or cached SSL Session
	 * @throws IOException if the SSLEngine cannot be created
	 */
	protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException
	{
		SSLEngine engine;
		if (channel != null)
		{
			String peerHost = channel.socket().getInetAddress().getHostAddress();
			int peerPort = channel.socket().getPort();
			engine = _sslContextFactory.newSslEngine(peerHost, peerPort);
		}
		else
		{
			engine = _sslContextFactory.newSslEngine();
		}

		engine.setUseClientMode(false);
		return engine;
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStart()
	 */
	@Override
	protected void doStart() throws Exception
	{
		_sslContextFactory.checkKeyStore();
		_sslContextFactory.start();

		SSLEngine sslEngine = _sslContextFactory.newSslEngine();

		sslEngine.setUseClientMode(false);

		SSLSession sslSession = sslEngine.getSession();

		_sslBuffers = BuffersFactory.newBuffers(
				getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
				getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,sslSession.getApplicationBufferSize(),
				getUseDirectBuffers()?Type.DIRECT:Type.INDIRECT,getMaxBuffers()
		);

		if (getRequestHeaderSize()<sslSession.getApplicationBufferSize())
			setRequestHeaderSize(sslSession.getApplicationBufferSize());
		if (getRequestBufferSize()<sslSession.getApplicationBufferSize())
			setRequestBufferSize(sslSession.getApplicationBufferSize());

		super.doStart();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStop()
	 */
	@Override
	protected void doStop() throws Exception
	{
		_sslBuffers=null;
		super.doStop();
	}

	/* ------------------------------------------------------------ */
	/**
	 * @return SSL buffers
	 */
	public Buffers getSslBuffers()
	{
		return _sslBuffers;
	}
}