Skip to content

Commit cf33164

Browse files
hchaverriomalley
authored andcommitted
HDFS-16591. Setup JaasConfiguration in ZKCuratorManager when SASL is enabled
Fixes #4447 Signed-off-by: Owen O'Malley <oomalley@linkedin.com>
1 parent 7eefdf8 commit cf33164

File tree

8 files changed

+174
-192
lines changed

8 files changed

+174
-192
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License. See accompanying LICENSE file.
13+
*/
14+
package org.apache.hadoop.security.authentication.util;
15+
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import javax.security.auth.login.AppConfigurationEntry;
19+
import javax.security.auth.login.Configuration;
20+
21+
22+
/**
23+
* Creates a programmatic version of a jaas.conf file. This can be used
24+
* instead of writing a jaas.conf file and setting the system property,
25+
* "java.security.auth.login.config", to point to that file. It is meant to be
26+
* used for connecting to ZooKeeper.
27+
*/
28+
public class JaasConfiguration extends Configuration {
29+
30+
private final javax.security.auth.login.Configuration baseConfig =
31+
javax.security.auth.login.Configuration.getConfiguration();
32+
private final AppConfigurationEntry[] entry;
33+
private final String entryName;
34+
35+
/**
36+
* Add an entry to the jaas configuration with the passed in name,
37+
* principal, and keytab. The other necessary options will be set for you.
38+
*
39+
* @param entryName The name of the entry (e.g. "Client")
40+
* @param principal The principal of the user
41+
* @param keytab The location of the keytab
42+
*/
43+
public JaasConfiguration(String entryName, String principal, String keytab) {
44+
this.entryName = entryName;
45+
Map<String, String> options = new HashMap<>();
46+
options.put("keyTab", keytab);
47+
options.put("principal", principal);
48+
options.put("useKeyTab", "true");
49+
options.put("storeKey", "true");
50+
options.put("useTicketCache", "false");
51+
options.put("refreshKrb5Config", "true");
52+
String jaasEnvVar = System.getenv("HADOOP_JAAS_DEBUG");
53+
if ("true".equalsIgnoreCase(jaasEnvVar)) {
54+
options.put("debug", "true");
55+
}
56+
entry = new AppConfigurationEntry[]{
57+
new AppConfigurationEntry(getKrb5LoginModuleName(),
58+
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
59+
options)};
60+
}
61+
62+
@Override
63+
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
64+
return (entryName.equals(name)) ? entry : ((baseConfig != null)
65+
? baseConfig.getAppConfigurationEntry(name) : null);
66+
}
67+
68+
private String getKrb5LoginModuleName() {
69+
String krb5LoginModuleName;
70+
if (System.getProperty("java.vendor").contains("IBM")) {
71+
krb5LoginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
72+
} else {
73+
krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
74+
}
75+
return krb5LoginModuleName;
76+
}
77+
}

hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ZKSignerSecretProvider.java

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@
1717
import java.nio.ByteBuffer;
1818
import java.security.SecureRandom;
1919
import java.util.Collections;
20-
import java.util.HashMap;
2120
import java.util.List;
22-
import java.util.Map;
2321
import java.util.Properties;
2422
import java.util.Random;
25-
import javax.security.auth.login.AppConfigurationEntry;
2623
import javax.security.auth.login.Configuration;
2724
import javax.servlet.ServletContext;
2825
import org.apache.curator.RetryPolicy;
@@ -429,62 +426,4 @@ public List<ACL> getAclForPath(String path) {
429426
return saslACL;
430427
}
431428
}
432-
433-
/**
434-
* Creates a programmatic version of a jaas.conf file. This can be used
435-
* instead of writing a jaas.conf file and setting the system property,
436-
* "java.security.auth.login.config", to point to that file. It is meant to be
437-
* used for connecting to ZooKeeper.
438-
*/
439-
@InterfaceAudience.Private
440-
public static class JaasConfiguration extends Configuration {
441-
442-
private final javax.security.auth.login.Configuration baseConfig =
443-
javax.security.auth.login.Configuration.getConfiguration();
444-
private static AppConfigurationEntry[] entry;
445-
private String entryName;
446-
447-
/**
448-
* Add an entry to the jaas configuration with the passed in name,
449-
* principal, and keytab. The other necessary options will be set for you.
450-
*
451-
* @param entryName The name of the entry (e.g. "Client")
452-
* @param principal The principal of the user
453-
* @param keytab The location of the keytab
454-
*/
455-
public JaasConfiguration(String entryName, String principal, String keytab) {
456-
this.entryName = entryName;
457-
Map<String, String> options = new HashMap<String, String>();
458-
options.put("keyTab", keytab);
459-
options.put("principal", principal);
460-
options.put("useKeyTab", "true");
461-
options.put("storeKey", "true");
462-
options.put("useTicketCache", "false");
463-
options.put("refreshKrb5Config", "true");
464-
String jaasEnvVar = System.getenv("HADOOP_JAAS_DEBUG");
465-
if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) {
466-
options.put("debug", "true");
467-
}
468-
entry = new AppConfigurationEntry[]{
469-
new AppConfigurationEntry(getKrb5LoginModuleName(),
470-
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
471-
options)};
472-
}
473-
474-
@Override
475-
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
476-
return (entryName.equals(name)) ? entry : ((baseConfig != null)
477-
? baseConfig.getAppConfigurationEntry(name) : null);
478-
}
479-
480-
private String getKrb5LoginModuleName() {
481-
String krb5LoginModuleName;
482-
if (System.getProperty("java.vendor").contains("IBM")) {
483-
krb5LoginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
484-
} else {
485-
krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
486-
}
487-
return krb5LoginModuleName;
488-
}
489-
}
490429
}

hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestJaasConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public void test() throws Exception {
3232
krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
3333
}
3434

35-
ZKSignerSecretProvider.JaasConfiguration jConf =
36-
new ZKSignerSecretProvider.JaasConfiguration("foo", "foo/localhost",
35+
JaasConfiguration jConf =
36+
new JaasConfiguration("foo", "foo/localhost",
3737
"/some/location/foo.keytab");
3838
AppConfigurationEntry[] entries = jConf.getAppConfigurationEntry("bar");
3939
Assert.assertNull(entries);

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,10 @@ public class CommonConfigurationKeys extends CommonConfigurationKeysPublic {
401401
public static final String ZK_AUTH = ZK_PREFIX + "auth";
402402
/** Principal name for zookeeper servers. */
403403
public static final String ZK_SERVER_PRINCIPAL = ZK_PREFIX + "server.principal";
404+
/** Kerberos principal name for zookeeper connection. */
405+
public static final String ZK_KERBEROS_PRINCIPAL = ZK_PREFIX + "kerberos.principal";
406+
/** Kerberos keytab for zookeeper connection. */
407+
public static final String ZK_KERBEROS_KEYTAB = ZK_PREFIX + "kerberos.keytab";
404408

405409
/** Address of the ZooKeeper ensemble. */
406410
public static final String ZK_ADDRESS = ZK_PREFIX + "address";

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/ZKDelegationTokenSecretManager.java

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,10 @@
2525
import java.io.IOException;
2626
import java.io.UncheckedIOException;
2727
import java.util.Collections;
28-
import java.util.HashMap;
2928
import java.util.List;
30-
import java.util.Map;
3129
import java.util.concurrent.atomic.AtomicInteger;
3230
import java.util.stream.Stream;
3331

34-
import javax.security.auth.login.AppConfigurationEntry;
35-
3632
import org.apache.curator.ensemble.fixed.FixedEnsembleProvider;
3733
import org.apache.curator.framework.CuratorFramework;
3834
import org.apache.curator.framework.CuratorFrameworkFactory;
@@ -52,6 +48,7 @@
5248
import org.apache.hadoop.classification.InterfaceStability.Unstable;
5349
import org.apache.hadoop.conf.Configuration;
5450
import org.apache.hadoop.security.SecurityUtil;
51+
import org.apache.hadoop.security.authentication.util.JaasConfiguration;
5552
import org.apache.hadoop.security.token.Token;
5653
import org.apache.hadoop.security.token.delegation.web.DelegationTokenManager;
5754
import static org.apache.hadoop.util.Time.now;
@@ -251,68 +248,6 @@ private String setJaasConfiguration(Configuration config) throws Exception {
251248
return principal.split("[/@]")[0];
252249
}
253250

254-
/**
255-
* Creates a programmatic version of a jaas.conf file. This can be used
256-
* instead of writing a jaas.conf file and setting the system property,
257-
* "java.security.auth.login.config", to point to that file. It is meant to be
258-
* used for connecting to ZooKeeper.
259-
*/
260-
@InterfaceAudience.Private
261-
public static class JaasConfiguration extends
262-
javax.security.auth.login.Configuration {
263-
264-
private final javax.security.auth.login.Configuration baseConfig =
265-
javax.security.auth.login.Configuration.getConfiguration();
266-
private static AppConfigurationEntry[] entry;
267-
private String entryName;
268-
269-
/**
270-
* Add an entry to the jaas configuration with the passed in name,
271-
* principal, and keytab. The other necessary options will be set for you.
272-
*
273-
* @param entryName
274-
* The name of the entry (e.g. "Client")
275-
* @param principal
276-
* The principal of the user
277-
* @param keytab
278-
* The location of the keytab
279-
*/
280-
public JaasConfiguration(String entryName, String principal, String keytab) {
281-
this.entryName = entryName;
282-
Map<String, String> options = new HashMap<String, String>();
283-
options.put("keyTab", keytab);
284-
options.put("principal", principal);
285-
options.put("useKeyTab", "true");
286-
options.put("storeKey", "true");
287-
options.put("useTicketCache", "false");
288-
options.put("refreshKrb5Config", "true");
289-
String jaasEnvVar = System.getenv("HADOOP_JAAS_DEBUG");
290-
if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) {
291-
options.put("debug", "true");
292-
}
293-
entry = new AppConfigurationEntry[] {
294-
new AppConfigurationEntry(getKrb5LoginModuleName(),
295-
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
296-
options) };
297-
}
298-
299-
@Override
300-
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
301-
return (entryName.equals(name)) ? entry : ((baseConfig != null)
302-
? baseConfig.getAppConfigurationEntry(name) : null);
303-
}
304-
305-
private String getKrb5LoginModuleName() {
306-
String krb5LoginModuleName;
307-
if (System.getProperty("java.vendor").contains("IBM")) {
308-
krb5LoginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
309-
} else {
310-
krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
311-
}
312-
return krb5LoginModuleName;
313-
}
314-
}
315-
316251
@Override
317252
public void startThreads() throws IOException {
318253
if (!isExternalClient) {

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/curator/ZKCuratorManager.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.apache.hadoop.conf.Configuration;
3434
import org.apache.hadoop.fs.CommonConfigurationKeys;
3535
import org.apache.hadoop.security.SecurityUtil;
36+
import org.apache.hadoop.security.authentication.util.JaasConfiguration;
3637
import org.apache.hadoop.util.ZKUtil;
3738
import org.apache.zookeeper.CreateMode;
3839
import org.apache.zookeeper.Watcher;
@@ -159,7 +160,9 @@ public void start(List<AuthInfo> authInfos) throws IOException {
159160
CuratorFramework client = CuratorFrameworkFactory.builder()
160161
.connectString(zkHostPort)
161162
.zookeeperFactory(new HadoopZookeeperFactory(
162-
conf.get(CommonConfigurationKeys.ZK_SERVER_PRINCIPAL)))
163+
conf.get(CommonConfigurationKeys.ZK_SERVER_PRINCIPAL),
164+
conf.get(CommonConfigurationKeys.ZK_KERBEROS_PRINCIPAL),
165+
conf.get(CommonConfigurationKeys.ZK_KERBEROS_KEYTAB)))
163166
.sessionTimeoutMs(zkSessionTimeout)
164167
.retryPolicy(retryPolicy)
165168
.authorization(authInfos)
@@ -445,10 +448,20 @@ public void setData(String path, byte[] data, int version)
445448
}
446449

