mirror of https://github.com/grpc/grpc-java.git
ALTS: add ComputeEngineChannelBuilder (#5473)
This commit is contained in:
parent
f155d60e75
commit
b4af5ad986
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019 The gRPC Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.grpc.alts;
|
||||
|
||||
import io.grpc.CallCredentials;
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ClientCall;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.Status;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** An implementation of {@link ClientInterceptor} that adds call credentials on each call. */
|
||||
final class CallCredentialsInterceptor implements ClientInterceptor {
|
||||
|
||||
@Nullable private final CallCredentials credentials;
|
||||
private final Status status;
|
||||
|
||||
public CallCredentialsInterceptor(@Nullable CallCredentials credentials, Status status) {
|
||||
this.credentials = credentials;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||
if (!status.isOk()) {
|
||||
return new FailingClientCall<>(status);
|
||||
}
|
||||
return next.newCall(method, callOptions.withCallCredentials(credentials));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2019 The gRPC Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.grpc.alts;
|
||||
|
||||
import com.google.auth.oauth2.ComputeEngineCredentials;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.grpc.CallCredentials;
|
||||
import io.grpc.ForwardingChannelBuilder;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.alts.internal.AltsClientOptions;
|
||||
import io.grpc.alts.internal.AltsProtocolNegotiator.LazyChannel;
|
||||
import io.grpc.alts.internal.AltsTsiHandshaker;
|
||||
import io.grpc.alts.internal.GoogleDefaultProtocolNegotiator;
|
||||
import io.grpc.alts.internal.HandshakerServiceGrpc;
|
||||
import io.grpc.alts.internal.RpcProtocolVersionsUtil;
|
||||
import io.grpc.alts.internal.TsiHandshaker;
|
||||
import io.grpc.alts.internal.TsiHandshakerFactory;
|
||||
import io.grpc.auth.MoreCallCredentials;
|
||||
import io.grpc.internal.GrpcUtil;
|
||||
import io.grpc.internal.SharedResourcePool;
|
||||
import io.grpc.netty.GrpcSslContexts;
|
||||
import io.grpc.netty.InternalNettyChannelBuilder;
|
||||
import io.grpc.netty.NettyChannelBuilder;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
/**
|
||||
* {@code ManagedChannelBuilder} for Google Compute Engine. This class sets up a secure channel
|
||||
* using ALTS if applicable and using TLS as fallback.
|
||||
*/
|
||||
public final class ComputeEngineChannelBuilder
|
||||
extends ForwardingChannelBuilder<GoogleDefaultChannelBuilder> {
|
||||
|
||||
private final NettyChannelBuilder delegate;
|
||||
private GoogleDefaultProtocolNegotiator negotiatorForTest;
|
||||
|
||||
private ComputeEngineChannelBuilder(String target) {
|
||||
delegate = NettyChannelBuilder.forTarget(target);
|
||||
InternalNettyChannelBuilder.setProtocolNegotiatorFactory(
|
||||
delegate(), new ProtocolNegotiatorFactory());
|
||||
CallCredentials credentials = MoreCallCredentials.from(ComputeEngineCredentials.create());
|
||||
Status status = Status.OK;
|
||||
if (!CheckGcpEnvironment.isOnGcp()) {
|
||||
status =
|
||||
Status.INTERNAL.withDescription(
|
||||
"Compute Engine Credentials can only be used on Google Cloud Platform");
|
||||
}
|
||||
delegate().intercept(new CallCredentialsInterceptor(credentials, status));
|
||||
}
|
||||
|
||||
/** "Overrides" the static method in {@link ManagedChannelBuilder}. */
|
||||
public static final ComputeEngineChannelBuilder forTarget(String target) {
|
||||
return new ComputeEngineChannelBuilder(target);
|
||||
}
|
||||
|
||||
/** "Overrides" the static method in {@link ManagedChannelBuilder}. */
|
||||
public static ComputeEngineChannelBuilder forAddress(String name, int port) {
|
||||
return forTarget(GrpcUtil.authorityFromHostAndPort(name, port));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NettyChannelBuilder delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
GoogleDefaultProtocolNegotiator getProtocolNegotiatorForTest() {
|
||||
return negotiatorForTest;
|
||||
}
|
||||
|
||||
private final class ProtocolNegotiatorFactory
|
||||
implements InternalNettyChannelBuilder.ProtocolNegotiatorFactory {
|
||||
|
||||
@Override
|
||||
public GoogleDefaultProtocolNegotiator buildProtocolNegotiator() {
|
||||
final LazyChannel lazyHandshakerChannel =
|
||||
new LazyChannel(
|
||||
SharedResourcePool.forResource(HandshakerServiceChannel.SHARED_HANDSHAKER_CHANNEL));
|
||||
TsiHandshakerFactory altsHandshakerFactory =
|
||||
new TsiHandshakerFactory() {
|
||||
@Override
|
||||
public TsiHandshaker newHandshaker(String authority) {
|
||||
AltsClientOptions handshakerOptions =
|
||||
new AltsClientOptions.Builder()
|
||||
.setRpcProtocolVersions(RpcProtocolVersionsUtil.getRpcProtocolVersions())
|
||||
.setTargetName(authority)
|
||||
.build();
|
||||
return AltsTsiHandshaker.newClient(
|
||||
HandshakerServiceGrpc.newStub(lazyHandshakerChannel.get()), handshakerOptions);
|
||||
}
|
||||
};
|
||||
SslContext sslContext;
|
||||
try {
|
||||
sslContext = GrpcSslContexts.forClient().build();
|
||||
} catch (SSLException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return negotiatorForTest =
|
||||
new GoogleDefaultProtocolNegotiator(
|
||||
altsHandshakerFactory, lazyHandshakerChannel, sslContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,13 +19,8 @@ package io.grpc.alts;
|
|||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.grpc.CallCredentials;
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ClientCall;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.ForwardingChannelBuilder;
|
||||
import io.grpc.ManagedChannelBuilder;
|
||||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.alts.internal.AltsClientOptions;
|
||||
import io.grpc.alts.internal.AltsProtocolNegotiator.LazyChannel;
|
||||
|
|
@ -70,7 +65,7 @@ public final class GoogleDefaultChannelBuilder
|
|||
.withDescription("Failed to get Google default credentials")
|
||||
.withCause(e);
|
||||
}
|
||||
delegate().intercept(new GoogleDefaultInterceptor(credentials, status));
|
||||
delegate().intercept(new CallCredentialsInterceptor(credentials, status));
|
||||
}
|
||||
|
||||
/** "Overrides" the static method in {@link ManagedChannelBuilder}. */
|
||||
|
|
@ -125,27 +120,4 @@ public final class GoogleDefaultChannelBuilder
|
|||
altsHandshakerFactory, lazyHandshakerChannel, sslContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link ClientInterceptor} that adds Google call credentials on each call.
|
||||
*/
|
||||
static final class GoogleDefaultInterceptor implements ClientInterceptor {
|
||||
|
||||
@Nullable private final CallCredentials credentials;
|
||||
private final Status status;
|
||||
|
||||
public GoogleDefaultInterceptor(@Nullable CallCredentials credentials, Status status) {
|
||||
this.credentials = credentials;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||
if (!status.isOk()) {
|
||||
return new FailingClientCall<>(status);
|
||||
}
|
||||
return next.newCall(method, callOptions.withCallCredentials(credentials));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019 The gRPC Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.grpc.alts;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import io.grpc.alts.internal.GoogleDefaultProtocolNegotiator;
|
||||
import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public final class ComputeEngineChannelBuilderTest {
|
||||
|
||||
@Test
|
||||
public void buildsNettyChannel() throws Exception {
|
||||
ComputeEngineChannelBuilder builder = ComputeEngineChannelBuilder.forTarget("localhost:8080");
|
||||
builder.build();
|
||||
|
||||
ProtocolNegotiator protocolNegotiator = builder.getProtocolNegotiatorForTest();
|
||||
assertThat(protocolNegotiator).isInstanceOf(GoogleDefaultProtocolNegotiator.class);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue