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}