refactored server for dependancy injection, combined tests to run correctly in a multithreaded build
This commit is contained in:
parent
c599902ad5
commit
ea3f84b830
3 changed files with 95 additions and 107 deletions
20
build.gradle
20
build.gradle
|
|
@ -20,6 +20,7 @@ plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'com.google.protobuf' version '0.8.8'
|
id 'com.google.protobuf' version '0.8.8'
|
||||||
id 'application'
|
id 'application'
|
||||||
|
id 'com.adarshr.test-logger' version '1.6.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
def grpcVersion = '1.20.0'
|
def grpcVersion = '1.20.0'
|
||||||
|
|
@ -49,6 +50,25 @@ dependencies {
|
||||||
compile 'io.netty:netty-tcnative-boringssl-static:2.0.22.Final'
|
compile 'io.netty:netty-tcnative-boringssl-static:2.0.22.Final'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
testLogging.showStandardStreams = true
|
||||||
|
testLogging.exceptionFormat = 'full'
|
||||||
|
}
|
||||||
|
|
||||||
|
testlogger {
|
||||||
|
theme 'standard'
|
||||||
|
showExceptions true
|
||||||
|
slowThreshold 2000
|
||||||
|
showSummary true
|
||||||
|
showPassed true
|
||||||
|
showSkipped true
|
||||||
|
showFailed true
|
||||||
|
showStandardStreams false
|
||||||
|
showPassedStandardStreams true
|
||||||
|
showSkippedStandardStreams true
|
||||||
|
showFailedStandardStreams true
|
||||||
|
}
|
||||||
|
|
||||||
// Define the main class for the application
|
// Define the main class for the application
|
||||||
mainClassName = 'JobServ.JobServClient'
|
mainClassName = 'JobServ.JobServClient'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,25 +32,17 @@ public class JobServServer {
|
||||||
private static final Logger logger = Logger.getLogger(JobServServer.class.getName());
|
private static final Logger logger = Logger.getLogger(JobServServer.class.getName());
|
||||||
|
|
||||||
private Server server;
|
private Server server;
|
||||||
private final int port;
|
|
||||||
private final SslContext ssl;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor
|
* Constructor
|
||||||
* Sets port and builds sslContext
|
* builds server object
|
||||||
*/
|
*/
|
||||||
public JobServServer(int port,
|
public JobServServer(SslContext ssl, int port) throws IOException {
|
||||||
String serverCert,
|
this.server = NettyServerBuilder.forPort(port)
|
||||||
String privateKey,
|
.addService(new ShellServerService())
|
||||||
String trustStore) throws SSLException {
|
.sslContext(ssl)
|
||||||
this.port = port;
|
.build()
|
||||||
SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(new File(serverCert), new File(privateKey));
|
.start();
|
||||||
|
|
||||||
// Mutual TLS trust store and require client auth
|
|
||||||
sslContextBuilder.trustManager(new File(trustStore));
|
|
||||||
sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
|
||||||
|
|
||||||
this.ssl = GrpcSslContexts.configure(sslContextBuilder).build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -59,11 +51,7 @@ public class JobServServer {
|
||||||
*/
|
*/
|
||||||
private void start() throws IOException {
|
private void start() throws IOException {
|
||||||
// TODO: this should be passed in from a configuration manager
|
// TODO: this should be passed in from a configuration manager
|
||||||
server = NettyServerBuilder.forPort(port)
|
server.start();
|
||||||
.addService(new ShellServerService())
|
|
||||||
.sslContext(this.ssl)
|
|
||||||
.build()
|
|
||||||
.start();
|
|
||||||
logger.info("Server initialized!");
|
logger.info("Server initialized!");
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
|
@ -112,7 +100,14 @@ public class JobServServer {
|
||||||
JobServServer server;
|
JobServServer server;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server = new JobServServer(Integer.parseInt(args[0]), args[1], args[2], args[3]);
|
SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(new File(args[1]), new File(args[2]));
|
||||||
|
|
||||||
|
// Mutual TLS trust store and require client auth
|
||||||
|
sslContextBuilder.trustManager(new File(args[3]));
|
||||||
|
sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
||||||
|
|
||||||
|
server = new JobServServer(GrpcSslContexts.configure(sslContextBuilder).build(),
|
||||||
|
Integer.parseInt(args[0]));
|
||||||
|
|
||||||
} catch (InputMismatchException e) {
|
} catch (InputMismatchException e) {
|
||||||
System.out.println("Invalid port!");
|
System.out.println("Invalid port!");
|
||||||
|
|
@ -121,9 +116,12 @@ public class JobServServer {
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
server.start();
|
} catch (IOException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
server.blockUntilShutdown();
|
server.blockUntilShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package JobServ;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.AdditionalAnswers.delegatesTo;
|
import static org.mockito.AdditionalAnswers.delegatesTo;
|
||||||
|
|
@ -17,8 +18,9 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import io.grpc.ManagedChannel;
|
import io.grpc.ManagedChannel;
|
||||||
import io.grpc.inprocess.InProcessChannelBuilder;
|
import io.grpc.netty.NettyChannelBuilder;
|
||||||
import io.grpc.inprocess.InProcessServerBuilder;
|
import io.grpc.StatusRuntimeException;
|
||||||
|
import io.grpc.ManagedChannelBuilder;
|
||||||
import io.grpc.stub.StreamObserver;
|
import io.grpc.stub.StreamObserver;
|
||||||
import io.grpc.testing.GrpcCleanupRule;
|
import io.grpc.testing.GrpcCleanupRule;
|
||||||
import io.grpc.netty.GrpcSslContexts;
|
import io.grpc.netty.GrpcSslContexts;
|
||||||
|
|
@ -28,7 +30,7 @@ import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import io.netty.handler.ssl.SslProvider;
|
import io.netty.handler.ssl.SslProvider;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
@ -46,43 +48,39 @@ import org.mockito.ArgumentMatchers;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class JobServerAuthenticationTest {
|
public class JobServerAuthenticationTest {
|
||||||
|
|
||||||
|
private final String projectRoot = "";
|
||||||
|
|
||||||
// Authorized client key/cert/ca
|
// Authorized client key/cert/ca
|
||||||
private final String clientCa = "resources/client/ca.crt";
|
private final String clientCa = projectRoot + "resources/client/ca.crt";
|
||||||
private final String clientKey = "resources/client/private.pem";
|
private final String clientKey = projectRoot + "resources/client/private.pem";
|
||||||
private final String clientCert = "resources/client/client.crt";
|
private final String clientCert = projectRoot + "resources/client/client.crt";
|
||||||
|
|
||||||
// Authorized server key/cert/ca
|
// Authorized server key/cert/ca
|
||||||
private final String serverCa = "resources/server/ca.crt";
|
private final String serverCa = projectRoot + "resources/server/ca.crt";
|
||||||
private final String serverKey = "resources/server/private.pem";
|
private final String serverKey = projectRoot + "resources/server/private.pem";
|
||||||
private final String serverCert = "resources/server/server.crt";
|
private final String serverCert = projectRoot + "resources/server/server.crt";
|
||||||
|
|
||||||
// controlled failure key/cert/ca
|
// controlled failure key/cert/ca
|
||||||
private final String badCa = "resources/test/ca.crt";
|
private final String badCa = projectRoot + "resources/test/ca.crt";
|
||||||
private final String badKey = "resources/test/private.pem";
|
private final String badKey = projectRoot + "resources/test/private.pem";
|
||||||
private final String badCert = "resources/test/test.crt";
|
private final String badCert = projectRoot + "resources/test/test.crt";
|
||||||
|
|
||||||
// Automates (graceful) shutdown at end of tests
|
|
||||||
@Rule
|
|
||||||
public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
|
|
||||||
|
|
||||||
private final ShellServerGrpc.ShellServerImplBase serviceImpl= mock(ShellServerGrpc.ShellServerImplBase.class,
|
|
||||||
delegatesTo(new ShellServerGrpc.ShellServerImplBase() {}));
|
|
||||||
|
|
||||||
// badClient uses unauthorized certs
|
// badClient uses unauthorized certs
|
||||||
private JobServClient goodClient;
|
private JobServClient goodClient;
|
||||||
private JobServClient badClient;
|
private JobServClient badClient;
|
||||||
|
private JobServServer server;
|
||||||
|
|
||||||
// was setUp able to use SSL Certs
|
// was setUp able to use SSL Certs
|
||||||
private Boolean serverSslInitialized;
|
private Boolean serverSslInitialized = true;
|
||||||
private Boolean clientSslInitialized;
|
private Boolean clientSslInitialized = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setUp()
|
* test constructor
|
||||||
* generates both clients and the server
|
* generates both clients and the server
|
||||||
*/
|
*/
|
||||||
@Before
|
public JobServerAuthenticationTest() throws Exception {
|
||||||
public void setUp() throws Exception {
|
|
||||||
String serverName = InProcessServerBuilder.generateName();
|
System.out.println("Ctrl print");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// generate SSL contexts
|
// generate SSL contexts
|
||||||
|
|
@ -91,42 +89,38 @@ public class JobServerAuthenticationTest {
|
||||||
serverContextBuilder.trustManager(new File(clientCa));
|
serverContextBuilder.trustManager(new File(clientCa));
|
||||||
serverContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
serverContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
||||||
|
|
||||||
grpcCleanup.register(InProcessServerBuilder.forName(serverName)
|
this.server = new JobServServer(GrpcSslContexts.configure(serverContextBuilder).build(), 8448);
|
||||||
.sslContext(serverContextBuilder.build())
|
|
||||||
.directExecutor()
|
|
||||||
.addService(this.serviceImpl)
|
|
||||||
.build().start());
|
|
||||||
|
|
||||||
this.serverSslInitialized = true;
|
this.serverSslInitialized = true;
|
||||||
|
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
// One of the certs or keys was bad, ssl cannot be used
|
|
||||||
this.serverSslInitialized = false;
|
this.serverSslInitialized = false;
|
||||||
grpcCleanup.register(InProcessServerBuilder.forName(serverName)
|
System.err.println(e.getMessage());
|
||||||
.directExecutor()
|
|
||||||
.addService(this.serviceImpl).build().start());
|
} catch (IOException e) {
|
||||||
|
this.serverSslInitialized = false;
|
||||||
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate ssl for clients
|
// generate ssl for clients
|
||||||
if (this.serverSslInitialized) {
|
if (this.serverSslInitialized) {
|
||||||
try {
|
try {
|
||||||
SslContextBuilder goodClientBuilder = SslContextBuilder.forClient();
|
SslContextBuilder goodClientBuilder = GrpcSslContexts.forClient();
|
||||||
goodClientBuilder.trustManager(new File(serverCa));
|
goodClientBuilder.trustManager(new File(serverCa));
|
||||||
goodClientBuilder.keyManager(new File(clientCert), new File(clientKey));
|
goodClientBuilder.keyManager(new File(clientCert), new File(clientKey));
|
||||||
|
|
||||||
SslContextBuilder badClientBuilder = SslContextBuilder.forClient();
|
SslContextBuilder badClientBuilder = GrpcSslContexts.forClient();
|
||||||
badClientBuilder.trustManager(new File(serverCa));
|
badClientBuilder.trustManager(new File(serverCa));
|
||||||
badClientBuilder.keyManager(new File(badCert), new File(badKey));
|
badClientBuilder.keyManager(new File(badCert), new File(badKey));
|
||||||
|
|
||||||
ManagedChannel goodChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName)
|
ManagedChannel goodChannel = NettyChannelBuilder.forAddress("localhost", 8448)
|
||||||
.sslContext(goodClientBuilder.build())
|
.sslContext(goodClientBuilder.build())
|
||||||
.directExecutor()
|
.directExecutor()
|
||||||
.build());
|
.build();
|
||||||
|
|
||||||
ManagedChannel badChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName)
|
ManagedChannel badChannel = NettyChannelBuilder.forAddress("localhost", 8448)
|
||||||
.sslContext(badClientBuilder.build())
|
.sslContext(badClientBuilder.build())
|
||||||
.directExecutor()
|
.directExecutor()
|
||||||
.build());
|
.build();
|
||||||
|
|
||||||
goodClient = new JobServClient(goodChannel);
|
goodClient = new JobServClient(goodChannel);
|
||||||
badClient = new JobServClient(badChannel);
|
badClient = new JobServClient(badChannel);
|
||||||
|
|
@ -134,53 +128,29 @@ public class JobServerAuthenticationTest {
|
||||||
|
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
this.clientSslInitialized = false;
|
this.clientSslInitialized = false;
|
||||||
ManagedChannel nonSslChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName)
|
System.err.println(e.getMessage());
|
||||||
.directExecutor()
|
|
||||||
.build());
|
|
||||||
goodClient = new JobServClient(nonSslChannel);
|
|
||||||
badClient = null; //
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.clientSslInitialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Server TLS Test
|
* TLS Cert Auth Test
|
||||||
* fails if server SslContext generation threw an SSLException
|
* this needed to be one test because running multiple tests at the same time
|
||||||
|
* fails as the server tries to rebind to the same port.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void serverTlsTest() {
|
public void certificateAuthenticationTest() {
|
||||||
assertEquals(this.serverSslInitialized, true);
|
assertEquals(true, serverSslInitialized);
|
||||||
}
|
assertEquals(true, clientSslInitialized);
|
||||||
|
|
||||||
/*
|
|
||||||
* Client TLS Test
|
|
||||||
* fails if client SslContext generation threw an SSL Exception
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void clientTlsTest() {
|
|
||||||
assertEquals(this.clientSslInitialized, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TLS Cert Auth Negative Test
|
|
||||||
* fails if badClient can successfully make requests of the server
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void certAuthNegTest() {
|
|
||||||
assertEquals(clientSslInitialized, true);
|
|
||||||
int result = badClient.sendNewJobMessage("test command");
|
int result = badClient.sendNewJobMessage("test command");
|
||||||
assertEquals(result, -2);
|
assertEquals(-2, result);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
result = goodClient.sendNewJobMessage("test command");
|
||||||
* TLS Cert Auth Positive Test
|
|
||||||
* fails if goodClient cannot make requests of the server
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void certAuthPosTest() {
|
|
||||||
assertEquals(clientSslInitialized, true);
|
|
||||||
int result = goodClient.sendNewJobMessage("test command");
|
|
||||||
Boolean assertCondition = result == -2;
|
Boolean assertCondition = result == -2;
|
||||||
assertEquals(result, false);
|
assertEquals(assertCondition, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue