1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.fail;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.util.List;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.security.User;
34 import org.apache.hadoop.hbase.testclassification.SmallTests;
35 import org.junit.AfterClass;
36 import org.junit.Assert;
37 import org.junit.Test;
38 import org.junit.experimental.categories.Category;
39
40 import com.google.common.collect.ImmutableMap;
41
42 @Category(SmallTests.class)
43 public class TestHBaseConfiguration {
44 private static final Log LOG = LogFactory.getLog(TestHBaseConfiguration.class);
45
46 private static HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility();
47
48 @AfterClass
49 public static void tearDown() throws IOException {
50 UTIL.cleanupTestDir();
51 }
52
53 @Test
54 public void testSubset() {
55 Configuration conf = HBaseConfiguration.create();
56
57
58 String prefix = "hbase.mapred.output.";
59 conf.set("hbase.security.authentication", "kerberos");
60 conf.set("hbase.regionserver.kerberos.principal", "hbasesource");
61 HBaseConfiguration.setWithPrefix(conf, prefix,
62 ImmutableMap.of(
63 "hbase.regionserver.kerberos.principal", "hbasedest",
64 "", "shouldbemissing")
65 .entrySet());
66
67 Configuration subsetConf = HBaseConfiguration.subset(conf, prefix);
68 assertNull(subsetConf.get(prefix + "hbase.regionserver.kerberos.principal"));
69 assertEquals("hbasedest", subsetConf.get("hbase.regionserver.kerberos.principal"));
70 assertNull(subsetConf.get("hbase.security.authentication"));
71 assertNull(subsetConf.get(""));
72
73 Configuration mergedConf = HBaseConfiguration.create(conf);
74 HBaseConfiguration.merge(mergedConf, subsetConf);
75
76 assertEquals("hbasedest", mergedConf.get("hbase.regionserver.kerberos.principal"));
77 assertEquals("kerberos", mergedConf.get("hbase.security.authentication"));
78 assertEquals("shouldbemissing", mergedConf.get(prefix));
79 }
80
81 @Test
82 public void testGetPassword() throws Exception {
83 Configuration conf = HBaseConfiguration.create();
84 conf.set(ReflectiveCredentialProviderClient.CREDENTIAL_PROVIDER_PATH, "jceks://file"
85 + new File(UTIL.getDataTestDir().toUri().getPath(), "foo.jks").getCanonicalPath());
86 ReflectiveCredentialProviderClient client = new ReflectiveCredentialProviderClient();
87 if (client.isHadoopCredentialProviderAvailable()) {
88 char[] keyPass = { 'k', 'e', 'y', 'p', 'a', 's', 's' };
89 char[] storePass = { 's', 't', 'o', 'r', 'e', 'p', 'a', 's', 's' };
90 client.createEntry(conf, "ssl.keypass.alias", keyPass);
91 client.createEntry(conf, "ssl.storepass.alias", storePass);
92
93 String keypass = HBaseConfiguration.getPassword(conf, "ssl.keypass.alias", null);
94 assertEquals(keypass, new String(keyPass));
95
96 String storepass = HBaseConfiguration.getPassword(conf, "ssl.storepass.alias", null);
97 assertEquals(storepass, new String(storePass));
98 }
99 }
100
101 @Test
102 public void testSecurityConfCaseInsensitive() {
103 Configuration conf = HBaseConfiguration.create();
104 conf.set("hbase.security.authentication", "kerberos");
105 Assert.assertTrue(User.isHBaseSecurityEnabled(conf));
106
107 conf.set("hbase.security.authentication", "KERBEROS");
108 Assert.assertTrue(User.isHBaseSecurityEnabled(conf));
109
110 conf.set("hbase.security.authentication", "KERBeros");
111 Assert.assertTrue(User.isHBaseSecurityEnabled(conf));
112 }
113
114 private static class ReflectiveCredentialProviderClient {
115 public static final String HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME =
116 "org.apache.hadoop.security.alias.JavaKeyStoreProvider$Factory";
117 public static final String
118 HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME = "getProviders";
119
120 public static final String HADOOP_CRED_PROVIDER_CLASS_NAME =
121 "org.apache.hadoop.security.alias.CredentialProvider";
122 public static final String
123 HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME =
124 "getCredentialEntry";
125 public static final String
126 HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME = "getAliases";
127 public static final String
128 HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME =
129 "createCredentialEntry";
130 public static final String HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME = "flush";
131
132 public static final String HADOOP_CRED_ENTRY_CLASS_NAME =
133 "org.apache.hadoop.security.alias.CredentialProvider$CredentialEntry";
134 public static final String HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME =
135 "getCredential";
136
137 public static final String CREDENTIAL_PROVIDER_PATH =
138 "hadoop.security.credential.provider.path";
139
140 private static Object hadoopCredProviderFactory = null;
141 private static Method getProvidersMethod = null;
142 private static Method getCredentialEntryMethod = null;
143 private static Method getCredentialMethod = null;
144 private static Method createCredentialEntryMethod = null;
145 private static Method flushMethod = null;
146 private static Boolean hadoopClassesAvailable = null;
147
148
149
150
151
152
153
154
155
156 private boolean isHadoopCredentialProviderAvailable() {
157 if (null != hadoopClassesAvailable) {
158
159 if (hadoopClassesAvailable && null != getProvidersMethod
160 && null != hadoopCredProviderFactory
161 && null != getCredentialEntryMethod && null != getCredentialMethod) {
162 return true;
163 } else {
164
165 return false;
166 }
167 }
168
169 hadoopClassesAvailable = false;
170
171
172 Class<?> hadoopCredProviderFactoryClz;
173 try {
174 hadoopCredProviderFactoryClz = Class
175 .forName(HADOOP_CRED_PROVIDER_FACTORY_CLASS_NAME);
176 } catch (ClassNotFoundException e) {
177 return false;
178 }
179
180 try {
181 hadoopCredProviderFactory =
182 hadoopCredProviderFactoryClz.getDeclaredConstructor().newInstance();
183 } catch (Exception e) {
184 return false;
185 }
186
187 try {
188 getProvidersMethod = loadMethod(hadoopCredProviderFactoryClz,
189 HADOOP_CRED_PROVIDER_FACTORY_GET_PROVIDERS_METHOD_NAME,
190 Configuration.class);
191
192 Class<?> hadoopCredProviderClz;
193 hadoopCredProviderClz = Class.forName(HADOOP_CRED_PROVIDER_CLASS_NAME);
194 getCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
195 HADOOP_CRED_PROVIDER_GET_CREDENTIAL_ENTRY_METHOD_NAME, String.class);
196
197 Method getAliasesMethod =
198 loadMethod(hadoopCredProviderClz, HADOOP_CRED_PROVIDER_GET_ALIASES_METHOD_NAME);
199
200 createCredentialEntryMethod = loadMethod(hadoopCredProviderClz,
201 HADOOP_CRED_PROVIDER_CREATE_CREDENTIAL_ENTRY_METHOD_NAME,
202 String.class, char[].class);
203
204 flushMethod = loadMethod(hadoopCredProviderClz,
205 HADOOP_CRED_PROVIDER_FLUSH_METHOD_NAME);
206
207
208 Class<?> hadoopCredentialEntryClz;
209 try {
210 hadoopCredentialEntryClz = Class
211 .forName(HADOOP_CRED_ENTRY_CLASS_NAME);
212 } catch (ClassNotFoundException e) {
213 LOG.error("Failed to load class:" + e);
214 return false;
215 }
216
217 getCredentialMethod = loadMethod(hadoopCredentialEntryClz,
218 HADOOP_CRED_ENTRY_GET_CREDENTIAL_METHOD_NAME);
219 } catch (Exception e1) {
220 return false;
221 }
222
223 hadoopClassesAvailable = true;
224 LOG.info("Credential provider classes have been" +
225 " loaded and initialized successfully through reflection.");
226 return true;
227 }
228
229 private Method loadMethod(Class<?> clz, String name, Class<?>... classes)
230 throws Exception {
231 Method method;
232 try {
233 method = clz.getMethod(name, classes);
234 } catch (SecurityException e) {
235 fail("security exception caught for: " + name + " in " + clz.getCanonicalName());
236 throw e;
237 } catch (NoSuchMethodException e) {
238 LOG.error("Failed to load the " + name + ": " + e);
239 fail("no such method: " + name + " in " + clz.getCanonicalName());
240 throw e;
241 }
242 return method;
243 }
244
245
246
247
248
249
250
251
252 @SuppressWarnings("unchecked")
253 protected List<Object> getCredentialProviders(Configuration conf) {
254
255 Object providersObj;
256 try {
257 providersObj = getProvidersMethod.invoke(hadoopCredProviderFactory,
258 conf);
259 } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
260 LOG.error("Failed to invoke: " + getProvidersMethod.getName() +
261 ": " + e);
262 return null;
263 }
264
265
266 try {
267 return (List<Object>) providersObj;
268 } catch (ClassCastException e) {
269 return null;
270 }
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284 public void createEntry(Configuration conf, String name, char[] credential)
285 throws Exception {
286 if (!isHadoopCredentialProviderAvailable()) {
287 return;
288 }
289
290 List<Object> providers = getCredentialProviders(conf);
291 if (null == providers) {
292 throw new IOException("Could not fetch any CredentialProviders, " +
293 "is the implementation available?");
294 }
295
296 Object provider = providers.get(0);
297 createEntryInProvider(provider, name, credential);
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313 private void createEntryInProvider(Object credentialProvider,
314 String name, char[] credential) throws Exception {
315 if (!isHadoopCredentialProviderAvailable()) {
316 return;
317 }
318
319 try {
320 createCredentialEntryMethod.invoke(credentialProvider, name, credential);
321 } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
322 return;
323 }
324
325 flushMethod.invoke(credentialProvider);
326 }
327 }
328 }