Repository: kafka
Updated Branches:
  refs/heads/trunk c1fdf575d -> 65edd64ca


KAFKA-3070: SASL unit tests dont work with IBM JDK

Use IBM Kerberos module for SASL tests if running on IBM JDK

Developed with edoardocomar
Based on https://github.com/apache/kafka/pull/738 by rajinisivaram

Author: Mickael Maison <mickael.mai...@gmail.com>

Reviewers: Ismael Juma <ism...@juma.me.uk>, Rajini Sivaram 
<rajinisiva...@googlemail.com>, Edoardo Comar <eco...@uk.ibm.com>

Closes #2878 from mimaison/KAFKA-3070


Project: http://git-wip-us.apache.org/repos/asf/kafka/repo
Commit: http://git-wip-us.apache.org/repos/asf/kafka/commit/65edd64c
Tree: http://git-wip-us.apache.org/repos/asf/kafka/tree/65edd64c
Diff: http://git-wip-us.apache.org/repos/asf/kafka/diff/65edd64c

Branch: refs/heads/trunk
Commit: 65edd64ca4902c9b2bc48e952056235f016031e1
Parents: c1fdf57
Author: Mickael Maison <mickael.mai...@gmail.com>
Authored: Thu May 18 16:11:14 2017 -0400
Committer: Rajini Sivaram <rajinisiva...@googlemail.com>
Committed: Thu May 18 16:11:14 2017 -0400

----------------------------------------------------------------------
 .../common/network/SaslChannelBuilder.java      |  3 +-
 .../org/apache/kafka/common/utils/Java.java     |  4 ++
 .../org/apache/kafka/common/utils/JavaTest.java | 56 ++++++++++++++++++++
 .../scala/kafka/security/minikdc/MiniKdc.scala  |  4 +-
 .../scala/unit/kafka/utils/JaasTestUtils.scala  | 49 +++++++++++++----
 .../test/scala/unit/kafka/utils/TestUtils.scala | 12 ++---
 6 files changed, 105 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
----------------------------------------------------------------------
diff --git 
a/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java 
b/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
index 6b5668f..9fe200f 100644
--- 
a/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
+++ 
b/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
@@ -32,6 +32,7 @@ import 
org.apache.kafka.common.security.authenticator.LoginManager;
 import org.apache.kafka.common.security.authenticator.SaslClientAuthenticator;
 import org.apache.kafka.common.security.authenticator.SaslServerAuthenticator;
 import org.apache.kafka.common.security.ssl.SslFactory;
+import org.apache.kafka.common.utils.Java;
 import org.apache.kafka.common.protocol.SecurityProtocol;
 import org.apache.kafka.common.KafkaException;
 import org.slf4j.Logger;
