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
The following commit(s) were added to refs/heads/RANGER-4076_master by this
push:
new bb1a6619e RANGER-5475: add JWT support in RangerRESTClient
bb1a6619e is described below
commit bb1a6619eaaf1d2d31ca6b57248f500ba9f4972c
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";