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