001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.ipc;
019
020import static org.junit.Assert.assertArrayEquals;
021import static org.junit.Assert.assertNotNull;
022import static org.junit.Assert.assertTrue;
023import static org.mockito.Mockito.mock;
024import static org.mockito.Mockito.when;
025
026import java.io.ByteArrayInputStream;
027import java.net.InetSocketAddress;
028import java.net.SocketAddress;
029import java.nio.charset.StandardCharsets;
030import java.security.cert.Certificate;
031import java.security.cert.CertificateException;
032import java.security.cert.CertificateFactory;
033import java.security.cert.X509Certificate;
034import java.util.Arrays;
035import java.util.Collection;
036import javax.net.ssl.SSLEngine;
037import javax.net.ssl.SSLPeerUnverifiedException;
038import javax.net.ssl.SSLSession;
039import org.apache.hadoop.hbase.HBaseClassTestRule;
040import org.apache.hadoop.hbase.HBaseTestingUtil;
041import org.apache.hadoop.hbase.TableName;
042import org.apache.hadoop.hbase.TableNameTestRule;
043import org.apache.hadoop.hbase.client.Get;
044import org.apache.hadoop.hbase.client.Put;
045import org.apache.hadoop.hbase.client.Result;
046import org.apache.hadoop.hbase.client.Table;
047import org.apache.hadoop.hbase.client.TableDescriptor;
048import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
049import org.apache.hadoop.hbase.regionserver.DisabledRegionSplitPolicy;
050import org.apache.hadoop.hbase.testclassification.MediumTests;
051import org.apache.hadoop.hbase.testclassification.RPCTests;
052import org.apache.hadoop.hbase.util.Bytes;
053import org.apache.hadoop.hbase.util.LoadTestKVGenerator;
054import org.junit.After;
055import org.junit.Before;
056import org.junit.ClassRule;
057import org.junit.Rule;
058import org.junit.Test;
059import org.junit.experimental.categories.Category;
060import org.junit.runner.RunWith;
061import org.junit.runners.Parameterized;
062import org.junit.runners.Parameterized.Parameters;
063
064import org.apache.hbase.thirdparty.io.netty.handler.ssl.SslHandler;
065
066@Category({ RPCTests.class, MediumTests.class })
067@RunWith(Parameterized.class)
068public class TestNettyRpcServer {
069
070  @ClassRule
071  public static final HBaseClassTestRule CLASS_RULE =
072    HBaseClassTestRule.forClass(TestNettyRpcServer.class);
073
074  private static final byte[] FAMILY = Bytes.toBytes("f");
075  private static final byte[] QUALIFIER = Bytes.toBytes("q");
076  private static final int NUM_ROWS = 100;
077  private static final int MIN_LEN = 1000;
078  private static final int MAX_LEN = 1000000;
079  protected static final LoadTestKVGenerator GENERATOR = new LoadTestKVGenerator(MIN_LEN, MAX_LEN);
080  protected static HBaseTestingUtil TEST_UTIL;
081
082  @Rule
083  public TableNameTestRule name = new TableNameTestRule();
084
085  @Parameterized.Parameter
086  public String allocatorType;
087
088  @Parameters
089  public static Collection<Object[]> parameters() {
090    return Arrays.asList(new Object[][] { { NettyRpcServer.POOLED_ALLOCATOR_TYPE },
091      { NettyRpcServer.UNPOOLED_ALLOCATOR_TYPE }, { NettyRpcServer.HEAP_ALLOCATOR_TYPE },
092      { SimpleByteBufAllocator.class.getName() } });
093  }
094
095  @Before
096  public void setup() throws Exception {
097    // A subclass may have already created TEST_UTIL and is now upcalling to us
098    if (TEST_UTIL == null) {
099      TEST_UTIL = new HBaseTestingUtil();
100    }
101    TEST_UTIL.getConfiguration().set(RpcServerFactory.CUSTOM_RPC_SERVER_IMPL_CONF_KEY,
102      NettyRpcServer.class.getName());
103    TEST_UTIL.getConfiguration().set(NettyRpcServer.HBASE_NETTY_ALLOCATOR_KEY, allocatorType);
104    TEST_UTIL.startMiniCluster();
105  }
106
107  @After
108  public void tearDown() throws Exception {
109    TEST_UTIL.shutdownMiniCluster();
110  }
111
112  @Test
113  public void testNettyRpcServer() throws Exception {
114    doTest(name.getTableName());
115  }
116
117  protected void doTest(TableName tableName) throws Exception {
118    // Splitting just complicates the test scenario, disable it
119    final TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName)
120      .setRegionSplitPolicyClassName(DisabledRegionSplitPolicy.class.getName()).build();
121    try (Table table =
122      TEST_UTIL.createTable(desc, new byte[][] { FAMILY }, TEST_UTIL.getConfiguration())) {
123      // put some test data
124      for (int i = 0; i < NUM_ROWS; i++) {
125        final byte[] rowKey = Bytes.toBytes(LoadTestKVGenerator.md5PrefixedKey(i));
126        final byte[] v = GENERATOR.generateRandomSizeValue(rowKey, QUALIFIER);
127        table.put(new Put(rowKey).addColumn(FAMILY, QUALIFIER, v));
128      }
129      // read to verify it.
130      for (int i = 0; i < NUM_ROWS; i++) {
131        final byte[] rowKey = Bytes.toBytes(LoadTestKVGenerator.md5PrefixedKey(i));
132        final Result r = table.get(new Get(rowKey).addColumn(FAMILY, QUALIFIER));
133        assertNotNull("Result was empty", r);
134        final byte[] v = r.getValue(FAMILY, QUALIFIER);
135        assertNotNull("Result did not contain expected value", v);
136        assertTrue("Value was not verified", LoadTestKVGenerator.verify(v, rowKey, QUALIFIER));
137      }
138    }
139  }
140
141  private static final String CERTIFICATE = "-----BEGIN CERTIFICATE-----\n"
142    + "MIIEITCCAwmgAwIBAgIUaLL8vLOhWLCLXVHEJqXJhfmsTB8wDQYJKoZIhvcNAQEL\n"
143    + "BQAwgawxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYD\n"
144    + "VQQHDAlDYW1icmlkZ2UxGDAWBgNVBAoMD25ldHR5IHRlc3QgY2FzZTEYMBYGA1UE\n"
145    + "CwwPbmV0dHkgdGVzdCBjYXNlMRgwFgYDVQQDDA9uZXR0eSB0ZXN0IGNhc2UxIzAh\n"
146    + "BgkqhkiG9w0BCQEWFGNjb25uZWxsQGh1YnNwb3QuY29tMB4XDTI0MDEyMTE5MzMy\n"
147    + "MFoXDTI1MDEyMDE5MzMyMFowgawxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNz\n"
148    + "YWNodXNldHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxGDAWBgNVBAoMD25ldHR5IHRl\n"
149    + "c3QgY2FzZTEYMBYGA1UECwwPbmV0dHkgdGVzdCBjYXNlMRgwFgYDVQQDDA9uZXR0\n"
150    + "eSB0ZXN0IGNhc2UxIzAhBgkqhkiG9w0BCQEWFGNjb25uZWxsQGh1YnNwb3QuY29t\n"
151    + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy+qzEZpQMjVdLj0siUcG\n"
152    + "y8LIHOW4S+tgHIKFkF865qWq6FVGbROe2Z0f5W6yIamZkdxzptT0iv+8S5okNNeW\n"
153    + "2NbsN/HNJIRtWfxku1Jh1gBqSkAYIjXyq7+20hIaJTzzxqike9M/Lc14EGb33Ja/\n"
154    + "kDPRV3UtiM3Ntf3eALXKbrWptkbgQngCaTgtfg8IkMAEpP270wZ9fW0lDHv3NPPt\n"
155    + "Zt0QSJzWSqWfu+l4ayvcUQYyNJesx9YmTHSJu69lvT4QApoX8FEiHfNCJ28R50CS\n"
156    + "aIgOpCWUvkH7rqx0p9q393uJRS/S6RlLbU30xUN1fNrVmP/XAapfy+R0PSgiUi8o\n"
157    + "EQIDAQABozkwNzAWBgNVHRIEDzANggt3d3cuZm9vLmNvbTAdBgNVHQ4EFgQUl4FD\n"
158    + "Y8jJ/JHJR68YqPsGUjUJuwgwDQYJKoZIhvcNAQELBQADggEBADVzivYz2M0qsWUc\n"
159    + "jXjCHymwTIr+7ud10um53FbYEAfKWsIY8Pp35fKpFzUwc5wVdCnLU86K/YMKRzNB\n"
160    + "zL2Auow3PJFRvXecOv7dWxNlNneLDcwbVrdNRu6nQXmZUgyz0oUKuJbF+JGtI+7W\n"
161    + "kRw7yhBfki+UCSQWeDqvaWzgmA4Us0N8NFq3euAs4xFbMMPMQWrT9Z7DGchCeRiB\n"
162    + "dkQBvh88vbR3v2Saq14W4Wt5rj2++vXWGQSeAQL6nGbOwc3ohW6isNNV0eGQQTmS\n"
163    + "khS2d/JDZq2XL5RGexf3CA6YYzWiTr9YZHNjuobvLH7mVnA2c8n6Zty/UhfnuK1x\n" + "JbkleFk=\n"
164    + "-----END CERTIFICATE-----";
165
166  @Test
167  public void testHandshakeCompleteHandler()
168    throws SSLPeerUnverifiedException, CertificateException {
169    NettyServerRpcConnection conn = mock(NettyServerRpcConnection.class);
170    SslHandler sslHandler = mock(SslHandler.class);
171    SocketAddress remoteAddress = new InetSocketAddress("localhost", 5555);
172    SSLEngine engine = mock(SSLEngine.class);
173    SSLSession session = mock(SSLSession.class);
174    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
175    X509Certificate x509Certificate = (X509Certificate) certificateFactory
176      .generateCertificate(new ByteArrayInputStream(CERTIFICATE.getBytes(StandardCharsets.UTF_8)));
177    Certificate[] certificates = new Certificate[] { x509Certificate };
178
179    when(sslHandler.engine()).thenReturn(engine);
180    when(engine.getSession()).thenReturn(session);
181    when(session.getPeerCertificates()).thenReturn(certificates);
182
183    NettyRpcServer.sslHandshakeCompleteHandler(conn, sslHandler, remoteAddress);
184
185    assertArrayEquals(certificates, conn.clientCertificateChain);
186  }
187
188}