/*
* Copyright 2016 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.server.util;
import com.thoughtworks.go.server.Jetty9Server;
import com.thoughtworks.go.server.config.GoSSLConfig;
import com.thoughtworks.go.util.ArrayUtil;
import com.thoughtworks.go.util.ListUtil;
import com.thoughtworks.go.util.SystemEnvironment;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class GoSslSocketConnectorTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
private File truststore;
private File keystore;
private GoSslSocketConnector sslSocketConnector;
@Before
public void setUp() throws Exception {
keystore = folder.newFile("keystore");
truststore = folder.newFile("truststore");
GoSSLConfig cipherSuite = mock(GoSSLConfig.class);
String[] cipherSuitesToBeIncluded = {"FOO"};
when(cipherSuite.getCipherSuitesToBeIncluded()).thenReturn(cipherSuitesToBeIncluded);
SystemEnvironment systemEnvironment = mock(SystemEnvironment.class);
when(systemEnvironment.getSslServerPort()).thenReturn(1234);
when(systemEnvironment.keystore()).thenReturn(keystore);
when(systemEnvironment.truststore()).thenReturn(truststore);
when(systemEnvironment.get(SystemEnvironment.RESPONSE_BUFFER_SIZE)).thenReturn(100);
when(systemEnvironment.get(SystemEnvironment.IDLE_TIMEOUT)).thenReturn(200);
when(systemEnvironment.getListenHost()).thenReturn("foo");
Jetty9Server jettyServer = mock(Jetty9Server.class);
when(jettyServer.getServer()).thenReturn(new Server());
sslSocketConnector = new GoSslSocketConnector(jettyServer, "password", systemEnvironment, cipherSuite);
}
@Test
public void shouldCreateSslConnectorWithRelevantPortAndTimeout() {
assertThat(sslSocketConnector.getConnector() instanceof ServerConnector, is(true));
ServerConnector connector = (ServerConnector) sslSocketConnector.getConnector();
assertThat(connector.getPort(), is(1234));
assertThat(connector.getHost(), is("foo"));
assertThat(connector.getIdleTimeout(), is(200l));
}
@Test
public void shouldSetupSslContextWithKeystoreAndTruststore() {
ServerConnector connector = (ServerConnector) sslSocketConnector.getConnector();
Collection<ConnectionFactory> connectionFactories = connector.getConnectionFactories();
SslContextFactory sslContextFactory = findSslContextFactory(connectionFactories);
assertThat(sslContextFactory.getKeyStorePath(), is(keystore.getAbsolutePath()));
assertThat(sslContextFactory.getTrustStore(), is(truststore.getAbsolutePath()));
assertThat(sslContextFactory.getWantClientAuth(), is(true));
}
@Test
public void shouldSetupCipherSuitesToBeIncluded() {
ServerConnector connector = (ServerConnector) sslSocketConnector.getConnector();
Collection<ConnectionFactory> connectionFactories = connector.getConnectionFactories();
SslContextFactory sslContextFactory = findSslContextFactory(connectionFactories);
List<String> includedCipherSuites = ArrayUtil.asList(sslContextFactory.getIncludeCipherSuites());
assertThat(includedCipherSuites.size(), is(1));
assertThat(includedCipherSuites.contains("FOO"), is(true));
}
@Test
public void shouldSetupHttpConnectionFactory() {
ServerConnector connector = (ServerConnector) sslSocketConnector.getConnector();
Collection<ConnectionFactory> connectionFactories = connector.getConnectionFactories();
HttpConnectionFactory httpConnectionFactory = getHttpConnectionFactory(connectionFactories);
assertThat(httpConnectionFactory.getHttpConfiguration().getOutputBufferSize(), is(100));
assertThat(httpConnectionFactory.getHttpConfiguration().getCustomizers().size(), is(2));
assertThat(httpConnectionFactory.getHttpConfiguration().getCustomizers().get(0), instanceOf(SecureRequestCustomizer.class));
assertThat(httpConnectionFactory.getHttpConfiguration().getCustomizers().get(1), instanceOf(ForwardedRequestCustomizer.class));
}
@Test
public void shouldNotSendAServerHeaderForSecurityReasons() throws Exception {
HttpConnectionFactory httpConnectionFactory = getHttpConnectionFactory(sslSocketConnector.getConnector().getConnectionFactories());
HttpConfiguration configuration = httpConnectionFactory.getHttpConfiguration();
assertThat(configuration.getSendServerVersion(), is(false));
}
private HttpConnectionFactory getHttpConnectionFactory(Collection<ConnectionFactory> connectionFactories) {
return (HttpConnectionFactory) getConnectionFactoryOfType(connectionFactories, HttpConnectionFactory.class);
}
private SslContextFactory findSslContextFactory(Collection<ConnectionFactory> connectionFactories) {
return ((SslConnectionFactory) getConnectionFactoryOfType(connectionFactories, SslConnectionFactory.class)).getSslContextFactory();
}
private ConnectionFactory getConnectionFactoryOfType(Collection<ConnectionFactory> connectionFactories, final Class<?> aClass) {
return ListUtil.find(connectionFactories, new ListUtil.Condition() {
@Override
public <T> boolean isMet(T item) {
return aClass.isInstance(item);
}
});
}
}