You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2020/09/18 00:56:59 UTC
[nifi] 10/11: NIFI-7799: Relogin with Kerberos on connect exception
in DBCPConnectionPool (#4519)
This is an automated email from the ASF dual-hosted git repository.
alopresto pushed a commit to branch support/nifi-1.12.x
in repository https://gitbox.apache.org/repos/asf/nifi.git
commit e952a76e4f9eba5e668ff06af5ff95554b851acf
Author: Matthew Burgess <ma...@apache.org>
AuthorDate: Thu Sep 17 13:33:54 2020 -0400
NIFI-7799: Relogin with Kerberos on connect exception in DBCPConnectionPool (#4519)
---
.../{ => nifi-kerberos-test-utils}/pom.xml | 43 ++++++-----
.../kerberos/MockKerberosCredentialsService.java | 85 ++++++++++++++++++++++
nifi-nar-bundles/nifi-extension-utils/pom.xml | 1 +
.../nifi-hive-bundle/nifi-hive3-processors/pom.xml | 6 ++
.../processors/hive/TestPutHive3Streaming.java | 67 ++---------------
.../nifi-dbcp-service/pom.xml | 19 +++++
.../org/apache/nifi/dbcp/DBCPConnectionPool.java | 9 +++
.../java/org/apache/nifi/dbcp/DBCPServiceTest.java | 38 ++++++++++
.../src/test/resources/fake.keytab | 0
9 files changed, 187 insertions(+), 81 deletions(-)
diff --git a/nifi-nar-bundles/nifi-extension-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/pom.xml
similarity index 57%
copy from nifi-nar-bundles/nifi-extension-utils/pom.xml
copy to nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/pom.xml
index 2980f23..a223d03 100644
--- a/nifi-nar-bundles/nifi-extension-utils/pom.xml
+++ b/nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/pom.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -17,25 +17,28 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.nifi</groupId>
- <artifactId>nifi-nar-bundles</artifactId>
- <version>1.12.1-SNAPSHOT</version>
+ <artifactId>nifi-extension-utils</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
</parent>
- <packaging>pom</packaging>
- <artifactId>nifi-extension-utils</artifactId>
- <description>
- This module contains reusable utilities related to extensions that can be shared across NARs.
- </description>
- <modules>
- <module>nifi-record-utils</module>
- <module>nifi-hadoop-utils</module>
- <module>nifi-processor-utils</module>
- <module>nifi-reporting-utils</module>
- <module>nifi-syslog-utils</module>
- <module>nifi-database-utils</module>
- <module>nifi-database-test-utils</module>
- <module>nifi-service-utils</module>
- <module>nifi-prometheus-utils</module>
- </modules>
+ <artifactId>nifi-kerberos-test-utils</artifactId>
-</project>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-api</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-utils</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-kerberos-credentials-service-api</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/src/main/java/org/apache/nifi/kerberos/MockKerberosCredentialsService.java b/nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/src/main/java/org/apache/nifi/kerberos/MockKerberosCredentialsService.java
new file mode 100644
index 0000000..b7b2a01
--- /dev/null
+++ b/nifi-nar-bundles/nifi-extension-utils/nifi-kerberos-test-utils/src/main/java/org/apache/nifi/kerberos/MockKerberosCredentialsService.java
@@ -0,0 +1,85 @@
+/*
+ * 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.nifi.kerberos;
+
+import org.apache.nifi.annotation.lifecycle.OnEnabled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.controller.AbstractControllerService;
+import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.reporting.InitializationException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MockKerberosCredentialsService extends AbstractControllerService implements KerberosCredentialsService {
+
+ public static String DEFAULT_KEYTAB = "src/test/resources/fake.keytab";
+ public static String DEFAULT_PRINCIPAL = "test@REALM.COM";
+
+ private volatile String keytab = DEFAULT_KEYTAB;
+ private volatile String principal = DEFAULT_PRINCIPAL;
+
+ public static final PropertyDescriptor PRINCIPAL = new PropertyDescriptor.Builder()
+ .name("Kerberos Principal")
+ .description("Kerberos principal to authenticate as. Requires nifi.kerberos.krb5.file to be set in your nifi.properties")
+ .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+ .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+ .required(true)
+ .build();
+
+ public static final PropertyDescriptor KEYTAB = new PropertyDescriptor.Builder()
+ .name("Kerberos Keytab")
+ .description("Kerberos keytab associated with the principal. Requires nifi.kerberos.krb5.file to be set in your nifi.properties")
+ .addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
+ .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+ .required(true)
+ .build();
+
+ public MockKerberosCredentialsService() {
+ }
+
+ @OnEnabled
+ public void onConfigured(final ConfigurationContext context) throws InitializationException {
+ keytab = context.getProperty(KEYTAB).getValue();
+ principal = context.getProperty(PRINCIPAL).getValue();
+ }
+
+ @Override
+ public String getKeytab() {
+ return keytab;
+ }
+
+ @Override
+ public String getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+ final List<PropertyDescriptor> properties = new ArrayList<>(2);
+ properties.add(KEYTAB);
+ properties.add(PRINCIPAL);
+ return properties;
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "kcs";
+ }
+}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-extension-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/pom.xml
index 2980f23..17e0572 100644
--- a/nifi-nar-bundles/nifi-extension-utils/pom.xml
+++ b/nifi-nar-bundles/nifi-extension-utils/pom.xml
@@ -36,6 +36,7 @@
<module>nifi-database-test-utils</module>
<module>nifi-service-utils</module>
<module>nifi-prometheus-utils</module>
+ <module>nifi-kerberos-test-utils</module>
</modules>
</project>
diff --git a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/pom.xml b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/pom.xml
index edd36f8..38a3234 100644
--- a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/pom.xml
@@ -147,6 +147,12 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-kerberos-test-utils</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/hive/TestPutHive3Streaming.java b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/hive/TestPutHive3Streaming.java
index 05e44fb..0db3cad 100644
--- a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/hive/TestPutHive3Streaming.java
+++ b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/hive/TestPutHive3Streaming.java
@@ -48,15 +48,11 @@ import org.apache.hive.streaming.StubSerializationError;
import org.apache.hive.streaming.StubStreamingIOFailure;
import org.apache.hive.streaming.StubTransactionError;
import org.apache.nifi.avro.AvroTypeUtil;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
-import org.apache.nifi.controller.ControllerService;
-import org.apache.nifi.controller.ControllerServiceInitializationContext;
import org.apache.nifi.hadoop.SecurityUtil;
import org.apache.nifi.json.JsonRecordSetWriter;
import org.apache.nifi.json.JsonTreeReader;
import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.MockKerberosCredentialsService;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.reporting.InitializationException;
@@ -96,7 +92,6 @@ import java.sql.Timestamp;
import java.time.Instant;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -293,6 +288,8 @@ public class TestPutHive3Streaming {
KerberosCredentialsService kcs = new MockKerberosCredentialsService();
runner.addControllerService("kcs", kcs);
runner.setProperty(KERBEROS_CREDENTIALS_SERVICE, "kcs");
+ runner.setProperty(kcs, MockKerberosCredentialsService.PRINCIPAL, "test");
+ runner.setProperty(kcs, MockKerberosCredentialsService.KEYTAB, "src/test/resources/core-site-security.xml");
runner.enableControllerService(kcs);
ugi = mock(UserGroupInformation.class);
when(hiveConfigurator.authenticate(eq(hiveConf), any(KerberosUser.class))).thenReturn(ugi);
@@ -313,8 +310,10 @@ public class TestPutHive3Streaming {
runner.setProperty(PutHive3Streaming.HIVE_CONFIGURATION_RESOURCES, "src/test/resources/core-site-security.xml, src/test/resources/hive-site-security.xml");
hiveConf.set(SecurityUtil.HADOOP_SECURITY_AUTHENTICATION, SecurityUtil.KERBEROS);
- KerberosCredentialsService kcs = new MockKerberosCredentialsService(null, null);
+ KerberosCredentialsService kcs = new MockKerberosCredentialsService();
runner.addControllerService("kcs", kcs);
+ runner.setProperty(kcs, MockKerberosCredentialsService.PRINCIPAL, "test");
+ runner.setProperty(kcs, MockKerberosCredentialsService.KEYTAB, "src/test/resources/core-site-security.xml");
runner.setProperty(KERBEROS_CREDENTIALS_SERVICE, "kcs");
runner.enableControllerService(kcs);
runner.assertNotValid();
@@ -1321,58 +1320,4 @@ public class TestPutHive3Streaming {
return null;
}
}
-
- private static class MockKerberosCredentialsService implements KerberosCredentialsService, ControllerService {
-
- private String keytab = "src/test/resources/fake.keytab";
- private String principal = "test@REALM.COM";
-
- public MockKerberosCredentialsService() {
- }
-
- public MockKerberosCredentialsService(String keytab, String principal) {
- this.keytab = keytab;
- this.principal = principal;
- }
-
- @Override
- public String getKeytab() {
- return keytab;
- }
-
- @Override
- public String getPrincipal() {
- return principal;
- }
-
- @Override
- public void initialize(ControllerServiceInitializationContext context) throws InitializationException {
-
- }
-
- @Override
- public Collection<ValidationResult> validate(ValidationContext context) {
- return Collections.EMPTY_LIST;
- }
-
- @Override
- public PropertyDescriptor getPropertyDescriptor(String name) {
- return null;
- }
-
- @Override
- public void onPropertyModified(PropertyDescriptor descriptor, String oldValue, String newValue) {
-
- }
-
- @Override
- public List<PropertyDescriptor> getPropertyDescriptors() {
- return null;
- }
-
- @Override
- public String getIdentifier() {
- return "kcs";
- }
- }
}
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/pom.xml
index 80e0feb..83ddffc 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/pom.xml
@@ -115,8 +115,27 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-kerberos-test-utils</artifactId>
+ <version>1.13.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
</dependency>
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes combine.children="append">
+ <exclude>src/test/resources/fake.keytab</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
index 786f9c3..de64a36 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
@@ -513,6 +513,15 @@ public class DBCPConnectionPool extends AbstractControllerService implements DBC
}
return con;
} catch (final SQLException e) {
+ // If using Kerberos, attempt to re-login
+ if (kerberosUser != null) {
+ try {
+ getLogger().info("Error getting connection, performing Kerberos re-login");
+ kerberosUser.login();
+ } catch (LoginException le) {
+ throw new ProcessException("Unable to authenticate Kerberos principal", le);
+ }
+ }
throw new ProcessException(e);
}
}
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
index 6071474..373d13e 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/java/org/apache/nifi/dbcp/DBCPServiceTest.java
@@ -17,6 +17,8 @@
package org.apache.nifi.dbcp;
import org.apache.derby.drda.NetworkServerControl;
+import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.MockKerberosCredentialsService;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.util.TestRunner;
@@ -304,6 +306,42 @@ public class DBCPServiceTest {
connection.close(); // return to pool
}
+ /**
+ * Test that we relogin to Kerberos if a ConnectException occurs during getConnection().
+ */
+ @Test(expected = ProcessException.class)
+ public void testConnectExceptionCausesKerberosRelogin() throws InitializationException, SQLException {
+ final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
+ final DBCPConnectionPool service = new DBCPConnectionPool();
+ runner.addControllerService("test-good1", service);
+
+ final KerberosCredentialsService kerberosCredentialsService = new MockKerberosCredentialsService();
+ runner.addControllerService("kcs", kerberosCredentialsService);
+ runner.setProperty(kerberosCredentialsService, MockKerberosCredentialsService.PRINCIPAL, "bad@PRINCIPAL.COM");
+ runner.setProperty(kerberosCredentialsService, MockKerberosCredentialsService.KEYTAB, "src/test/resources/fake.keytab");
+ runner.enableControllerService(kerberosCredentialsService);
+
+ // set fake Derby database connection url
+ runner.setProperty(service, DBCPConnectionPool.DATABASE_URL, "jdbc:derby://localhost:1527/NoDB");
+ runner.setProperty(service, DBCPConnectionPool.DB_USER, "tester");
+ runner.setProperty(service, DBCPConnectionPool.DB_PASSWORD, "testerp");
+ // Use the client driver here rather than the embedded one, as it will generate a ConnectException for the test
+ runner.setProperty(service, DBCPConnectionPool.DB_DRIVERNAME, "org.apache.derby.jdbc.ClientDriver");
+ runner.setProperty(service, DBCPConnectionPool.KERBEROS_CREDENTIALS_SERVICE, "kcs");
+
+ try {
+ runner.enableControllerService(service);
+ } catch (AssertionError ae) {
+ // Ignore, this happens because it tries to do the initial Kerberos login
+ }
+
+ runner.assertValid(service);
+ final DBCPService dbcpService = (DBCPService) runner.getProcessContext().getControllerServiceLookup().getControllerService("test-good1");
+ Assert.assertNotNull(dbcpService);
+
+ dbcpService.getConnection();
+ }
+
@Rule
public ExpectedException exception = ExpectedException.none();
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/resources/fake.keytab b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/resources/fake.keytab
new file mode 100644
index 0000000..e69de29