From e05524d6b064ce0018ed9754f66c1d01b219e230 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 15:18:51 +0100 Subject: [PATCH 01/18] adding command line args and tests --- .../grpc/polyglot/config/CommandLineArgs.java | 50 +++++++++++++++++++ .../polyglot/config/ConfigurationLoader.java | 23 +++++++++ .../oauth2/RefreshTokenCredentials.java | 4 +- .../polyglot/config/CommandLineArgsTest.java | 38 ++++++++++++++ .../config/ConfigurationLoaderTest.java | 26 ++++++++++ 5 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index 986de84..9f45c8b 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -2,6 +2,8 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -47,6 +49,21 @@ public class CommandLineArgs { @Option(name = "--tls_ca_cert_path", metaVar = "") private String tlsCaCertPath; + @Option(name = "--oauth_refresh_token_endpoint_url", metaVar = "") + private String oauthRefreshTokenEndpointUrl; + + @Option(name = "--oauth_client_id", metaVar = "") + private String oauthClientId; + + @Option(name = "--oauth_client_secret", metaVar = "") + private String oauthClientSecret; + + @Option(name = "--oauth_refresh_token_path", metaVar = "") + private String oauthRefreshTokenPath; + + @Option(name = "--oauth_access_token_path", metaVar = "") + private String oauthAccessTokenPath; + @Option(name = "--help") private Boolean help; @@ -153,6 +170,26 @@ public Optional tlsCaCertPath() { return maybePath(tlsCaCertPath); } + public Optional oauthRefreshTokenEndpointUrl() { + return maybeUrl(oauthRefreshTokenEndpointUrl); + } + + public Optional oauthClientId() { + return Optional.ofNullable(oauthClientId); + } + + public Optional oauthClientSecret() { + return Optional.ofNullable(oauthClientSecret); + } + + public Optional oauthRefreshTokenPath() { + return maybePath(oauthRefreshTokenPath); + } + + public Optional oauthAccessTokenPath() { + return maybePath(oauthAccessTokenPath); + } + /** * First stage of a migration towards a "command"-based instantiation of polyglot. * Supported commands: @@ -214,4 +251,17 @@ private static Optional maybePath(String rawPath) { Preconditions.checkArgument(Files.exists(path), "File " + rawPath + " does not exist"); return Optional.of(Paths.get(rawPath)); } + + private static Optional maybeUrl(String rawUrl) { + if (rawUrl == null) { + return Optional.empty(); + } + try { + URL url = new URL(rawUrl); + return Optional.of(url); + } catch (MalformedURLException mURLE) { + throw new IllegalArgumentException("URL " + rawUrl +" is invalid", mURLE); + } + + } } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index 8dd9f16..ec01e04 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -131,6 +131,29 @@ private Configuration applyOverrides(Configuration configuration) { resultBuilder.getCallConfigBuilder().setTlsCaCertPath( overrides.get().tlsCaCertPath().get().toString()); } + if (overrides.get().oauthRefreshTokenEndpointUrl().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); + } + if (overrides.get().oauthClientId().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .getClientBuilder().setId(overrides.get().oauthClientId().get()); + } + if (overrides.get().oauthClientSecret().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); + } + if (overrides.get().oauthRefreshTokenPath().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); + } + // Note the ordering of setting these fields is important. Oauth configuration has a oneof field, corresponding + // to access or refresh tokens. We want access tokens to take precedence, setting this field last will ensure this + // occurs. See https://developers.google.com/protocol-buffers/docs/proto#oneof + if (overrides.get().oauthAccessTokenPath().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getAccessTokenCredentialsBuilder() + .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); + } return resultBuilder.build(); } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java b/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java index b27b4e9..7140504 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java @@ -71,10 +71,10 @@ public AccessToken refreshAccessToken() throws IOException { logger.info("Refresh successful, got access token"); return new AccessToken( refreshResponse.getAccessToken(), - computeExpirtyDate(refreshResponse.getExpiresInSeconds())); + computeExpiryDate(refreshResponse.getExpiresInSeconds())); } - private Date computeExpirtyDate(long expiresInSeconds) { + private Date computeExpiryDate(long expiresInSeconds) { long expiresInSecondsWithMargin = (long) (expiresInSeconds * ACCESS_TOKEN_EXPIRY_MARGIN); return Date.from(clock.instant().plusSeconds(expiresInSecondsWithMargin)); } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java index e268b27..ba06dee 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java @@ -45,6 +45,44 @@ public void parsesAdditionalIncludesMulti() { assertThat(params.additionalProtocIncludes()).hasSize(1); } + @Test + public void parsesOauthRefreshTokenEndpointUrl() { + String url = "https://github.com/grpc-ecosystem/polyglot"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_refresh_token_endpoint_url=%s", url))); + assertThat(params.oauthRefreshTokenEndpointUrl().get().toString()).isEqualTo(url); + } + + @Test + public void parsesOauthClientId() { + String client_id = "client_id"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_client_id=%s",client_id))); + assertThat(params.oauthClientId().get()).isEqualTo(client_id); + } + + @Test + public void parsesOauthClientSecret() { + String client_secret = "client_secret"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_client_secret=%s", client_secret))); + assertThat(params.oauthClientSecret().get()).isEqualTo(client_secret); + } + + @Test + public void parsesOauthRefreshTokenPath() { + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); + assertThat(params.oauthRefreshTokenPath().get().toString()).isEqualTo(tempFile1.toString()); + } + + @Test + public void parsesOauthAccessTokenPath() { + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_access_token_path=%s", tempFile1.toString()))); + assertThat(params.oauthAccessTokenPath().get().toString()).isEqualTo(tempFile1.toString()); + } + private static CommandLineArgs parseArgs(ImmutableList args) { ImmutableList allArgs = ImmutableList.builder() .addAll(args) diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 3d8f5eb..9532924 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -1,7 +1,9 @@ package me.dinowernli.grpc.polyglot.config; +import java.net.MalformedURLException; import java.nio.file.Paths; import java.util.Optional; +import java.net.URL; import com.google.common.collect.ImmutableList; import me.dinowernli.junit.TestClass; @@ -17,6 +19,8 @@ import polyglot.ConfigProto.ConfigurationSet; import polyglot.ConfigProto.OutputConfiguration.Destination; +import javax.swing.text.html.Option; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; @@ -78,6 +82,11 @@ public void appliesOverrides() { when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); + when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); + when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); + when(mockOverrides.oauthRefreshTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.empty()); Configuration config = ConfigurationLoader .forDefaultConfigSet() @@ -88,6 +97,16 @@ public void appliesOverrides() { assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) + .isEqualTo("id"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) + .isEqualTo("secret"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) + .isNotEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) + .isEmpty(); } private static Configuration namedConfig(String name) { @@ -95,4 +114,11 @@ private static Configuration namedConfig(String name) { .setName(name) .build(); } + private static URL getTestUrl(String testUrl) { + try { + return new URL(testUrl); + } catch (MalformedURLException mUrlE) { + throw new RuntimeException(); + } + } } From 17991d572def997b1d303104d0daee87e6df17fd Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 15:50:22 +0100 Subject: [PATCH 02/18] adding access token test --- .../config/ConfigurationLoaderTest.java | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 9532924..fdd5f57 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -75,7 +75,7 @@ public void loadsNamedConfig() { } @Test - public void appliesOverrides() { + public void appliesOverridesWithRefreshToken() { when(mockOverrides.useTls()).thenReturn(Optional.of(true)); when(mockOverrides.outputFilePath()).thenReturn(Optional.of(Paths.get("asdf"))); when(mockOverrides.additionalProtocIncludes()).thenReturn(ImmutableList.of(Paths.get("."))); @@ -89,9 +89,9 @@ public void appliesOverrides() { when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.empty()); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getCallConfig().getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -109,6 +109,42 @@ public void appliesOverrides() { .isEmpty(); } + @Test + public void appliesOverridesWithAccessToken() { + when(mockOverrides.useTls()).thenReturn(Optional.of(true)); + when(mockOverrides.outputFilePath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.additionalProtocIncludes()).thenReturn(ImmutableList.of(Paths.get("."))); + when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); + when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); + when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); + when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); + when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); + when(mockOverrides.oauthRefreshTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + + Configuration config = ConfigurationLoader + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); + + assertThat(config.getCallConfig().getUseTls()).isTrue(); + assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); + assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); + assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); + // Setting the access token path will unset all of the refresh token properties + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) + .isNotEmpty(); + } + private static Configuration namedConfig(String name) { return Configuration.newBuilder() .setName(name) From 7fa9284d43fefac1622dfb96a6591a678e4e3a43 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 16:02:44 +0100 Subject: [PATCH 03/18] improving logging for case of no stdin --- .../java/me/dinowernli/grpc/polyglot/command/ServiceCall.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java b/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java index 54313b8..7ef76b0 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java @@ -71,6 +71,8 @@ public static void callEndpoint( dynamicClient = DynamicGrpcClient.create(methodDescriptor, hostAndPort, callConfig); } + logger.info("Reading input from stdin"); + ImmutableList requestMessages = MessageReader.forStdin(methodDescriptor.getInputType()).read(); StreamObserver streamObserver = From bdc040908472f0ac137648f1ae545cbe155be48c Mon Sep 17 00:00:00 2001 From: Paul Gross Date: Thu, 31 Aug 2017 00:28:15 +0000 Subject: [PATCH 04/18] Add client cert support Add three new options for specifying client cert authentication: --tls_client_cert_path --tls_client_key_path --tls_client_override_authority Update instructions and generate new test certificates, including a client cert. --- README.md | 3 + .../grpc/polyglot/config/CommandLineArgs.java | 27 +++++++- .../polyglot/config/ConfigurationLoader.java | 14 +++- .../grpc/polyglot/grpc/DynamicGrpcClient.java | 26 +++++--- .../grpc/polyglot/testing/TestServer.java | 21 ++++-- .../grpc/polyglot/testing/TestUtils.java | 10 +++ .../polyglot/testing/test-certificates/ca.pem | 20 +++--- .../testing/test-certificates/client.key | 16 +++++ .../testing/test-certificates/client.pem | 64 +++++++++++++++++++ .../testing/test-certificates/readme.txt | 19 ++++-- .../testing/test-certificates/server.key | 28 ++++---- .../testing/test-certificates/server.pem | 64 +++++++++---------- src/main/proto/config.proto | 7 +- .../config/ConfigurationLoaderTest.java | 6 ++ .../integration/TlsIntegrationTest.java | 27 +++++++- 15 files changed, 271 insertions(+), 81 deletions(-) create mode 100644 src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.key create mode 100644 src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.pem diff --git a/README.md b/README.md index 24dd452..3681ea4 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,9 @@ The general philosophy is for the configuration to drive Polyglot's behavior and Polyglot uses statically linked [boringssl](https://boringssl.googlesource.com/boringssl/) libraries under the hood and doesn't require the host machine to have any specific libraries. Whether or not the client uses TLS to talk to the server can be controlled using the `--use_tls` flag or the corresponding configuration entry. +Polyglot can also do client certificate authentication with the `--tls_client_cert_path` and `--tls_client_key_path` flags. If the hostname on the server does not match the endpoint (e.g. connecting +to `localhost`, but the server thinks it's `foo.example.com`), `--tls_client_override_authority=foo.example.com` can be used. + ### Authenticating requests using OAuth Polyglot has built-in support for authentication of requests using OAuth tokens in two ways: diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index 986de84..f8622f8 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -7,13 +7,13 @@ import java.nio.file.Paths; import java.util.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; - /** Provides easy access to the arguments passed on the command line. */ public class CommandLineArgs { @Option(name = "--full_method", metaVar = "") @@ -47,6 +47,15 @@ public class CommandLineArgs { @Option(name = "--tls_ca_cert_path", metaVar = "") private String tlsCaCertPath; + @Option(name = "--tls_client_cert_path", metaVar = "") + private String tlsClientCertPath; + + @Option(name = "--tls_client_key_path", metaVar = "") + private String tlsClientKeyPath; + + @Option(name = "--tls_client_override_authority", metaVar = "") + private String tlsClientOverrideAuthority; + @Option(name = "--help") private Boolean help; @@ -153,6 +162,18 @@ public Optional tlsCaCertPath() { return maybePath(tlsCaCertPath); } + public Optional tlsClientCertPath() { + return maybePath(tlsClientCertPath); + } + + public Optional tlsClientKeyPath() { + return maybePath(tlsClientKeyPath); + } + + public Optional tlsClientOverrideAuthority() { + return Optional.ofNullable(tlsClientOverrideAuthority); + } + /** * First stage of a migration towards a "command"-based instantiation of polyglot. * Supported commands: diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index 8dd9f16..e927912 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -129,7 +129,19 @@ private Configuration applyOverrides(Configuration configuration) { } if (overrides.get().tlsCaCertPath().isPresent()) { resultBuilder.getCallConfigBuilder().setTlsCaCertPath( - overrides.get().tlsCaCertPath().get().toString()); + overrides.get().tlsCaCertPath().get().toString()); + } + if (overrides.get().tlsClientCertPath().isPresent()) { + resultBuilder.getCallConfigBuilder().setTlsClientCertPath( + overrides.get().tlsClientCertPath().get().toString()); + } + if (overrides.get().tlsClientKeyPath().isPresent()) { + resultBuilder.getCallConfigBuilder().setTlsClientKeyPath( + overrides.get().tlsClientKeyPath().get().toString()); + } + if (overrides.get().tlsClientOverrideAuthority().isPresent()) { + resultBuilder.getCallConfigBuilder().setTlsClientOverrideAuthority( + overrides.get().tlsClientOverrideAuthority().get()); } return resultBuilder.build(); } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java b/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java index 6a0c0dd..49e564d 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java @@ -7,8 +7,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.Executors; -import javax.net.ssl.SSLException; - import com.google.auth.Credentials; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; @@ -21,6 +19,10 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.protobuf.Descriptors.MethodDescriptor; import com.google.protobuf.DynamicMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.ClientCall; @@ -34,9 +36,8 @@ import io.grpc.stub.StreamObserver; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; +import javax.net.ssl.SSLException; import me.dinowernli.grpc.polyglot.protobuf.DynamicMessageMarshaller; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import polyglot.ConfigProto.CallConfiguration; /** A grpc client which operates on dynamic messages. */ @@ -232,10 +233,15 @@ private static Channel createChannel(HostAndPort endpoint, CallConfiguration cal if (!callConfiguration.getUseTls()) { return createPlaintextChannel(endpoint); } - return NettyChannelBuilder.forAddress(endpoint.getHostText(), endpoint.getPort()) - .sslContext(createSslContext(callConfiguration)) - .negotiationType(NegotiationType.TLS) - .build(); + NettyChannelBuilder nettyChannelBuilder = NettyChannelBuilder.forAddress(endpoint.getHostText(), endpoint.getPort()) + .sslContext(createSslContext(callConfiguration)) + .negotiationType(NegotiationType.TLS); + + if (!callConfiguration.getTlsClientOverrideAuthority().isEmpty()) { + nettyChannelBuilder.overrideAuthority(callConfiguration.getTlsClientOverrideAuthority()); + } + + return nettyChannelBuilder.build(); } private static SslContext createSslContext(CallConfiguration callConfiguration) { @@ -243,6 +249,10 @@ private static SslContext createSslContext(CallConfiguration callConfiguration) if (!callConfiguration.getTlsCaCertPath().isEmpty()) { resultBuilder.trustManager(loadFile(callConfiguration.getTlsCaCertPath())); } + if (!callConfiguration.getTlsClientCertPath().isEmpty()) { + resultBuilder.keyManager(loadFile(callConfiguration.getTlsClientCertPath()), + loadFile(callConfiguration.getTlsClientKeyPath())); + } try { return resultBuilder.build(); } catch (SSLException e) { diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java index 75e74ca..40ffa87 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java @@ -5,10 +5,13 @@ import java.util.Random; import com.google.common.base.Throwables; + import io.grpc.Server; import io.grpc.netty.GrpcSslContexts; import io.grpc.netty.NettyServerBuilder; +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 polyglot.test.TestProto.TestResponse; import polyglot.test.TestServiceGrpc.TestServiceImplBase; @@ -101,13 +104,23 @@ public void blockingShutdown() { /** An {@link SslContext} for use in unit test servers. Loads our testing certificates. */ public static SslContext serverSslContextForTesting() throws IOException { - return GrpcSslContexts - .forServer(TestUtils.loadServerChainCert(), TestUtils.loadServerKey()) - .trustManager(TestUtils.loadRootCaCert()) - .sslProvider(SslProvider.OPENSSL) + return getSslContextBuilder().build(); + } + + /** An {@link SslContext} for use in unit test servers with client certs. Loads our testing certificates. */ + public static SslContext serverSslContextWithClientCertsForTesting() throws IOException { + return getSslContextBuilder() + .clientAuth(ClientAuth.REQUIRE) .build(); } + private static SslContextBuilder getSslContextBuilder() { + return GrpcSslContexts + .forServer(TestUtils.loadServerChainCert(), TestUtils.loadServerKey()) + .trustManager(TestUtils.loadRootCaCert()) + .sslProvider(SslProvider.OPENSSL); + } + /** Starts a grpc server on the given port, throws {@link IOException} on failure. */ private static Server tryStartServer( int port, diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestUtils.java b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestUtils.java index 558e4c5..ab6e381 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestUtils.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestUtils.java @@ -60,6 +60,16 @@ public static File loadRootCaCert() { return Paths.get(TESTING_CERTS_DIR.toString(), "ca.pem").toFile(); } + /** Returns a file containing a client certificate for use in tests. */ + public static File loadClientCert() { + return Paths.get(TESTING_CERTS_DIR.toString(), "client.pem").toFile(); + } + + /** Returns a file containing a client key for use in tests. */ + public static File loadClientKey() { + return Paths.get(TESTING_CERTS_DIR.toString(), "client.key").toFile(); + } + /** Returns a file containing a certificate chain from our testing root CA to our server. */ public static File loadServerChainCert() { return Paths.get(TESTING_CERTS_DIR.toString(), "server.pem").toFile(); diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/ca.pem b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/ca.pem index 715ca9c..c697b9f 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/ca.pem +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/ca.pem @@ -1,15 +1,15 @@ -----BEGIN CERTIFICATE----- -MIICZjCCAc+gAwIBAgIJAOsqHrpa5cF9MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV +MIICZjCCAc+gAwIBAgIJAJqx8JYIArI0MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNjA1MTUwOTIz -MDZaFw0yNjA1MTMwOTIzMDZaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l +aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNzA4MzEyMzM3 +MDNaFw0yNzA4MjkyMzM3MDNaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV -BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9T39HWNC -0r9NjD7wmFF6luJJ+NuWG0tuuZoGpbNldQpsZXlS0J/OwNAk+55p6it2Yr89jxM9 -Ea83oYTnjLuGQ/tJmUmPNau2Z4Q/M41000lD6Hd0Sxw7St2nLlgTOMRyEJEAaBBC -yKtHiq6cvu3UmNzY+jok5hmRjGlWHnNsWisCAwEAAaM2MDQwCQYDVR0TBAIwADAL +BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzroPZgt6 +jX0qwmuo5Y04J8eATK2Lq/ohFfI+LoaqXJ7nOrHViPLpQfqErtHCrcuOD++BcTJ4 +0iw6d0uwxTT0L73cfKI+1zJKcI6jAJ1a86kpYJVqNY5mIDqVXSP2/Ig6Q7I3qDOZ +RM/sNIypd56bQy8GmQYcL1ng1zqy1kBn4jsCAwEAAaM2MDQwCQYDVR0TBAIwADAL BgNVHQ8EBAMCBeAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3 -DQEBCwUAA4GBAJg2NDTZZB9Kl9mFgjIsL/M4dz/wspsGhwuglpOSwarFkKvSYkxD -61Ls4rp4qT5vEt0EJjksTsxNVdzR9DD0k+LENuEzM+VlzPaKoKrrZRZeiLYnfY28 -etxVuVVW78jd03rx+FpVOql+lKT1hnWn40IVLjLdT60shHfVt34Z6t98 +DQEBCwUAA4GBAAPiapcOh3JBfC6f7dkUAP9KDpNHK8JA1My4+CxkRyShC0rKf+K6 +3wRLLb6f9qyvs3FkSF5uTcD12Irj88SzlMPiu/civVv4ldY/5w1XKmh3BoWwe+cH +jaqPi0MX/uarPCgbgkt219INsBi/Sc8V8Yp1qjZp+pvJ0A80/XdD56/x -----END CERTIFICATE----- diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.key b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.key new file mode 100644 index 0000000..efa74b8 --- /dev/null +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALRoMQCMeQfDcMgk +rs1BREc+4EcGenojetkw10HJ5erZBM05PgdtDTkBT+QVrddVDmn0HUn6S5jZGZGe +NXPOwDoVBHTYdCDKRrnaBg8v8hB2pgMVUaw6idg4FlUbNlit7n07thhXEBGhhw7x +g7cjd8IsV8s1f84+7eC3H2ySVk8hAgMBAAECgYBEH0/ZoDGXj+JHgSqMkQeiS4jO +6RBYjIs39ixiSEXMX3RjtijJDxG+I9OyEcmaFSEjOy3QIHZpWhlAllgiycBly6zi +QjIrdIwTrQHDapxRotT6ap+76/ev1e6145wgyUetSCwzuXdjmP24ujG9coCIP5EB +Rcb5DO8QKZm1gOsgAQJBAOR/PHZSdTT3RsWBW2q03GA+sHpkjuiDaOek7rWJf3U6 +ptZCHjt28VFJa9qDqLKzdcvltqpT+IyskAOrNnyf7CECQQDKHyO5YnEjgMAAnFM6 +3wsm6u+B1ru7UUKOhAr/n+nfSd775A1qF6wQ9YGoHFUHt3k4TjzRWNilQC0jsfUn +sgMBAkAfOM+PL2c6jItME4flRb9TG13L64+nb8VW2a+QeLBE2XXQkwpEf9UrkUe+ +fP0BJgpziPjzvzOYLUAkcDGqx8NhAkEAnOGWpOnXzyq73L15jJRa35Yy2KCHjlkA +RAYRU2AX8wwvW2wjTVmaYH9uZ8G17gtmt2Fiq0s+vOUXJEGYe3scAQJBALmnIp1R +JsAPzxaMa4pJkciHxyZyfH7roLwVUxT3Af+bWPyjOffR7lx9nzsbYf0UuTbiMfEp +YHvy7BUwpIerndI= +-----END PRIVATE KEY----- diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.pem b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.pem new file mode 100644 index 0000000..22580e4 --- /dev/null +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/client.pem @@ -0,0 +1,64 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost + Validity + Not Before: Aug 31 23:37:41 2017 GMT + Not After : Aug 29 23:37:41 2027 GMT + Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost-client + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:b4:68:31:00:8c:79:07:c3:70:c8:24:ae:cd:41: + 44:47:3e:e0:47:06:7a:7a:23:7a:d9:30:d7:41:c9: + e5:ea:d9:04:cd:39:3e:07:6d:0d:39:01:4f:e4:15: + ad:d7:55:0e:69:f4:1d:49:fa:4b:98:d9:19:91:9e: + 35:73:ce:c0:3a:15:04:74:d8:74:20:ca:46:b9:da: + 06:0f:2f:f2:10:76:a6:03:15:51:ac:3a:89:d8:38: + 16:55:1b:36:58:ad:ee:7d:3b:b6:18:57:10:11:a1: + 87:0e:f1:83:b7:23:77:c2:2c:57:cb:35:7f:ce:3e: + ed:e0:b7:1f:6c:92:56:4f:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Key Identifier: + E2:53:8F:A6:30:9A:43:C6:24:84:5A:FB:4D:8F:9D:5B:C8:24:28:F8 + X509v3 Authority Key Identifier: + DirName:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=localhost + serial:9A:B1:F0:96:08:02:B2:34 + + X509v3 Issuer Alternative Name: + DNS:localhost, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 4f:a3:04:df:c8:bc:7e:b1:76:a1:5f:8a:35:61:78:60:4b:a5: + 7a:7f:78:91:59:6f:d9:cb:4c:34:8f:b7:b7:dc:53:46:a3:4e: + 08:e4:6b:33:ab:1b:ec:b9:f3:68:34:7d:c1:10:21:66:fd:41: + ef:56:98:9b:bb:d7:1d:ce:6e:ac:55:23:78:05:99:0f:f3:8a: + df:67:28:9c:4b:2f:b1:6f:b7:eb:16:b3:0b:e0:81:ea:f6:fe: + 1d:a6:e5:66:fe:ab:6a:e3:e8:a5:a1:3d:4a:c0:47:4c:bb:6d: + 4f:68:96:88:fe:93:90:77:c0:12:5a:b9:ea:2a:fa:9c:4d:85: + 46:33 +-----BEGIN CERTIFICATE----- +MIIC+zCCAmSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTcwODMxMjMzNzQxWhcNMjcw +ODI5MjMzNzQxWjBgMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRkwFwYDVQQDDBBsb2Nh +bGhvc3QtY2xpZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0aDEAjHkH +w3DIJK7NQURHPuBHBnp6I3rZMNdByeXq2QTNOT4HbQ05AU/kFa3XVQ5p9B1J+kuY +2RmRnjVzzsA6FQR02HQgyka52gYPL/IQdqYDFVGsOonYOBZVGzZYre59O7YYVxAR +oYcO8YO3I3fCLFfLNX/OPu3gtx9sklZPIQIDAQABo4HLMIHIMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgMB0GA1UdDgQWBBTiU4+mMJpDxiSEWvtNj51byCQo+DBzBgNV +HSMEbDBqoV2kWzBZMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2Nh +bGhvc3SCCQCasfCWCAKyNDAaBgNVHRIEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJ +KoZIhvcNAQELBQADgYEAT6ME38i8frF2oV+KNWF4YEulen94kVlv2ctMNI+3t9xT +RqNOCORrM6sb7LnzaDR9wRAhZv1B71aYm7vXHc5urFUjeAWZD/OK32conEsvsW+3 +6xazC+CB6vb+HablZv6rauPopaE9SsBHTLttT2iWiP6TkHfAElq56ir6nE2FRjM= +-----END CERTIFICATE----- diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/readme.txt b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/readme.txt index 00e6738..96bc506 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/readme.txt +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/readme.txt @@ -2,11 +2,13 @@ The required files for the tests are: * ca.pem * server.pem * server.key +* client.pem +* client.key Generating these files requires only: * openssl.cnf -In order to generate the three files above from "openssl.cnf", do the following: +In order to generate the files above from "openssl.cnf", do the following: 1) openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config openssl.cnf -days 3650 -extensions v3_req @@ -18,7 +20,14 @@ all default, except common name: "localhost" all default, except common name: "localhost" -5) mv privkey.pem ca.key -6) touch index.txt -7) echo "01" > serial -8) openssl ca -in server.csr -out server.pem -keyfile ca.key -cert ca.pem -verbose -config openssl.cnf -days 3650 -updatedb +5) openssl genrsa -out client.key.rsa 1024 +6) openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt +7) openssl req -new -key client.key -out client.csr + +all default, except common name: "localhost-client" + +8) mv privkey.pem ca.key +9) touch index.txt +10) echo "01" > serial +11) openssl ca -in server.csr -out server.pem -keyfile ca.key -cert ca.pem -verbose -config openssl.cnf -days 3650 -batch +12) openssl ca -in client.csr -out client.pem -keyfile ca.key -cert ca.pem -verbose -config openssl.cnf -days 3650 -batch diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.key b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.key index eb3df9e..7343c9d 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.key +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.key @@ -1,16 +1,16 @@ -----BEGIN PRIVATE KEY----- -MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANi3NkLfK5HWIWDb -1JH0pCZUm5vwrFtUByBC6mpiShDMkD9/SkzmTPYFWVEgxqs9n3On6VrnUMHb0zIw -TsZTNhSCcSq1aWuQLIaXwxilaWKLq0p3BBH/j8IRmWeKiP00G1yXG+0lPAGPL3qy -SVDEpTP8lpnY8Oq+SRoKmLfrk7ElAgMBAAECgYB17DOlbaRapcbh2pyvkwwjI1TN -JMfUpkN+ZYsCulsNCxLOymfWslZcZIq2X3xbP5vdJhgPc+D4q7IfFDQ5LJw2yhpR -mgsv1lro4BVmsKvjvC10BdbWhhXVdlv345ySxwW30cMZcRFlSusRfu16GAkWosqD -qc85VaNbKZpok7hUvQJBAPgJJpdK/olfSIXfxoM4J3JbGKsgWI25y7KAJgOfBD+o -UgZGBDMWODuXpsJNHiNgkKMy2lKLyHEBKvHRmYS9V8cCQQDfrJxcc/85a66f+zwY -Kqql/GVfldjdzubbXcDhXpwAKy0kZQJHQnLMncpYwjU/Gukc3WcJscmH6z5vqjHG -sCezAkBZzH5TQgx7UarhBQ5KzZbCeSaqNfC5hu2vd2PL5dNU9KyVpt24XTAIqzPt -npvttPVIkI2oWwE7oG+a0wagnyhbAkEAoFHaaTIDV6blLWooMrIySnLUPmTrYmCw -e7+BRohHjJ9l5dY4gdcQ7bSTmnbpL2gcekH/XqV969wjjmoQ73bHnQJAO2tr4zrR -fICKQA+i7ARPMwlLZvHgIY1gTrgk5/1CpkZCBf9pVxeMUqNWZQrKhKOWnBSqXd7X -lzYGTbGfiTd+7g== +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMxSJo9P48u4mDxI +m+D+C/ad3ZClg6IUO0VbzMtuxBVwAk1SMFusPZzwyKMJYar7qRwB5+pLuXRK8vE/ +0S6SoBZvQaKP5364y7qwCbLC8gf8OKvexKIgVybRKHZIkdacaE1Cuq0QgVzu0w/T +shmJwIa/erG7f2C/LKy0ClvADek7AgMBAAECgYAT7MLz4M+PE05NOqtw0nVqNFTi +ATIIAT8ScXRUNlYK3SRsU+KBXheYEWcPdx++I9KG96ydDYtlStXMLvQAPa48tTIU +yI9T2/CFez1a/ZaDPXDqhHTPSUhSENU9yBlyA/Zb4zMRuiCGm5rHwf+aoU7P2UHW +zn5O/RtiDSSiOQn8SQJBAO48yGEuwh3kyxBLzw+uq9xIDpkGxV9cowXhNXoftm+7 +iG6r9pc5PVTdLDw/8bdoA9SbXHcpwz4LqlOqvtU7I78CQQDbjgGIPjpKiKqoFHtl +VVofsXy7VXxf5dTxKMkk/5mb5XRfdIn2m5yIKPJC1RwMcySAfst1uCJvSfsGa2o4 +FWmFAkEAn5RxeL90YcfOyaSuF0gecJiHxrNFZEJOJPMc+ifh8WgB1Hg13kgGMCFS +ryz6AauX3UMQJfYAhUAVIKQf3f8WSwJBAMymcYcteeg/u9MwRFUQWhFwv3NfG6/H +69Vezx9NoUFPgEn5tx/HrQC+KhNh0eNI8J1VkxEHshFKRFKXjUr5qoECQQCyOtfU +VAJBWi31jHil8UXryxUVWYCTzuNAM6acRaBJd3sHei+4PzzGqh7I7Us0kNoGNQFK +ymC8EYUIcFtqLSly -----END PRIVATE KEY----- diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.pem b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.pem index be425c2..68a686c 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.pem +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/test-certificates/server.pem @@ -5,22 +5,22 @@ Certificate: Signature Algorithm: sha256WithRSAEncryption Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost Validity - Not Before: May 15 09:30:44 2016 GMT - Not After : May 13 09:30:44 2026 GMT + Not Before: Aug 31 23:37:36 2017 GMT + Not After : Aug 29 23:37:36 2027 GMT Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: - 00:d8:b7:36:42:df:2b:91:d6:21:60:db:d4:91:f4: - a4:26:54:9b:9b:f0:ac:5b:54:07:20:42:ea:6a:62: - 4a:10:cc:90:3f:7f:4a:4c:e6:4c:f6:05:59:51:20: - c6:ab:3d:9f:73:a7:e9:5a:e7:50:c1:db:d3:32:30: - 4e:c6:53:36:14:82:71:2a:b5:69:6b:90:2c:86:97: - c3:18:a5:69:62:8b:ab:4a:77:04:11:ff:8f:c2:11: - 99:67:8a:88:fd:34:1b:5c:97:1b:ed:25:3c:01:8f: - 2f:7a:b2:49:50:c4:a5:33:fc:96:99:d8:f0:ea:be: - 49:1a:0a:98:b7:eb:93:b1:25 + 00:cc:52:26:8f:4f:e3:cb:b8:98:3c:48:9b:e0:fe: + 0b:f6:9d:dd:90:a5:83:a2:14:3b:45:5b:cc:cb:6e: + c4:15:70:02:4d:52:30:5b:ac:3d:9c:f0:c8:a3:09: + 61:aa:fb:a9:1c:01:e7:ea:4b:b9:74:4a:f2:f1:3f: + d1:2e:92:a0:16:6f:41:a2:8f:e7:7e:b8:cb:ba:b0: + 09:b2:c2:f2:07:fc:38:ab:de:c4:a2:20:57:26:d1: + 28:76:48:91:d6:9c:68:4d:42:ba:ad:10:81:5c:ee: + d3:0f:d3:b2:19:89:c0:86:bf:7a:b1:bb:7f:60:bf: + 2c:ac:b4:0a:5b:c0:0d:e9:3b Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: @@ -28,37 +28,37 @@ Certificate: X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment X509v3 Subject Key Identifier: - F0:04:D5:DC:B2:06:D6:C4:30:75:A3:E5:73:0F:99:88:7D:DF:D5:2A + DA:88:D3:69:24:78:C9:79:E6:D4:36:21:2E:0A:B4:AC:C6:11:85:F3 X509v3 Authority Key Identifier: DirName:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=localhost - serial:EB:2A:1E:BA:5A:E5:C1:7D + serial:9A:B1:F0:96:08:02:B2:34 X509v3 Issuer Alternative Name: DNS:localhost, IP Address:127.0.0.1 Signature Algorithm: sha256WithRSAEncryption - 32:94:72:6c:56:db:26:dc:89:cd:aa:46:c5:e0:8f:53:62:5e: - 65:d4:40:51:d0:5a:3a:a0:49:54:60:d0:0d:60:4b:0c:19:92: - 9c:70:e6:cc:97:3f:ed:0e:12:5d:e9:56:86:6a:09:20:0f:69: - ed:3d:e7:8b:9f:59:3d:24:cd:f2:c4:5e:98:a4:24:66:84:89: - f2:23:0e:45:62:79:ef:0f:a6:93:cd:df:f4:20:53:29:5c:bc: - 7d:8b:6d:71:3d:e0:09:a2:53:47:fe:49:cc:73:e1:51:36:49: - 20:1c:a1:fc:05:de:ff:f7:f2:74:0f:49:86:a5:0d:bf:67:8c: - 54:46 + 60:2d:71:74:f5:03:c8:bd:7e:ed:52:6d:ed:12:35:73:bd:06: + fe:9d:16:8a:cb:56:97:61:1c:f8:b8:42:9a:39:44:33:76:19: + 8f:85:22:c1:ce:18:19:da:e4:08:ff:1c:6f:b4:86:51:b6:07: + 2d:3e:2f:63:9a:f0:c6:1e:19:cd:9d:48:0f:f7:27:1c:03:9c: + c3:d8:d1:20:cb:c0:5d:4f:88:73:72:c6:4b:84:f9:01:2b:a7: + 91:f1:5b:90:e8:ee:ba:e4:41:cd:75:ae:d5:12:ab:a3:89:31: + 4b:0b:bf:f6:12:61:ba:e6:8b:f2:6c:b4:a3:cc:63:63:14:dd: + d9:9e -----BEGIN CERTIFICATE----- MIIC9DCCAl2gAwIBAgIBATANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTYwNTE1MDkzMDQ0WhcNMjYw -NTEzMDkzMDQ0WjBZMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh +dHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTcwODMxMjMzNzM2WhcNMjcw +ODI5MjMzNzM2WjBZMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2Nh -bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANi3NkLfK5HWIWDb1JH0 -pCZUm5vwrFtUByBC6mpiShDMkD9/SkzmTPYFWVEgxqs9n3On6VrnUMHb0zIwTsZT -NhSCcSq1aWuQLIaXwxilaWKLq0p3BBH/j8IRmWeKiP00G1yXG+0lPAGPL3qySVDE -pTP8lpnY8Oq+SRoKmLfrk7ElAgMBAAGjgcswgcgwCQYDVR0TBAIwADALBgNVHQ8E -BAMCBeAwHQYDVR0OBBYEFPAE1dyyBtbEMHWj5XMPmYh939UqMHMGA1UdIwRsMGqh +bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMxSJo9P48u4mDxIm+D+ +C/ad3ZClg6IUO0VbzMtuxBVwAk1SMFusPZzwyKMJYar7qRwB5+pLuXRK8vE/0S6S +oBZvQaKP5364y7qwCbLC8gf8OKvexKIgVybRKHZIkdacaE1Cuq0QgVzu0w/TshmJ +wIa/erG7f2C/LKy0ClvADek7AgMBAAGjgcswgcgwCQYDVR0TBAIwADALBgNVHQ8E +BAMCBeAwHQYDVR0OBBYEFNqI02kkeMl55tQ2IS4KtKzGEYXzMHMGA1UdIwRsMGqh XaRbMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdIIJ -AOsqHrpa5cF9MBoGA1UdEgQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0B -AQsFAAOBgQAylHJsVtsm3InNqkbF4I9TYl5l1EBR0Fo6oElUYNANYEsMGZKccObM -lz/tDhJd6VaGagkgD2ntPeeLn1k9JM3yxF6YpCRmhInyIw5FYnnvD6aTzd/0IFMp -XLx9i21xPeAJolNH/knMc+FRNkkgHKH8Bd7/9/J0D0mGpQ2/Z4xURg== +AJqx8JYIArI0MBoGA1UdEgQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0B +AQsFAAOBgQBgLXF09QPIvX7tUm3tEjVzvQb+nRaKy1aXYRz4uEKaOUQzdhmPhSLB +zhgZ2uQI/xxvtIZRtgctPi9jmvDGHhnNnUgP9yccA5zD2NEgy8BdT4hzcsZLhPkB +K6eR8VuQ6O665EHNda7VEqujiTFLC7/2EmG65ovybLSjzGNjFN3Zng== -----END CERTIFICATE----- diff --git a/src/main/proto/config.proto b/src/main/proto/config.proto index 561966b..263ad75 100644 --- a/src/main/proto/config.proto +++ b/src/main/proto/config.proto @@ -27,6 +27,11 @@ message CallConfiguration { // If set, this file will be used as a root certificate for calls using TLS. string tls_ca_cert_path = 4; + + // If set, this will use client certs for authentication + string tls_client_cert_path = 5; + string tls_client_key_path = 6; + string tls_client_override_authority = 7; } // Holds the necessary parameters for adding authentication to requests using @@ -93,4 +98,4 @@ message ProtoConfiguration { // Include paths used to resolve imports of the files being analyzed. repeated string include_paths = 2; -} \ No newline at end of file +} diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 3d8f5eb..971f467 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -78,6 +78,9 @@ public void appliesOverrides() { when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.tlsClientCertPath()).thenReturn(Optional.of(Paths.get("client_cert"))); + when(mockOverrides.tlsClientKeyPath()).thenReturn(Optional.of(Paths.get("client_key"))); + when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); Configuration config = ConfigurationLoader .forDefaultConfigSet() @@ -88,6 +91,9 @@ public void appliesOverrides() { assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); + assertThat(config.getCallConfig().getTlsClientCertPath()).isEqualTo("client_cert"); + assertThat(config.getCallConfig().getTlsClientKeyPath()).isEqualTo("client_key"); + assertThat(config.getCallConfig().getTlsClientOverrideAuthority()).isEqualTo("override_authority"); } private static Configuration namedConfig(String name) { diff --git a/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java b/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java index 7b871b8..6461f78 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java @@ -49,7 +49,6 @@ public void setUp() throws Throwable { responseFilePath = Files.createTempFile("response", "pb.ascii"); storedStdin = System.in; - testServer = TestServer.createAndStart(Optional.of(TestServer.serverSslContextForTesting())); } @After @@ -63,9 +62,9 @@ public void tearDown() throws Throwable { @Test public void makesRoundTripUnary() throws Throwable { - int serverPort = testServer.getGrpcServerPort(); + testServer = TestServer.createAndStart(Optional.of(TestServer.serverSslContextForTesting())); ImmutableList args = ImmutableList.builder() - .addAll(makeArgs(serverPort, TestUtils.TESTING_PROTO_ROOT.toString(), TEST_UNARY_METHOD)) + .addAll(makeArgs(testServer.getGrpcServerPort(), TestUtils.TESTING_PROTO_ROOT.toString(), TEST_UNARY_METHOD)) .add(makeArgument("output_file_path", responseFilePath.toString())) .add(makeArgument("tls_ca_cert_path", TestUtils.loadRootCaCert().getAbsolutePath())) .add(makeArgument("use_tls", "true")) @@ -81,6 +80,28 @@ public void makesRoundTripUnary() throws Throwable { assertThat(responses.get(0)).isEqualTo(TestServer.UNARY_SERVER_RESPONSE); } + @Test + public void makesRoundTripWithClientCerts() throws Throwable { + testServer = TestServer.createAndStart(Optional.of(TestServer.serverSslContextWithClientCertsForTesting())); + ImmutableList args = ImmutableList.builder() + .addAll(makeArgs(testServer.getGrpcServerPort(), TestUtils.TESTING_PROTO_ROOT.toString(), TEST_UNARY_METHOD)) + .add(makeArgument("output_file_path", responseFilePath.toString())) + .add(makeArgument("tls_ca_cert_path", TestUtils.loadRootCaCert().getAbsolutePath())) + .add(makeArgument("tls_client_cert_path", TestUtils.loadClientCert().getAbsolutePath())) + .add(makeArgument("tls_client_key_path", TestUtils.loadClientKey().getAbsolutePath())) + .add(makeArgument("use_tls", "true")) + .build(); + setStdinContents(MessageWriter.writeJsonStream(ImmutableList.of(REQUEST))); + + // Run the full client. + me.dinowernli.grpc.polyglot.Main.main(args.toArray(new String[0])); + + // Make sure we can parse the response from the file. + ImmutableList responses = TestUtils.readResponseFile(responseFilePath); + assertThat(responses).hasSize(1); + assertThat(responses.get(0)).isEqualTo(TestServer.UNARY_SERVER_RESPONSE); + } + private static ImmutableList makeArgs(int port, String protoRoot, String method) { return TestUtils.makePolyglotCallArgs( Joiner.on(':').join("localhost", port), protoRoot, method); From 07b0eefcc51ebfd09124f3c0de2c5f9308ed871a Mon Sep 17 00:00:00 2001 From: Dino Wernli Date: Fri, 1 Sep 2017 11:24:58 +0100 Subject: [PATCH 05/18] Fix a few style nits. --- .../grpc/polyglot/grpc/DynamicGrpcClient.java | 12 +++++---- .../grpc/polyglot/testing/TestServer.java | 7 +++--- .../config/ConfigurationLoaderTest.java | 15 ++++++----- .../integration/TlsIntegrationTest.java | 25 ++++++++++++------- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java b/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java index 49e564d..01a0a4f 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/grpc/DynamicGrpcClient.java @@ -233,9 +233,10 @@ private static Channel createChannel(HostAndPort endpoint, CallConfiguration cal if (!callConfiguration.getUseTls()) { return createPlaintextChannel(endpoint); } - NettyChannelBuilder nettyChannelBuilder = NettyChannelBuilder.forAddress(endpoint.getHostText(), endpoint.getPort()) - .sslContext(createSslContext(callConfiguration)) - .negotiationType(NegotiationType.TLS); + NettyChannelBuilder nettyChannelBuilder = + NettyChannelBuilder.forAddress(endpoint.getHostText(), endpoint.getPort()) + .sslContext(createSslContext(callConfiguration)) + .negotiationType(NegotiationType.TLS); if (!callConfiguration.getTlsClientOverrideAuthority().isEmpty()) { nettyChannelBuilder.overrideAuthority(callConfiguration.getTlsClientOverrideAuthority()); @@ -250,8 +251,9 @@ private static SslContext createSslContext(CallConfiguration callConfiguration) resultBuilder.trustManager(loadFile(callConfiguration.getTlsCaCertPath())); } if (!callConfiguration.getTlsClientCertPath().isEmpty()) { - resultBuilder.keyManager(loadFile(callConfiguration.getTlsClientCertPath()), - loadFile(callConfiguration.getTlsClientKeyPath())); + resultBuilder.keyManager( + loadFile(callConfiguration.getTlsClientCertPath()), + loadFile(callConfiguration.getTlsClientKeyPath())); } try { return resultBuilder.build(); diff --git a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java index 40ffa87..60ad9ff 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/testing/TestServer.java @@ -115,10 +115,9 @@ public static SslContext serverSslContextWithClientCertsForTesting() throws IOEx } private static SslContextBuilder getSslContextBuilder() { - return GrpcSslContexts - .forServer(TestUtils.loadServerChainCert(), TestUtils.loadServerKey()) - .trustManager(TestUtils.loadRootCaCert()) - .sslProvider(SslProvider.OPENSSL); + return GrpcSslContexts.forServer(TestUtils.loadServerChainCert(), TestUtils.loadServerKey()) + .trustManager(TestUtils.loadRootCaCert()) + .sslProvider(SslProvider.OPENSSL); } /** Starts a grpc server on the given port, throws {@link IOException} on failure. */ diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 971f467..3d269b5 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -13,6 +13,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import polyglot.ConfigProto.CallConfiguration; import polyglot.ConfigProto.Configuration; import polyglot.ConfigProto.ConfigurationSet; import polyglot.ConfigProto.OutputConfiguration.Destination; @@ -87,13 +88,15 @@ public void appliesOverrides() { .withOverrides(mockOverrides) .getDefaultConfiguration(); - assertThat(config.getCallConfig().getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); - assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); - assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); - assertThat(config.getCallConfig().getTlsClientCertPath()).isEqualTo("client_cert"); - assertThat(config.getCallConfig().getTlsClientKeyPath()).isEqualTo("client_key"); - assertThat(config.getCallConfig().getTlsClientOverrideAuthority()).isEqualTo("override_authority"); + + CallConfiguration callConfig = config.getCallConfig(); + assertThat(callConfig.getUseTls()).isTrue(); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + assertThat(callConfig.getTlsCaCertPath()).isNotEmpty(); + assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); + assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); + assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); } private static Configuration namedConfig(String name) { diff --git a/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java b/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java index 6461f78..3a13528 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/integration/TlsIntegrationTest.java @@ -64,7 +64,10 @@ public void tearDown() throws Throwable { public void makesRoundTripUnary() throws Throwable { testServer = TestServer.createAndStart(Optional.of(TestServer.serverSslContextForTesting())); ImmutableList args = ImmutableList.builder() - .addAll(makeArgs(testServer.getGrpcServerPort(), TestUtils.TESTING_PROTO_ROOT.toString(), TEST_UNARY_METHOD)) + .addAll(makeArgs( + testServer.getGrpcServerPort(), + TestUtils.TESTING_PROTO_ROOT.toString(), + TEST_UNARY_METHOD)) .add(makeArgument("output_file_path", responseFilePath.toString())) .add(makeArgument("tls_ca_cert_path", TestUtils.loadRootCaCert().getAbsolutePath())) .add(makeArgument("use_tls", "true")) @@ -82,15 +85,19 @@ public void makesRoundTripUnary() throws Throwable { @Test public void makesRoundTripWithClientCerts() throws Throwable { - testServer = TestServer.createAndStart(Optional.of(TestServer.serverSslContextWithClientCertsForTesting())); + testServer = TestServer.createAndStart( + Optional.of(TestServer.serverSslContextWithClientCertsForTesting())); ImmutableList args = ImmutableList.builder() - .addAll(makeArgs(testServer.getGrpcServerPort(), TestUtils.TESTING_PROTO_ROOT.toString(), TEST_UNARY_METHOD)) - .add(makeArgument("output_file_path", responseFilePath.toString())) - .add(makeArgument("tls_ca_cert_path", TestUtils.loadRootCaCert().getAbsolutePath())) - .add(makeArgument("tls_client_cert_path", TestUtils.loadClientCert().getAbsolutePath())) - .add(makeArgument("tls_client_key_path", TestUtils.loadClientKey().getAbsolutePath())) - .add(makeArgument("use_tls", "true")) - .build(); + .addAll(makeArgs( + testServer.getGrpcServerPort(), + TestUtils.TESTING_PROTO_ROOT.toString(), + TEST_UNARY_METHOD)) + .add(makeArgument("output_file_path", responseFilePath.toString())) + .add(makeArgument("tls_ca_cert_path", TestUtils.loadRootCaCert().getAbsolutePath())) + .add(makeArgument("tls_client_cert_path", TestUtils.loadClientCert().getAbsolutePath())) + .add(makeArgument("tls_client_key_path", TestUtils.loadClientKey().getAbsolutePath())) + .add(makeArgument("use_tls", "true")) + .build(); setStdinContents(MessageWriter.writeJsonStream(ImmutableList.of(REQUEST))); // Run the full client. From 82e649f05cc396221c182aa8beace4f2f6dd4ff9 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Sat, 2 Sep 2017 01:07:44 +0100 Subject: [PATCH 06/18] formatting --- .../grpc/polyglot/config/CommandLineArgs.java | 20 ++++---- .../polyglot/config/ConfigurationLoader.java | 22 ++++----- .../polyglot/config/CommandLineArgsTest.java | 24 +++++----- .../config/ConfigurationLoaderTest.java | 46 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index c88f277..698b135 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -91,23 +91,23 @@ public class CommandLineArgs { // TODO: Move to a "list_services"-specific flag container @Option( - name = "--service_filter", - metaVar = "service_name", - usage="Filters service names containing this string e.g. --service_filter TestService") + name = "--service_filter", + metaVar = "service_name", + usage="Filters service names containing this string e.g. --service_filter TestService") private String serviceFilterArg; // TODO: Move to a "list_services"-specific flag container @Option( - name = "--method_filter", - metaVar = "method_name", - usage="Filters service methods to those containing this string e.g. --method_name List") + name = "--method_filter", + metaVar = "method_name", + usage="Filters service methods to those containing this string e.g. --method_name List") private String methodFilterArg; //TODO: Move to a "list_services"-specific flag container @Option( - name = "--with_message", - metaVar = "true|false", - usage="If true, then the message specification for the method is rendered") + name = "--with_message", + metaVar = "true|false", + usage="If true, then the message specification for the method is rendered") private String withMessageArg; // ************************************************************************* @@ -281,7 +281,7 @@ private static Optional maybeUrl(String rawUrl) { URL url = new URL(rawUrl); return Optional.of(url); } catch (MalformedURLException mURLE) { - throw new IllegalArgumentException("URL " + rawUrl +" is invalid", mURLE); + throw new IllegalArgumentException("URL " + rawUrl + " is invalid", mURLE); } } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index 84b33e7..ed0d286 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -93,9 +93,9 @@ private Configuration getDefaultConfigurationInternal() { private Configuration getNamedConfigurationInternal(String name) { Preconditions.checkState(!isEmptyConfig(), "Cannot load named config with a config set"); return configSet.get().getConfigurationsList().stream() - .filter(config -> config.getName().equals(name)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); + .filter(config -> config.getName().equals(name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); } /** Returns the {@link Configuration} with overrides, if any, applied to it. */ @@ -111,7 +111,7 @@ private Configuration applyOverrides(Configuration configuration) { if (overrides.get().outputFilePath().isPresent()) { resultBuilder.getOutputConfigBuilder().setDestination(Destination.FILE); resultBuilder.getOutputConfigBuilder().setFilePath( - overrides.get().outputFilePath().get().toString()); + overrides.get().outputFilePath().get().toString()); } if (!overrides.get().additionalProtocIncludes().isEmpty()) { List additionalIncludes = new ArrayList<>(); @@ -122,7 +122,7 @@ private Configuration applyOverrides(Configuration configuration) { } if (overrides.get().protoDiscoveryRoot().isPresent()) { resultBuilder.getProtoConfigBuilder().setProtoDiscoveryRoot( - overrides.get().protoDiscoveryRoot().get().toString()); + overrides.get().protoDiscoveryRoot().get().toString()); } if (overrides.get().getRpcDeadlineMs().isPresent()) { resultBuilder.getCallConfigBuilder().setDeadlineMs(overrides.get().getRpcDeadlineMs().get()); @@ -141,30 +141,30 @@ private Configuration applyOverrides(Configuration configuration) { } if (overrides.get().tlsClientOverrideAuthority().isPresent()) { resultBuilder.getCallConfigBuilder().setTlsClientOverrideAuthority( - overrides.get().tlsClientOverrideAuthority().get()); + overrides.get().tlsClientOverrideAuthority().get()); } if (overrides.get().oauthRefreshTokenEndpointUrl().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); + .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); } if (overrides.get().oauthClientId().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .getClientBuilder().setId(overrides.get().oauthClientId().get()); + .getClientBuilder().setId(overrides.get().oauthClientId().get()); } if (overrides.get().oauthClientSecret().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); + .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); } if (overrides.get().oauthRefreshTokenPath().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); + .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); } // Note the ordering of setting these fields is important. Oauth configuration has a oneof field, corresponding // to access or refresh tokens. We want access tokens to take precedence, setting this field last will ensure this // occurs. See https://developers.google.com/protocol-buffers/docs/proto#oneof if (overrides.get().oauthAccessTokenPath().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getAccessTokenCredentialsBuilder() - .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); + .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); } return resultBuilder.build(); } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java index ba06dee..71169e9 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java @@ -34,14 +34,14 @@ public void tearDown() throws Throwable { @Test public void parsesAdditionalIncludesSingle() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--add_protoc_includes=%s,%s", tempFile1.toString(), tempFile2.toString()))); + String.format("--add_protoc_includes=%s,%s", tempFile1.toString(), tempFile2.toString()))); assertThat(params.additionalProtocIncludes()).hasSize(2); } @Test public void parsesAdditionalIncludesMulti() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--add_protoc_includes=%s", tempFile1.toString()))); + String.format("--add_protoc_includes=%s", tempFile1.toString()))); assertThat(params.additionalProtocIncludes()).hasSize(1); } @@ -49,7 +49,7 @@ public void parsesAdditionalIncludesMulti() { public void parsesOauthRefreshTokenEndpointUrl() { String url = "https://github.com/grpc-ecosystem/polyglot"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_refresh_token_endpoint_url=%s", url))); + String.format("--oauth_refresh_token_endpoint_url=%s", url))); assertThat(params.oauthRefreshTokenEndpointUrl().get().toString()).isEqualTo(url); } @@ -57,7 +57,7 @@ public void parsesOauthRefreshTokenEndpointUrl() { public void parsesOauthClientId() { String client_id = "client_id"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_client_id=%s",client_id))); + String.format("--oauth_client_id=%s",client_id))); assertThat(params.oauthClientId().get()).isEqualTo(client_id); } @@ -65,31 +65,31 @@ public void parsesOauthClientId() { public void parsesOauthClientSecret() { String client_secret = "client_secret"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_client_secret=%s", client_secret))); + String.format("--oauth_client_secret=%s", client_secret))); assertThat(params.oauthClientSecret().get()).isEqualTo(client_secret); } @Test public void parsesOauthRefreshTokenPath() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); + String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); assertThat(params.oauthRefreshTokenPath().get().toString()).isEqualTo(tempFile1.toString()); } @Test public void parsesOauthAccessTokenPath() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_access_token_path=%s", tempFile1.toString()))); + String.format("--oauth_access_token_path=%s", tempFile1.toString()))); assertThat(params.oauthAccessTokenPath().get().toString()).isEqualTo(tempFile1.toString()); } private static CommandLineArgs parseArgs(ImmutableList args) { ImmutableList allArgs = ImmutableList.builder() - .addAll(args) - .add("--endpoint=somehost:1234") - .add("--full_method=some.package/Method") - .add("--proto_discovery_root=.") - .build(); + .addAll(args) + .add("--endpoint=somehost:1234") + .add("--full_method=some.package/Method") + .add("--proto_discovery_root=.") + .build(); return CommandLineArgs.parse(allArgs.toArray(new String[0])); } } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 7dbdcce..bed4594 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -48,7 +48,7 @@ public void tearDown() { @Test public void loadsDefaultConfig() { Configuration defaultConfig = - ConfigurationLoader.forDefaultConfigSet().getDefaultConfiguration(); + ConfigurationLoader.forDefaultConfigSet().getDefaultConfiguration(); assertThat(defaultConfig).isEqualTo(Configuration.getDefaultInstance()); assertThat(defaultConfig.getCallConfig().getUseTls()).isFalse(); @@ -63,15 +63,15 @@ public void throwsIfAskedToLoadNamedFromDefaultSet() { @Test(expected = IllegalArgumentException.class) public void throwsIfNamedConfigMissing() { ConfigurationLoader.forConfigSet(ConfigurationSet.getDefaultInstance()) - .getNamedConfiguration("asfd"); + .getNamedConfiguration("asfd"); } @Test public void loadsNamedConfig() { ConfigurationLoader loader = ConfigurationLoader.forConfigSet(ConfigurationSet.newBuilder() - .addConfigurations(namedConfig("foo")) - .addConfigurations(namedConfig("bar")) - .build()); + .addConfigurations(namedConfig("foo")) + .addConfigurations(namedConfig("bar")) + .build()); assertThat(loader.getNamedConfiguration("foo").getName()).isEqualTo("foo"); } @@ -93,9 +93,9 @@ public void appliesOverridesWithRefreshToken() { when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.empty()); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -109,15 +109,15 @@ public void appliesOverridesWithRefreshToken() { assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEqualTo("id"); + .isEqualTo("id"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEqualTo("secret"); + .isEqualTo("secret"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isNotEmpty(); + .isNotEmpty(); assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isEmpty(); + .isEmpty(); } @Test @@ -135,9 +135,9 @@ public void appliesOverridesWithAccessToken() { when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getCallConfig().getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -145,21 +145,21 @@ public void appliesOverridesWithAccessToken() { assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); // Setting the access token path will unset all of the refresh token properties assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isNotEmpty(); + .isNotEmpty(); } private static Configuration namedConfig(String name) { return Configuration.newBuilder() - .setName(name) - .build(); + .setName(name) + .build(); } private static URL getTestUrl(String testUrl) { try { From 9b0abbbfe473c80870d70db7af4f1a1d30a2952f Mon Sep 17 00:00:00 2001 From: Dino Wernli Date: Sun, 3 Sep 2017 13:47:34 +0100 Subject: [PATCH 07/18] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3681ea4..5265849 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ In particular, it is not necessary to generate grpc classes for the service or t * Parses proto files at runtime to discover services. Supports pretty-printing discovered services. * Supports authentication via oauth. * Accepts request protos through stdin and can output responses to stdout to allow chaining. +* Suppors plain text connections as well as TLS. ## Usage From 028ea90a791f166c4b1709a4e9be096f1e9a9b95 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Mon, 4 Sep 2017 11:48:22 +0100 Subject: [PATCH 08/18] renaming to fit convention and fixing test --- .../grpc/polyglot/config/CommandLineArgs.java | 4 +- .../config/ConfigurationLoaderTest.java | 50 +++++++++---------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index 698b135..c0c0921 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -280,8 +280,8 @@ private static Optional maybeUrl(String rawUrl) { try { URL url = new URL(rawUrl); return Optional.of(url); - } catch (MalformedURLException mURLE) { - throw new IllegalArgumentException("URL " + rawUrl + " is invalid", mURLE); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("URL " + rawUrl + " is invalid", e); } } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index bed4594..6b272a4 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -106,18 +106,13 @@ public void appliesOverridesWithRefreshToken() { assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); - assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); - assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEqualTo("id"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEqualTo("secret"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isNotEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isEmpty(); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getId()).isEqualTo("id"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()).isEqualTo("secret"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()).isNotEmpty(); + assertThat(callConfig.getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()).isEmpty(); } @Test @@ -128,6 +123,9 @@ public void appliesOverridesWithAccessToken() { when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.tlsClientCertPath()).thenReturn(Optional.of(Paths.get("client_cert"))); + when(mockOverrides.tlsClientKeyPath()).thenReturn(Optional.of(Paths.get("client_key"))); + when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); @@ -139,21 +137,21 @@ public void appliesOverridesWithAccessToken() { .withOverrides(mockOverrides) .getDefaultConfiguration(); - assertThat(config.getCallConfig().getUseTls()).isTrue(); + CallConfiguration callConfig = config.getCallConfig(); + assertThat(callConfig.getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); - assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); - assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); - // Setting the access token path will unset all of the refresh token properties - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isNotEmpty(); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + assertThat(callConfig.getTlsCaCertPath()).isNotEmpty(); + assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); + assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); + assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + // Setting the access token path will unset all of the refresh token properties (due to the oneof semantics) + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getId()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()).isEmpty(); + assertThat(callConfig.getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()).isNotEmpty(); } private static Configuration namedConfig(String name) { From 848d1088dde60a682490dbb7676c5aae619cac60 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 6 Sep 2017 12:50:45 +0100 Subject: [PATCH 09/18] Fix documentation typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5265849..2322d49 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ In particular, it is not necessary to generate grpc classes for the service or t * Parses proto files at runtime to discover services. Supports pretty-printing discovered services. * Supports authentication via oauth. * Accepts request protos through stdin and can output responses to stdout to allow chaining. -* Suppors plain text connections as well as TLS. +* Supports plain text connections as well as TLS. ## Usage From 7a8b0df68cacba606b81f1a1dce8e710e24b342f Mon Sep 17 00:00:00 2001 From: Dino Wernli Date: Thu, 7 Sep 2017 12:00:41 +0100 Subject: [PATCH 10/18] Update RELEASE-NOTES.md --- RELEASE-NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 7869ea8..6b430b8 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -6,6 +6,10 @@ Quick links: ## Upcoming release +## 1.3.0 +* Upgraded to grpc 1.4.0. +* Added support for client certificates to TLS. + ## 1.2.0 * Upgraded to grpc 1.0.0. From cae5b3ff9257bae8264160f541781cbffdd30750 Mon Sep 17 00:00:00 2001 From: Dino Wernli Date: Thu, 7 Sep 2017 12:05:52 +0100 Subject: [PATCH 11/18] Bump version. --- src/main/java/me/dinowernli/grpc/polyglot/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/Main.java b/src/main/java/me/dinowernli/grpc/polyglot/Main.java index 9d7b80a..d17b92c 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/Main.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/Main.java @@ -18,7 +18,7 @@ public class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); - private static final String VERSION = "1.2.0+dev"; + private static final String VERSION = "1.3.0"; public static void main(String[] args) { // Fix the logging setup. From 79960ea9b63eb1c8ac4cb60faacd633d18f5f7e8 Mon Sep 17 00:00:00 2001 From: Dino Wernli Date: Thu, 7 Sep 2017 12:06:37 +0100 Subject: [PATCH 12/18] Bump version again. --- src/main/java/me/dinowernli/grpc/polyglot/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/Main.java b/src/main/java/me/dinowernli/grpc/polyglot/Main.java index d17b92c..d34bc41 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/Main.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/Main.java @@ -18,7 +18,7 @@ public class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); - private static final String VERSION = "1.3.0"; + private static final String VERSION = "1.3.0+dev"; public static void main(String[] args) { // Fix the logging setup. From 80222a8771364c32e1fdeb7563292da76bd845e6 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 15:18:51 +0100 Subject: [PATCH 13/18] adding command line args and tests --- .../grpc/polyglot/config/CommandLineArgs.java | 50 +++++++++++++++++++ .../polyglot/config/ConfigurationLoader.java | 23 +++++++++ .../oauth2/RefreshTokenCredentials.java | 4 +- .../polyglot/config/CommandLineArgsTest.java | 38 ++++++++++++++ .../config/ConfigurationLoaderTest.java | 28 +++++++++++ 5 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index f8622f8..ce7e40f 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -2,6 +2,8 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -56,6 +58,21 @@ public class CommandLineArgs { @Option(name = "--tls_client_override_authority", metaVar = "") private String tlsClientOverrideAuthority; + @Option(name = "--oauth_refresh_token_endpoint_url", metaVar = "") + private String oauthRefreshTokenEndpointUrl; + + @Option(name = "--oauth_client_id", metaVar = "") + private String oauthClientId; + + @Option(name = "--oauth_client_secret", metaVar = "") + private String oauthClientSecret; + + @Option(name = "--oauth_refresh_token_path", metaVar = "") + private String oauthRefreshTokenPath; + + @Option(name = "--oauth_access_token_path", metaVar = "") + private String oauthAccessTokenPath; + @Option(name = "--help") private Boolean help; @@ -162,6 +179,26 @@ public Optional tlsCaCertPath() { return maybePath(tlsCaCertPath); } + public Optional oauthRefreshTokenEndpointUrl() { + return maybeUrl(oauthRefreshTokenEndpointUrl); + } + + public Optional oauthClientId() { + return Optional.ofNullable(oauthClientId); + } + + public Optional oauthClientSecret() { + return Optional.ofNullable(oauthClientSecret); + } + + public Optional oauthRefreshTokenPath() { + return maybePath(oauthRefreshTokenPath); + } + + public Optional oauthAccessTokenPath() { + return maybePath(oauthAccessTokenPath); + } + public Optional tlsClientCertPath() { return maybePath(tlsClientCertPath); } @@ -235,4 +272,17 @@ private static Optional maybePath(String rawPath) { Preconditions.checkArgument(Files.exists(path), "File " + rawPath + " does not exist"); return Optional.of(Paths.get(rawPath)); } + + private static Optional maybeUrl(String rawUrl) { + if (rawUrl == null) { + return Optional.empty(); + } + try { + URL url = new URL(rawUrl); + return Optional.of(url); + } catch (MalformedURLException mURLE) { + throw new IllegalArgumentException("URL " + rawUrl +" is invalid", mURLE); + } + + } } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index e927912..84b33e7 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -143,6 +143,29 @@ private Configuration applyOverrides(Configuration configuration) { resultBuilder.getCallConfigBuilder().setTlsClientOverrideAuthority( overrides.get().tlsClientOverrideAuthority().get()); } + if (overrides.get().oauthRefreshTokenEndpointUrl().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); + } + if (overrides.get().oauthClientId().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .getClientBuilder().setId(overrides.get().oauthClientId().get()); + } + if (overrides.get().oauthClientSecret().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); + } + if (overrides.get().oauthRefreshTokenPath().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() + .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); + } + // Note the ordering of setting these fields is important. Oauth configuration has a oneof field, corresponding + // to access or refresh tokens. We want access tokens to take precedence, setting this field last will ensure this + // occurs. See https://developers.google.com/protocol-buffers/docs/proto#oneof + if (overrides.get().oauthAccessTokenPath().isPresent()) { + resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getAccessTokenCredentialsBuilder() + .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); + } return resultBuilder.build(); } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java b/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java index b27b4e9..7140504 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/oauth2/RefreshTokenCredentials.java @@ -71,10 +71,10 @@ public AccessToken refreshAccessToken() throws IOException { logger.info("Refresh successful, got access token"); return new AccessToken( refreshResponse.getAccessToken(), - computeExpirtyDate(refreshResponse.getExpiresInSeconds())); + computeExpiryDate(refreshResponse.getExpiresInSeconds())); } - private Date computeExpirtyDate(long expiresInSeconds) { + private Date computeExpiryDate(long expiresInSeconds) { long expiresInSecondsWithMargin = (long) (expiresInSeconds * ACCESS_TOKEN_EXPIRY_MARGIN); return Date.from(clock.instant().plusSeconds(expiresInSecondsWithMargin)); } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java index e268b27..ba06dee 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java @@ -45,6 +45,44 @@ public void parsesAdditionalIncludesMulti() { assertThat(params.additionalProtocIncludes()).hasSize(1); } + @Test + public void parsesOauthRefreshTokenEndpointUrl() { + String url = "https://github.com/grpc-ecosystem/polyglot"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_refresh_token_endpoint_url=%s", url))); + assertThat(params.oauthRefreshTokenEndpointUrl().get().toString()).isEqualTo(url); + } + + @Test + public void parsesOauthClientId() { + String client_id = "client_id"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_client_id=%s",client_id))); + assertThat(params.oauthClientId().get()).isEqualTo(client_id); + } + + @Test + public void parsesOauthClientSecret() { + String client_secret = "client_secret"; + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_client_secret=%s", client_secret))); + assertThat(params.oauthClientSecret().get()).isEqualTo(client_secret); + } + + @Test + public void parsesOauthRefreshTokenPath() { + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); + assertThat(params.oauthRefreshTokenPath().get().toString()).isEqualTo(tempFile1.toString()); + } + + @Test + public void parsesOauthAccessTokenPath() { + CommandLineArgs params = parseArgs(ImmutableList.of( + String.format("--oauth_access_token_path=%s", tempFile1.toString()))); + assertThat(params.oauthAccessTokenPath().get().toString()).isEqualTo(tempFile1.toString()); + } + private static CommandLineArgs parseArgs(ImmutableList args) { ImmutableList allArgs = ImmutableList.builder() .addAll(args) diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 3d269b5..5c58094 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -1,7 +1,9 @@ package me.dinowernli.grpc.polyglot.config; +import java.net.MalformedURLException; import java.nio.file.Paths; import java.util.Optional; +import java.net.URL; import com.google.common.collect.ImmutableList; import me.dinowernli.junit.TestClass; @@ -18,6 +20,8 @@ import polyglot.ConfigProto.ConfigurationSet; import polyglot.ConfigProto.OutputConfiguration.Destination; +import javax.swing.text.html.Option; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; @@ -79,6 +83,11 @@ public void appliesOverrides() { when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); + when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); + when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); + when(mockOverrides.oauthRefreshTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.empty()); when(mockOverrides.tlsClientCertPath()).thenReturn(Optional.of(Paths.get("client_cert"))); when(mockOverrides.tlsClientKeyPath()).thenReturn(Optional.of(Paths.get("client_key"))); when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); @@ -97,6 +106,18 @@ public void appliesOverrides() { assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); + assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); + assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) + .isEqualTo("id"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) + .isEqualTo("secret"); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) + .isNotEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) + .isEmpty(); } private static Configuration namedConfig(String name) { @@ -104,4 +125,11 @@ private static Configuration namedConfig(String name) { .setName(name) .build(); } + private static URL getTestUrl(String testUrl) { + try { + return new URL(testUrl); + } catch (MalformedURLException mUrlE) { + throw new RuntimeException(); + } + } } From ae0dbf8567bf493fa6aff15f8662e92b20ce06f5 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 15:50:22 +0100 Subject: [PATCH 14/18] adding access token test --- .../config/ConfigurationLoaderTest.java | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 5c58094..ba8504f 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -76,7 +76,7 @@ public void loadsNamedConfig() { } @Test - public void appliesOverrides() { + public void appliesOverridesWithRefreshToken() { when(mockOverrides.useTls()).thenReturn(Optional.of(true)); when(mockOverrides.outputFilePath()).thenReturn(Optional.of(Paths.get("asdf"))); when(mockOverrides.additionalProtocIncludes()).thenReturn(ImmutableList.of(Paths.get("."))); @@ -93,9 +93,9 @@ public void appliesOverrides() { when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -120,6 +120,42 @@ public void appliesOverrides() { .isEmpty(); } + @Test + public void appliesOverridesWithAccessToken() { + when(mockOverrides.useTls()).thenReturn(Optional.of(true)); + when(mockOverrides.outputFilePath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.additionalProtocIncludes()).thenReturn(ImmutableList.of(Paths.get("."))); + when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); + when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); + when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); + when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); + when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); + when(mockOverrides.oauthRefreshTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); + + Configuration config = ConfigurationLoader + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); + + assertThat(config.getCallConfig().getUseTls()).isTrue(); + assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); + assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); + assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); + // Setting the access token path will unset all of the refresh token properties + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) + .isEmpty(); + assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) + .isNotEmpty(); + } + private static Configuration namedConfig(String name) { return Configuration.newBuilder() .setName(name) From 8e65f0ae21eaa349d1e3dfc4dd99c5bbe2f49d97 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Thu, 31 Aug 2017 16:02:44 +0100 Subject: [PATCH 15/18] improving logging for case of no stdin --- .../java/me/dinowernli/grpc/polyglot/command/ServiceCall.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java b/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java index 54313b8..7ef76b0 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/command/ServiceCall.java @@ -71,6 +71,8 @@ public static void callEndpoint( dynamicClient = DynamicGrpcClient.create(methodDescriptor, hostAndPort, callConfig); } + logger.info("Reading input from stdin"); + ImmutableList requestMessages = MessageReader.forStdin(methodDescriptor.getInputType()).read(); StreamObserver streamObserver = From 26da455501a3adb5783970cdcb24957ab549e976 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Sat, 2 Sep 2017 01:07:44 +0100 Subject: [PATCH 16/18] formatting --- .../grpc/polyglot/config/CommandLineArgs.java | 20 ++++---- .../polyglot/config/ConfigurationLoader.java | 22 ++++----- .../polyglot/config/CommandLineArgsTest.java | 24 +++++----- .../config/ConfigurationLoaderTest.java | 46 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index ce7e40f..bb5cbe2 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -91,23 +91,23 @@ public class CommandLineArgs { // TODO: Move to a "list_services"-specific flag container @Option( - name = "--service_filter", - metaVar = "service_name", - usage="Filters service names containing this string e.g. --service_filter TestService") + name = "--service_filter", + metaVar = "service_name", + usage="Filters service names containing this string e.g. --service_filter TestService") private String serviceFilterArg; // TODO: Move to a "list_services"-specific flag container @Option( - name = "--method_filter", - metaVar = "method_name", - usage="Filters service methods to those containing this string e.g. --method_name List") + name = "--method_filter", + metaVar = "method_name", + usage="Filters service methods to those containing this string e.g. --method_name List") private String methodFilterArg; //TODO: Move to a "list_services"-specific flag container @Option( - name = "--with_message", - metaVar = "true|false", - usage="If true, then the message specification for the method is rendered") + name = "--with_message", + metaVar = "true|false", + usage="If true, then the message specification for the method is rendered") private String withMessageArg; // ************************************************************************* @@ -281,7 +281,7 @@ private static Optional maybeUrl(String rawUrl) { URL url = new URL(rawUrl); return Optional.of(url); } catch (MalformedURLException mURLE) { - throw new IllegalArgumentException("URL " + rawUrl +" is invalid", mURLE); + throw new IllegalArgumentException("URL " + rawUrl + " is invalid", mURLE); } } diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java index 84b33e7..ed0d286 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoader.java @@ -93,9 +93,9 @@ private Configuration getDefaultConfigurationInternal() { private Configuration getNamedConfigurationInternal(String name) { Preconditions.checkState(!isEmptyConfig(), "Cannot load named config with a config set"); return configSet.get().getConfigurationsList().stream() - .filter(config -> config.getName().equals(name)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); + .filter(config -> config.getName().equals(name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Could not find named config: " + name)); } /** Returns the {@link Configuration} with overrides, if any, applied to it. */ @@ -111,7 +111,7 @@ private Configuration applyOverrides(Configuration configuration) { if (overrides.get().outputFilePath().isPresent()) { resultBuilder.getOutputConfigBuilder().setDestination(Destination.FILE); resultBuilder.getOutputConfigBuilder().setFilePath( - overrides.get().outputFilePath().get().toString()); + overrides.get().outputFilePath().get().toString()); } if (!overrides.get().additionalProtocIncludes().isEmpty()) { List additionalIncludes = new ArrayList<>(); @@ -122,7 +122,7 @@ private Configuration applyOverrides(Configuration configuration) { } if (overrides.get().protoDiscoveryRoot().isPresent()) { resultBuilder.getProtoConfigBuilder().setProtoDiscoveryRoot( - overrides.get().protoDiscoveryRoot().get().toString()); + overrides.get().protoDiscoveryRoot().get().toString()); } if (overrides.get().getRpcDeadlineMs().isPresent()) { resultBuilder.getCallConfigBuilder().setDeadlineMs(overrides.get().getRpcDeadlineMs().get()); @@ -141,30 +141,30 @@ private Configuration applyOverrides(Configuration configuration) { } if (overrides.get().tlsClientOverrideAuthority().isPresent()) { resultBuilder.getCallConfigBuilder().setTlsClientOverrideAuthority( - overrides.get().tlsClientOverrideAuthority().get()); + overrides.get().tlsClientOverrideAuthority().get()); } if (overrides.get().oauthRefreshTokenEndpointUrl().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); + .setTokenEndpointUrl(overrides.get().oauthRefreshTokenEndpointUrl().get().toString()); } if (overrides.get().oauthClientId().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .getClientBuilder().setId(overrides.get().oauthClientId().get()); + .getClientBuilder().setId(overrides.get().oauthClientId().get()); } if (overrides.get().oauthClientSecret().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); + .getClientBuilder().setSecret(overrides.get().oauthClientSecret().get()); } if (overrides.get().oauthRefreshTokenPath().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getRefreshTokenCredentialsBuilder() - .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); + .setRefreshTokenPath(overrides.get().oauthRefreshTokenPath().get().toString()); } // Note the ordering of setting these fields is important. Oauth configuration has a oneof field, corresponding // to access or refresh tokens. We want access tokens to take precedence, setting this field last will ensure this // occurs. See https://developers.google.com/protocol-buffers/docs/proto#oneof if (overrides.get().oauthAccessTokenPath().isPresent()) { resultBuilder.getCallConfigBuilder().getOauthConfigBuilder().getAccessTokenCredentialsBuilder() - .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); + .setAccessTokenPath(overrides.get().oauthAccessTokenPath().get().toString()); } return resultBuilder.build(); } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java index ba06dee..71169e9 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/CommandLineArgsTest.java @@ -34,14 +34,14 @@ public void tearDown() throws Throwable { @Test public void parsesAdditionalIncludesSingle() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--add_protoc_includes=%s,%s", tempFile1.toString(), tempFile2.toString()))); + String.format("--add_protoc_includes=%s,%s", tempFile1.toString(), tempFile2.toString()))); assertThat(params.additionalProtocIncludes()).hasSize(2); } @Test public void parsesAdditionalIncludesMulti() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--add_protoc_includes=%s", tempFile1.toString()))); + String.format("--add_protoc_includes=%s", tempFile1.toString()))); assertThat(params.additionalProtocIncludes()).hasSize(1); } @@ -49,7 +49,7 @@ public void parsesAdditionalIncludesMulti() { public void parsesOauthRefreshTokenEndpointUrl() { String url = "https://github.com/grpc-ecosystem/polyglot"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_refresh_token_endpoint_url=%s", url))); + String.format("--oauth_refresh_token_endpoint_url=%s", url))); assertThat(params.oauthRefreshTokenEndpointUrl().get().toString()).isEqualTo(url); } @@ -57,7 +57,7 @@ public void parsesOauthRefreshTokenEndpointUrl() { public void parsesOauthClientId() { String client_id = "client_id"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_client_id=%s",client_id))); + String.format("--oauth_client_id=%s",client_id))); assertThat(params.oauthClientId().get()).isEqualTo(client_id); } @@ -65,31 +65,31 @@ public void parsesOauthClientId() { public void parsesOauthClientSecret() { String client_secret = "client_secret"; CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_client_secret=%s", client_secret))); + String.format("--oauth_client_secret=%s", client_secret))); assertThat(params.oauthClientSecret().get()).isEqualTo(client_secret); } @Test public void parsesOauthRefreshTokenPath() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); + String.format("--oauth_refresh_token_path=%s", tempFile1.toString()))); assertThat(params.oauthRefreshTokenPath().get().toString()).isEqualTo(tempFile1.toString()); } @Test public void parsesOauthAccessTokenPath() { CommandLineArgs params = parseArgs(ImmutableList.of( - String.format("--oauth_access_token_path=%s", tempFile1.toString()))); + String.format("--oauth_access_token_path=%s", tempFile1.toString()))); assertThat(params.oauthAccessTokenPath().get().toString()).isEqualTo(tempFile1.toString()); } private static CommandLineArgs parseArgs(ImmutableList args) { ImmutableList allArgs = ImmutableList.builder() - .addAll(args) - .add("--endpoint=somehost:1234") - .add("--full_method=some.package/Method") - .add("--proto_discovery_root=.") - .build(); + .addAll(args) + .add("--endpoint=somehost:1234") + .add("--full_method=some.package/Method") + .add("--proto_discovery_root=.") + .build(); return CommandLineArgs.parse(allArgs.toArray(new String[0])); } } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index ba8504f..89df67b 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -48,7 +48,7 @@ public void tearDown() { @Test public void loadsDefaultConfig() { Configuration defaultConfig = - ConfigurationLoader.forDefaultConfigSet().getDefaultConfiguration(); + ConfigurationLoader.forDefaultConfigSet().getDefaultConfiguration(); assertThat(defaultConfig).isEqualTo(Configuration.getDefaultInstance()); assertThat(defaultConfig.getCallConfig().getUseTls()).isFalse(); @@ -63,15 +63,15 @@ public void throwsIfAskedToLoadNamedFromDefaultSet() { @Test(expected = IllegalArgumentException.class) public void throwsIfNamedConfigMissing() { ConfigurationLoader.forConfigSet(ConfigurationSet.getDefaultInstance()) - .getNamedConfiguration("asfd"); + .getNamedConfiguration("asfd"); } @Test public void loadsNamedConfig() { ConfigurationLoader loader = ConfigurationLoader.forConfigSet(ConfigurationSet.newBuilder() - .addConfigurations(namedConfig("foo")) - .addConfigurations(namedConfig("bar")) - .build()); + .addConfigurations(namedConfig("foo")) + .addConfigurations(namedConfig("bar")) + .build()); assertThat(loader.getNamedConfiguration("foo").getName()).isEqualTo("foo"); } @@ -93,9 +93,9 @@ public void appliesOverridesWithRefreshToken() { when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -109,15 +109,15 @@ public void appliesOverridesWithRefreshToken() { assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEqualTo("id"); + .isEqualTo("id"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEqualTo("secret"); + .isEqualTo("secret"); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isNotEmpty(); + .isNotEmpty(); assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isEmpty(); + .isEmpty(); } @Test @@ -135,9 +135,9 @@ public void appliesOverridesWithAccessToken() { when(mockOverrides.oauthAccessTokenPath()).thenReturn(Optional.of(Paths.get("asdf"))); Configuration config = ConfigurationLoader - .forDefaultConfigSet() - .withOverrides(mockOverrides) - .getDefaultConfiguration(); + .forDefaultConfigSet() + .withOverrides(mockOverrides) + .getDefaultConfiguration(); assertThat(config.getCallConfig().getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); @@ -145,21 +145,21 @@ public void appliesOverridesWithAccessToken() { assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); // Setting the access token path will unset all of the refresh token properties assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isEmpty(); + .isEmpty(); assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isNotEmpty(); + .isNotEmpty(); } private static Configuration namedConfig(String name) { return Configuration.newBuilder() - .setName(name) - .build(); + .setName(name) + .build(); } private static URL getTestUrl(String testUrl) { try { From 1e7cf9c1a7b6986f7189a926477b31127c94e2c4 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Mon, 4 Sep 2017 11:48:22 +0100 Subject: [PATCH 17/18] renaming to fit convention and fixing test --- .../grpc/polyglot/config/CommandLineArgs.java | 4 +- .../config/ConfigurationLoaderTest.java | 50 +++++++++---------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index bb5cbe2..6ab698a 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -280,8 +280,8 @@ private static Optional maybeUrl(String rawUrl) { try { URL url = new URL(rawUrl); return Optional.of(url); - } catch (MalformedURLException mURLE) { - throw new IllegalArgumentException("URL " + rawUrl + " is invalid", mURLE); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("URL " + rawUrl + " is invalid", e); } } diff --git a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java index 89df67b..1a337a6 100644 --- a/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java +++ b/src/test/java/me/dinowernli/grpc/polyglot/config/ConfigurationLoaderTest.java @@ -106,18 +106,13 @@ public void appliesOverridesWithRefreshToken() { assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); - assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); - assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEqualTo("id"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEqualTo("secret"); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isNotEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isEmpty(); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) + .isEqualTo("https://github.com/grpc-ecosystem/polyglot"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getId()).isEqualTo("id"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()).isEqualTo("secret"); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()).isNotEmpty(); + assertThat(callConfig.getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()).isEmpty(); } @Test @@ -128,6 +123,9 @@ public void appliesOverridesWithAccessToken() { when(mockOverrides.protoDiscoveryRoot()).thenReturn(Optional.of(Paths.get("."))); when(mockOverrides.getRpcDeadlineMs()).thenReturn(Optional.of(25)); when(mockOverrides.tlsCaCertPath()).thenReturn(Optional.of(Paths.get("asdf"))); + when(mockOverrides.tlsClientCertPath()).thenReturn(Optional.of(Paths.get("client_cert"))); + when(mockOverrides.tlsClientKeyPath()).thenReturn(Optional.of(Paths.get("client_key"))); + when(mockOverrides.tlsClientOverrideAuthority()).thenReturn(Optional.of("override_authority")); when(mockOverrides.oauthRefreshTokenEndpointUrl()).thenReturn(Optional.of(getTestUrl("https://github.com/grpc-ecosystem/polyglot"))); when(mockOverrides.oauthClientId()).thenReturn(Optional.of("id")); when(mockOverrides.oauthClientSecret()).thenReturn(Optional.of("secret")); @@ -139,21 +137,21 @@ public void appliesOverridesWithAccessToken() { .withOverrides(mockOverrides) .getDefaultConfiguration(); - assertThat(config.getCallConfig().getUseTls()).isTrue(); + CallConfiguration callConfig = config.getCallConfig(); + assertThat(callConfig.getUseTls()).isTrue(); assertThat(config.getOutputConfig().getDestination()).isEqualTo(Destination.FILE); - assertThat(config.getCallConfig().getDeadlineMs()).isEqualTo(25); - assertThat(config.getCallConfig().getTlsCaCertPath()).isNotEmpty(); - // Setting the access token path will unset all of the refresh token properties - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getId()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()) - .isEmpty(); - assertThat(config.getCallConfig().getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()) - .isNotEmpty(); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + assertThat(callConfig.getTlsCaCertPath()).isNotEmpty(); + assertThat(callConfig.getTlsClientCertPath()).isEqualTo("client_cert"); + assertThat(callConfig.getTlsClientKeyPath()).isEqualTo("client_key"); + assertThat(callConfig.getTlsClientOverrideAuthority()).isEqualTo("override_authority"); + assertThat(callConfig.getDeadlineMs()).isEqualTo(25); + // Setting the access token path will unset all of the refresh token properties (due to the oneof semantics) + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getTokenEndpointUrl()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getId()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getClient().getSecret()).isEmpty(); + assertThat(callConfig.getOauthConfig().getRefreshTokenCredentials().getRefreshTokenPath()).isEmpty(); + assertThat(callConfig.getOauthConfig().getAccessTokenCredentials().getAccessTokenPath()).isNotEmpty(); } private static Configuration namedConfig(String name) { From 3b2926655a3d84869db4592558a725248f768837 Mon Sep 17 00:00:00 2001 From: Peter Boothroyd Date: Tue, 12 Sep 2017 13:08:20 +0100 Subject: [PATCH 18/18] merging and removing duplicate definitions --- .../grpc/polyglot/config/CommandLineArgs.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java index b26ffd8..c0c0921 100644 --- a/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java +++ b/src/main/java/me/dinowernli/grpc/polyglot/config/CommandLineArgs.java @@ -179,26 +179,6 @@ public Optional tlsCaCertPath() { return maybePath(tlsCaCertPath); } - public Optional oauthRefreshTokenEndpointUrl() { - return maybeUrl(oauthRefreshTokenEndpointUrl); - } - - public Optional oauthClientId() { - return Optional.ofNullable(oauthClientId); - } - - public Optional oauthClientSecret() { - return Optional.ofNullable(oauthClientSecret); - } - - public Optional oauthRefreshTokenPath() { - return maybePath(oauthRefreshTokenPath); - } - - public Optional oauthAccessTokenPath() { - return maybePath(oauthAccessTokenPath); - } - public Optional tlsClientCertPath() { return maybePath(tlsClientCertPath); }