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

madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new f98a149d5 RANGER-5475: add JWT support in RangerRESTClient (#831)
f98a149d5 is described below

commit f98a149d56fb4589cc47d03e55bd16b0adf4a153
Author: Abhishek Kumar <[email protected]>
AuthorDate: Sat Jan 31 18:46:38 2026 -0800

    RANGER-5475: add JWT support in RangerRESTClient (#831)
---
 .../ranger/plugin/util/RangerRESTClient.java       | 138 +++++++++++++++++----
 .../tagsync/sink/tagadmin/TagAdminRESTSink.java    |   2 +-
 .../process/RangerUgSyncRESTClient.java            |   6 +-
 3 files changed, 116 insertions(+), 30 deletions(-)

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 da1e0eee9..a073173a9 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
@@ -22,6 +22,7 @@
 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientRequest;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.api.client.config.ClientConfig;
@@ -48,9 +49,11 @@
 import javax.ws.rs.core.Cookie;
 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;
@@ -82,8 +85,10 @@ public class RangerRESTClient {
     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 final    List<String> configuredURLs;
+    private final    String       propertyPrefix;
     private          String       mUrl;
     private final    String       mSslConfigFileName;
     private          String       mUsername;
@@ -104,30 +109,26 @@ public class RangerRESTClient {
     private          int          lastKnownActiveUrlIndex;
     private volatile Client       client;
     private volatile Client       cookieAuthClient;
+    private          ClientFilter jwtAuthFilter;
     private          ClientFilter basicAuthFilter;
 
     public RangerRESTClient(String url, String sslConfigFileName, 
Configuration config) {
-        mUrl               = url;
-        mSslConfigFileName = sslConfigFileName;
-        configuredURLs     = StringUtil.getURLs(mUrl);
+        this(url, sslConfigFileName, config, getPropertyPrefix(config));
+    }
+
+    public RangerRESTClient(String url, String sslConfigFileName, 
Configuration config, String propertyPrefix) {
+        mUrl                = url;
+        mSslConfigFileName  = sslConfigFileName;
+        configuredURLs      = StringUtil.getURLs(mUrl);
+        this.propertyPrefix = propertyPrefix;
+
         if (StringUtil.isEmpty(url)) {
             throw new IllegalArgumentException("Ranger URL is null or empty. 
Likely caused by incorrect configuration");
         } else {
             setLastKnownActiveUrlIndex((new 
Random()).nextInt(getConfiguredURLs().size()));
         }
-        init(config);
-    }
-
-    protected static WebResource setQueryParams(WebResource webResource, 
Map<String, String> params) {
-        WebResource ret = webResource;
-
-        if (webResource != null && params != null) {
-            for (Map.Entry<String, String> entry : params.entrySet()) {
-                ret = ret.queryParam(entry.getKey(), entry.getValue());
-            }
-        }
 
-        return ret;
+        init(config);
     }
 
     public String getUrl() {
@@ -684,6 +685,22 @@ protected void setTrustStoreType(String mTrustStoreType) {
         this.mTrustStoreType = mTrustStoreType;
     }
 
+    protected static WebResource setQueryParams(WebResource webResource, 
Map<String, String> params) {
+        WebResource ret = webResource;
+
+        if (webResource != null && params != null) {
+            for (Map.Entry<String, String> entry : params.entrySet()) {
+                ret = ret.queryParam(entry.getKey(), entry.getValue());
+            }
+        }
+
+        return ret;
+    }
+
+    private static String getPropertyPrefix(Configuration config) {
+        return (config instanceof RangerPluginConfig) ? ((RangerPluginConfig) 
config).getPropertyPrefix() : "ranger.plugin";
+    }
+
     private Client getCookieAuthClient() {
         Client ret = cookieAuthClient;
 
@@ -694,6 +711,10 @@ private Client getCookieAuthClient() {
                 if (ret == null) {
                     cookieAuthClient = buildClient();
 
+                    if (jwtAuthFilter != null) {
+                        cookieAuthClient.removeFilter(jwtAuthFilter);
+                    }
+
                     if (basicAuthFilter != null) {
                         cookieAuthClient.removeFilter(basicAuthFilter);
                     }
@@ -732,8 +753,11 @@ private Client buildClient() {
             client = Client.create(config);
         }
 
-        if (basicAuthFilter != null && 
!client.isFilterPresent(basicAuthFilter)) {
-            client.addFilter(basicAuthFilter);
+        // use JWT if present
+        ClientFilter authFilter = jwtAuthFilter != null ? jwtAuthFilter : 
basicAuthFilter;
+
+        if (authFilter != null && !client.isFilterPresent(authFilter)) {
+            client.addFilter(authFilter);
         }
 
         // Set Connection Timeout and ReadTime for the PolicyRefresh
@@ -743,6 +767,23 @@ private Client buildClient() {
         return client;
     }
 
+    private void setJWTFilter(String jwtAsString) {
+        if (StringUtils.isNotBlank(jwtAsString)) {
+            LOG.info("Registering JWT auth header in REST client");
+
+            jwtAuthFilter = new ClientFilter() {
+                @Override
+                public ClientResponse handle(ClientRequest clientRequest) 
throws ClientHandlerException {
+                    clientRequest.getHeaders().add("Authorization", 
JWT_HEADER_PREFIX + jwtAsString);
+
+                    return getNext().handle(clientRequest);
+                }
+            };
+        } else {
+            jwtAuthFilter = null;
+        }
+    }
+
     private void setBasicAuthFilter(String username, String password) {
         if (StringUtils.isNotEmpty(username) && 
StringUtils.isNotEmpty(password)) {
             basicAuthFilter = new HTTPBasicAuthFilter(username, password);
@@ -780,22 +821,67 @@ private void init(Configuration config) {
             }
         }
 
-        final String pluginPropertyPrefix;
-
-        if (config instanceof RangerPluginConfig) {
-            pluginPropertyPrefix = ((RangerPluginConfig) 
config).getPropertyPrefix();
-        } else {
-            pluginPropertyPrefix = "ranger.plugin";
-        }
+        String jwtAsString = fetchJWT(propertyPrefix, config);
+        String username    = config.get(propertyPrefix + 
".policy.rest.client.username");
+        String password    = config.get(propertyPrefix + 
".policy.rest.client.password");
 
-        String username = config.get(pluginPropertyPrefix + 
".policy.rest.client.username");
-        String password = config.get(pluginPropertyPrefix + 
".policy.rest.client.password");
+        setJWTFilter(jwtAsString);
 
         if (StringUtils.isNotBlank(username) && 
StringUtils.isNotBlank(password)) {
             setBasicAuthFilter(username, password);
         }
     }
 
+    private String fetchJWT(String propertyPrefix, Configuration config) {
+        final 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)) {
+                            return 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("#")) {
+                                        return line;
+                                    }
+                                }
+                            } 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)) {
+                            return jwt;
+                        }
+                    }
+                    break;
+            }
+        } else {
+            LOG.info("JWT source not configured, proceeding without JWT");
+        }
+
+        return null;
+    }
+
     private boolean isSslEnabled(String url) {
         return !StringUtils.isEmpty(url) && 
url.toLowerCase().startsWith("https");
     }
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 58dba7400..961ebfb53 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
@@ -85,7 +85,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 aab18d0f7..56fca65e0 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
@@ -37,11 +37,11 @@
 
 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";
+        boolean isKerberized = "kerberos".equalsIgnoreCase(authenticationType) 
&& SecureClientLogin.isKerberosCredentialExists(principal, keytab);
 
-        if (!(authKerberos.equalsIgnoreCase(authenticationType) && 
SecureClientLogin.isKerberosCredentialExists(principal, keytab))) {
+        if (!isKerberized) {
             setBasicAuthInfo(polMgrUsername, polMgrPassword);
         }
 

Reply via email to