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