You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ra...@apache.org on 2026/08/22 11:09:24 UTC
(ranger) branch master updated: RANGER-5723: Plugin SPIFFE outbound auth for audit-server destination (#1139)
This is an automated email from the ASF dual-hosted git repository.
ramackri 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 8e7716cd3 RANGER-5723: Plugin SPIFFE outbound auth for audit-server destination (#1139)
8e7716cd3 is described below
commit 8e7716cd3c36da395b8edc8470e328f736fbd984
Author: Ramachandran Krishnan <ra...@gmail.com>
AuthorDate: Sat Aug 22 16:39:19 2026 +0530
RANGER-5723: Plugin SPIFFE outbound auth for audit-server destination (#1139)
* RANGER-5723: Plugin SPIFFE outbound auth for audit-server destination
Add PluginHeaderAuthConfig, SpiffeIdentityResolver, and
RangerRESTClient.setTrustedAuthHeaders(); wire SPIFFE headers into
RangerAuditServerDestination when audit XML authn.header.enabled=true.
* RANGER-5723: Remove unused SPIFFE prefix-discovery helpers
Drop configPrefixForServiceType, resolveEnabledConfigPrefix, and
RANGER_CONFIG_PREFIX; audit destination passes an explicit config prefix to
buildSpiffeAuthHeaders.
* RANGER-5723: Address PR review comments for SPIFFE outbound auth
Remove redundant SPIFFE ID trim, add misconfiguration and REST client
header tests, and document that SPIFFE header auth is additive to authn.type.
* RANGER-5723: Fix Checkstyle import order in TestRangerRESTClient
Add blank line between javax and java import groups required by
dev-support/checkstyle.xml ImportOrder rule.
* Update SpiffeIdentityResolver.java
* Update SpiffeIdentityResolver.java
* RANGER-5723: Fix checkstyle and address remaining PR review comments
Fix SpiffeIdentityResolver checkstyle violations, rename buildSpiffeAuthHeaders
to buildTrustedAuthHeaders, and add generic authn.header.headers slot-based
configuration with file:/env: value resolution.
* RANGER-5723: Document trusted-header config modes and value specs
Expand PluginHeaderAuthConfig Javadoc for legacy SPIFFE and generic slot
configuration, including file:/env:/literal value spec examples.
* RANGER-5723: Use header-name-as-property for trusted auth config
Address PR review: configure outbound trusted headers as
authn.header.{Header-Name}=value specs (file:/env:/literal) instead
of slot-based or legacy SPIFFE properties.
* Update RangerAuditServerDestination.java
* Update RangerAuditServerDestinationTest.java
* Update TestRangerRESTClient.java
* Update PluginHeaderAuthConfig.java
* RANGER-5723: Drop outbound SPIFFE validation and SpiffeIdentityResolver
Address PR review: trusted outbound headers pass resolved values
through without SPIFFE format checks; remove SpiffeIdentityResolver
and obsolete tests for the old authn.spiffe.* resolution model.
* Update PluginHeaderAuthConfig.java
* Update PluginHeaderAuthConfig.java
* RANGER-5723: Remove unnecessary property-name sorting in header auth config.
HTTP header order does not affect auth; iterate props directly per review feedback.
---------
Co-authored-by: ramk <ra...@cloudera.com>
Co-authored-by: Madhan Neethiraj <ma...@apache.org>
---
agents-audit/dest-auditserver/pom.xml | 6 +
.../destination/RangerAuditServerDestination.java | 11 ++
.../RangerAuditServerDestinationTest.java | 56 +++++++
.../ranger/plugin/util/RangerRESTClient.java | 24 +++
.../ranger/plugin/util/TestRangerRESTClient.java | 51 +++++++
.../ranger/plugin/util/PluginHeaderAuthConfig.java | 166 +++++++++++++++++++++
.../plugin/util/PluginHeaderAuthConfigTest.java | 92 ++++++++++++
7 files changed, 406 insertions(+)
diff --git a/agents-audit/dest-auditserver/pom.xml b/agents-audit/dest-auditserver/pom.xml
index 41aa1baee..d512ebbae 100644
--- a/agents-audit/dest-auditserver/pom.xml
+++ b/agents-audit/dest-auditserver/pom.xml
@@ -74,6 +74,12 @@
</dependency>
<!-- Test -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <version>${junit.jupiter.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
diff --git a/agents-audit/dest-auditserver/src/main/java/org/apache/ranger/audit/destination/RangerAuditServerDestination.java b/agents-audit/dest-auditserver/src/main/java/org/apache/ranger/audit/destination/RangerAuditServerDestination.java
index a7eacb999..421ac0710 100644
--- a/agents-audit/dest-auditserver/src/main/java/org/apache/ranger/audit/destination/RangerAuditServerDestination.java
+++ b/agents-audit/dest-auditserver/src/main/java/org/apache/ranger/audit/destination/RangerAuditServerDestination.java
@@ -27,6 +27,7 @@
import org.apache.ranger.audit.model.AuthzAuditEvent;
import org.apache.ranger.audit.provider.MiscUtil;
import org.apache.ranger.plugin.authn.DefaultJwtProvider;
+import org.apache.ranger.plugin.util.PluginHeaderAuthConfig;
import org.apache.ranger.plugin.util.RangerRESTClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -98,6 +99,16 @@ public void init(Properties props, String propPrefix) {
this.restClient.setMaxRetryAttempts(maxRetryAttempts);
this.restClient.setRetryIntervalMs(retryIntervalMs);
+ // Trusted header auth is orthogonal to authn.type (JWT/Basic/Kerberos): when enabled,
+ // trusted headers are added in addition to whatever authType configured above.
+ Map<String, String> trustedHeaders = PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, propPrefix);
+
+ if (!trustedHeaders.isEmpty()) {
+ this.restClient.setTrustedAuthHeaders(trustedHeaders);
+
+ LOG.debug("Trusted authentication headers added for audit-server destination");
+ }
+
LOG.info("<== RangerAuditServerDestination:init()");
}
diff --git a/agents-audit/dest-auditserver/src/test/java/org/apache/ranger/audit/destination/RangerAuditServerDestinationTest.java b/agents-audit/dest-auditserver/src/test/java/org/apache/ranger/audit/destination/RangerAuditServerDestinationTest.java
new file mode 100644
index 000000000..4ba059e3f
--- /dev/null
+++ b/agents-audit/dest-auditserver/src/test/java/org/apache/ranger/audit/destination/RangerAuditServerDestinationTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.audit.destination;
+
+import org.apache.ranger.plugin.util.PluginHeaderAuthConfig;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class RangerAuditServerDestinationTest {
+ private static final String AUDIT_DEST_PREFIX = "xasecure.audit.destination.auditserver";
+
+ @Test
+ public void buildTrustedAuthHeadersUsesAuditDestinationPrefix() {
+ Properties props = new Properties();
+
+ props.setProperty(AUDIT_DEST_PREFIX + ".authn.header.enabled", "true");
+ props.setProperty(AUDIT_DEST_PREFIX + ".authn.header.X-Spiffe-Id", "spiffe://prod-cluster.k8s.example.com/ns/ranger/sa/hive");
+
+ Map<String, String> headers = PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, AUDIT_DEST_PREFIX);
+
+ assertEquals(1, headers.size());
+ assertEquals("spiffe://prod-cluster.k8s.example.com/ns/ranger/sa/hive", headers.get("X-Spiffe-Id"));
+ }
+
+ @Test
+ public void buildTrustedAuthHeadersEmptyWhenAuditDestinationDisabled() {
+ Properties props = new Properties();
+
+ props.setProperty(AUDIT_DEST_PREFIX + ".authn.header.enabled", "false");
+ props.setProperty(AUDIT_DEST_PREFIX + ".authn.header.X-Spiffe-Id", "spiffe://prod-cluster.k8s.example.com/ns/ranger/sa/hive");
+
+ Map<String, String> headers = PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, AUDIT_DEST_PREFIX);
+
+ assertTrue(headers.isEmpty());
+ }
+}
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 d4d49523b..94046a549 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
@@ -60,6 +60,8 @@
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -143,6 +145,7 @@ public String getMethod() {
private volatile Client cookieAuthClient;
private JwtProvider jwtProvider;
private volatile String authHeader;
+ private volatile Map<String, String> trustedAuthHeaders = Collections.emptyMap();
public RangerRESTClient(String url, String sslConfigFileName, Configuration config) {
this(url, sslConfigFileName, config, getPropertyPrefix(config));
@@ -215,6 +218,19 @@ public void setRetryIntervalMs(int retryIntervalMs) {
this.retryIntervalMs = retryIntervalMs;
}
+ /**
+ * Trusted HTTP headers for SPIFFE or other header-based auth.
+ * Applied to every REST request from this client.
+ */
+ public void setTrustedAuthHeaders(Map<String, String> headers) {
+ if (headers == null || headers.isEmpty()) {
+ trustedAuthHeaders = Collections.emptyMap();
+ } else {
+ trustedAuthHeaders = Collections.unmodifiableMap(new LinkedHashMap<>(headers));
+ }
+ resetClient();
+ }
+
public void setBasicAuthInfo(String username, String password) {
setBasicAuthFilter(username, password);
}
@@ -494,9 +510,17 @@ private Invocation.Builder createInvocationBuilder(int currentIndex, String rela
builder = builder.cookie(sessionId);
}
+ applyTrustedAuthHeaders(builder);
+
return builder;
}
+ private void applyTrustedAuthHeaders(Invocation.Builder builder) {
+ for (Map.Entry<String, String> entry : trustedAuthHeaders.entrySet()) {
+ builder.header(entry.getKey(), entry.getValue());
+ }
+ }
+
private Response performRequest(HttpMethod method, String relativeUrl, Map<String, String> params, Object requestBody, Cookie sessionId) throws Exception {
Response finalResponse = null;
int startIndex = this.lastKnownActiveUrlIndex;
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/util/TestRangerRESTClient.java b/agents-common/src/test/java/org/apache/ranger/plugin/util/TestRangerRESTClient.java
index 9d837a2c4..2f5f6ca22 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/util/TestRangerRESTClient.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/util/TestRangerRESTClient.java
@@ -19,11 +19,23 @@
package org.apache.ranger.plugin.util;
+import com.sun.net.httpserver.HttpServer;
+import org.apache.hadoop.conf.Configuration;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.junit.jupiter.api.Test;
+import javax.ws.rs.core.Response;
+
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -33,6 +45,8 @@ public class TestRangerRESTClient {
private static final String SERVICE_NAME = "test-service";
private static final String APP_ID = "test-app";
private static final String ERR_MESSAGE = "Ranger URL is null or empty.";
+ private static final String VALID_SPIFFE =
+ "spiffe://prod-cluster.k8s.example.com/ns/ranger/sa/om";
@Test
public void testPluginInit_WithNoUrl_ThrowsException() {
@@ -50,4 +64,41 @@ public void testPluginInit_WithValidUrl_Succeeds() {
plugin.init();
assertNotNull(plugin, "RangerBasePlugin should be initialized successfully");
}
+
+ @Test
+ public void setTrustedAuthHeadersAddsHeaderToOutboundRequest() throws Exception {
+ AtomicReference<String> capturedSpiffeHeader = new AtomicReference<>();
+ HttpServer httpServer = HttpServer.create(new InetSocketAddress(0), 0);
+
+ httpServer.createContext("/", exchange -> {
+ List<String> values = exchange.getRequestHeaders().get("X-Spiffe-Id");
+
+ if (values != null && !values.isEmpty()) {
+ capturedSpiffeHeader.set(values.get(0));
+ }
+
+ exchange.sendResponseHeaders(200, -1);
+ exchange.close();
+ });
+
+ httpServer.start();
+
+ try {
+ String serverUrl = "http://localhost:" + httpServer.getAddress().getPort();
+ Configuration conf = new Configuration();
+ RangerRESTClient client = new RangerRESTClient(serverUrl, null, conf);
+ Map<String, String> headers = new LinkedHashMap<>();
+
+ headers.put("X-Spiffe-Id", VALID_SPIFFE);
+ client.setTrustedAuthHeaders(headers);
+
+ try (Response response = client.get("/test", Collections.emptyMap())) {
+ assertEquals(200, response.getStatus());
+ }
+
+ assertEquals(VALID_SPIFFE, capturedSpiffeHeader.get());
+ } finally {
+ httpServer.stop(0);
+ }
+ }
}
diff --git a/common-utils/src/main/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfig.java b/common-utils/src/main/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfig.java
new file mode 100644
index 000000000..a96a81fa9
--- /dev/null
+++ b/common-utils/src/main/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfig.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Outbound trusted-header auth for audit-server and other REST clients.
+ *
+ * <p>When {@code authn.header.enabled=true}, trusted HTTP headers are added to every
+ * outbound REST request. Each header is configured as a property whose name is the
+ * HTTP header name under {@code authn.header} (audit destination example):
+ * <pre>
+ * xasecure.audit.destination.auditserver.authn.header.enabled=true
+ * xasecure.audit.destination.auditserver.authn.header.X-Spiffe-Id=file:/path/to/spiffe-id.file
+ * # valid value specs:
+ * # file:/path/to/spiffe-id.file
+ * # env:SPIFFE_ID
+ * # spiffe://trust-domain/ns/.../sa/... (literal string)
+ * </pre>
+ */
+public final class PluginHeaderAuthConfig {
+ private static final Logger LOG = LoggerFactory.getLogger(PluginHeaderAuthConfig.class);
+
+ public static final String PROP_HEADER_PREFIX = "authn.header.";
+ public static final String PROP_HEADER_AUTH_ENABLED = PROP_HEADER_PREFIX + "enabled";
+
+ private static final String VALUE_PREFIX_FILE = "file:";
+ private static final String VALUE_PREFIX_ENV = "env:";
+
+ private PluginHeaderAuthConfig() {
+ // to block instantiation
+ }
+
+ /**
+ * Returns whether trusted header auth is enabled for the given config prefix.
+ *
+ * @param props plugin or site configuration properties
+ * @param configPrefix property prefix for header-auth settings
+ * @return {@code true} when header auth is enabled
+ */
+ public static boolean isHeaderAuthEnabled(final Properties props, final String configPrefix) {
+ return props != null && StringUtils.isNotBlank(configPrefix) && Boolean.parseBoolean(props.getProperty(configPrefix + "." + PROP_HEADER_AUTH_ENABLED, "false"));
+ }
+
+ /**
+ * Builds trusted HTTP headers for outbound REST calls when header auth is enabled.
+ *
+ * @param props plugin or site configuration properties
+ * @param configPrefix prefix such as {@code xasecure.audit.destination.auditserver}
+ * @return immutable header map; empty when auth is disabled or misconfigured
+ */
+ public static Map<String, String> buildTrustedAuthHeaders(final Properties props, final String configPrefix) {
+ final Map<String, String> ret;
+
+ if (isHeaderAuthEnabled(props, configPrefix)) {
+ String propertyPrefix = configPrefix + "." + PROP_HEADER_PREFIX;
+ Map<String, String> headers = new LinkedHashMap<>();
+
+ for (String propertyName : props.stringPropertyNames()) {
+ if (!propertyName.startsWith(propertyPrefix)) {
+ continue;
+ }
+
+ String headerName = propertyName.substring(propertyPrefix.length());
+
+ if (StringUtils.isBlank(headerName) || "enabled".equals(headerName)) {
+ continue;
+ }
+
+ String headerValue = resolveConfiguredValue(props.getProperty(propertyName));
+
+ addConfiguredHeader(headers, configPrefix, headerName, headerValue);
+ }
+
+ if (headers.isEmpty()) {
+ LOG.warn("Plugin header auth enabled for {} but no trusted headers could be resolved", configPrefix);
+ }
+
+ ret = Collections.unmodifiableMap(headers);
+ } else {
+ ret = Collections.emptyMap();
+ }
+
+ return ret;
+ }
+
+ private static void addConfiguredHeader(final Map<String, String> headers, final String configPrefix, final String headerName, final String headerValue) {
+ if (StringUtils.isBlank(headerValue)) {
+ LOG.warn("Plugin header auth enabled for {} but trusted header {} has no resolvable value", configPrefix, headerName);
+ } else {
+ headers.put(headerName, headerValue);
+ }
+ }
+
+ private static String resolveConfiguredValue(final String valueSpec) {
+ final String ret;
+
+ if (StringUtils.isBlank(valueSpec)) {
+ ret = null;
+ } else if (valueSpec.startsWith(VALUE_PREFIX_FILE)) {
+ ret = readFirstNonBlankLine(valueSpec.substring(VALUE_PREFIX_FILE.length()));
+ } else if (valueSpec.startsWith(VALUE_PREFIX_ENV)) {
+ ret = StringUtils.trimToNull(System.getenv(valueSpec.substring(VALUE_PREFIX_ENV.length())));
+ } else {
+ ret = StringUtils.trimToNull(valueSpec);
+ }
+
+ return ret;
+ }
+
+ private static String readFirstNonBlankLine(final String filePath) {
+ String ret = null;
+
+ if (StringUtils.isNotBlank(filePath)) {
+ try {
+ Path path = Paths.get(filePath.trim());
+
+ if (Files.isRegularFile(path)) {
+ for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) {
+ String trimmed = StringUtils.trimToNull(line);
+
+ if (trimmed != null) {
+ ret = trimmed;
+
+ break;
+ }
+ }
+ }
+ } catch (IOException ex) {
+ LOG.debug("Unable to read trusted header value from file {}", filePath, ex);
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/common-utils/src/test/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfigTest.java b/common-utils/src/test/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfigTest.java
new file mode 100644
index 000000000..98286c39a
--- /dev/null
+++ b/common-utils/src/test/java/org/apache/ranger/plugin/util/PluginHeaderAuthConfigTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class PluginHeaderAuthConfigTest {
+ private static final String VALID_SPIFFE =
+ "spiffe://prod-cluster.k8s.example.com/ns/ranger/sa/om";
+
+ @Test
+ public void buildTrustedAuthHeadersUsesLiteralHeaderValue() {
+ Properties props = new Properties();
+ props.setProperty("ranger.ozone.authn.header.enabled", "true");
+ props.setProperty("ranger.ozone.authn.header.X-Spiffe-Id", VALID_SPIFFE);
+
+ Map<String, String> headers = PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, "ranger.ozone");
+
+ assertEquals(VALID_SPIFFE, headers.get("X-Spiffe-Id"));
+ }
+
+ @Test
+ public void buildTrustedAuthHeadersUsesFileValueSpec(@TempDir Path tempDir) throws Exception {
+ Path spiffeFile = tempDir.resolve("spiffe");
+ Files.writeString(spiffeFile, VALID_SPIFFE + "\n", StandardCharsets.UTF_8);
+
+ Properties props = new Properties();
+ props.setProperty("ranger.ozone.authn.header.enabled", "true");
+ props.setProperty("ranger.ozone.authn.header.X-Spiffe-Id", "file:" + spiffeFile);
+
+ Map<String, String> headers = PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, "ranger.ozone");
+
+ assertEquals(VALID_SPIFFE, headers.get("X-Spiffe-Id"));
+ }
+
+ @Test
+ public void buildTrustedAuthHeadersEmptyWhenDisabled() {
+ Properties props = new Properties();
+ props.setProperty("ranger.ozone.authn.header.enabled", "false");
+ props.setProperty("ranger.ozone.authn.header.X-Spiffe-Id", VALID_SPIFFE);
+
+ assertTrue(PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, "ranger.ozone").isEmpty());
+ }
+
+ @Test
+ public void isHeaderAuthEnabledFalseForMissingPrefix() {
+ assertFalse(PluginHeaderAuthConfig.isHeaderAuthEnabled(new Properties(), "ranger.ozone"));
+ }
+
+ @Test
+ public void buildTrustedAuthHeadersEmptyWhenNoHeadersConfigured() {
+ Properties props = new Properties();
+ props.setProperty("ranger.ozone.authn.header.enabled", "true");
+
+ assertTrue(PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, "ranger.ozone").isEmpty());
+ }
+
+ @Test
+ public void buildTrustedAuthHeadersEmptyWhenSpiffeIdUnresolved() {
+ Properties props = new Properties();
+ props.setProperty("ranger.ozone.authn.header.enabled", "true");
+ props.setProperty("ranger.ozone.authn.header.X-Spiffe-Id", "env:UNSET_SPIFFE_ID_VAR");
+
+ assertTrue(PluginHeaderAuthConfig.buildTrustedAuthHeaders(props, "ranger.ozone").isEmpty());
+ }
+}