This is an automated email from the ASF dual-hosted git repository.

pradeep pushed a commit to branch RANGER-4076_master
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit c5e458d50f10f2db0e3cfedc753dc23ec3dd5363
Author: Pradeep AgrawaL <[email protected]>
AuthorDate: Thu Feb 5 18:46:16 2026 +0530

    RANGER-5475: add JWT support in RangerRESTClient
---
 .../audit/utils/RangerJSONAuditWriterTest.java     |  28 ++++--
 .../ranger/plugin/util/RangerRESTClient.java       | 104 ++++++++++++++++++---
 .../tagsync/sink/tagadmin/TagAdminRESTSink.java    |   2 +-
 .../process/RangerUgSyncRESTClient.java            |   2 +-
 4 files changed, 112 insertions(+), 24 deletions(-)

diff --git 
a/agents-audit/core/src/test/java/org/apache/ranger/audit/utils/RangerJSONAuditWriterTest.java
 
b/agents-audit/core/src/test/java/org/apache/ranger/audit/utils/RangerJSONAuditWriterTest.java
index 18b93c8ba..88046089b 100644
--- 
a/agents-audit/core/src/test/java/org/apache/ranger/audit/utils/RangerJSONAuditWriterTest.java
+++ 
b/agents-audit/core/src/test/java/org/apache/ranger/audit/utils/RangerJSONAuditWriterTest.java
@@ -73,7 +73,9 @@ public void verifyAppendToFileWhenEnabledWithConfig() throws 
Exception {
         assertTrue(jsonAuditWriter.logJSON(Collections.singleton("Last log 
file will be opened in append mode and this event will be written")));
         assertTrue(jsonAuditWriter.logJSON(Collections.singleton("This event 
will also be written in append mode")));
 
-        jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        if (jsonAuditWriter.auditPath != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        }
     }
 
     @Test
@@ -120,8 +122,12 @@ public void verifyFileRolloverWithAppend() throws 
Exception {
         assertNotEquals(auditPath1, jsonAuditWriter.auditPath);
 
         // cleanup
-        jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
-        jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        if (auditPath1 != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
+        }
+        if (jsonAuditWriter.auditPath != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        }
         jsonAuditWriter.closeWriter();
     }
 
@@ -150,8 +156,12 @@ public void verifyNoAppendToFileWhenDisabledWithConfig() 
throws Exception {
         assertFalse(jsonAuditWriter.reUseLastLogFile);
 
         // cleanup
-        jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
-        jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        if (auditPath1 != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
+        }
+        if (jsonAuditWriter.auditPath != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        }
     }
 
     @Test
@@ -175,8 +185,12 @@ public void verifyFileRolloverAfterThreshold() throws 
Exception {
         assertTrue(jsonAuditWriter.logJSON(Collections.singleton("Second file 
created since rollover happened!")));
 
         // cleanup
-        jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
-        jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        if (auditPath1 != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(auditPath1);
+        }
+        if (jsonAuditWriter.auditPath != null) {
+            jsonAuditWriter.fileSystem.deleteOnExit(jsonAuditWriter.auditPath);
+        }
         jsonAuditWriter.closeWriter();
     }
 }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTClient.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTClient.java
index 1177f4bc6..da471e0c5 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTClient.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTClient.java
@@ -48,9 +48,11 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyManagementException;
@@ -62,6 +64,7 @@
 import java.security.cert.CertificateException;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -83,16 +86,18 @@ public class RangerRESTClient {
     public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL     
  = "xasecure.policymgr.clientssl.truststore.credential.file";
     public static final String 
RANGER_POLICYMGR_TRUSTSTORE_FILE_CREDENTIAL_ALIAS = "sslTrustStore";
     public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT   
  = "jks";
-
     public static final String RANGER_SSL_KEYMANAGER_ALGO_TYPE                 
  = KeyManagerFactory.getDefaultAlgorithm();
     public static final String RANGER_SSL_TRUSTMANAGER_ALGO_TYPE               
  = TrustManagerFactory.getDefaultAlgorithm();
     public static final String RANGER_SSL_CONTEXT_ALGO_TYPE                    
  = "TLSv1.2";
 
+    public static final String JWT_HEADER_PREFIX                               
  = "Bearer ";
+
     private          String       mUrl;
     private final    String       mSslConfigFileName;
     private          String       mUsername;
     private          String       mPassword;
     private          boolean      mIsSSL;
+    private          String       jwt;
     private          String       mKeyStoreURL;
     private          String       mKeyStoreAlias;
     private          String       mKeyStoreFile;
@@ -108,11 +113,16 @@ public class RangerRESTClient {
     private          int          lastKnownActiveUrlIndex;
 
     private final List<String> configuredURLs;
+    private final String       propertyPrefix;
 
     private volatile Client  client;
     private volatile Client  cookieAuthClient;
 
     public RangerRESTClient(String url, String sslConfigFileName, 
Configuration config) {
+        this(url, sslConfigFileName, config, getPropertyPrefix(config));
+    }
+
+    public RangerRESTClient(String url, String sslConfigFileName, 
Configuration config, String propertyPrefix) {
         mUrl               = url;
         mSslConfigFileName = sslConfigFileName;
         configuredURLs     = StringUtil.getURLs(mUrl);
@@ -121,6 +131,7 @@ public RangerRESTClient(String url, String 
sslConfigFileName, Configuration conf
         } else {
             setLastKnownActiveUrlIndex((new 
Random()).nextInt(getConfiguredURLs().size()));
         }
+        this.propertyPrefix = propertyPrefix;
         init(config);
     }
 
@@ -198,7 +209,7 @@ public Client getClient() {
                 result = client;
 
                 if (result == null) {
-                    result = buildClient(true);
+                    result = buildClient();
                     client = result;
                 }
             }
@@ -215,7 +226,7 @@ public Client getCookieAuthClient() {
                 ret = cookieAuthClient;
 
                 if (ret == null) {
-                    cookieAuthClient        = buildClient(true);
+                    cookieAuthClient        = buildClient();
                     //Pending : need to remove basic auth filter from client.
                     ret = cookieAuthClient;
                 }
@@ -225,7 +236,11 @@ public Client getCookieAuthClient() {
         return ret;
     }
 
-    private Client buildClient(boolean isBasicAuth) {
+    private static String getPropertyPrefix(Configuration config) {
+        return (config instanceof RangerPluginConfig) ? ((RangerPluginConfig) 
config).getPropertyPrefix() : "ranger.plugin";
+    }
+
+    private Client buildClient() {
         RangerJersey2ClientBuilder.SafeClientBuilder clientBuilder;
         ClientConfig config = new ClientConfig();
 
@@ -263,11 +278,21 @@ public boolean verify(String urlHostName, SSLSession 
session) {
         // Validate that MOXy prevention is properly configured
         RangerJersey2ClientBuilder.validateAntiMoxyConfiguration(config);
 
-        if (isBasicAuth && StringUtils.isNotEmpty(mUsername) && 
StringUtils.isNotEmpty(mPassword)) {
+        final String authHeader;
+        if (StringUtils.isNotEmpty(jwt)) { // use JWT if present
+            authHeader = JWT_HEADER_PREFIX + jwt;
+            LOG.info("Registering JWT auth header in REST client");
+        } else if (StringUtils.isNotEmpty(mUsername) && 
StringUtils.isNotEmpty(mPassword)) {
+            authHeader = "Basic " + 
java.util.Base64.getEncoder().encodeToString((mUsername + ":" + 
mPassword).getBytes());
+            LOG.info("Registering Basic auth header in REST client");
+        } else {
+            authHeader = null;
+        }
+
+        if (StringUtils.isNotEmpty(authHeader)) {
             config.register(new javax.ws.rs.client.ClientRequestFilter() {
                 @Override
                 public void filter(javax.ws.rs.client.ClientRequestContext 
requestContext) {
-                    String authHeader = "Basic " + 
java.util.Base64.getEncoder().encodeToString((mUsername + ":" + 
mPassword).getBytes());
                     requestContext.getHeaders().add("Authorization", 
authHeader);
                 }
             });
@@ -314,16 +339,11 @@ private void init(Configuration config) {
             }
         }
 
-        final String pluginPropertyPrefix;
-
-        if (config instanceof RangerPluginConfig) {
-            pluginPropertyPrefix = ((RangerPluginConfig) 
config).getPropertyPrefix();
-        } else {
-            pluginPropertyPrefix = "ranger.plugin";
-        }
+        Optional<String> jwtAsString = fetchJWT(propertyPrefix, config);
+        jwtAsString.ifPresent(s -> this.jwt = s);
 
-        String username = config.get(pluginPropertyPrefix + 
".policy.rest.client.username");
-        String password = config.get(pluginPropertyPrefix + 
".policy.rest.client.password");
+        String username = config.get(propertyPrefix + 
".policy.rest.client.username");
+        String password = config.get(propertyPrefix + 
".policy.rest.client.password");
 
         if (StringUtils.isNotBlank(username) && 
StringUtils.isNotBlank(password)) {
             setBasicAuthInfo(username, password);
@@ -334,6 +354,60 @@ private boolean isSsl(String url) {
         return !StringUtils.isEmpty(url) && 
url.toLowerCase().startsWith("https");
     }
 
+    private Optional<String> fetchJWT(String propertyPrefix, Configuration 
config) {
+        Optional<String> ret = Optional.empty();
+        String jwtSrc        = config.get(propertyPrefix + 
".policy.rest.client.jwt.source");
+
+        if (StringUtils.isNotEmpty(jwtSrc)) {
+            switch(jwtSrc) {
+                case "env": {
+                    String jwtEnvVar = config.get(propertyPrefix + 
".policy.rest.client.jwt.env");
+                    if (StringUtils.isNotEmpty(jwtEnvVar)){
+                        String jwt = System.getenv(jwtEnvVar);
+                        if (StringUtils.isNotBlank(jwt)) {
+                            ret = Optional.of(jwt);
+                        }
+                    }
+                    break;
+                }
+                case "file": {
+                    String jwtFilePath = config.get(propertyPrefix + 
".policy.rest.client.jwt.file");
+                    if (StringUtils.isNotEmpty(jwtFilePath)){
+                        File jwtFile = new File(jwtFilePath);
+                        if (jwtFile.exists()) {
+                            try (BufferedReader reader = new 
BufferedReader(new FileReader(jwtFile))) {
+                                String line = null;
+                                while ((line = reader.readLine()) != null) {
+                                    if (StringUtils.isNotBlank(line) && 
!line.startsWith("#")) {
+                                        ret = Optional.of(line);
+                                        break;
+                                    }
+                                }
+                            } catch (IOException e) {
+                                LOG.error("Failed to read JWT from file: {}", 
jwtFilePath, e);
+                            }
+                        }
+                    }
+                    break;
+                }
+                case "cred": {
+                    String credFilePath = config.get(propertyPrefix + 
".policy.rest.client.jwt.cred.file");
+                    String credAlias    = config.get(propertyPrefix + 
".policy.rest.client.jwt.cred.alias");
+                    if (StringUtils.isNotEmpty(credFilePath) && 
StringUtils.isNotEmpty(credAlias)){
+                        String jwt = 
RangerCredentialProvider.getInstance().getCredentialString(credFilePath, 
credAlias);
+                        if (StringUtils.isNotBlank(jwt)) {
+                            ret = Optional.of(jwt);
+                        }
+                    }
+                    break;
+                }
+            }
+        } else {
+            LOG.info("JWT source not configured, proceeding without JWT");
+        }
+        return ret;
+    }
+
     private KeyManager[] getKeyManagers() {
         KeyManager[] kmList = null;
 
diff --git 
a/tagsync/src/main/java/org/apache/ranger/tagsync/sink/tagadmin/TagAdminRESTSink.java
 
b/tagsync/src/main/java/org/apache/ranger/tagsync/sink/tagadmin/TagAdminRESTSink.java
index e232e55de..3862b0621 100644
--- 
a/tagsync/src/main/java/org/apache/ranger/tagsync/sink/tagadmin/TagAdminRESTSink.java
+++ 
b/tagsync/src/main/java/org/apache/ranger/tagsync/sink/tagadmin/TagAdminRESTSink.java
@@ -87,7 +87,7 @@ public boolean initialize(Properties properties) {
         LOG.debug("isKerberized={}", isKerberized);
 
         if (StringUtils.isNotBlank(restUrl)) {
-            tagRESTClient = new RangerRESTClient(restUrl, sslConfigFile, 
TagSyncConfig.getInstance());
+            tagRESTClient = new RangerRESTClient(restUrl, sslConfigFile, 
TagSyncConfig.getInstance(), "ranger.tagsync");
 
             if (!isKerberized) {
                 tagRESTClient.setBasicAuthInfo(userName, password);
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/RangerUgSyncRESTClient.java
 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/RangerUgSyncRESTClient.java
index a6270239b..54553d2a9 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/RangerUgSyncRESTClient.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/RangerUgSyncRESTClient.java
@@ -33,7 +33,7 @@
 
 public class RangerUgSyncRESTClient extends RangerRESTClient {
     public RangerUgSyncRESTClient(String policyMgrBaseUrls, String 
ugKeyStoreFile, String ugKeyStoreFilepwd, String ugKeyStoreType, String 
ugTrustStoreFile, String ugTrustStoreFilepwd, String ugTrustStoreType, String 
authenticationType, String principal, String keytab, String polMgrUsername, 
String polMgrPassword) {
-        super(policyMgrBaseUrls, "", 
UserGroupSyncConfig.getInstance().getConfig());
+        super(policyMgrBaseUrls, "", 
UserGroupSyncConfig.getInstance().getConfig(), "ranger.usersync");
 
         String authKerberos = "kerberos";
 

Reply via email to