netty: Add ServerCredentials

This commit is contained in:
Eric Anderson 2020-11-06 16:00:56 -08:00 committed by Eric Anderson
parent 60319dad2d
commit edcc6854a6
13 changed files with 525 additions and 62 deletions

View File

@ -21,9 +21,11 @@ import static com.google.common.truth.Truth.assertThat;
import io.grpc.ChannelCredentials;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.InsecureServerCredentials;
import io.grpc.ManagedChannel;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerCredentials;
import io.grpc.TlsServerCredentials;
import io.grpc.internal.testing.TestUtils;
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
@ -69,14 +71,15 @@ public final class ShadingTest {
@Test
public void serviceLoaderFindsNetty() throws Exception {
assertThat(ServerBuilder.forPort(0)).isInstanceOf(NettyServerBuilder.class);
assertThat(Grpc.newServerBuilderForPort(0, InsecureServerCredentials.create()))
.isInstanceOf(NettyServerBuilder.class);
assertThat(Grpc.newChannelBuilder("localhost:1234", InsecureChannelCredentials.create()))
.isInstanceOf(NettyChannelBuilder.class);
}
@Test
public void basic() throws Exception {
server = ServerBuilder.forPort(0)
server = Grpc.newServerBuilderForPort(0, InsecureServerCredentials.create())
.addService(new SimpleServiceImpl())
.build().start();
channel = Grpc.newChannelBuilder(
@ -89,8 +92,9 @@ public final class ShadingTest {
@Test
public void tcnative() throws Exception {
server = NettyServerBuilder.forPort(0)
.useTransportSecurity(TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key"))
ServerCredentials serverCreds = TlsServerCredentials.create(
TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key"));
server = Grpc.newServerBuilderForPort(0, serverCreds)
.addService(new SimpleServiceImpl())
.build().start();
ChannelCredentials creds = NettySslContextChannelCredentials.create(

View File

@ -18,8 +18,6 @@ package io.grpc.netty;
import io.grpc.ChannelCredentials;
import io.grpc.Internal;
import io.netty.channel.ChannelHandler;
import io.netty.util.AsciiString;
/**
* Internal {@link NettyChannelCredentials} accessor. This is intended for usage internal to the
@ -50,27 +48,8 @@ public final class InternalNettyChannelCredentials {
@Override
public InternalProtocolNegotiator.ProtocolNegotiator newNegotiator() {
final ProtocolNegotiator pn = result.negotiator.newNegotiator();
final class LocalProtocolNegotiator
implements InternalProtocolNegotiator.ProtocolNegotiator {
@Override
public AsciiString scheme() {
return pn.scheme();
}
@Override
public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) {
return pn.newHandler(grpcHandler);
}
@Override
public void close() {
pn.close();
}
}
return new LocalProtocolNegotiator();
return new InternalProtocolNegotiator.ProtocolNegotiatorAdapter(
result.negotiator.newNegotiator());
}
@Override

View File

@ -0,0 +1,69 @@
/*
* Copyright 2020 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.netty;
import io.grpc.Internal;
import io.grpc.ServerCredentials;
import io.grpc.internal.ObjectPool;
import java.util.concurrent.Executor;
/**
* Internal {@link NettyServerCredentials} accessor. This is intended for usage internal to the
* gRPC team. If you *really* think you need to use this, contact the gRPC team first.
*/
@Internal
public final class InternalNettyServerCredentials {
private InternalNettyServerCredentials() {}
/** Creates a {@link ServerCredentials} that will use the provided {@code negotiator}. */
public static ServerCredentials create(InternalProtocolNegotiator.ProtocolNegotiator negotiator) {
return NettyServerCredentials.create(ProtocolNegotiators.fixedServerFactory(negotiator));
}
/**
* Creates a {@link ServerCredentials} that will use the provided {@code negotiator}. Use of
* {@link #create(io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator)} is preferred over
* this method when possible.
*/
public static ServerCredentials create(InternalProtocolNegotiator.ServerFactory negotiator) {
return NettyServerCredentials.create(negotiator);
}
/**
* Converts a {@link ServerCredentials} to a negotiator, in similar fashion as for a new server.
*
* @throws IllegalArgumentException if unable to convert
*/
public static InternalProtocolNegotiator.ServerFactory toNegotiator(
ServerCredentials channelCredentials) {
final ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(channelCredentials);
if (result.error != null) {
throw new IllegalArgumentException(result.error);
}
final class ServerFactory implements InternalProtocolNegotiator.ServerFactory {
@Override
public InternalProtocolNegotiator.ProtocolNegotiator newNegotiator(
ObjectPool<? extends Executor> offloadExecutorPool) {
return new InternalProtocolNegotiator.ProtocolNegotiatorAdapter(
result.negotiator.newNegotiator(offloadExecutorPool));
}
}
return new ServerFactory();
}
}

View File

@ -16,7 +16,12 @@
package io.grpc.netty;
import com.google.common.base.Preconditions;
import io.grpc.Internal;
import io.grpc.internal.ObjectPool;
import io.netty.channel.ChannelHandler;
import io.netty.util.AsciiString;
import java.util.concurrent.Executor;
/**
* Internal accessor for {@link ProtocolNegotiator}.
@ -28,7 +33,35 @@ public final class InternalProtocolNegotiator {
public interface ProtocolNegotiator extends io.grpc.netty.ProtocolNegotiator {}
static final class ProtocolNegotiatorAdapter
implements InternalProtocolNegotiator.ProtocolNegotiator {
private final io.grpc.netty.ProtocolNegotiator negotiator;
public ProtocolNegotiatorAdapter(io.grpc.netty.ProtocolNegotiator negotiator) {
this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator");
}
@Override
public AsciiString scheme() {
return negotiator.scheme();
}
@Override
public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) {
return negotiator.newHandler(grpcHandler);
}
@Override
public void close() {
negotiator.close();
}
}
public interface ClientFactory extends io.grpc.netty.ProtocolNegotiator.ClientFactory {
@Override ProtocolNegotiator newNegotiator();
}
public interface ServerFactory extends io.grpc.netty.ProtocolNegotiator.ServerFactory {
@Override ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadExecutorPool);
}
}

View File

@ -29,6 +29,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.grpc.ExperimentalApi;
import io.grpc.Internal;
import io.grpc.ServerBuilder;
import io.grpc.ServerCredentials;
import io.grpc.ServerStreamTracer;
import io.grpc.internal.AbstractServerImplBuilder;
import io.grpc.internal.FixedObjectPool;
@ -58,7 +59,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import javax.net.ssl.SSLException;
/**
@ -98,8 +98,8 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
private ObjectPool<? extends EventLoopGroup> workerEventLoopGroupPool =
DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL;
private boolean forceHeapBuffer;
private SslContext sslContext;
private ProtocolNegotiator protocolNegotiator;
private ProtocolNegotiator.ServerFactory protocolNegotiatorFactory;
private final boolean freezeProtocolNegotiatorFactory;
private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
private boolean autoFlowControl = true;
private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
@ -121,7 +121,18 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
*/
@CheckReturnValue
public static NettyServerBuilder forPort(int port) {
return new NettyServerBuilder(port);
return forAddress(new InetSocketAddress(port));
}
/**
* Creates a server builder that will bind to the given port.
*
* @param port the port on which the server is to be bound.
* @return the server builder.
*/
@CheckReturnValue
public static NettyServerBuilder forPort(int port, ServerCredentials creds) {
return forAddress(new InetSocketAddress(port), creds);
}
/**
@ -135,6 +146,21 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
return new NettyServerBuilder(address);
}
/**
* Creates a server builder configured with the given {@link SocketAddress}.
*
* @param address the socket address on which the server is to be bound.
* @return the server builder
*/
@CheckReturnValue
public static NettyServerBuilder forAddress(SocketAddress address, ServerCredentials creds) {
ProtocolNegotiators.FromServerCredentialsResult result = ProtocolNegotiators.from(creds);
if (result.error != null) {
throw new IllegalArgumentException(result.error);
}
return new NettyServerBuilder(address, result.negotiator);
}
private final class NettyClientTransportServersBuilder implements ClientTransportServersBuilder {
@Override
public List<? extends InternalServer> buildClientTransportServers(
@ -143,16 +169,21 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
}
}
@CheckReturnValue
private NettyServerBuilder(int port) {
serverImplBuilder = new ServerImplBuilder(new NettyClientTransportServersBuilder());
this.listenAddresses.add(new InetSocketAddress(port));
}
@CheckReturnValue
private NettyServerBuilder(SocketAddress address) {
serverImplBuilder = new ServerImplBuilder(new NettyClientTransportServersBuilder());
this.listenAddresses.add(address);
this.protocolNegotiatorFactory = ProtocolNegotiators.serverPlaintextFactory();
this.freezeProtocolNegotiatorFactory = false;
}
@CheckReturnValue
NettyServerBuilder(
SocketAddress address, ProtocolNegotiator.ServerFactory negotiatorFactory) {
serverImplBuilder = new ServerImplBuilder(new NettyClientTransportServersBuilder());
this.listenAddresses.add(address);
this.protocolNegotiatorFactory = checkNotNull(negotiatorFactory, "negotiatorFactory");
this.freezeProtocolNegotiatorFactory = true;
}
@Internal
@ -317,25 +348,28 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
* have been configured with {@link GrpcSslContexts}, but options could have been overridden.
*/
public NettyServerBuilder sslContext(SslContext sslContext) {
checkState(!freezeProtocolNegotiatorFactory,
"Cannot change security when using ServerCredentials");
if (sslContext != null) {
checkArgument(sslContext.isServer(),
"Client SSL context can not be used for server");
GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
} else {
protocolNegotiatorFactory = ProtocolNegotiators.serverPlaintextFactory();
}
this.sslContext = sslContext;
return this;
}
/**
* Sets the {@link ProtocolNegotiator} to be used. If non-{@code null}, overrides the value
* specified in {@link #sslContext(SslContext)}.
*
* <p>Default: {@code null}.
* Sets the {@link ProtocolNegotiator} to be used. Overrides the value specified in {@link
* #sslContext(SslContext)}.
*/
@Internal
public final NettyServerBuilder protocolNegotiator(
@Nullable ProtocolNegotiator protocolNegotiator) {
this.protocolNegotiator = protocolNegotiator;
public final NettyServerBuilder protocolNegotiator(ProtocolNegotiator protocolNegotiator) {
checkState(!freezeProtocolNegotiatorFactory,
"Cannot change security when using ServerCredentials");
this.protocolNegotiatorFactory = ProtocolNegotiators.fixedServerFactory(protocolNegotiator);
return this;
}
@ -586,12 +620,8 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
List<? extends ServerStreamTracer.Factory> streamTracerFactories) {
assertEventLoopsAndChannelType();
ProtocolNegotiator negotiator = protocolNegotiator;
if (negotiator == null) {
negotiator = sslContext != null
? ProtocolNegotiators.serverTls(sslContext, this.serverImplBuilder.getExecutorPool())
: ProtocolNegotiators.serverPlaintext();
}
ProtocolNegotiator negotiator = protocolNegotiatorFactory.newNegotiator(
this.serverImplBuilder.getExecutorPool());
List<NettyServer> transportServers = new ArrayList<>(listenAddresses.size());
for (SocketAddress listenAddress : listenAddresses) {
@ -631,23 +661,31 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder<NettySer
@Override
public NettyServerBuilder useTransportSecurity(File certChain, File privateKey) {
checkState(!freezeProtocolNegotiatorFactory,
"Cannot change security when using ServerCredentials");
SslContext sslContext;
try {
sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
} catch (SSLException e) {
// This should likely be some other, easier to catch exception.
throw new RuntimeException(e);
}
protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
return this;
}
@Override
public NettyServerBuilder useTransportSecurity(InputStream certChain, InputStream privateKey) {
checkState(!freezeProtocolNegotiatorFactory,
"Cannot change security when using ServerCredentials");
SslContext sslContext;
try {
sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
} catch (SSLException e) {
// This should likely be some other, easier to catch exception.
throw new RuntimeException(e);
}
protocolNegotiatorFactory = ProtocolNegotiators.serverTlsFactory(sslContext);
return this;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2020 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.netty;
import com.google.common.base.Preconditions;
import io.grpc.ServerCredentials;
/** A credential with full control over the security handshake. */
final class NettyServerCredentials extends ServerCredentials {
public static ServerCredentials create(ProtocolNegotiator.ServerFactory negotiator) {
return new NettyServerCredentials(negotiator);
}
private final ProtocolNegotiator.ServerFactory negotiator;
private NettyServerCredentials(ProtocolNegotiator.ServerFactory negotiator) {
this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator");
}
public ProtocolNegotiator.ServerFactory getNegotiator() {
return negotiator;
}
}

View File

@ -17,10 +17,11 @@
package io.grpc.netty;
import io.grpc.Internal;
import io.grpc.ServerCredentials;
import io.grpc.ServerProvider;
import java.net.InetSocketAddress;
/** Provider for {@link NettyChannelBuilder} instances. */
/** Provider for {@link NettyServerBuilder} instances. */
@Internal
public final class NettyServerProvider extends ServerProvider {
@ -38,5 +39,15 @@ public final class NettyServerProvider extends ServerProvider {
protected NettyServerBuilder builderForPort(int port) {
return NettyServerBuilder.forPort(port);
}
@Override
protected NewServerBuilderResult newServerBuilderForPort(int port, ServerCredentials creds) {
ProtocolNegotiators.FromServerCredentialsResult result = ProtocolNegotiators.from(creds);
if (result.error != null) {
return NewServerBuilderResult.error(result.error);
}
return NewServerBuilderResult.serverBuilder(
new NettyServerBuilder(new InetSocketAddress(port), result.negotiator));
}
}

View File

@ -16,6 +16,7 @@
package io.grpc.netty;
import com.google.common.base.Preconditions;
import io.grpc.ChannelCredentials;
import io.grpc.ExperimentalApi;
import io.netty.handler.ssl.SslContext;
@ -30,6 +31,9 @@ public final class NettySslContextChannelCredentials {
* with {@link GrpcSslContexts}, but options could have been overridden.
*/
public static ChannelCredentials create(SslContext sslContext) {
Preconditions.checkArgument(sslContext.isClient(),
"Server SSL context can not be used for client channel");
GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
return NettyChannelCredentials.create(ProtocolNegotiators.tlsClientFactory(sslContext));
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2020 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.netty;
import com.google.common.base.Preconditions;
import io.grpc.ExperimentalApi;
import io.grpc.ServerCredentials;
import io.netty.handler.ssl.SslContext;
/** A credential that performs TLS with Netty's SslContext as configuration. */
@ExperimentalApi("There is no plan to make this API stable, given transport API instability")
public final class NettySslContextServerCredentials {
private NettySslContextServerCredentials() {}
/**
* Create a credential using Netty's SslContext as configuration. It must have been configured
* with {@link GrpcSslContexts}, but options could have been overridden.
*/
public static ServerCredentials create(SslContext sslContext) {
Preconditions.checkArgument(sslContext.isServer(),
"Client SSL context can not be used for server");
GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
return NettyServerCredentials.create(ProtocolNegotiators.serverTlsFactory(sslContext));
}
}

View File

@ -16,8 +16,10 @@
package io.grpc.netty;
import io.grpc.internal.ObjectPool;
import io.netty.channel.ChannelHandler;
import io.netty.util.AsciiString;
import java.util.concurrent.Executor;
/**
* An class that provides a Netty handler to control protocol negotiation.
@ -52,4 +54,13 @@ interface ProtocolNegotiator {
/** Returns the implicit port to use if no port was specified explicitly by the user. */
int getDefaultPort();
}
interface ServerFactory {
/**
* Creates a new negotiator.
*
* @param offloadExecutorPool an executor pool for time-consuming tasks
*/
ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadExecutorPool);
}
}

View File

@ -28,15 +28,19 @@ import io.grpc.ChannelCredentials;
import io.grpc.ChannelLogger;
import io.grpc.ChannelLogger.ChannelLogLevel;
import io.grpc.ChoiceChannelCredentials;
import io.grpc.ChoiceServerCredentials;
import io.grpc.CompositeCallCredentials;
import io.grpc.CompositeChannelCredentials;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.InsecureServerCredentials;
import io.grpc.InternalChannelz.Security;
import io.grpc.InternalChannelz.Tls;
import io.grpc.SecurityLevel;
import io.grpc.ServerCredentials;
import io.grpc.Status;
import io.grpc.TlsChannelCredentials;
import io.grpc.TlsServerCredentials;
import io.grpc.internal.GrpcAttributes;
import io.grpc.internal.GrpcUtil;
import io.grpc.internal.ObjectPool;
@ -57,12 +61,14 @@ import io.netty.handler.proxy.ProxyConnectionEvent;
import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.OpenSslEngine;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.handler.ssl.SslProvider;
import io.netty.util.AsciiString;
import io.netty.util.Attribute;
import io.netty.util.AttributeMap;
import java.io.ByteArrayInputStream;
import java.net.SocketAddress;
import java.net.URI;
import java.nio.channels.ClosedChannelException;
@ -85,6 +91,8 @@ final class ProtocolNegotiators {
private static final Logger log = Logger.getLogger(ProtocolNegotiators.class.getName());
private static final EnumSet<TlsChannelCredentials.Feature> understoodTlsFeatures =
EnumSet.noneOf(TlsChannelCredentials.Feature.class);
private static final EnumSet<TlsServerCredentials.Feature> understoodServerTlsFeatures =
EnumSet.noneOf(TlsServerCredentials.Feature.class);
private ProtocolNegotiators() {
@ -167,6 +175,72 @@ final class ProtocolNegotiators {
}
}
public static FromServerCredentialsResult from(ServerCredentials creds) {
if (creds instanceof TlsServerCredentials) {
TlsServerCredentials tlsCreds = (TlsServerCredentials) creds;
Set<TlsServerCredentials.Feature> incomprehensible =
tlsCreds.incomprehensible(understoodServerTlsFeatures);
if (!incomprehensible.isEmpty()) {
return FromServerCredentialsResult.error(
"TLS features not understood: " + incomprehensible);
}
SslContextBuilder builder = GrpcSslContexts.forServer(
new ByteArrayInputStream(tlsCreds.getCertificateChain()),
new ByteArrayInputStream(tlsCreds.getPrivateKey()),
tlsCreds.getPrivateKeyPassword());
SslContext sslContext;
try {
sslContext = builder.build();
} catch (SSLException ex) {
throw new IllegalArgumentException(
"Unexpected error converting ServerCredentials to Netty SslContext", ex);
}
return FromServerCredentialsResult.negotiator(serverTlsFactory(sslContext));
} else if (creds instanceof InsecureServerCredentials) {
return FromServerCredentialsResult.negotiator(serverPlaintextFactory());
} else if (creds instanceof NettyServerCredentials) {
NettyServerCredentials nettyCreds = (NettyServerCredentials) creds;
return FromServerCredentialsResult.negotiator(nettyCreds.getNegotiator());
} else if (creds instanceof ChoiceServerCredentials) {
ChoiceServerCredentials choiceCreds = (ChoiceServerCredentials) creds;
StringBuilder error = new StringBuilder();
for (ServerCredentials innerCreds : choiceCreds.getCredentialsList()) {
FromServerCredentialsResult result = from(innerCreds);
if (result.error == null) {
return result;
}
error.append(", ");
error.append(result.error);
}
return FromServerCredentialsResult.error(error.substring(2));
} else {
return FromServerCredentialsResult.error(
"Unsupported credential type: " + creds.getClass().getName());
}
}
public static final class FromServerCredentialsResult {
public final ProtocolNegotiator.ServerFactory negotiator;
public final String error;
private FromServerCredentialsResult(ProtocolNegotiator.ServerFactory negotiator, String error) {
this.negotiator = negotiator;
this.error = error;
}
public static FromServerCredentialsResult error(String error) {
return new FromServerCredentialsResult(null, Preconditions.checkNotNull(error, "error"));
}
public static FromServerCredentialsResult negotiator(ProtocolNegotiator.ServerFactory factory) {
return new FromServerCredentialsResult(Preconditions.checkNotNull(factory, "factory"), null);
}
}
static ChannelLogger negotiationLogger(ChannelHandlerContext ctx) {
return negotiationLogger(ctx.channel());
}
@ -190,6 +264,26 @@ final class ProtocolNegotiators {
return new NoopChannelLogger();
}
public static ProtocolNegotiator.ServerFactory fixedServerFactory(
ProtocolNegotiator negotiator) {
return new FixedProtocolNegotiatorServerFactory(negotiator);
}
private static final class FixedProtocolNegotiatorServerFactory
implements ProtocolNegotiator.ServerFactory {
private final ProtocolNegotiator protocolNegotiator;
public FixedProtocolNegotiatorServerFactory(ProtocolNegotiator protocolNegotiator) {
this.protocolNegotiator =
Preconditions.checkNotNull(protocolNegotiator, "protocolNegotiator");
}
@Override
public ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadExecutorPool) {
return protocolNegotiator;
}
}
/**
* Create a server plaintext handler for gRPC.
*/
@ -197,6 +291,41 @@ final class ProtocolNegotiators {
return new PlaintextProtocolNegotiator();
}
/**
* Create a server plaintext handler factory for gRPC.
*/
public static ProtocolNegotiator.ServerFactory serverPlaintextFactory() {
return new PlaintextProtocolNegotiatorServerFactory();
}
@VisibleForTesting
static final class PlaintextProtocolNegotiatorServerFactory
implements ProtocolNegotiator.ServerFactory {
@Override
public ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadExecutorPool) {
return serverPlaintext();
}
}
public static ProtocolNegotiator.ServerFactory serverTlsFactory(SslContext sslContext) {
return new TlsProtocolNegotiatorServerFactory(sslContext);
}
@VisibleForTesting
static final class TlsProtocolNegotiatorServerFactory
implements ProtocolNegotiator.ServerFactory {
private final SslContext sslContext;
public TlsProtocolNegotiatorServerFactory(SslContext sslContext) {
this.sslContext = Preconditions.checkNotNull(sslContext, "sslContext");
}
@Override
public ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadExecutorPool) {
return serverTls(sslContext, offloadExecutorPool);
}
}
/**
* Create a server TLS handler for HTTP/2 capable of using ALPN/NPN.
* @param executorPool a dedicated {@link Executor} pool for time-consuming TLS tasks

View File

@ -16,10 +16,13 @@
package io.grpc.netty;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import io.grpc.InsecureServerCredentials;
import io.grpc.ServerCredentials;
import io.grpc.ServerProvider;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -45,4 +48,20 @@ public class NettyServerProviderTest {
public void builderIsANettyBuilder() {
assertSame(NettyServerBuilder.class, provider.builderForPort(443).getClass());
}
@Test
public void newServerBuilderForPort_success() {
ServerProvider.NewServerBuilderResult result =
provider.newServerBuilderForPort(80, InsecureServerCredentials.create());
assertThat(result.getServerBuilder()).isInstanceOf(NettyServerBuilder.class);
}
@Test
public void newServerBuilderForPort_fail() {
ServerProvider.NewServerBuilderResult result = provider.newServerBuilderForPort(
80, new FakeServerCredentials());
assertThat(result.getError()).contains("FakeServerCredentials");
}
private static final class FakeServerCredentials extends ServerCredentials {}
}

View File

@ -33,14 +33,18 @@ import io.grpc.Attributes;
import io.grpc.CallCredentials;
import io.grpc.ChannelCredentials;
import io.grpc.ChoiceChannelCredentials;
import io.grpc.ChoiceServerCredentials;
import io.grpc.CompositeChannelCredentials;
import io.grpc.Grpc;
import io.grpc.InsecureChannelCredentials;
import io.grpc.InsecureServerCredentials;
import io.grpc.InternalChannelz.Security;
import io.grpc.SecurityLevel;
import io.grpc.ServerCredentials;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.grpc.TlsChannelCredentials;
import io.grpc.TlsServerCredentials;
import io.grpc.internal.GrpcAttributes;
import io.grpc.internal.testing.TestUtils;
import io.grpc.netty.ProtocolNegotiators.ClientTlsHandler;
@ -110,6 +114,7 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.DisableOnDebug;
@ -128,6 +133,15 @@ public class ProtocolNegotiatorsTest {
@Override public void run() {}
};
private static File server1Cert;
private static File server1Key;
@BeforeClass
public static void loadCerts() throws Exception {
server1Cert = TestUtils.loadCert("server1.pem");
server1Key = TestUtils.loadCert("server1.key");
}
private static final int TIMEOUT_SECONDS = 60;
@Rule public final TestRule globalTimeout = new DisableOnDebug(Timeout.seconds(TIMEOUT_SECONDS));
@SuppressWarnings("deprecation") // https://github.com/grpc/grpc-java/issues/7467
@ -168,7 +182,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_unknown() {
public void fromClient_unknown() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(new ChannelCredentials() {});
assertThat(result.error).isNotNull();
@ -177,7 +191,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_tls() {
public void fromClient_tls() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(TlsChannelCredentials.create());
assertThat(result.error).isNull();
@ -187,7 +201,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_unspportedTls() {
public void fromClient_unsupportedTls() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(TlsChannelCredentials.newBuilder().requireFakeFeature().build());
assertThat(result.error).contains("FAKE");
@ -196,7 +210,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_insecure() {
public void fromClient_insecure() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(InsecureChannelCredentials.create());
assertThat(result.error).isNull();
@ -206,7 +220,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_composite() {
public void fromClient_composite() {
CallCredentials callCredentials = mock(CallCredentials.class);
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(CompositeChannelCredentials.create(
@ -225,7 +239,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_netty() {
public void fromClient_netty() {
ProtocolNegotiator.ClientFactory factory = mock(ProtocolNegotiator.ClientFactory.class);
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(NettyChannelCredentials.create(factory));
@ -235,7 +249,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_choice() {
public void fromClient_choice() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(ChoiceChannelCredentials.create(
new ChannelCredentials() {},
@ -257,7 +271,7 @@ public class ProtocolNegotiatorsTest {
}
@Test
public void from_choice_unknown() {
public void fromClient_choice_unknown() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(ChoiceChannelCredentials.create(
new ChannelCredentials() {}));
@ -266,6 +280,82 @@ public class ProtocolNegotiatorsTest {
assertThat(result.negotiator).isNull();
}
@Test
public void fromServer_unknown() {
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(new ServerCredentials() {});
assertThat(result.error).isNotNull();
assertThat(result.negotiator).isNull();
}
@Test
public void fromServer_tls() throws Exception {
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(TlsServerCredentials.create(server1Cert, server1Key));
assertThat(result.error).isNull();
assertThat(result.negotiator)
.isInstanceOf(ProtocolNegotiators.TlsProtocolNegotiatorServerFactory.class);
}
@Test
public void fromServer_unsupportedTls() throws Exception {
ProtocolNegotiators.FromServerCredentialsResult result = ProtocolNegotiators.from(
TlsServerCredentials.newBuilder()
.keyManager(server1Cert, server1Key)
.requireFakeFeature()
.build());
assertThat(result.error).contains("FAKE");
assertThat(result.negotiator).isNull();
}
@Test
public void fromServer_insecure() {
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(InsecureServerCredentials.create());
assertThat(result.error).isNull();
assertThat(result.negotiator)
.isInstanceOf(ProtocolNegotiators.PlaintextProtocolNegotiatorServerFactory.class);
}
@Test
public void fromServer_netty() {
ProtocolNegotiator.ServerFactory factory = mock(ProtocolNegotiator.ServerFactory.class);
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(NettyServerCredentials.create(factory));
assertThat(result.error).isNull();
assertThat(result.negotiator).isSameInstanceAs(factory);
}
@Test
public void fromServer_choice() throws Exception {
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(ChoiceServerCredentials.create(
new ServerCredentials() {},
TlsServerCredentials.create(server1Cert, server1Key),
InsecureServerCredentials.create()));
assertThat(result.error).isNull();
assertThat(result.negotiator)
.isInstanceOf(ProtocolNegotiators.TlsProtocolNegotiatorServerFactory.class);
result = ProtocolNegotiators.from(ChoiceServerCredentials.create(
InsecureServerCredentials.create(),
new ServerCredentials() {},
TlsServerCredentials.create(server1Cert, server1Key)));
assertThat(result.error).isNull();
assertThat(result.negotiator)
.isInstanceOf(ProtocolNegotiators.PlaintextProtocolNegotiatorServerFactory.class);
}
@Test
public void fromServer_choice_unknown() {
ProtocolNegotiators.FromServerCredentialsResult result =
ProtocolNegotiators.from(ChoiceServerCredentials.create(
new ServerCredentials() {}));
assertThat(result.error).isNotNull();
assertThat(result.negotiator).isNull();
}
@Test
public void waitUntilActiveHandler_handlerAdded() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);