Skip to content

Commit

Permalink
Remove security options for a separate PR
Browse files Browse the repository at this point in the history
Change-Id: Ibe2fb899f83744d4e38debc58379e9942350a83f
  • Loading branch information
jackdingilian committed Oct 7, 2024
1 parent 52832b2 commit 5a617b4
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,8 +26,7 @@
import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.ServerStream;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.OAuth2Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auto.value.AutoValue;
import com.google.bigtable.v2.Column;
import com.google.bigtable.v2.Family;
Expand Down Expand Up @@ -60,6 +59,9 @@
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -70,6 +72,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.threeten.bp.Duration;

/** Java implementation of the CBT test proxy. Used to test the Java CBT client. */
Expand All @@ -92,13 +95,50 @@ static CbtClient create(BigtableDataSettings settings, BigtableDataClient dataCl

private static final Logger logger = Logger.getLogger(CbtTestProxy.class.getName());

private CbtTestProxy() {
private CbtTestProxy(
boolean encrypted,
@Nullable String rootCerts,
@Nullable String sslTarget,
@Nullable String credential) {
this.encrypted = encrypted;
this.rootCerts = rootCerts;
this.sslTarget = sslTarget;
this.credential = credential;
this.idClientMap = new ConcurrentHashMap<>();
}

/** Factory method to return a proxy instance. */
public static CbtTestProxy create() {
return new CbtTestProxy();
/**
* Factory method to return a proxy instance that interacts with server unencrypted and
* unauthenticated.
*/
public static CbtTestProxy createUnencrypted() {
return new CbtTestProxy(false, null, null, null);
}

/**
* Factory method to return a proxy instance that interacts with server encrypted. Default
* authority and public certificates are used if null values are passed in.
*
* @param rootCertsPemPath The path to a root certificate PEM file
* @param sslTarget The override of SSL target name
* @param credentialJsonPath The path to a credential JSON file
*/
public static CbtTestProxy createEncrypted(
@Nullable String rootCertsPemPath,
@Nullable String sslTarget,
@Nullable String credentialJsonPath)
throws IOException {
String tmpRootCerts = null, tmpCredential = null;
if (rootCertsPemPath != null) {
Path file = Paths.get(rootCertsPemPath);
tmpRootCerts = new String(Files.readAllBytes(file), UTF_8);
}
if (credentialJsonPath != null) {
Path file = Paths.get(credentialJsonPath);
tmpCredential = new String(Files.readAllBytes(file), UTF_8);
}

return new CbtTestProxy(true, tmpRootCerts, sslTarget, tmpCredential);
}

/**
Expand Down Expand Up @@ -152,26 +192,19 @@ private CbtClient getClient(String id) throws StatusException {
@Override
public synchronized void createClient(
CreateClientRequest request, StreamObserver<CreateClientResponse> responseObserver) {

Preconditions.checkArgument(!request.getClientId().isEmpty(), "client id must be provided");
Preconditions.checkArgument(!request.getProjectId().isEmpty(), "project id must be provided");
Preconditions.checkArgument(!request.getInstanceId().isEmpty(), "instance id must be provided");
Preconditions.checkArgument(!request.getDataTarget().isEmpty(), "data target must be provided");
Preconditions.checkArgument(
!request.getSecurityOptions().getUseSsl()
|| !request.getSecurityOptions().getSslRootCertsPemBytes().isEmpty(),
"security_options.ssl_root_certs_pem must be provided if security_options.use_ssl is true");

if (idClientMap.containsKey(request.getClientId())) {
if (idClientMap.contains(request.getClientId())) {
responseObserver.onError(
Status.ALREADY_EXISTS
.withDescription("Client " + request.getClientId() + " already exists.")
.asException());
return;
}

// setRefreshingChannel is needed for now.
@SuppressWarnings("deprecation")
BigtableDataSettings.Builder settingsBuilder =
BigtableDataSettings.newBuilder()
// Disable channel refreshing when not using the real server
Expand All @@ -180,6 +213,9 @@ public synchronized void createClient(
.setInstanceId(request.getInstanceId())
.setAppProfileId(request.getAppProfileId());

settingsBuilder.stubSettings().setEnableRoutingCookie(false);
settingsBuilder.stubSettings().setEnableRetryInfo(false);

if (request.hasPerOperationTimeout()) {
Duration newTimeout = Duration.ofMillis(Durations.toMillis(request.getPerOperationTimeout()));
settingsBuilder = overrideTimeoutSetting(newTimeout, settingsBuilder);
Expand Down Expand Up @@ -213,13 +249,8 @@ public synchronized void createClient(
settingsBuilder
.stubSettings()
.setEndpoint(request.getDataTarget())
.setTransportChannelProvider(
getTransportChannel(
request.getSecurityOptions().getUseSsl(),
request.getSecurityOptions().getSslRootCertsPem(),
request.getSecurityOptions().getSslEndpointOverride()))
.setCredentialsProvider(
getCredentialsProvider(request.getSecurityOptions().getAccessToken()));
.setTransportChannelProvider(getTransportChannel())
.setCredentialsProvider(getCredentialsProvider());
}
BigtableDataSettings settings = settingsBuilder.build();
BigtableDataClient client = BigtableDataClient.create(settings);
Expand Down Expand Up @@ -749,60 +780,52 @@ private static String extractTableIdFromTableName(String fullTableName)
return matcher.group(3);
}

@SuppressWarnings("rawtypes")
private InstantiatingGrpcChannelProvider getTransportChannel(
boolean encrypted, String rootCertsPem, String sslTarget) {
private InstantiatingGrpcChannelProvider getTransportChannel() throws IOException {
if (!encrypted) {
return EnhancedBigtableStubSettings.defaultGrpcTransportProviderBuilder()
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
.build();
}

final SslContext sslContext;
if (rootCertsPem.isEmpty()) {
sslContext = null;
} else {
try {
sslContext =
GrpcSslContexts.forClient()
.trustManager(new ByteArrayInputStream(rootCertsPem.getBytes(UTF_8)))
.build();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
if (rootCerts == null) {
return EnhancedBigtableStubSettings.defaultGrpcTransportProviderBuilder().build();
}

final SslContext secureContext =
GrpcSslContexts.forClient()
.trustManager(new ByteArrayInputStream(rootCerts.getBytes(UTF_8)))
.build();
return EnhancedBigtableStubSettings.defaultGrpcTransportProviderBuilder()
.setChannelConfigurator(
new ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder>() {
@Override
public ManagedChannelBuilder apply(ManagedChannelBuilder input) {
NettyChannelBuilder channelBuilder = (NettyChannelBuilder) input;

if (sslContext != null) {
channelBuilder.sslContext(sslContext);
}

if (!sslTarget.isEmpty()) {
channelBuilder.overrideAuthority(sslTarget);
}

channelBuilder.sslContext(secureContext).overrideAuthority(sslTarget);
return channelBuilder;
}
})
.build();
}

private CredentialsProvider getCredentialsProvider(String accessToken) {
if (accessToken.isEmpty()) {
private CredentialsProvider getCredentialsProvider() throws IOException {
if (credential == null) {
return NoCredentialsProvider.create();
}

return FixedCredentialsProvider.create(
OAuth2Credentials.create(new AccessToken(accessToken, null)));
final GoogleCredentials creds =
GoogleCredentials.fromStream(new ByteArrayInputStream(credential.getBytes(UTF_8)));

return FixedCredentialsProvider.create(creds);
}

private final ConcurrentHashMap<String, CbtClient> idClientMap;
private final boolean encrypted;

// Parameters that may be needed when "encrypted" is true.
private final String rootCerts;
private final String sslTarget;
private final String credential;

private static final Pattern tablePattern =
Pattern.compile("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,19 @@ public static void main(String[] args) throws InterruptedException, IOException
throw new IllegalArgumentException(String.format("Port %d is not > 0.", port));
}

CbtTestProxy cbtTestProxy = CbtTestProxy.create();
CbtTestProxy cbtTestProxy;

// If encryption is specified
boolean encrypted = Boolean.getBoolean("encrypted");
if (encrypted) {
String rootCertsPemPath = System.getProperty("root.certs.pem.path");
String sslTarget = System.getProperty("ssl.target");
String credentialJsonPath = System.getProperty("credential.json.path");
cbtTestProxy = CbtTestProxy.createEncrypted(rootCertsPemPath, sslTarget, credentialJsonPath);
} else {
cbtTestProxy = CbtTestProxy.createUnencrypted();
}

logger.info(String.format("Test proxy starting on %d", port));
ServerBuilder.forPort(port).addService(cbtTestProxy).build().start().awaitTermination();
}
Expand Down
32 changes: 0 additions & 32 deletions test-proxy/src/main/proto/test_proxy.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,6 @@ enum OptionalFeatureConfig {

// Request to test proxy service to create a client object.
message CreateClientRequest {
message SecurityOptions {
// Access token to use for client credentials. If empty, the client will not
// use any call credentials. Certain implementations may require `use_ssl`
// to be set when using this.
string access_token = 1;

// Whether to use SSL channel credentials when connecting to the data
// endpoint.
bool use_ssl = 2;

// If using SSL channel credentials, override the SSL endpoint to match the
// host that is specified in the backend's certificate. Also sets the
// client's authority header value.
string ssl_endpoint_override = 3;

// PEM encoding of the server root certificates. If not set, the default
// root certs will be used instead. The default can be overridden via the
// GRPC_DEFAULT_SSL_ROOTS_FILE_PATH env var.
string ssl_root_certs_pem = 4;
}

// A unique ID associated with the client object to be created.
string client_id = 1;

Expand Down Expand Up @@ -87,17 +66,6 @@ message CreateClientRequest {
// Optional config that dictates how the optional features should be enabled
// during the client creation. Please check the enum type's docstring above.
OptionalFeatureConfig optional_feature_config = 7;

// Options to allow connecting to backends with channel and/or call
// credentials. This is needed internally by Cloud Bigtable's own testing
// frameworks.It is not necessary to support these fields for client
// conformance testing.
//
// WARNING: this allows the proxy to connect to a real production
// CBT backend with the right options, however, the proxy itself is insecure
// so it is not recommended to use it with real credentials or outside testing
// contexts.
SecurityOptions security_options = 8;
}

// Response from test proxy service for CreateClientRequest.
Expand Down

0 comments on commit 5a617b4

Please sign in to comment.