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.replication; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021 022import java.io.File; 023import java.io.IOException; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.function.Supplier; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.HBaseTestingUtil; 029import org.apache.hadoop.hbase.client.Admin; 030import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 031import org.apache.hadoop.hbase.mapreduce.replication.VerifyReplication; 032import org.apache.hadoop.hbase.security.HBaseKerberosUtils; 033import org.apache.hadoop.hbase.security.access.AccessController; 034import org.apache.hadoop.hbase.security.access.SecureTestUtil; 035import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier; 036import org.apache.hadoop.hbase.security.token.TokenProvider; 037import org.apache.hadoop.hbase.security.visibility.VisibilityTestUtil; 038import org.apache.hadoop.hbase.testclassification.LargeTests; 039import org.apache.hadoop.hbase.testclassification.ReplicationTests; 040import org.apache.hadoop.hbase.zookeeper.ZKClusterId; 041import org.apache.hadoop.hbase.zookeeper.ZKConfig; 042import org.apache.hadoop.io.Text; 043import org.apache.hadoop.mapreduce.Job; 044import org.apache.hadoop.minikdc.MiniKdc; 045import org.apache.hadoop.security.Credentials; 046import org.apache.hadoop.security.UserGroupInformation; 047import org.apache.hadoop.security.token.Token; 048import org.apache.hadoop.security.token.TokenIdentifier; 049import org.junit.jupiter.api.AfterAll; 050import org.junit.jupiter.api.BeforeAll; 051import org.junit.jupiter.api.Tag; 052import org.junit.jupiter.params.ParameterizedTest; 053import org.junit.jupiter.params.provider.MethodSource; 054 055@Tag(ReplicationTests.TAG) 056@Tag(LargeTests.TAG) 057public class TestVerifyReplicationSecureClusterCredentials { 058 059 private static MiniKdc KDC; 060 private static final HBaseTestingUtil UTIL1 = new HBaseTestingUtil(); 061 private static final HBaseTestingUtil UTIL2 = new HBaseTestingUtil(); 062 063 private static final File KEYTAB_FILE = 064 new File(UTIL1.getDataTestDir("keytab").toUri().getPath()); 065 066 private static final String LOCALHOST = "localhost"; 067 private static String CLUSTER_PRINCIPAL; 068 private static String FULL_USER_PRINCIPAL; 069 private static String HTTP_PRINCIPAL; 070 071 private static void setUpKdcServer() throws Exception { 072 KDC = UTIL1.setupMiniKdc(KEYTAB_FILE); 073 String username = UserGroupInformation.getLoginUser().getShortUserName(); 074 String userPrincipal = username + '/' + LOCALHOST; 075 CLUSTER_PRINCIPAL = userPrincipal; 076 FULL_USER_PRINCIPAL = userPrincipal + '@' + KDC.getRealm(); 077 HTTP_PRINCIPAL = "HTTP/" + LOCALHOST; 078 KDC.createPrincipal(KEYTAB_FILE, CLUSTER_PRINCIPAL, HTTP_PRINCIPAL); 079 } 080 081 private static void setupCluster(HBaseTestingUtil util) throws Exception { 082 Configuration conf = util.getConfiguration(); 083 084 SecureTestUtil.enableSecurity(conf); 085 VisibilityTestUtil.enableVisiblityLabels(conf); 086 SecureTestUtil.verifyConfiguration(conf); 087 088 conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 089 AccessController.class.getName() + ',' + TokenProvider.class.getName()); 090 091 HBaseKerberosUtils.setSecuredConfiguration(conf, CLUSTER_PRINCIPAL + '@' + KDC.getRealm(), 092 HTTP_PRINCIPAL + '@' + KDC.getRealm()); 093 094 util.startMiniCluster(); 095 } 096 097 /** 098 * Sets the security firstly for getting the correct default realm. 099 */ 100 @BeforeAll 101 public static void beforeClass() throws Exception { 102 setUpKdcServer(); 103 setupCluster(UTIL1); 104 setupCluster(UTIL2); 105 106 try (Admin admin = UTIL1.getAdmin()) { 107 admin.addReplicationPeer("1", 108 ReplicationPeerConfig.newBuilder() 109 .setClusterKey(ZKConfig.getZooKeeperClusterKey(UTIL2.getConfiguration())) 110 .putConfiguration(HBaseKerberosUtils.KRB_PRINCIPAL, 111 UTIL2.getConfiguration().get(HBaseKerberosUtils.KRB_PRINCIPAL)) 112 .putConfiguration(HBaseKerberosUtils.MASTER_KRB_PRINCIPAL, 113 UTIL2.getConfiguration().get(HBaseKerberosUtils.MASTER_KRB_PRINCIPAL)) 114 .build()); 115 } 116 } 117 118 @AfterAll 119 public static void cleanup() throws IOException { 120 UTIL1.shutdownMiniCluster(); 121 UTIL2.shutdownMiniCluster(); 122 } 123 124 public static Collection<Supplier<String>> peer() { 125 return Arrays.asList(() -> "1", 126 () -> ZKConfig.getZooKeeperClusterKey(UTIL2.getConfiguration())); 127 } 128 129 @ParameterizedTest 130 @MethodSource("peer") 131 @SuppressWarnings("unchecked") 132 public void testJobCredentials(Supplier<String> peer) throws Exception { 133 Job job = new VerifyReplication().createSubmittableJob( 134 new Configuration(UTIL1.getConfiguration()), new String[] { peer.get(), "table" }); 135 136 Credentials credentials = job.getCredentials(); 137 Collection<Token<? extends TokenIdentifier>> tokens = credentials.getAllTokens(); 138 assertEquals(2, tokens.size()); 139 140 String clusterId1 = ZKClusterId.readClusterIdZNode(UTIL1.getZooKeeperWatcher()); 141 Token<AuthenticationTokenIdentifier> tokenForCluster1 = 142 (Token<AuthenticationTokenIdentifier>) credentials.getToken(new Text(clusterId1)); 143 assertEquals(FULL_USER_PRINCIPAL, tokenForCluster1.decodeIdentifier().getUsername()); 144 145 String clusterId2 = ZKClusterId.readClusterIdZNode(UTIL2.getZooKeeperWatcher()); 146 Token<AuthenticationTokenIdentifier> tokenForCluster2 = 147 (Token<AuthenticationTokenIdentifier>) credentials.getToken(new Text(clusterId2)); 148 assertEquals(FULL_USER_PRINCIPAL, tokenForCluster2.decodeIdentifier().getUsername()); 149 } 150}