@@ -143,7 +144,7 @@ public class SaslChannelBuilder implements ChannelBuilder {
         Class<?> classRef;
         Method getInstanceMethod;
         Method getDefaultRealmMethod;
-        if (System.getProperty("java.vendor").contains("IBM")) {
+        if (Java.isIBMJdk()) {
             classRef = Class.forName("com.ibm.security.krb5.internal.Config");
         } else {
             classRef = Class.forName("sun.security.krb5.Config");

http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/clients/src/main/java/org/apache/kafka/common/utils/Java.java
----------------------------------------------------------------------
diff --git a/clients/src/main/java/org/apache/kafka/common/utils/Java.java 
b/clients/src/main/java/org/apache/kafka/common/utils/Java.java
index 34eb6bf..b374c24 100644
--- a/clients/src/main/java/org/apache/kafka/common/utils/Java.java
+++ b/clients/src/main/java/org/apache/kafka/common/utils/Java.java
@@ -41,4 +41,8 @@ public final class Java {
     public static final boolean IS_JAVA9_COMPATIBLE = JVM_MAJOR_VERSION > 1 ||
             (JVM_MAJOR_VERSION == 1 && JVM_MINOR_VERSION >= 9);
 
+    public static boolean isIBMJdk() {
+        return System.getProperty("java.vendor").contains("IBM");
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/clients/src/test/java/org/apache/kafka/common/utils/JavaTest.java
----------------------------------------------------------------------
diff --git a/clients/src/test/java/org/apache/kafka/common/utils/JavaTest.java 
b/clients/src/test/java/org/apache/kafka/common/utils/JavaTest.java
new file mode 100644
index 0000000..057ff50
--- /dev/null
+++ b/clients/src/test/java/org/apache/kafka/common/utils/JavaTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.kafka.common.utils;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JavaTest {
+
+    private String javaVendor;
+
+    @Before
+    public void before() {
+        javaVendor = System.getProperty("java.vendor");
+    }
+
+    @After
+    public void after() {
+        System.setProperty("java.vendor", javaVendor);
+    }
+
+    @Test
+    public void testIsIBMJdk() {
+        System.setProperty("java.vendor", "Oracle Corporation");
+        assertFalse(Java.isIBMJdk());
+        System.setProperty("java.vendor", "IBM Corporation");
+        assertTrue(Java.isIBMJdk());
+    }
+
+    @Test
+    public void testLoadKerberosLoginModule() throws ClassNotFoundException {
+        String clazz = Java.isIBMJdk()
+                ? "com.ibm.security.auth.module.Krb5LoginModule"
+                : "com.sun.security.auth.module.Krb5LoginModule";
+        Class.forName(clazz);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/core/src/test/scala/kafka/security/minikdc/MiniKdc.scala
----------------------------------------------------------------------
diff --git a/core/src/test/scala/kafka/security/minikdc/MiniKdc.scala 
b/core/src/test/scala/kafka/security/minikdc/MiniKdc.scala
index c08dd99..c7b8973 100644
--- a/core/src/test/scala/kafka/security/minikdc/MiniKdc.scala
+++ b/core/src/test/scala/kafka/security/minikdc/MiniKdc.scala
@@ -50,7 +50,7 @@ import 
org.apache.directory.server.kerberos.shared.keytab.{Keytab, KeytabEntry}
 import org.apache.directory.server.protocol.shared.transport.{TcpTransport, 
UdpTransport}
 import org.apache.directory.server.xdbm.Index
 import org.apache.directory.shared.kerberos.KerberosTime
-import org.apache.kafka.common.utils.Utils
+import org.apache.kafka.common.utils.{Java, Utils}
 
 /**
   * Mini KDC based on Apache Directory Server that can be embedded in tests or 
used from command line as a standalone
@@ -256,7 +256,7 @@ class MiniKdc(config: Properties, workDir: File) extends 
Logging {
 
   private def refreshJvmKerberosConfig(): Unit = {
     val klass =
-      if (System.getProperty("java.vendor").contains("IBM"))
+      if (Java.isIBMJdk)
         Class.forName("com.ibm.security.krb5.internal.Config")
       else
         Class.forName("sun.security.krb5.Config")

http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/core/src/test/scala/unit/kafka/utils/JaasTestUtils.scala
----------------------------------------------------------------------
diff --git a/core/src/test/scala/unit/kafka/utils/JaasTestUtils.scala 
b/core/src/test/scala/unit/kafka/utils/JaasTestUtils.scala
index d10e861..9517789 100644
--- a/core/src/test/scala/unit/kafka/utils/JaasTestUtils.scala
+++ b/core/src/test/scala/unit/kafka/utils/JaasTestUtils.scala
@@ -17,6 +17,9 @@
 package kafka.utils
 
 import java.io.{File, BufferedWriter, FileWriter}
+import java.util.Properties
+import kafka.server.KafkaConfig
+import org.apache.kafka.common.utils.Java
 
 object JaasTestUtils {
 
@@ -27,15 +30,25 @@ object JaasTestUtils {
                              debug: Boolean,
                              serviceName: Option[String]) extends JaasModule {
 
-    def name = "com.sun.security.auth.module.Krb5LoginModule"
-
-    def entries: Map[String, String] = Map(
-      "useKeyTab" -> useKeyTab.toString,
-      "storeKey" -> storeKey.toString,
-      "keyTab" -> keyTab,
-      "principal" -> principal
-    ) ++ serviceName.map(s => Map("serviceName" -> s)).getOrElse(Map.empty)
-
+    def name =
+      if (Java.isIBMJdk)
+        "com.ibm.security.auth.module.Krb5LoginModule"
+      else
+        "com.sun.security.auth.module.Krb5LoginModule"
+
+    def entries: Map[String, String] =
+      if (Java.isIBMJdk)
+        Map(
+          "principal" -> principal,
+          "credsType" -> "both"
+        ) ++ (if (useKeyTab) Map("useKeytab" -> s"file:$keyTab") else 
Map.empty)
+      else
+        Map(
+          "useKeyTab" -> useKeyTab.toString,
+          "storeKey" -> storeKey.toString,
+          "keyTab" -> keyTab,
+          "principal" -> principal
+        ) ++ serviceName.map(s => Map("serviceName" -> s)).getOrElse(Map.empty)
   }
 
   case class PlainLoginModule(username: String,
@@ -120,6 +133,20 @@ object JaasTestUtils {
   val KafkaScramAdmin = "scram-admin"
   val KafkaScramAdminPassword = "scram-admin-secret"
 
+  val serviceName = "kafka"
+
+  def saslConfigs(saslProperties: Option[Properties]): Properties = {
+    val result = saslProperties match {
+      case Some(properties) => properties
+      case None => new Properties
+    }
+    // IBM Kerberos module doesn't support the serviceName JAAS property, 
hence it needs to be
+    // passed as a Kafka property
+    if (Java.isIBMJdk && 
!result.contains(KafkaConfig.SaslKerberosServiceNameProp))
+      result.put(KafkaConfig.SaslKerberosServiceNameProp, serviceName)
+    result
+  }
+
   def writeJaasContextsToFile(jaasSections: Seq[JaasSection]): File = {
     val jaasFile = TestUtils.tempFile()
     writeToFile(jaasFile, jaasSections)
@@ -146,7 +173,7 @@ object JaasTestUtils {
           keyTab = keytabLocation.getOrElse(throw new 
IllegalArgumentException("Keytab location not specified for 
GSSAPI")).getAbsolutePath,
           principal = KafkaServerPrincipal,
           debug = true,
-          serviceName = Some("kafka"))
+          serviceName = Some(serviceName))
       case "PLAIN" =>
         PlainLoginModule(
           KafkaPlainAdmin,
@@ -180,7 +207,7 @@ object JaasTestUtils {
           keyTab = keytabLocation.getOrElse(throw new 
IllegalArgumentException("Keytab location not specified for 
GSSAPI")).getAbsolutePath,
           principal = clientPrincipal,
           debug = true,
-          serviceName = Some("kafka")
+          serviceName = Some(serviceName)
         )
       case "PLAIN" =>
         PlainLoginModule(

http://git-wip-us.apache.org/repos/asf/kafka/blob/65edd64c/core/src/test/scala/unit/kafka/utils/TestUtils.scala
----------------------------------------------------------------------
diff --git a/core/src/test/scala/unit/kafka/utils/TestUtils.scala 
b/core/src/test/scala/unit/kafka/utils/TestUtils.scala
index 90dcacd..5097637 100755
--- a/core/src/test/scala/unit/kafka/utils/TestUtils.scala
+++ b/core/src/test/scala/unit/kafka/utils/TestUtils.scala
@@ -245,7 +245,7 @@ object TestUtils extends Logging {
       props.putAll(sslConfigs(Mode.SERVER, false, trustStoreFile, 
s"server$nodeId"))
 
     if (protocolAndPorts.exists { case (protocol, _) => 
usesSaslAuthentication(protocol) })
-      props.putAll(saslConfigs(saslProperties))
+      props.putAll(JaasTestUtils.saslConfigs(saslProperties))
 
     interBrokerSecurityProtocol.foreach { protocol =>
       props.put(KafkaConfig.InterBrokerSecurityProtocolProp, protocol.name)
@@ -509,8 +509,9 @@ object TestUtils extends Logging {
     val props = new Properties
     if (usesSslTransportLayer(securityProtocol))
       props.putAll(sslConfigs(mode, securityProtocol == SecurityProtocol.SSL, 
trustStoreFile, certAlias))
+
     if (usesSaslAuthentication(securityProtocol))
-      props.putAll(saslConfigs(saslProperties))
+      props.putAll(JaasTestUtils.saslConfigs(saslProperties))
     props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, 
securityProtocol.name)
     props
   }
@@ -1184,13 +1185,6 @@ object TestUtils extends Logging {
     sslProps
   }
 
-  def saslConfigs(saslProperties: Option[Properties]): Properties = {
-    saslProperties match {
-      case Some(properties) => properties
-      case None => new Properties
-    }
-  }
-
   // a X509TrustManager to trust self-signed certs for unit tests.
   def trustAllCerts: X509TrustManager = {
     val trustManager = new X509TrustManager() {

Reply via email to