447450
public static class HadoopZookeeperFactory implements ZookeeperFactory {
451+
public final static String JAAS_CLIENT_ENTRY = "HadoopZookeeperClient";
448452
private final String zkPrincipal;
453+
private final String kerberosPrincipal;
454+
private final String kerberosKeytab;
449455

450456
public HadoopZookeeperFactory(String zkPrincipal) {
457+
this(zkPrincipal, null, null);
458+
}
459+
460+
public HadoopZookeeperFactory(String zkPrincipal, String kerberosPrincipal,
461+
String kerberosKeytab) {
451462
this.zkPrincipal = zkPrincipal;
463+
this.kerberosPrincipal = kerberosPrincipal;
464+
this.kerberosKeytab = kerberosKeytab;
452465
}
453466

454467
@Override
@@ -462,8 +475,32 @@ public ZooKeeper newZooKeeper(String connectString, int sessionTimeout,
462475
zkClientConfig.setProperty(ZKClientConfig.ZK_SASL_CLIENT_USERNAME,
463476
zkPrincipal);
464477
}
478+
if (zkClientConfig.isSaslClientEnabled() && !isJaasConfigurationSet(zkClientConfig)) {
479+
setJaasConfiguration(zkClientConfig);
480+
}
465481
return new ZooKeeper(connectString, sessionTimeout, watcher,
466482
canBeReadOnly, zkClientConfig);
467483
}
484+
485+
private boolean isJaasConfigurationSet(ZKClientConfig zkClientConfig) {
486+
String clientConfig = zkClientConfig.getProperty(ZKClientConfig.LOGIN_CONTEXT_NAME_KEY,
487+
ZKClientConfig.LOGIN_CONTEXT_NAME_KEY_DEFAULT);
488+
return javax.security.auth.login.Configuration.getConfiguration()
489+
.getAppConfigurationEntry(clientConfig) != null;
490+
}
491+
492+
private void setJaasConfiguration(ZKClientConfig zkClientConfig) throws IOException {
493+
if (kerberosPrincipal == null || kerberosKeytab == null) {
494+
LOG.warn("JaasConfiguration has not been set since kerberos principal "
495+
+ "or keytab is not specified");
496+
return;
497+
}
498+
499+
String principal = SecurityUtil.getServerPrincipal(kerberosPrincipal, "");
500+
JaasConfiguration jconf = new JaasConfiguration(JAAS_CLIENT_ENTRY, principal,
501+
kerberosKeytab);
502+
javax.security.auth.login.Configuration.setConfiguration(jconf);
503+
zkClientConfig.setProperty(ZKClientConfig.LOGIN_CONTEXT_NAME_KEY, JAAS_CLIENT_ENTRY);
504+
}
468505
}
469506
}

0 commit comments

Comments
 (0)