You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by pr...@apache.org on 2026/02/04 10:51:22 UTC
(ranger) 11/11: RANGER-5475: add JWT support in RangerRESTClient (#831)
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 <pr...@apache.org>
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);
}