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.security; 019 020import java.util.ArrayList; 021import java.util.List; 022import java.util.stream.Stream; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate; 025import org.apache.hadoop.hbase.io.crypto.tls.X509KeyType; 026import org.apache.hadoop.hbase.io.crypto.tls.X509Util; 027import org.apache.hadoop.hbase.testclassification.RPCTests; 028import org.apache.hadoop.hbase.testclassification.SmallTests; 029import org.junit.jupiter.api.Tag; 030import org.junit.jupiter.params.provider.Arguments; 031 032/** 033 * Comprehensively tests all permutations of ClientAuth modes and host verification 034 * enabled/disabled. Tests each permutation of that against each relevant value of 035 * {@link CertConfig}, i.e. passing no cert, a bad cert, etc. See inline comments in {@link #data()} 036 * below for what the expectations are 037 */ 038@Tag(RPCTests.TAG) 039@Tag(SmallTests.TAG) 040@HBaseParameterizedTestTemplate(name = "{index}: caKeyType={0}, certKeyType={1}, keyPassword={2}, " 041 + "validateServerHostnames={3}, testCase={4}, certConfig={5}, clientAuthMode={6}") 042public class TestMutualTlsServerSide extends AbstractTestMutualTls { 043 044 private X509Util.ClientAuth clientAuthMode; 045 046 public static Stream<Arguments> parameters() { 047 List<Arguments> params = new ArrayList<>(); 048 for (X509KeyType caKeyType : X509KeyType.values()) { 049 for (X509KeyType certKeyType : X509KeyType.values()) { 050 for (String keyPassword : new String[] { "", "pa$$w0rd" }) { 051 // we want to run with and without validating hostnames. we encode the expected success 052 // criteria 053 // in the TestCase config. See below. 054 for (boolean validateClientHostnames : new Boolean[] { true, false }) { 055 // ClientAuth.NONE should succeed in all cases, because it never requests the 056 // certificate for verification 057 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, true, 058 validateClientHostnames, CertConfig.NO_CLIENT_CERT, X509Util.ClientAuth.NONE)); 059 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, true, 060 validateClientHostnames, CertConfig.NON_VERIFIABLE_CERT, X509Util.ClientAuth.NONE)); 061 params 062 .add(Arguments.of(caKeyType, certKeyType, keyPassword, true, validateClientHostnames, 063 CertConfig.VERIFIABLE_CERT_WITH_BAD_HOST, X509Util.ClientAuth.NONE)); 064 065 // ClientAuth.WANT should succeed if no cert, but if the cert is provided it is 066 // validated. So should fail on bad cert or good cert with bad host when host 067 // verification is enabled 068 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, true, 069 validateClientHostnames, CertConfig.NO_CLIENT_CERT, X509Util.ClientAuth.WANT)); 070 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, false, 071 validateClientHostnames, CertConfig.NON_VERIFIABLE_CERT, X509Util.ClientAuth.WANT)); 072 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, !validateClientHostnames, 073 validateClientHostnames, CertConfig.VERIFIABLE_CERT_WITH_BAD_HOST, 074 X509Util.ClientAuth.WANT)); 075 076 // ClientAuth.NEED is most restrictive, failing in all cases except "good cert/bad host" 077 // when host verification is disabled 078 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, false, 079 validateClientHostnames, CertConfig.NO_CLIENT_CERT, X509Util.ClientAuth.NEED)); 080 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, false, 081 validateClientHostnames, CertConfig.NON_VERIFIABLE_CERT, X509Util.ClientAuth.NEED)); 082 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, !validateClientHostnames, 083 validateClientHostnames, CertConfig.VERIFIABLE_CERT_WITH_BAD_HOST, 084 X509Util.ClientAuth.NEED)); 085 086 // additionally ensure that all modes succeed when a good cert is presented 087 for (X509Util.ClientAuth mode : X509Util.ClientAuth.values()) { 088 params.add(Arguments.of(caKeyType, certKeyType, keyPassword, true, 089 validateClientHostnames, CertConfig.GOOD_CERT, mode)); 090 } 091 } 092 } 093 } 094 } 095 return params.stream(); 096 } 097 098 public TestMutualTlsServerSide(X509KeyType caKeyType, X509KeyType certKeyType, String keyPassword, 099 boolean expectSuccess, boolean validateHostnames, CertConfig certConfig, 100 X509Util.ClientAuth clientAuthMode) { 101 super(caKeyType, certKeyType, keyPassword, expectSuccess, validateHostnames, certConfig); 102 this.clientAuthMode = clientAuthMode; 103 } 104 105 @Override 106 protected void initialize(Configuration serverConf, Configuration clientConf) throws Exception { 107 // server enables client auth mode and verifies client host names 108 // inject bad certs into client side 109 serverConf.set(X509Util.HBASE_SERVER_NETTY_TLS_CLIENT_AUTH_MODE, clientAuthMode.name()); 110 serverConf.setBoolean(X509Util.HBASE_SERVER_NETTY_TLS_VERIFY_CLIENT_HOSTNAME, 111 validateHostnames); 112 handleCertConfig(clientConf); 113 } 114}