Search in sources :

Example 1 with SslSessionValidator

use of com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator in project rest.li by linkedin.

the class SimpleLoadBalancerStateTest method testGetClientWithSSLValidation.

@Test(groups = { "small", "back-end" })
public void testGetClientWithSSLValidation() throws URISyntaxException {
    reset(true, true);
    URI uri = URI.create("https://cluster-1/test");
    List<String> schemes = new ArrayList<>();
    Map<Integer, PartitionData> partitionData = new HashMap<>(1);
    partitionData.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(1d));
    Map<URI, Map<Integer, PartitionData>> uriData = new HashMap<>();
    uriData.put(uri, partitionData);
    schemes.add("https");
    // set up state
    _state.listenToCluster("cluster-1", new NullStateListenerCallback());
    _state.listenToService("service-1", new NullStateListenerCallback());
    Map<String, Object> transportClientProperties = new HashMap<>();
    transportClientProperties.put(HttpClientFactory.HTTP_SSL_CONTEXT, _sslContext);
    transportClientProperties.put(HttpClientFactory.HTTP_SSL_PARAMS, _sslParameters);
    transportClientProperties = Collections.unmodifiableMap(transportClientProperties);
    final List<String> sslValidationList = Arrays.asList("validation1", "validation2");
    _clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1", Collections.emptyList(), Collections.emptyMap(), Collections.emptySet(), NullPartitionProperties.getInstance(), sslValidationList, (Map<String, Object>) null, false));
    _serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", Arrays.asList("random"), Collections.<String, Object>emptyMap(), transportClientProperties, null, schemes, null));
    _uriRegistry.put("cluster-1", new UriProperties("cluster-1", uriData));
    TrackerClient client = _state.getClient("service-1", uri);
    assertNotNull(client);
    assertEquals(client.getUri(), uri);
    RequestContext requestContext = new RequestContext();
    client.restRequest(new RestRequestBuilder(URI.create("http://cluster-1/test")).build(), requestContext, new HashMap<>(), response -> {
    });
    @SuppressWarnings("unchecked") final SslSessionValidator validator = (SslSessionValidator) requestContext.getLocalAttr(R2Constants.REQUESTED_SSL_SESSION_VALIDATOR);
    assertNotNull(validator);
}
Also used : SslSessionValidator(com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) NullStateListenerCallback(com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback) ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) PartitionData(com.linkedin.d2.balancer.properties.PartitionData) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) Map(java.util.Map) HashMap(java.util.HashMap) Test(org.testng.annotations.Test) DegraderLoadBalancerTest(com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerTest)

Example 2 with SslSessionValidator

use of com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator in project rest.li by linkedin.

the class HttpNettyClient method doWriteRequest.

@Override
protected void doWriteRequest(RestRequest request, RequestContext requestContext, SocketAddress address, Map<String, String> wireAttrs, final TimeoutTransportCallback<RestResponse> callback, long requestTimeout) {
    final RestRequest newRequest = new RestRequestBuilder(request).overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build();
    requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
    final AsyncPool<Channel> pool;
    try {
        pool = getChannelPoolManagerPerRequest(request).getPoolForAddress(address);
    } catch (IllegalStateException e) {
        errorResponse(callback, e);
        return;
    }
    final Cancellable pendingGet = pool.get(new Callback<Channel>() {

        @Override
        public void onSuccess(final Channel channel) {
            // This handler ensures the channel is returned to the pool at the end of the
            // Netty pipeline.
            channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).set(pool);
            callback.addTimeoutTask(() -> {
                AsyncPool<Channel> pool1 = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
                if (pool1 != null) {
                    pool1.dispose(channel);
                }
            });
            TransportCallback<RestResponse> sslTimingCallback = SslHandshakeTimingHandler.getSslTimingCallback(channel, requestContext, callback);
            // This handler invokes the callback with the response once it arrives.
            channel.attr(RAPResponseHandler.CALLBACK_ATTR_KEY).set(sslTimingCallback);
            // Set the session validator requested by the user
            SslSessionValidator sslSessionValidator = (SslSessionValidator) requestContext.getLocalAttr(R2Constants.REQUESTED_SSL_SESSION_VALIDATOR);
            channel.attr(NettyChannelAttributes.SSL_SESSION_VALIDATOR).set(sslSessionValidator);
            final NettyClientState state = _state.get();
            if (state == NettyClientState.REQUESTS_STOPPING || state == NettyClientState.SHUTDOWN) {
                // In this case, we acquired a channel from the pool as request processing is halting.
                // The shutdown task might not timeout this callback, since it may already have scanned
                // all the channels for pending requests before we set the callback as the channel
                // attachment.  The TimeoutTransportCallback ensures the user callback in never
                // invoked more than once, so it is safe to invoke it unconditionally.
                errorResponse(sslTimingCallback, new TimeoutException("Operation did not complete before shutdown"));
                // The channel is usually release in two places: timeout or in the netty pipeline.
                // Since we call the callback above, the timeout associated will be never invoked. On top of that
                // we never send the request to the pipeline (due to the return statement), and nobody is releasing the channel
                // until the channel is forcefully closed by the shutdownTimeout. Therefore we have to release it here
                AsyncPool<Channel> pool = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
                if (pool != null) {
                    pool.put(channel);
                }
                return;
            }
            // here we want the exception in outbound operations to be passed back through pipeline so that
            // the user callback would be invoked with the exception and the channel can be put back into the pool
            channel.writeAndFlush(newRequest).addListener(new ErrorChannelFutureListener());
        }

        @Override
        public void onError(Throwable e) {
            errorResponse(callback, e);
        }
    });
    if (pendingGet != null) {
        callback.addTimeoutTask(pendingGet::cancel);
    }
}
Also used : TimeoutTransportCallback(com.linkedin.r2.transport.http.client.TimeoutTransportCallback) TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) SslSessionValidator(com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator) Cancellable(com.linkedin.r2.util.Cancellable) Channel(io.netty.channel.Channel) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) NettyClientState(com.linkedin.r2.netty.common.NettyClientState) AsyncPool(com.linkedin.r2.transport.http.client.AsyncPool) TimeoutException(java.util.concurrent.TimeoutException) ErrorChannelFutureListener(com.linkedin.r2.transport.http.client.common.ErrorChannelFutureListener)

