View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.security.token;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.Properties;
26  
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.fs.Path;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.LocalHBaseCluster;
32  import org.apache.hadoop.hbase.TableName;
33  import org.apache.hadoop.hbase.client.Connection;
34  import org.apache.hadoop.hbase.client.ConnectionFactory;
35  import org.apache.hadoop.hbase.client.Table;
36  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
37  import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil;
38  import org.apache.hadoop.hbase.ipc.AsyncRpcClient;
39  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
40  import org.apache.hadoop.hbase.ipc.RpcClient;
41  import org.apache.hadoop.hbase.ipc.RpcClientFactory;
42  import org.apache.hadoop.hbase.ipc.RpcClientImpl;
43  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
44  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos;
45  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.GetAuthenticationTokenRequest;
46  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIRequest;
47  import org.apache.hadoop.hbase.protobuf.generated.AuthenticationProtos.WhoAmIResponse;
48  import org.apache.hadoop.hbase.security.AccessDeniedException;
49  import org.apache.hadoop.hbase.security.HBaseKerberosUtils;
50  import org.apache.hadoop.hbase.testclassification.MediumTests;
51  import org.apache.hadoop.hbase.util.FSUtils;
52  import org.apache.hadoop.hdfs.DFSConfigKeys;
53  import org.apache.hadoop.http.HttpConfig;
54  import org.apache.hadoop.minikdc.MiniKdc;
55  import org.apache.hadoop.security.UserGroupInformation;
56  import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
57  import org.apache.hadoop.security.token.Token;
58  import org.apache.hadoop.security.token.TokenIdentifier;
59  import org.junit.AfterClass;
60  import org.junit.BeforeClass;
61  import org.junit.Test;
62  import org.junit.experimental.categories.Category;
63  
64  import com.google.protobuf.ServiceException;
65  
66  @Category(MediumTests.class)
67  public class TestGenerateDelegationToken {
68  
69    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
70  
71    private static LocalHBaseCluster CLUSTER;
72  
73    private static final File KEYTAB_FILE = new File(TEST_UTIL.getDataTestDir("keytab").toUri()
74        .getPath());
75    private static MiniKdc KDC;
76  
77    private static String HOST = "localhost";
78  
79    private static String USERNAME;
80  
81    private static String PRINCIPAL;
82  
83    private static String HTTP_PRINCIPAL;
84  
85    private static void setHdfsSecuredConfiguration(Configuration conf) throws Exception {
86      // change XXX_USER_NAME_KEY to XXX_KERBEROS_PRINCIPAL_KEY after we drop support for hadoop-2.4.1
87      conf.set(DFSConfigKeys.DFS_NAMENODE_USER_NAME_KEY, PRINCIPAL + "@" + KDC.getRealm());
88      conf.set(DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY, KEYTAB_FILE.getAbsolutePath());
89      conf.set(DFSConfigKeys.DFS_DATANODE_USER_NAME_KEY, PRINCIPAL + "@" + KDC.getRealm());
90      conf.set(DFSConfigKeys.DFS_DATANODE_KEYTAB_FILE_KEY, KEYTAB_FILE.getAbsolutePath());
91      conf.set(DFSConfigKeys.DFS_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL_KEY, HTTP_PRINCIPAL + "@"
92          + KDC.getRealm());
93      conf.setBoolean(DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY, true);
94      conf.set("dfs.http.policy", HttpConfig.Policy.HTTPS_ONLY.name());
95      conf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0");
96      conf.set(DFSConfigKeys.DFS_DATANODE_HTTPS_ADDRESS_KEY, "localhost:0");
97  
98      File keystoresDir = new File(TEST_UTIL.getDataTestDir("keystore").toUri().getPath());
99      keystoresDir.mkdirs();
100     String sslConfDir = KeyStoreTestUtil.getClasspathDir(TestGenerateDelegationToken.class);
101     KeyStoreTestUtil.setupSSLConfig(keystoresDir.getAbsolutePath(), sslConfDir, conf, false);
102 
103     conf.setBoolean("ignore.secure.ports.for.testing", true);
104   }
105 
106   @BeforeClass
107   public static void setUp() throws Exception {
108     Properties conf = MiniKdc.createConf();
109     conf.put(MiniKdc.DEBUG, true);
110     KDC = new MiniKdc(conf, new File(TEST_UTIL.getDataTestDir("kdc").toUri().getPath()));
111     KDC.start();
112     USERNAME = UserGroupInformation.getLoginUser().getShortUserName();
113     PRINCIPAL = USERNAME + "/" + HOST;
114     HTTP_PRINCIPAL = "HTTP/" + HOST;
115     KDC.createPrincipal(KEYTAB_FILE, PRINCIPAL, HTTP_PRINCIPAL);
116     TEST_UTIL.startMiniZKCluster();
117 
118     HBaseKerberosUtils.setKeytabFileForTesting(KEYTAB_FILE.getAbsolutePath());
119     HBaseKerberosUtils.setPrincipalForTesting(PRINCIPAL + "@" + KDC.getRealm());
120     HBaseKerberosUtils.setSecuredConfiguration(TEST_UTIL.getConfiguration());
121     setHdfsSecuredConfiguration(TEST_UTIL.getConfiguration());
122     UserGroupInformation.setConfiguration(TEST_UTIL.getConfiguration());
123     TEST_UTIL.getConfiguration().setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
124       TokenProvider.class.getName());
125     TEST_UTIL.startMiniDFSCluster(1);
126     Path rootdir = TEST_UTIL.getDataTestDirOnTestFS("TestGenerateDelegationToken");
127     FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootdir);
128     CLUSTER = new LocalHBaseCluster(TEST_UTIL.getConfiguration(), 1);
129     CLUSTER.startup();
130   }
131 
132   @AfterClass
133   public static void tearDown() throws Exception {
134     if (CLUSTER != null) {
135       CLUSTER.shutdown();
136     }
137     CLUSTER.join();
138     if (KDC != null) {
139       KDC.stop();
140     }
141     TEST_UTIL.shutdownMiniCluster();
142   }
143 
144   private void testTokenAuth(Class<? extends RpcClient> rpcImplClass) throws IOException,
145       ServiceException {
146     TEST_UTIL.getConfiguration().set(RpcClientFactory.CUSTOM_RPC_CLIENT_IMPL_CONF_KEY,
147       rpcImplClass.getName());
148     try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
149         Table table = conn.getTable(TableName.META_TABLE_NAME)) {
150       CoprocessorRpcChannel rpcChannel = table.coprocessorService(HConstants.EMPTY_START_ROW);
151       AuthenticationProtos.AuthenticationService.BlockingInterface service =
152           AuthenticationProtos.AuthenticationService.newBlockingStub(rpcChannel);
153       WhoAmIResponse response = service.whoAmI(null, WhoAmIRequest.getDefaultInstance());
154       assertEquals(USERNAME, response.getUsername());
155       assertEquals(AuthenticationMethod.TOKEN.name(), response.getAuthMethod());
156       try {
157         service.getAuthenticationToken(null, GetAuthenticationTokenRequest.getDefaultInstance());
158       } catch (ServiceException e) {
159         AccessDeniedException exc = (AccessDeniedException) ProtobufUtil.getRemoteException(e);
160         assertTrue(exc.getMessage().contains(
161           "Token generation only allowed for Kerberos authenticated clients"));
162       }
163     }
164   }
165 
166   @Test
167   public void test() throws Exception {
168     try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
169       Token<? extends TokenIdentifier> token = TokenUtil.obtainToken(conn);
170       UserGroupInformation.getCurrentUser().addToken(token);
171       testTokenAuth(RpcClientImpl.class);
172       testTokenAuth(AsyncRpcClient.class);
173     }
174 
175   }
176 }