Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oauth config override #63

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static void callEndpoint(
dynamicClient = DynamicGrpcClient.create(methodDescriptor, hostAndPort, callConfig);
}

logger.info("Reading input from stdin");

ImmutableList<DynamicMessage> requestMessages =
MessageReader.forStdin(methodDescriptor.getInputType()).read();
StreamObserver<DynamicMessage> streamObserver =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -47,6 +49,21 @@ public class CommandLineArgs {
@Option(name = "--tls_ca_cert_path", metaVar = "<path>")
private String tlsCaCertPath;

@Option(name = "--oauth_refresh_token_endpoint_url", metaVar = "<url>")
private String oauthRefreshTokenEndpointUrl;

@Option(name = "--oauth_client_id", metaVar = "<client-id>")
private String oauthClientId;

@Option(name = "--oauth_client_secret", metaVar = "<client-secret>")
private String oauthClientSecret;

@Option(name = "--oauth_refresh_token_path", metaVar = "<path>")
private String oauthRefreshTokenPath;

@Option(name = "--oauth_access_token_path", metaVar = "<path>")
private String oauthAccessTokenPath;

@Option(name = "--help")
private Boolean help;

Expand Down Expand Up @@ -153,6 +170,26 @@ public Optional<Path> tlsCaCertPath() {
return maybePath(tlsCaCertPath);
}

public Optional<URL> oauthRefreshTokenEndpointUrl() {
return maybeUrl(oauthRefreshTokenEndpointUrl);
}

public Optional<String> oauthClientId() {
return Optional.ofNullable(oauthClientId);
}

public Optional<String> oauthClientSecret() {
return Optional.ofNullable(oauthClientSecret);
}

public Optional<Path> oauthRefreshTokenPath() {
return maybePath(oauthRefreshTokenPath);
}

public Optional<Path> oauthAccessTokenPath() {
return maybePath(oauthAccessTokenPath);
}

/**
* First stage of a migration towards a "command"-based instantiation of polyglot.
* Supported commands:
Expand Down Expand Up @@ -214,4 +251,17 @@ private static Optional<Path> maybePath(String rawPath) {
Preconditions.checkArgument(Files.exists(path), "File " + rawPath + " does not exist");
return Optional.of(Paths.get(rawPath));
}

private static Optional<URL> maybeUrl(String rawUrl) {
if (rawUrl == null) {
return Optional.empty();
}
try {
URL url = new URL(rawUrl);
return Optional.of(url);
} catch (MalformedURLException mURLE) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/mURLE/e

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure what this means

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant that the standard naming convention is "e" rather than "mURLE".

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok thanks, will do

throw new IllegalArgumentException("URL " + rawUrl +" is invalid", mURLE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing space after +

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation looks bad

}
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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> args) {
ImmutableList<String> allArgs = ImmutableList.<String>builder()
.addAll(args)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -71,28 +75,86 @@ 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(".")));
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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent here as well

please fix throughout the pr

.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().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();
}

@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();
.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)
.build();
}
private static URL getTestUrl(String testUrl) {
try {
return new URL(testUrl);
} catch (MalformedURLException mUrlE) {
throw new RuntimeException();
}
}
}