Example 3 with SslSessionValidator

use of com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator in project rest.li by linkedin.

the class TestHttpsCheckCertificate method testHttpsEchoWithSessionValidator.

private void testHttpsEchoWithSessionValidator(SslSessionValidator sslSessionValidator) throws Exception {
    final RestEchoClient client = getEchoClient(_client, Bootstrap.getEchoURI());
    final String msg = "This is a simple echo message";
    final FutureCallback<String> callback = new FutureCallback<>();
    RequestContext requestContext = new RequestContext();
    requestContext.putLocalAttr(R2Constants.REQUESTED_SSL_SESSION_VALIDATOR, sslSessionValidator);
    client.echo(msg, requestContext, callback);
    String actual = callback.get(20, TimeUnit.SECONDS);
    Assert.assertEquals(actual, msg);
}
Also used : RestEchoClient(com.linkedin.r2.sample.echo.rest.RestEchoClient) RequestContext(com.linkedin.r2.message.RequestContext) FutureCallback(com.linkedin.common.callback.FutureCallback)

Example 4 with SslSessionValidator

use of com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator in project rest.li by linkedin.

the class CertificateHandler method write.

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
    _sslHandler.handshakeFuture().addListener(future -> {
        // SSLValidation, nor send anything on the channel
        if (!future.isSuccess()) {
            return;
        }
        SslSessionValidator sslSessionValidator = ctx.channel().attr(NettyChannelAttributes.SSL_SESSION_VALIDATOR).getAndSet(null);
        // Also if sslSessionValidator is the same as the previous one we cached, skipping the check.
        if (sslSessionValidator != null && !sslSessionValidator.equals(_cachedSessionValidator)) {
            _cachedSessionValidator = sslSessionValidator;
            try {
                sslSessionValidator.validatePeerSession(_sslHandler.engine().getSession());
            } catch (SslSessionNotTrustedException e) {
                ctx.fireExceptionCaught(e);
                return;
            }
        }
        ctx.write(msg, promise);
    });
}
Also used : SslSessionNotTrustedException(com.linkedin.r2.transport.http.client.common.ssl.SslSessionNotTrustedException) SslSessionValidator(com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator)

Aggregations

SslSessionValidator (com.linkedin.r2.transport.http.client.common.ssl.SslSessionValidator)3 RequestContext (com.linkedin.r2.message.RequestContext)2 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)2 FutureCallback (com.linkedin.common.callback.FutureCallback)1 NullStateListenerCallback (com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback)1 TrackerClient (com.linkedin.d2.balancer.clients.TrackerClient)1 ClusterProperties (com.linkedin.d2.balancer.properties.ClusterProperties)1 PartitionData (com.linkedin.d2.balancer.properties.PartitionData)1 ServiceProperties (com.linkedin.d2.balancer.properties.ServiceProperties)1 UriProperties (com.linkedin.d2.balancer.properties.UriProperties)1 DegraderLoadBalancerTest (com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerTest)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 NettyClientState (com.linkedin.r2.netty.common.NettyClientState)1 RestEchoClient (com.linkedin.r2.sample.echo.rest.RestEchoClient)1 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)1 AsyncPool (com.linkedin.r2.transport.http.client.AsyncPool)1 TimeoutTransportCallback (com.linkedin.r2.transport.http.client.TimeoutTransportCallback)1 ErrorChannelFutureListener (com.linkedin.r2.transport.http.client.common.ErrorChannelFutureListener)1 SslSessionNotTrustedException (com.linkedin.r2.transport.http.client.common.ssl.SslSessionNotTrustedException)1 Cancellable (com.linkedin.r2.util.Cancellable)1