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.io.crypto.tls;
019
020import java.io.File;
021import java.io.IOException;
022import java.security.Security;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.stream.Stream;
026import org.apache.commons.io.FileUtils;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.hbase.HBaseCommonTestingUtil;
029import org.bouncycastle.jce.provider.BouncyCastleProvider;
030import org.junit.jupiter.api.AfterAll;
031import org.junit.jupiter.api.AfterEach;
032import org.junit.jupiter.api.BeforeAll;
033import org.junit.jupiter.api.BeforeEach;
034import org.junit.jupiter.params.provider.Arguments;
035
036/**
037 * Base class for parameterized unit tests that use X509TestContext for testing different X509
038 * parameter combinations (CA key type, cert key type, with/without a password, with/without
039 * hostname verification, etc).
040 * <p/>
041 * This base class takes care of setting up / cleaning up the test environment, and caching the
042 * X509TestContext objects used by the tests.
043 * <p/>
044 * This file has been copied from the Apache ZooKeeper project.
045 * @see <a href=
046 *      "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/BaseX509ParameterizedTestCase.java">Base
047 *      revision</a>
048 */
049public abstract class AbstractTestX509Parameterized {
050
051  private static final HBaseCommonTestingUtil UTIL = new HBaseCommonTestingUtil();
052  private static X509TestContextProvider PROVIDER;
053
054  private X509KeyType caKeyType;
055  private X509KeyType certKeyType;
056  private char[] keyPassword;
057
058  public AbstractTestX509Parameterized(X509KeyType caKeyType, X509KeyType certKeyType,
059    char[] keyPassword) {
060    this.caKeyType = caKeyType;
061    this.certKeyType = certKeyType;
062    this.keyPassword = keyPassword;
063  }
064
065  /**
066   * Default parameters suitable for most subclasses. See example usage in {@link TestX509Util}.
067   * @return a stream of parameter combinations to test with.
068   */
069  public static Stream<Arguments> parameters() {
070    List<Arguments> result = new ArrayList<>();
071    for (X509KeyType caKeyType : X509KeyType.values()) {
072      for (X509KeyType certKeyType : X509KeyType.values()) {
073        for (char[] keyPassword : new char[][] { "".toCharArray(), "pa$$w0rd".toCharArray() }) {
074          result.add(Arguments.of(caKeyType, certKeyType, keyPassword));
075        }
076      }
077    }
078    return result.stream();
079  }
080
081  /**
082   * Because key generation and writing / deleting files is kind of expensive, we cache the certs
083   * and on-disk files between test cases. None of the test cases modify any of this data so it's
084   * safe to reuse between tests. This caching makes all test cases after the first one for a given
085   * parameter combination complete almost instantly.
086   */
087  protected static Configuration conf;
088
089  protected X509TestContext x509TestContext;
090
091  @BeforeAll
092  public static void setUpBaseClass() throws Exception {
093    Security.addProvider(new BouncyCastleProvider());
094    File dir = new File(UTIL.getDataTestDir(TestX509Util.class.getSimpleName()).toString())
095      .getCanonicalFile();
096    FileUtils.forceMkdir(dir);
097    PROVIDER = new X509TestContextProvider(UTIL.getConfiguration(), dir);
098  }
099
100  @AfterAll
101  public static void cleanUpBaseClass() {
102    Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
103    UTIL.cleanupTestDir();
104  }
105
106  @BeforeEach
107  public void setUp() throws IOException {
108    x509TestContext = PROVIDER.get(caKeyType, certKeyType, keyPassword);
109    x509TestContext.setConfigurations(KeyStoreFileType.JKS, KeyStoreFileType.JKS);
110    conf = new Configuration(UTIL.getConfiguration());
111  }
112
113  @AfterEach
114  public void cleanUp() {
115    x509TestContext.clearConfigurations();
116    x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP);
117    x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR);
118    x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL);
119    System.clearProperty("com.sun.net.ssl.checkRevocation");
120    System.clearProperty("com.sun.security.enableCRLDP");
121    Security.setProperty("ocsp.enable", Boolean.FALSE.toString());
122    Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString());
123  }
124}