This is an automated email from the ASF dual-hosted git repository.
tpalfy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new a3c68f290cd NIFI-16254 Added KerberosUserService to
SmbjClientProviderService (#11593)
a3c68f290cd is described below
commit a3c68f290cde9edc9d128511653db91007e9ff70
Author: Peter Turcsanyi <[email protected]>
AuthorDate: Thu Sep 3 15:27:52 2026 +0200
NIFI-16254 Added KerberosUserService to SmbjClientProviderService (#11593)
Signed-off-by: Tamas Palfy <[email protected]>
---
.../nifi-smb-bundle/nifi-smb-processors/pom.xml | 5 ++
.../processors/smb/util/LocalSmbProperties.java | 3 +
.../services/smb/SmbjClientProviderService.java | 4 ++
.../nifi-smb-bundle/nifi-smb-smbj-common/pom.xml | 14 ++++
.../nifi/services/smb/SmbjClientProvider.java | 83 +++++++++++++++++++---
.../org/apache/nifi/smb/common/SmbProperties.java | 50 +++++++++++++
6 files changed, 148 insertions(+), 11 deletions(-)
diff --git a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/pom.xml
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/pom.xml
index e867474606e..5f9cd028daa 100644
--- a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/pom.xml
+++ b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/pom.xml
@@ -77,5 +77,10 @@
<artifactId>nifi-distributed-cache-client-service-api</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-kerberos-user-service-api</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/util/LocalSmbProperties.java
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/util/LocalSmbProperties.java
index e8dafa5d2f9..fe2bf075b77 100644
---
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/util/LocalSmbProperties.java
+++
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-processors/src/main/java/org/apache/nifi/processors/smb/util/LocalSmbProperties.java
@@ -93,18 +93,21 @@ public class LocalSmbProperties {
public static final PropertyDescriptor DOMAIN = new
PropertyDescriptor.Builder()
.fromPropertyDescriptor(SmbProperties.DOMAIN)
.description(SmbProperties.DOMAIN.getDescription() +
DEPRECATION_TAG)
+ .clearDependsOn()
.dependsOn(CONNECTION_CONFIGURATION_STRATEGY,
ConnectionConfigurationStrategy.LOCAL_PROPERTIES)
.build();
public static final PropertyDescriptor USERNAME = new
PropertyDescriptor.Builder()
.fromPropertyDescriptor(SmbProperties.USERNAME)
.description(SmbProperties.USERNAME.getDescription() +
DEPRECATION_TAG)
+ .clearDependsOn()
.dependsOn(CONNECTION_CONFIGURATION_STRATEGY,
ConnectionConfigurationStrategy.LOCAL_PROPERTIES)
.build();
public static final PropertyDescriptor PASSWORD = new
PropertyDescriptor.Builder()
.fromPropertyDescriptor(SmbProperties.PASSWORD)
.description(SmbProperties.PASSWORD.getDescription() +
DEPRECATION_TAG)
+ .clearDependsOn()
.dependsOn(CONNECTION_CONFIGURATION_STRATEGY,
ConnectionConfigurationStrategy.LOCAL_PROPERTIES)
.build();
diff --git
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
index 01c1b40e1d0..0b438746839 100644
---
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
+++
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-client/src/main/java/org/apache/nifi/services/smb/SmbjClientProviderService.java
@@ -31,9 +31,11 @@ import java.net.URI;
import java.util.List;
import java.util.Map;
+import static org.apache.nifi.smb.common.SmbProperties.AUTHENTICATION_TYPE;
import static org.apache.nifi.smb.common.SmbProperties.DOMAIN;
import static org.apache.nifi.smb.common.SmbProperties.ENABLE_DFS;
import static org.apache.nifi.smb.common.SmbProperties.HOSTNAME;
+import static org.apache.nifi.smb.common.SmbProperties.KERBEROS_USER_SERVICE;
import static
org.apache.nifi.smb.common.SmbProperties.OLD_DOMAIN_PROPERTY_NAME;
import static
org.apache.nifi.smb.common.SmbProperties.OLD_ENABLE_DFS_PROPERTY_NAME;
import static
org.apache.nifi.smb.common.SmbProperties.OLD_HOSTNAME_PROPERTY_NAME;
@@ -60,9 +62,11 @@ public class SmbjClientProviderService extends
AbstractControllerService impleme
HOSTNAME,
PORT,
SHARE,
+ AUTHENTICATION_TYPE,
USERNAME,
PASSWORD,
DOMAIN,
+ KERBEROS_USER_SERVICE,
SMB_DIALECT,
USE_ENCRYPTION,
ENABLE_DFS,
diff --git
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/pom.xml
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/pom.xml
index 9c305b66525..e1562fde0a8 100644
--- a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/pom.xml
+++ b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/pom.xml
@@ -41,6 +41,20 @@
<artifactId>smbj</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-kerberos-user-service-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-kerberos-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-kerberos</artifactId>
+ <version>2.12.0-SNAPSHOT</version>
+ </dependency>
+
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
diff --git
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
index dc420f85c62..9f2162538ba 100644
---
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
+++
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/services/smb/SmbjClientProvider.java
@@ -18,20 +18,33 @@ package org.apache.nifi.services.smb;
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.auth.AuthenticationContext;
+import com.hierynomus.smbj.auth.GSSAuthenticationContext;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.Share;
import org.apache.nifi.context.PropertyContext;
+import org.apache.nifi.kerberos.KerberosUserService;
import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.security.krb.KerberosAction;
+import org.apache.nifi.security.krb.KerberosUser;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import static org.apache.nifi.smb.common.SmbProperties.AUTHENTICATION_TYPE;
+import static org.apache.nifi.smb.common.SmbProperties.AuthenticationType;
import static org.apache.nifi.smb.common.SmbProperties.DOMAIN;
import static org.apache.nifi.smb.common.SmbProperties.HOSTNAME;
+import static org.apache.nifi.smb.common.SmbProperties.KERBEROS_USER_SERVICE;
import static org.apache.nifi.smb.common.SmbProperties.PASSWORD;
import static org.apache.nifi.smb.common.SmbProperties.PORT;
import static org.apache.nifi.smb.common.SmbProperties.SHARE;
@@ -40,19 +53,21 @@ import static
org.apache.nifi.smb.common.SmbUtils.buildSmbClient;
public class SmbjClientProvider implements SmbClientProvider, Closeable {
+ private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+
private final PropertyContext context;
private final ComponentLog logger;
private final SMBClient smbClient;
- private AuthenticationContext authenticationContext;
+ private final KerberosUser kerberosUser;
public SmbjClientProvider(final PropertyContext context, final
ComponentLog logger) {
this.context = context;
this.logger = logger;
this.smbClient = buildSmbClient(context);
- createAuthenticationContext(context);
+ this.kerberosUser = initKerberosUser();
}
@Override
@@ -86,7 +101,7 @@ public class SmbjClientProvider implements
SmbClientProvider, Closeable {
final Share share;
try {
- session = connection.authenticate(authenticationContext);
+ session =
connection.authenticate(createAuthenticationContext(logger));
} catch (Exception e) {
throw new IOException("Could not create session for share " +
serviceLocation, e);
}
@@ -117,16 +132,62 @@ public class SmbjClientProvider implements
SmbClientProvider, Closeable {
}
}
- private void createAuthenticationContext(final PropertyContext context) {
+ private KerberosUser initKerberosUser() {
+ if (getAuthenticationType() == AuthenticationType.KERBEROS) {
+ final KerberosUserService kerberosUserService =
context.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class);
+
+ final KerberosUser kerberosUser =
kerberosUserService.createKerberosUser();
+ kerberosUser.login();
+
+ return kerberosUser;
+ } else {
+ return null;
+ }
+ }
+
+ private AuthenticationType getAuthenticationType() {
+ if (context.getProperty(AUTHENTICATION_TYPE).isSet()) {
+ return
context.getProperty(AUTHENTICATION_TYPE).asAllowableValue(AuthenticationType.class);
+ } else {
+ return AuthenticationType.PASSWORD;
+ }
+ }
+
+ private AuthenticationContext createAuthenticationContext(final
ComponentLog logger) {
+ return switch (getAuthenticationType()) {
+ case PASSWORD -> createPasswordAuthenticationContext();
+ case KERBEROS -> createKerberosAuthenticationContext(logger);
+ };
+ }
+
+ private AuthenticationContext createPasswordAuthenticationContext() {
if (context.getProperty(USERNAME).isSet()) {
- final String userName = context.getProperty(USERNAME).getValue();
- final String password =
- context.getProperty(PASSWORD).isSet() ?
context.getProperty(PASSWORD).getValue() : "";
- final String domainOrNull =
- context.getProperty(DOMAIN).isSet() ?
context.getProperty(DOMAIN).getValue() : null;
- authenticationContext = new AuthenticationContext(userName,
password.toCharArray(), domainOrNull);
+ final String username = context.getProperty(USERNAME).getValue();
+ final String password = context.getProperty(PASSWORD).isSet() ?
context.getProperty(PASSWORD).getValue() : "";
+ final String domain = context.getProperty(DOMAIN).isSet() ?
context.getProperty(DOMAIN).getValue() : null;
+
+ return new AuthenticationContext(username, password.toCharArray(),
domain);
} else {
- authenticationContext = AuthenticationContext.anonymous();
+ return AuthenticationContext.anonymous();
}
}
+
+ private AuthenticationContext createKerberosAuthenticationContext(final
ComponentLog logger) {
+ return new KerberosAction<AuthenticationContext>(kerberosUser,
+ () -> {
+ final Subject subject = Subject.current();
+
+ final KerberosPrincipal krbPrincipal =
subject.getPrincipals(KerberosPrincipal.class)
+ .iterator()
+ .next();
+
+ final GSSManager gssManager = GSSManager.getInstance();
+ final GSSName gssName =
gssManager.createName(krbPrincipal.getName(), GSSName.NT_USER_NAME);
+ final GSSCredential gssCredential =
gssManager.createCredential(gssName, GSSCredential.DEFAULT_LIFETIME, new
Oid(SPNEGO_OID), GSSCredential.INITIATE_ONLY);
+
+ return new
GSSAuthenticationContext(krbPrincipal.getName(), krbPrincipal.getRealm(),
subject, gssCredential);
+ },
+ logger)
+ .execute();
+ }
}
diff --git
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
index 781ff56d9be..be2e88f4c0c 100644
---
a/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
+++
b/nifi-extension-bundles/nifi-smb-bundle/nifi-smb-smbj-common/src/main/java/org/apache/nifi/smb/common/SmbProperties.java
@@ -16,8 +16,10 @@
*/
package org.apache.nifi.smb.common;
+import org.apache.nifi.components.DescribedValue;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.kerberos.KerberosUserService;
import static
org.apache.nifi.processor.util.StandardValidators.NON_BLANK_VALIDATOR;
import static
org.apache.nifi.processor.util.StandardValidators.NON_EMPTY_VALIDATOR;
@@ -25,6 +27,7 @@ import static
org.apache.nifi.processor.util.StandardValidators.PORT_VALIDATOR;
import static
org.apache.nifi.processor.util.StandardValidators.TIME_PERIOD_VALIDATOR;
public class SmbProperties {
+
public static final String OLD_HOSTNAME_PROPERTY_NAME = "hostname";
public static final String OLD_PORT_PROPERTY_NAME = "port";
public static final String OLD_SHARE_PROPERTY_NAME = "share";
@@ -36,6 +39,34 @@ public class SmbProperties {
public static final String OLD_ENABLE_DFS_PROPERTY_NAME = "enable-dfs";
public static final String OLD_TIMEOUT_PROPERTY_NAME = "timeout";
+ public enum AuthenticationType implements DescribedValue {
+ PASSWORD("Password", "Use username and password to authenticate"),
+ KERBEROS("Kerberos", "Use Kerberos to authenticate"),;
+
+ private final String displayName;
+ private final String description;
+
+ AuthenticationType(final String displayName, final String description)
{
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ @Override
+ public String getValue() {
+ return displayName;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+ }
+
public static final PropertyDescriptor HOSTNAME = new
PropertyDescriptor.Builder()
.name("Hostname")
.description("The network host of the SMB file server.")
@@ -62,11 +93,20 @@ public class SmbProperties {
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.build();
+ public static final PropertyDescriptor AUTHENTICATION_TYPE = new
PropertyDescriptor.Builder()
+ .name("Authentication Type")
+ .description("The authentication type.")
+ .required(true)
+ .allowableValues(AuthenticationType.class)
+ .defaultValue(AuthenticationType.PASSWORD)
+ .build();
+
public static final PropertyDescriptor DOMAIN = new
PropertyDescriptor.Builder()
.name("Domain")
.description("The domain used for authentication. Optional, in
most cases username and password is sufficient.")
.required(false)
.addValidator(NON_EMPTY_VALIDATOR)
+ .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD)
.build();
public static final PropertyDescriptor USERNAME = new
PropertyDescriptor.Builder()
@@ -74,6 +114,7 @@ public class SmbProperties {
.description("The username used for authentication. If no username
is set then anonymous authentication is attempted.")
.required(false)
.addValidator(NON_EMPTY_VALIDATOR)
+ .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD)
.build();
public static final PropertyDescriptor PASSWORD = new
PropertyDescriptor.Builder()
@@ -82,6 +123,15 @@ public class SmbProperties {
.required(false)
.addValidator(NON_EMPTY_VALIDATOR)
.sensitive(true)
+ .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD)
+ .build();
+
+ public static final PropertyDescriptor KERBEROS_USER_SERVICE = new
PropertyDescriptor.Builder()
+ .name("Kerberos User Service")
+ .description("The Kerberos User Controller Service used for
authentication")
+ .identifiesControllerService(KerberosUserService.class)
+ .required(true)
+ .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS)
.build();
public static final PropertyDescriptor SMB_DIALECT = new
PropertyDescriptor.Builder()