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.token; 019 020import static org.hamcrest.CoreMatchers.containsString; 021import static org.hamcrest.CoreMatchers.instanceOf; 022import static org.hamcrest.MatcherAssert.assertThat; 023import static org.junit.Assert.assertEquals; 024import static org.junit.Assert.assertThrows; 025 026import java.io.IOException; 027import java.security.PrivilegedExceptionAction; 028import java.util.Arrays; 029import java.util.Collection; 030import org.apache.hadoop.hbase.HBaseClassTestRule; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.client.AsyncConnection; 034import org.apache.hadoop.hbase.client.AsyncTable; 035import org.apache.hadoop.hbase.client.Connection; 036import org.apache.hadoop.hbase.client.ConnectionFactory; 037import org.apache.hadoop.hbase.ipc.NettyRpcClient; 038import org.apache.hadoop.hbase.ipc.RpcClientFactory; 039import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.AuthenticationService; 040import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.GetAuthenticationTokenRequest; 041import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.GetAuthenticationTokenResponse; 042import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIRequest; 043import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIResponse; 044import org.apache.hadoop.hbase.security.AccessDeniedException; 045import org.apache.hadoop.hbase.security.User; 046import org.apache.hadoop.hbase.testclassification.MediumTests; 047import org.apache.hadoop.hbase.testclassification.SecurityTests; 048import org.apache.hadoop.hbase.util.FutureUtils; 049import org.apache.hadoop.security.UserGroupInformation; 050import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; 051import org.apache.hadoop.security.token.Token; 052import org.apache.hadoop.security.token.TokenIdentifier; 053import org.junit.Before; 054import org.junit.BeforeClass; 055import org.junit.ClassRule; 056import org.junit.Test; 057import org.junit.experimental.categories.Category; 058import org.junit.runner.RunWith; 059import org.junit.runners.Parameterized; 060import org.junit.runners.Parameterized.Parameter; 061import org.junit.runners.Parameterized.Parameters; 062 063@RunWith(Parameterized.class) 064@Category({ SecurityTests.class, MediumTests.class }) 065public class TestGenerateDelegationToken extends SecureTestCluster { 066 067 @ClassRule 068 public static final HBaseClassTestRule CLASS_RULE = 069 HBaseClassTestRule.forClass(TestGenerateDelegationToken.class); 070 071 @BeforeClass 072 public static void setUp() throws Exception { 073 SecureTestCluster.setUp(); 074 try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) { 075 Token<? extends TokenIdentifier> token = ClientTokenUtil.obtainToken(conn); 076 UserGroupInformation.getCurrentUser().addToken(token); 077 } 078 } 079 080 @Parameters(name = "{index}: rpcClientImpl={0}") 081 public static Collection<Object> parameters() { 082 // Client connection supports only non-blocking RPCs (due to master registry restriction), hence 083 // we only test NettyRpcClient. 084 return Arrays.asList(new Object[] { NettyRpcClient.class.getName() }); 085 } 086 087 @Parameter 088 public String rpcClientImpl; 089 090 @Before 091 public void setUpBeforeMethod() { 092 TEST_UTIL.getConfiguration().set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY, 093 rpcClientImpl); 094 } 095 096 private void testToken() throws Exception { 097 try (AsyncConnection conn = 098 ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get()) { 099 AsyncTable<?> table = conn.getTable(TableName.META_TABLE_NAME); 100 WhoAmIResponse response = 101 table.<AuthenticationService.Interface, WhoAmIResponse> coprocessorService( 102 AuthenticationService::newStub, 103 (s, c, r) -> s.whoAmI(c, WhoAmIRequest.getDefaultInstance(), r), 104 HConstants.EMPTY_START_ROW).get(); 105 assertEquals(USERNAME, response.getUsername()); 106 assertEquals(AuthenticationMethod.TOKEN.name(), response.getAuthMethod()); 107 IOException ioe = 108 assertThrows(IOException.class, 109 () -> FutureUtils.get(table.<AuthenticationService.Interface, 110 GetAuthenticationTokenResponse> coprocessorService(AuthenticationService::newStub, 111 (s, c, r) -> s.getAuthenticationToken(c, 112 GetAuthenticationTokenRequest.getDefaultInstance(), r), 113 HConstants.EMPTY_START_ROW))); 114 assertThat(ioe, instanceOf(AccessDeniedException.class)); 115 assertThat(ioe.getMessage(), 116 containsString("Token generation only allowed for Kerberos authenticated clients")); 117 } 118 119 } 120 121 /** 122 * Confirm that we will use delegation token first if token and kerberos tickets are both present 123 */ 124 @Test 125 public void testTokenFirst() throws Exception { 126 testToken(); 127 } 128 129 /** 130 * Confirm that we can connect to cluster successfully when there is only token present, i.e, no 131 * kerberos ticket 132 */ 133 @Test 134 public void testOnlyToken() throws Exception { 135 User user = 136 User.createUserForTesting(TEST_UTIL.getConfiguration(), "no_krb_user", new String[0]); 137 for (Token<? extends TokenIdentifier> token : User.getCurrent().getUGI().getCredentials() 138 .getAllTokens()) { 139 user.getUGI().addToken(token); 140 } 141 user.getUGI().doAs(new PrivilegedExceptionAction<Void>() { 142 143 @Override 144 public Void run() throws Exception { 145 testToken(); 146 return null; 147 } 148 }); 149 } 150}