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()

Reply via email to