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 static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getClientKeytabForTesting; 021import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getClientPrincipalForTesting; 022import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getKeytabFileForTesting; 023import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getPrincipalForTesting; 024import static org.apache.hadoop.hbase.security.HBaseKerberosUtils.getSecuredConfiguration; 025import static org.junit.jupiter.api.Assertions.assertEquals; 026import static org.junit.jupiter.api.Assertions.assertFalse; 027import static org.junit.jupiter.api.Assertions.assertNotNull; 028import static org.junit.jupiter.api.Assertions.assertTrue; 029 030import java.io.File; 031import java.io.IOException; 032import org.apache.hadoop.conf.Configuration; 033import org.apache.hadoop.hbase.AuthUtil; 034import org.apache.hadoop.hbase.HBaseTestingUtil; 035import org.apache.hadoop.hbase.testclassification.SecurityTests; 036import org.apache.hadoop.hbase.testclassification.SmallTests; 037import org.apache.hadoop.minikdc.MiniKdc; 038import org.apache.hadoop.security.UserGroupInformation; 039import org.junit.jupiter.api.AfterAll; 040import org.junit.jupiter.api.BeforeAll; 041import org.junit.jupiter.api.Tag; 042import org.junit.jupiter.api.Test; 043 044@Tag(SecurityTests.TAG) 045@Tag(SmallTests.TAG) 046public class TestUsersOperationsWithSecureHadoop { 047 048 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 049 private static final File KEYTAB_FILE = 050 new File(TEST_UTIL.getDataTestDir("keytab").toUri().getPath()); 051 052 private static MiniKdc KDC; 053 054 private static String HOST = "localhost"; 055 056 private static String PRINCIPAL; 057 058 private static String CLIENT_NAME; 059 060 private static String OTHER_CLIENT_NAME; 061 062 @BeforeAll 063 public static void setUp() throws Exception { 064 KDC = TEST_UTIL.setupMiniKdc(KEYTAB_FILE); 065 PRINCIPAL = "hbase/" + HOST; 066 CLIENT_NAME = "foo"; 067 OTHER_CLIENT_NAME = "bar"; 068 KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL, CLIENT_NAME, OTHER_CLIENT_NAME); 069 HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm()); 070 HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath()); 071 HBaseKerberosUtils.setClientPrincipalForTesting(CLIENT_NAME + "@" + KDC.getRealm()); 072 HBaseKerberosUtils.setClientKeytabForTesting(KEYTAB_FILE.getAbsolutePath()); 073 } 074 075 @AfterAll 076 public static void tearDown() throws IOException { 077 if (KDC != null) { 078 KDC.stop(); 079 } 080 TEST_UTIL.cleanupTestDir(); 081 } 082 083 /** 084 * test login with security enabled configuration To run this test, we must specify the following 085 * system properties: 086 * <p> 087 * <b> hbase.regionserver.kerberos.principal </b> 088 * <p> 089 * <b> hbase.regionserver.keytab.file </b> 090 */ 091 @Test 092 public void testUserLoginInSecureHadoop() throws Exception { 093 // Default login is system user. 094 UserGroupInformation defaultLogin = UserGroupInformation.getCurrentUser(); 095 096 String nnKeyTab = getKeytabFileForTesting(); 097 String dnPrincipal = getPrincipalForTesting(); 098 099 assertNotNull("KerberosKeytab was not specified", nnKeyTab); 100 assertNotNull("KerberosPrincipal was not specified", dnPrincipal); 101 102 Configuration conf = getSecuredConfiguration(); 103 UserGroupInformation.setConfiguration(conf); 104 105 User.login(conf, HBaseKerberosUtils.KRB_KEYTAB_FILE, HBaseKerberosUtils.KRB_PRINCIPAL, 106 "localhost"); 107 UserGroupInformation successLogin = UserGroupInformation.getLoginUser(); 108 assertFalse(defaultLogin.equals(successLogin), 109 "ugi should be different in in case success login"); 110 } 111 112 @Test 113 public void testLoginWithUserKeytabAndPrincipal() throws Exception { 114 String clientKeytab = getClientKeytabForTesting(); 115 String clientPrincipal = getClientPrincipalForTesting(); 116 assertNotNull("Path for client keytab is not specified.", clientKeytab); 117 assertNotNull("Client principal is not specified.", clientPrincipal); 118 119 Configuration conf = getSecuredConfiguration(); 120 conf.set(AuthUtil.HBASE_CLIENT_KEYTAB_FILE, clientKeytab); 121 conf.set(AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL, clientPrincipal); 122 UserGroupInformation.setConfiguration(conf); 123 124 UserProvider provider = UserProvider.instantiate(conf); 125 assertTrue(provider.shouldLoginFromKeytab(), "Client principal or keytab is empty"); 126 127 provider.login(AuthUtil.HBASE_CLIENT_KEYTAB_FILE, AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL); 128 User loginUser = provider.getCurrent(); 129 assertEquals(CLIENT_NAME, loginUser.getShortName()); 130 assertEquals(getClientPrincipalForTesting(), loginUser.getName()); 131 } 132 133 @Test 134 public void testAuthUtilLoginWithExistingLoginUser() throws Exception { 135 String clientKeytab = getClientKeytabForTesting(); 136 String clientPrincipal = getClientPrincipalForTesting(); 137 Configuration conf = getSecuredConfiguration(); 138 conf.set(AuthUtil.HBASE_CLIENT_KEYTAB_FILE, clientKeytab); 139 conf.set(AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL, clientPrincipal); 140 UserGroupInformation.setConfiguration(conf); 141 142 UserGroupInformation.loginUserFromKeytab(CLIENT_NAME, clientKeytab); 143 144 User user = AuthUtil.loginClient(conf); 145 assertTrue(user.isLoginFromKeytab()); 146 assertEquals(CLIENT_NAME, user.getShortName()); 147 assertEquals(getClientPrincipalForTesting(), user.getName()); 148 } 149 150 @Test 151 public void testAuthUtilLoginWithDifferentExistingUser() throws Exception { 152 String clientKeytab = getClientKeytabForTesting(); 153 String clientPrincipal = getClientPrincipalForTesting(); 154 Configuration conf = getSecuredConfiguration(); 155 conf.set(AuthUtil.HBASE_CLIENT_KEYTAB_FILE, clientKeytab); 156 conf.set(AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL, clientPrincipal); 157 UserGroupInformation.setConfiguration(conf); 158 159 // Login with other principal first 160 String otherPrincipal = OTHER_CLIENT_NAME + "@" + KDC.getRealm(); 161 UserGroupInformation.loginUserFromKeytab(otherPrincipal, clientKeytab); 162 163 User user = AuthUtil.loginClient(conf); 164 assertTrue(user.isLoginFromKeytab()); 165 // The existing login user (bar) doesn't match the principal configured in 166 // HBASE_CLIENT_KERBEROS_PRINCIPAL (foo), so loginClient should re-login 167 // with the configured principal. 168 assertEquals(CLIENT_NAME, user.getShortName()); 169 assertEquals(getClientPrincipalForTesting(), user.getName()); 170 171 conf.set(AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL, otherPrincipal); 172 173 user = AuthUtil.loginClient(conf); 174 assertTrue(user.isLoginFromKeytab()); 175 // After updating HBASE_CLIENT_KERBEROS_PRINCIPAL to bar, loginClient should re-login with bar. 176 assertEquals(OTHER_CLIENT_NAME, user.getShortName()); 177 assertEquals(otherPrincipal, user.getName()); 178 } 179}