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 1cb016ba248b6827e1586aadd7c9b7944c304d00
Author: Pradeep AgrawaL <[email protected]>
AuthorDate: Wed Feb 4 14:41:19 2026 +0530

    RANGER-5475: add JWT support in RangerRESTClient (#831)
---
 .../ranger/plugin/util/RangerRESTClient.java       | 141 ++++++++++++++++-----
 .../tagsync/sink/tagadmin/TagAdminRESTSink.java    |   2 +-
 .../process/RangerUgSyncRESTClient.java            |   8 +-
 3 files changed, 117 insertions(+), 34 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 1177f4bc6..742116d9f 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;
@@ -69,58 +71,63 @@
 public class RangerRESTClient {
     private static final Logger LOG = 
LoggerFactory.getLogger(RangerRESTClient.class);
 
-    public static final String RANGER_PROP_POLICYMGR_URL                       
  = "ranger.service.store.rest.url";
-    public static final String RANGER_PROP_POLICYMGR_SSLCONFIG_FILENAME        
  = "ranger.service.store.rest.ssl.config.file";
-
+    public static final String JWT_HEADER_PREFIX                               
  = "Bearer ";
     public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE                
  = "xasecure.policymgr.clientssl.keystore";
-    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE           
  = "xasecure.policymgr.clientssl.keystore.type";
     public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL     
  = "xasecure.policymgr.clientssl.keystore.credential.file";
     public static final String 
RANGER_POLICYMGR_CLIENT_KEY_FILE_CREDENTIAL_ALIAS = "sslKeyStore";
+    public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE           
  = "xasecure.policymgr.clientssl.keystore.type";
     public static final String RANGER_POLICYMGR_CLIENT_KEY_FILE_TYPE_DEFAULT   
  = "jks";
-
     public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE                
  = "xasecure.policymgr.clientssl.truststore";
-    public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE           
  = "xasecure.policymgr.clientssl.truststore.type";
     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           
  = "xasecure.policymgr.clientssl.truststore.type";
     public static final String RANGER_POLICYMGR_TRUSTSTORE_FILE_TYPE_DEFAULT   
  = "jks";
-
+    public static final String RANGER_PROP_POLICYMGR_SSLCONFIG_FILENAME        
  = "ranger.service.store.rest.ssl.config.file";
+    public static final String RANGER_PROP_POLICYMGR_URL                       
  = "ranger.service.store.rest.url";
+    public static final String RANGER_SSL_CONTEXT_ALGO_TYPE                    
  = "TLSv1.2";
     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";
 
-    private          String       mUrl;
+    private final    List<String> configuredURLs;
     private final    String       mSslConfigFileName;
-    private          String       mUsername;
-    private          String       mPassword;
-    private          boolean      mIsSSL;
-    private          String       mKeyStoreURL;
+    private final    String       propertyPrefix;
+    private          String       jwtAsString;
     private          String       mKeyStoreAlias;
     private          String       mKeyStoreFile;
     private          String       mKeyStoreType;
-    private          String       mTrustStoreURL;
+    private          String       mKeyStoreURL;
+    private          String       mPassword;
     private          String       mTrustStoreAlias;
     private          String       mTrustStoreFile;
     private          String       mTrustStoreType;
+    private          String       mTrustStoreURL;
+    private          String       mUrl;
+    private          String       mUsername;
+    private          boolean      mIsSSL;
+    private          int          lastKnownActiveUrlIndex;
     private          int          mRestClientConnTimeOutMs;
     private          int          mRestClientReadTimeOutMs;
     private          int          maxRetryAttempts;
     private          int          retryIntervalMs;
-    private          int          lastKnownActiveUrlIndex;
-
-    private final List<String> configuredURLs;
-
     private volatile Client  client;
     private volatile Client  cookieAuthClient;
 
     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);
     }
 
@@ -177,6 +184,14 @@ public void setBasicAuthInfo(String username, String 
password) {
         mPassword = password;
     }
 
+    public String getJwtAsString() {
+        return jwtAsString;
+    }
+
+    public void setJwtAsString(String jwtAsString) {
+        this.jwtAsString = jwtAsString;
+    }
+
     public WebTarget getResource(String relativeUrl) {
         return getClient().target(getUrl() + relativeUrl);
     }
