From 77e0cb3450fbfda282851f43d8e2b8e60b62e7da Mon Sep 17 00:00:00 2001 From: Aidan Hahn Date: Tue, 21 May 2019 13:25:50 -0700 Subject: [PATCH] added tests for TLS Authentication --- src/main/java/JobServ/JobServClient.java | 4 +- .../JobServ/JobServerAuthenticationTest.java | 182 ++++++++++++++++++ .../JobServ/JobServerAuthenticationTest.java~ | 27 +++ 3 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/test/java/JobServ/JobServerAuthenticationTest.java create mode 100644 src/test/java/JobServ/JobServerAuthenticationTest.java~ diff --git a/src/main/java/JobServ/JobServClient.java b/src/main/java/JobServ/JobServClient.java index be67d06..cb7751e 100644 --- a/src/main/java/JobServ/JobServClient.java +++ b/src/main/java/JobServ/JobServClient.java @@ -105,6 +105,8 @@ public class JobServClient { * sendNewJobMessage() * sends a shell command to the api server * returns new pid of job + * or -1 if server failed to create job + * or -2 if failed to connect to API */ public int sendNewJobMessage(String command) { // thought of escaping this, but the vulnerability is only client side, from client user input. @@ -120,7 +122,7 @@ public class JobServClient { response = blockingStub.newJob(request); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "(API Failure) Request for new job failed: " + e.getStatus()); - return -1; + return -2; } if(response.getPid() == -1) { diff --git a/src/test/java/JobServ/JobServerAuthenticationTest.java b/src/test/java/JobServ/JobServerAuthenticationTest.java new file mode 100644 index 0000000..1388899 --- /dev/null +++ b/src/test/java/JobServ/JobServerAuthenticationTest.java @@ -0,0 +1,182 @@ +/* + * JobServerAuthenticationTest + * + * v1.0 + * + * May 21, 2019 + */ + +package JobServ; + +import static org.junit.Assert.assertEquals; +import static org.mockito.AdditionalAnswers.delegatesTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.grpc.ManagedChannel; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import io.grpc.netty.GrpcSslContexts; + +import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; + +/* + * JobServerAuthenticationTest + * Creates a client using authorized certs and another one using unauthorized certs + * Ensures only the client with authorized certs can connect to the server. + * For more information on the hardcoded paths check buildwrapper.sh + */ + +@RunWith(JUnit4.class) +public class JobServerAuthorizationTest { + + // Authorized client key/cert/ca + private final String clientCa = "resources/client/ca.crt"; + private final String clientKey = "resources/client/private.pem"; + private final String clientCert = "resources/client/client.crt"; + + // Authorized server key/cert/ca + private final String serverCa = "resources/server/ca.crt"; + private final String serverKey = "resources/server/private.pem"; + private final String serverCert = "resources/server/server.crt"; + + // controlled failure key/cert/ca + private final String badCa = "resources/test/ca.crt"; + private final String badKey = "resources/test/private.pem"; + private final String badCert = "resources/test/test.crt"; + + // Automates (graceful) shutdown at end of tests + @Rule + public final GrpcCleanupRule grpcCleanup = newCleanupRule(); + + private final ShellServerGrpc.ShellServerImplBase = mock(ShellServerGrpc.ShellServerImplBase.class, + delegatesTo(new ShellServerGrpc.ShellServerImplBase() {})); + + // badClient uses unauthorized certs + private JobServClient goodClient; + private JobServClient badClient; + + // was setUp able to use SSL Certs + private Boolean serverSslInitialized; + private Boolean clientSslInitialized; + + /* + * setUp() + * generates both clients and the server + */ + @Before + public void setUp() throws Exception { + String serverName = InProcessServerBuilder.generateName(); + + try { + // generate SSL contexts + SslContextBuilder serverContextBuilder = SslContextBuilder.forServer(new File(serverCert), + new File(serverKey)); + serverContextBuilder.trustManager(new File(clientCa)); + serverContextBuilder.clientAuth(ClientAuth.REQUIRE); + + grpcCleanup.register(InProcessServerBuilder.forName(serverName) + .sslContext(serverContextBuilder.build()) + .directExecutor() + .addService(this.serviceImpl); + .build().start()); + + this.serverSslInitialized = true; + + } catch (SSLException e) { + // One of the certs or keys was bad, ssl cannot be used + this.serverSslInitialized = false; + grpcCleanup.register(InProcessServerBuilder.forName(serverName) + .directExecutor() + .addService(this.serviceImpl).build().start()); + } + + // generate ssl for clients + if (this.serverSslInitialized) { + try { + SslContextBuilder goodClientBuilder = SslContextBuilder.forClient(); + goodClientBuilder.trustManager(new File(serverCa)); + goodClientBuilder.keyManager(new File(clientCert), new File(clientKey)); + + SslContextBuilder badClientBuilder = SslContextBuilder.forClient(); + badClientBuilder.trustManager(new File(serverCa)); + badClientBuilder.keyManager(new File(badCert), new File(badKey)); + + ManagedChannel goodChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName) + .sslContext(goodClientBuilder.build()) + .directExecutor() + .build()); + + ManagedChannel badChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName) + .sslContext(badClientBuilder.build()) + .directExecutor() + .build()); + + goodClient = new JobServClient(goodChannel); + badClient = new JobServClient(badChannel); + this.clientSslInitialized = true; + + } catch (SSLException e) { + this.clientSslInitialized = false; + ManagedChannel nonSslChannel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName) + .directExecutor() + .build()); + goodClient = new JobServClient(nonSslChannel); + badClient = null; // + } + } + } + + /* + * Server TLS Test + * fails if server SslContext generation threw an SSLException + */ + @Test + public void serverTlsTest() { + assertEquals(this.serverSslInitialized, true); + } + + /* + * 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"); + assertEquals(result, -2); + } + + /* + * 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"); + assertNotEquals(result, -2); + } +} diff --git a/src/test/java/JobServ/JobServerAuthenticationTest.java~ b/src/test/java/JobServ/JobServerAuthenticationTest.java~ new file mode 100644 index 0000000..c289791 --- /dev/null +++ b/src/test/java/JobServ/JobServerAuthenticationTest.java~ @@ -0,0 +1,27 @@ +/* + * JobServerAuthenticationTest + * + * v1.0 + * + * May 21, 2019 + */ + +package JobServ; + +import static org.junit.Assert.assertEquals; +import static org.mockito.AdditionalAnswers.delegatesTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.grpc.ManagedChannel; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; \ No newline at end of file