@@ -227,7 +242,7 @@ public Client getCookieAuthClient() {
 
     private Client buildClient(boolean isBasicAuth) {
         RangerJersey2ClientBuilder.SafeClientBuilder clientBuilder;
-        ClientConfig config = new ClientConfig();
+        ClientConfig clientConfig = new ClientConfig();
 
         if (mIsSSL) {
             try {
@@ -254,17 +269,25 @@ public boolean verify(String urlHostName, SSLSession 
session) {
         }
 
         // Apply centralized anti-MOXy configuration using the utility
-        RangerJersey2ClientBuilder.applyAntiMoxyConfiguration(config);
+        RangerJersey2ClientBuilder.applyAntiMoxyConfiguration(clientConfig);
 
         // Set timeouts
-        config.property(ClientProperties.CONNECT_TIMEOUT, 
mRestClientConnTimeOutMs);
-        config.property(ClientProperties.READ_TIMEOUT, 
mRestClientReadTimeOutMs);
+        clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 
mRestClientConnTimeOutMs);
+        clientConfig.property(ClientProperties.READ_TIMEOUT, 
mRestClientReadTimeOutMs);
 
         // Validate that MOXy prevention is properly configured
-        RangerJersey2ClientBuilder.validateAntiMoxyConfiguration(config);
+        RangerJersey2ClientBuilder.validateAntiMoxyConfiguration(clientConfig);
 
-        if (isBasicAuth && StringUtils.isNotEmpty(mUsername) && 
StringUtils.isNotEmpty(mPassword)) {
-            config.register(new javax.ws.rs.client.ClientRequestFilter() {
+        if (StringUtils.isNotBlank(jwtAsString)) {
+            LOG.info("Registering JWT auth header in REST client");
+            clientConfig.register(new javax.ws.rs.client.ClientRequestFilter() 
{
+                @Override
+                public void filter(javax.ws.rs.client.ClientRequestContext 
requestContext) {
+                    requestContext.getHeaders().add("Authorization", 
JWT_HEADER_PREFIX + jwtAsString);
+                }
+            });
+        } else if (isBasicAuth && StringUtils.isNotEmpty(mUsername) && 
StringUtils.isNotEmpty(mPassword)) {
+            clientConfig.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());
@@ -273,7 +296,7 @@ public void filter(javax.ws.rs.client.ClientRequestContext 
requestContext) {
             });
         }
 
-        Client client = clientBuilder.withConfig(config).build();
+        Client client = clientBuilder.withConfig(clientConfig).build();
 
         return client;
     }
@@ -322,6 +345,7 @@ private void init(Configuration config) {
             pluginPropertyPrefix = "ranger.plugin";
         }
 
+        jwtAsString = fetchJWT(propertyPrefix, config);
         String username = config.get(pluginPropertyPrefix + 
".policy.rest.client.username");
         String password = config.get(pluginPropertyPrefix + 
".policy.rest.client.password");
 
@@ -467,14 +491,18 @@ protected SSLContext getSSLContext(KeyManager[] kmList, 
TrustManager[] tmList) {
             try {
                 String              algo = 
TrustManagerFactory.getDefaultAlgorithm();
                 TrustManagerFactory tmf  = 
TrustManagerFactory.getInstance(algo);
+
                 tmf.init((KeyStore) null);
+
                 tmList = tmf.getTrustManagers();
             } catch (NoSuchAlgorithmException | KeyStoreException | 
IllegalStateException e) {
                 LOG.error("Unable to get the default SSL TrustStore for the 
JVM", e);
                 tmList = null;
             }
         }
+
         Validate.notNull(tmList, "TrustManager is not specified");
+
         try {
             SSLContext sslContext = 
SSLContext.getInstance(RANGER_SSL_CONTEXT_ALGO_TYPE);
 
@@ -483,6 +511,7 @@ protected SSLContext getSSLContext(KeyManager[] kmList, 
TrustManager[] tmList) {
             return sslContext;
         } catch (NoSuchAlgorithmException e) {
             LOG.error("SSL algorithm is not available in the environment", e);
+
             throw new IllegalStateException("SSL algorithm is not available in 
the environment: " + e.getMessage(), e);
         } catch (KeyManagementException e) {
             LOG.error("Unable to initials the SSLContext", e);
@@ -688,4 +717,58 @@ protected void setKeyStoreType(String mKeyStoreType) {
     protected void setTrustStoreType(String mTrustStoreType) {
         this.mTrustStoreType = mTrustStoreType;
     }
+
+    private static String getPropertyPrefix(Configuration config) {
+        return (config instanceof RangerPluginConfig) ? ((RangerPluginConfig) 
config).getPropertyPrefix() : "ranger.plugin";
+    }
+
+    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;
+    }
 }
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..86818bd43 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,12 +33,12 @@
 
 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());
-
-        String authKerberos = "kerberos";
+        super(policyMgrBaseUrls, "", 
UserGroupSyncConfig.getInstance().getConfig(), "ranger.usersync");
 
         UserGroupSyncConfig userGroupSyncConfig = 
UserGroupSyncConfig.getInstance();
-        if (!(authenticationType != null && 
authKerberos.equalsIgnoreCase(authenticationType) && 
SecureClientLogin.isKerberosCredentialExists(principal, keytab))) {
+        boolean isKerberized = "kerberos".equalsIgnoreCase(authenticationType) 
&& SecureClientLogin.isKerberosCredentialExists(principal, keytab);
+
+        if (!isKerberized) {
             setBasicAuthInfo(polMgrUsername, polMgrPassword);
         }
 

Reply via email to