You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2026/09/08 09:32:43 UTC
(knox) branch master updated: KNOX-3438: Address review comments from delegation policy admin API (#1381)
This is an automated email from the ASF dual-hosted git repository.
smolnar82 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 8872f980e KNOX-3438: Address review comments from delegation policy admin API (#1381)
8872f980e is described below
commit 8872f980e8ac326d498b74f910e50f60a2f8de76
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Tue Sep 8 11:32:37 2026 +0200
KNOX-3438: Address review comments from delegation policy admin API (#1381)
* KNOX-3438: read delegation policy TTL bounds from topology init-params with fail-fast validation instead of gateway config
* KNOX-3438: use app clock for delegation policy updated_at to match created_at
* KNOX-3438: audit delegation policy read endpoints (list, getOne) under Action.ACCESS
* KNOX-3438: validate configured default token TTL against admin API bounds at startup
---
.../gateway/config/impl/GatewayConfigImpl.java | 10 ---
.../delegation/DelegationPolicyDatabase.java | 20 +++--
.../delegation/EmptyDelegationPolicyService.java | 8 ++
.../delegation/JdbcDelegationPolicyService.java | 5 ++
.../service/knoxidf/DelegationPolicyResource.java | 64 ++++++++++++++--
.../knoxidf/DelegationPolicyResourceTest.java | 87 ++++++++++++++++------
.../org/apache/knox/gateway/GatewayTestConfig.java | 10 ---
.../apache/knox/gateway/config/GatewayConfig.java | 8 --
.../delegation/DelegationPolicyService.java | 9 +++
9 files changed, 155 insertions(+), 66 deletions(-)
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index fc065ad78..21b4ae150 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -1982,14 +1982,4 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
public int getDelegationServiceListMaxPerAuthority() {
return getInt(DELEGATION_SERVICE_LIST_MAX_PER_AUTHORITY, DELEGATION_SERVICE_LIST_MAX_PER_AUTHORITY_DEFAULT);
}
-
- @Override
- public int getDelegationServiceMinTokenTtlSec() {
- return getInt(DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC, DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC_DEFAULT);
- }
-
- @Override
- public int getDelegationServiceMaxTokenTtlSec() {
- return getInt(DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC, DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC_DEFAULT);
- }
}
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyDatabase.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyDatabase.java
index dbd5fd31c..baa157d59 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyDatabase.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyDatabase.java
@@ -25,6 +25,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -51,14 +52,16 @@ class DelegationPolicyDatabase extends KnoxDatabase {
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
// actor_authority/actor_id/created_by/created_at are deliberately absent from SET: identity and
- // creation metadata are immutable after registration. updated_at is computed by the database,
- // not supplied by the caller. The WHERE clause requires the identity fields to still match, so
- // an update attempting to change them affects 0 rows -- indistinguishable from (and reported the
- // same as) registrationId not existing at all.
+ // creation metadata are immutable after registration. updated_at is computed by the storage layer
+ // and bound below (param 6) from the app clock -- the same source INSERT uses for created_at, so
+ // both columns share one clock/zone and stay comparable (a DB-side CURRENT_TIMESTAMP could read
+ // earlier than the JVM-written created_at). The WHERE clause requires the identity fields to still
+ // match, so an update attempting to change them affects 0 rows -- indistinguishable from (and
+ // reported the same as) registrationId not existing at all.
private static final String UPDATE_CORE_SQL =
"UPDATE " + CORE_TABLE + " SET "
+ "name = ?, status = ?, token_ttl_sec = ?, description = ?, allow_headless_exchange = ?, "
- + "updated_at = CURRENT_TIMESTAMP "
+ + "updated_at = ? "
+ "WHERE registration_id = ? AND actor_authority = ? AND actor_id = ?";
private static final String DELETE_REGISTRATION_SQL =
@@ -310,9 +313,10 @@ class DelegationPolicyDatabase extends KnoxDatabase {
}
ps.setString(4, policy.getDescription());
ps.setBoolean(5, policy.isAllowHeadlessExchange());
- ps.setString(6, registrationId);
- ps.setString(7, policy.getActorAuthority());
- ps.setString(8, policy.getActorId());
+ ps.setTimestamp(6, Timestamp.from(Instant.now()));
+ ps.setString(7, registrationId);
+ ps.setString(8, policy.getActorAuthority());
+ ps.setString(9, policy.getActorId());
return ps.executeUpdate();
}
}
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/EmptyDelegationPolicyService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/EmptyDelegationPolicyService.java
index 4edc21d59..561e917a3 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/EmptyDelegationPolicyService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/EmptyDelegationPolicyService.java
@@ -85,4 +85,12 @@ public class EmptyDelegationPolicyService implements DelegationPolicyService {
public PolicyDecision evaluate(PolicyCheckRequest request) {
return new PolicyDecision("service_not_configured", 0);
}
+
+ @Override
+ public int getConfiguredTokenTtlSec() {
+ // This stub is only in play when the service role is not deployed (so the admin API is not
+ // deployed either). Return the gateway-config default so any bounds check still sees an
+ // in-range value rather than 0.
+ return GatewayConfig.DELEGATION_SERVICE_TOKEN_TTL_SEC_DEFAULT;
+ }
}
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/JdbcDelegationPolicyService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/JdbcDelegationPolicyService.java
index 8685436c3..b09cf9d67 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/JdbcDelegationPolicyService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/JdbcDelegationPolicyService.java
@@ -204,6 +204,11 @@ public class JdbcDelegationPolicyService implements DelegationPolicyService {
}
}
+ @Override
+ public int getConfiguredTokenTtlSec() {
+ return configuredKnoxTokenTtlSec;
+ }
+
@Override
public PolicyDecision evaluate(PolicyCheckRequest request) {
// Step 1: look up registration
diff --git a/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResource.java b/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResource.java
index 968984556..9480e276a 100644
--- a/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResource.java
+++ b/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResource.java
@@ -27,7 +27,6 @@ import org.apache.knox.gateway.audit.api.AuditServiceFactory;
import org.apache.knox.gateway.audit.api.Auditor;
import org.apache.knox.gateway.audit.api.ResourceType;
import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
-import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.knoxidf.delegation.DelegationPolicy;
@@ -67,6 +66,11 @@ public class DelegationPolicyResource {
static final String RESOURCE_PATH = "knoxidf/admin/v1/delegation-policies";
+ static final String MIN_TOKEN_TTL_SEC_PARAM = "knox.delegation.min.token.ttl.sec";
+ static final String MAX_TOKEN_TTL_SEC_PARAM = "knox.delegation.max.token.ttl.sec";
+ static final int DEFAULT_MIN_TOKEN_TTL_SEC = 60; // 1 minute
+ static final int DEFAULT_MAX_TOKEN_TTL_SEC = 86400; // 24 hours
+
private static final ObjectMapper MAPPER = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
@@ -84,20 +88,52 @@ public class DelegationPolicyResource {
private DelegationPolicyService policyService;
- private int minTokenTtlSec = GatewayConfig.DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC_DEFAULT;
- private int maxTokenTtlSec = GatewayConfig.DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC_DEFAULT;
+ private int minTokenTtlSec = DEFAULT_MIN_TOKEN_TTL_SEC;
+ private int maxTokenTtlSec = DEFAULT_MAX_TOKEN_TTL_SEC;
@PostConstruct
public void init() {
final GatewayServices services = (GatewayServices)
servletContext.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
policyService = services.getService(ServiceType.DELEGATION_POLICY_SERVICE);
+ configureTtlBounds();
+ }
+
+ private void configureTtlBounds() {
+ minTokenTtlSec = readPositiveIntParam(MIN_TOKEN_TTL_SEC_PARAM, DEFAULT_MIN_TOKEN_TTL_SEC);
+ maxTokenTtlSec = readPositiveIntParam(MAX_TOKEN_TTL_SEC_PARAM, DEFAULT_MAX_TOKEN_TTL_SEC);
+ if (minTokenTtlSec > maxTokenTtlSec) {
+ throw new IllegalStateException("Invalid delegation policy TTL bounds: "
+ + MIN_TOKEN_TTL_SEC_PARAM + " (" + minTokenTtlSec + ") must not exceed "
+ + MAX_TOKEN_TTL_SEC_PARAM + " (" + maxTokenTtlSec + ")");
+ }
- final GatewayConfig config = (GatewayConfig) servletContext.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
- if (config != null) {
- minTokenTtlSec = config.getDelegationServiceMinTokenTtlSec();
- maxTokenTtlSec = config.getDelegationServiceMaxTokenTtlSec();
+ final int configuredDefaultTtlSec = policyService.getConfiguredTokenTtlSec();
+ if (configuredDefaultTtlSec < minTokenTtlSec || configuredDefaultTtlSec > maxTokenTtlSec) {
+ throw new IllegalStateException("Configured default delegation token TTL ("
+ + configuredDefaultTtlSec + "s) is outside the enforced bounds [" + minTokenTtlSec + ", "
+ + maxTokenTtlSec + "]; policies without an explicit tokenTtlSec would receive an "
+ + "out-of-range effective TTL");
+ }
+ }
+
+ private int readPositiveIntParam(String paramName, int defaultValue) {
+ final String raw = servletContext.getInitParameter(paramName);
+ if (StringUtils.isBlank(raw)) {
+ return defaultValue;
+ }
+ final int value;
+ try {
+ value = Integer.parseInt(raw.trim());
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException("Invalid value for " + paramName + ": \"" + raw
+ + "\" is not an integer");
+ }
+ if (value <= 0) {
+ throw new IllegalStateException("Invalid value for " + paramName + ": " + value
+ + " must be a positive number of seconds");
}
+ return value;
}
@POST
@@ -181,29 +217,41 @@ public class DelegationPolicyResource {
@GET
public Response list(@QueryParam("actorAuthority") String actorAuthority) {
+ final String filter = StringUtils.isBlank(actorAuthority) ? null : actorAuthority;
+ String outcome = ActionOutcome.FAILURE;
try {
- final String filter = StringUtils.isBlank(actorAuthority) ? null : actorAuthority;
final DelegationPolicyList result = policyService.list(filter);
final DelegationPolicyListResponse body = new DelegationPolicyListResponse();
body.setPolicies(result.getPolicies().stream().map(DelegationPolicyResource::toResponse).collect(Collectors.toList()));
body.setHasMore(result.hasMore());
+ outcome = ActionOutcome.SUCCESS;
return Response.ok(writeJson(body)).build();
} catch (RuntimeException e) {
return errorResponse(Response.Status.INTERNAL_SERVER_ERROR, "storage_error", "Failed to list delegation policies");
+ } finally {
+ final String operatorId = getOperatorId();
+ auditor.audit(Action.ACCESS, filter != null ? filter : "ALL", ResourceType.DELEGATION_POLICY,
+ outcome, "event_type=policy_listed performed_by=" + auditLabel(operatorId));
}
}
@GET
@Path("/{registrationId}")
public Response getOne(@PathParam("registrationId") String registrationId) {
+ String outcome = ActionOutcome.FAILURE;
try {
final Optional<DelegationPolicy> found = policyService.get(registrationId);
if (!found.isPresent()) {
return errorResponse(Response.Status.NOT_FOUND, "policy_not_found", "Delegation policy not found: " + registrationId);
}
+ outcome = ActionOutcome.SUCCESS;
return Response.ok(writeJson(toResponse(found.get()))).build();
} catch (RuntimeException e) {
return errorResponse(Response.Status.INTERNAL_SERVER_ERROR, "storage_error", "Failed to read delegation policy");
+ } finally {
+ final String operatorId = getOperatorId();
+ auditor.audit(Action.ACCESS, registrationId, ResourceType.DELEGATION_POLICY,
+ outcome, "event_type=policy_read performed_by=" + auditLabel(operatorId));
}
}
diff --git a/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResourceTest.java b/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResourceTest.java
index f5363f00a..01a551038 100644
--- a/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResourceTest.java
+++ b/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DelegationPolicyResourceTest.java
@@ -22,7 +22,6 @@ import org.apache.knox.gateway.audit.api.Action;
import org.apache.knox.gateway.audit.api.ActionOutcome;
import org.apache.knox.gateway.audit.api.Auditor;
import org.apache.knox.gateway.audit.api.ResourceType;
-import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.knoxidf.delegation.DelegationPolicy;
@@ -63,8 +62,8 @@ public class DelegationPolicyResourceTest {
private static final String ACTOR_ID = "svc-1";
private static final String REGISTRATION_ID = "reg-123";
private static final String OPERATOR = "admin";
- private static final int MIN_TTL = GatewayConfig.DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC_DEFAULT;
- private static final int MAX_TTL = GatewayConfig.DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC_DEFAULT;
+ private static final int MIN_TTL = DelegationPolicyResource.DEFAULT_MIN_TOKEN_TTL_SEC;
+ private static final int MAX_TTL = DelegationPolicyResource.DEFAULT_MAX_TOKEN_TTL_SEC;
private static final ObjectMapper MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());
private static final String ISO_INSTANT_PATTERN =
@@ -775,6 +774,7 @@ public class DelegationPolicyResourceTest {
EasyMock.expect(mockService.list(null))
.andReturn(new DelegationPolicyList(Collections.singletonList(existingPolicy(REGISTRATION_ID, Instant.now())), false))
.once();
+ expectReadAudit("ALL", ActionOutcome.SUCCESS, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.list(null);
@@ -791,6 +791,7 @@ public class DelegationPolicyResourceTest {
EasyMock.expect(mockService.list(ACTOR_AUTHORITY))
.andReturn(new DelegationPolicyList(Collections.emptyList(), false))
.once();
+ expectReadAudit(ACTOR_AUTHORITY, ActionOutcome.SUCCESS, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
resource.list(ACTOR_AUTHORITY);
@@ -803,6 +804,7 @@ public class DelegationPolicyResourceTest {
EasyMock.expect(mockService.list(null))
.andReturn(new DelegationPolicyList(Collections.emptyList(), false))
.once();
+ expectReadAudit("ALL", ActionOutcome.SUCCESS, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
resource.list("");
@@ -815,6 +817,7 @@ public class DelegationPolicyResourceTest {
EasyMock.expect(mockService.list(null))
.andReturn(new DelegationPolicyList(Collections.emptyList(), false))
.once();
+ expectReadAudit("ALL", ActionOutcome.SUCCESS, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.list(null);
@@ -831,6 +834,7 @@ public class DelegationPolicyResourceTest {
EasyMock.expect(mockService.list(null))
.andReturn(new DelegationPolicyList(Collections.emptyList(), true))
.once();
+ expectReadAudit("ALL", ActionOutcome.SUCCESS, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
final DelegationPolicyListResponse body = parseListResponse(resource.list(null));
@@ -842,6 +846,7 @@ public class DelegationPolicyResourceTest {
@Test
public void testListStorageFailure() {
EasyMock.expect(mockService.list(null)).andThrow(new RuntimeException("DB error")).once();
+ expectReadAudit("ALL", ActionOutcome.FAILURE, "policy_listed");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.list(null);
@@ -859,6 +864,7 @@ public class DelegationPolicyResourceTest {
public void testGetOneFound() throws Exception {
final DelegationPolicy stored = existingPolicy(REGISTRATION_ID, Instant.now());
EasyMock.expect(mockService.get(REGISTRATION_ID)).andReturn(Optional.of(stored)).once();
+ expectReadAudit(REGISTRATION_ID, ActionOutcome.SUCCESS, "policy_read");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.getOne(REGISTRATION_ID);
@@ -871,6 +877,7 @@ public class DelegationPolicyResourceTest {
@Test
public void testGetOneNotFound() {
EasyMock.expect(mockService.get(REGISTRATION_ID)).andReturn(Optional.empty()).once();
+ expectReadAudit(REGISTRATION_ID, ActionOutcome.FAILURE, "policy_read");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.getOne(REGISTRATION_ID);
@@ -883,6 +890,7 @@ public class DelegationPolicyResourceTest {
@Test
public void testGetOneStorageFailure() {
EasyMock.expect(mockService.get(REGISTRATION_ID)).andThrow(new RuntimeException("DB error")).once();
+ expectReadAudit(REGISTRATION_ID, ActionOutcome.FAILURE, "policy_read");
EasyMock.replay(mockService, mockAuditor);
final Response response = resource.getOne(REGISTRATION_ID);
@@ -1178,6 +1186,7 @@ public class DelegationPolicyResourceTest {
@Test
public void testInitWiresServiceFromGatewayServices() throws Exception {
final DelegationPolicyService svc = EasyMock.createNiceMock(DelegationPolicyService.class);
+ EasyMock.expect(svc.getConfiguredTokenTtlSec()).andReturn(3600).anyTimes();
EasyMock.replay(svc);
final GatewayServices gws = EasyMock.createNiceMock(GatewayServices.class);
@@ -1186,7 +1195,6 @@ public class DelegationPolicyResourceTest {
final ServletContext ctx = EasyMock.createNiceMock(ServletContext.class);
EasyMock.expect(ctx.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(gws).once();
- EasyMock.expect(ctx.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(null).once();
EasyMock.replay(ctx);
final DelegationPolicyResource res = new DelegationPolicyResource();
@@ -1194,38 +1202,65 @@ public class DelegationPolicyResourceTest {
injectField(res, "request", buildRequest(buildPrincipal(OPERATOR)));
res.init();
+ // No init-params configured -> code-constant defaults apply.
assertEquals(MIN_TTL, ((Number) readField(res, "minTokenTtlSec")).intValue());
assertEquals(MAX_TTL, ((Number) readField(res, "maxTokenTtlSec")).intValue());
EasyMock.verify(gws, ctx);
}
@Test
- public void testInitWiresTokenTtlBoundsFromGatewayConfig() throws Exception {
+ public void testInitReadsTokenTtlBoundsFromInitParams() throws Exception {
+ final DelegationPolicyResource res = initResourceWithBounds("120", "7200");
+ assertEquals(120, ((Number) readField(res, "minTokenTtlSec")).intValue());
+ assertEquals(7200, ((Number) readField(res, "maxTokenTtlSec")).intValue());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInitRejectsNonNumericBound() throws Exception {
+ initResourceWithBounds("not-a-number", null);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInitRejectsNonPositiveBound() throws Exception {
+ initResourceWithBounds("0", null);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInitRejectsMinGreaterThanMax() throws Exception {
+ initResourceWithBounds("7200", "120");
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testInitRejectsConfiguredDefaultOutsideBounds() throws Exception {
+ // Default bounds are [60, 86400]; a gateway-wide default above max would let policies without
+ // an explicit tokenTtlSec yield an out-of-range effective TTL, so init() must fail fast.
+ initResource(null, null, 100000);
+ }
+
+ private DelegationPolicyResource initResourceWithBounds(String min, String max) throws Exception {
+ return initResource(min, max, 3600);
+ }
+
+ private DelegationPolicyResource initResource(String min, String max, int configuredDefault) throws Exception {
final DelegationPolicyService svc = EasyMock.createNiceMock(DelegationPolicyService.class);
+ EasyMock.expect(svc.getConfiguredTokenTtlSec()).andReturn(configuredDefault).anyTimes();
EasyMock.replay(svc);
final GatewayServices gws = EasyMock.createNiceMock(GatewayServices.class);
- EasyMock.expect(gws.getService(ServiceType.DELEGATION_POLICY_SERVICE)).andReturn(svc).once();
+ EasyMock.expect(gws.getService(ServiceType.DELEGATION_POLICY_SERVICE)).andReturn(svc).anyTimes();
EasyMock.replay(gws);
- final GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
- EasyMock.expect(config.getDelegationServiceMinTokenTtlSec()).andReturn(120).once();
- EasyMock.expect(config.getDelegationServiceMaxTokenTtlSec()).andReturn(7200).once();
- EasyMock.replay(config);
-
final ServletContext ctx = EasyMock.createNiceMock(ServletContext.class);
- EasyMock.expect(ctx.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(gws).once();
- EasyMock.expect(ctx.getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(config).once();
+ EasyMock.expect(ctx.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(gws).anyTimes();
+ EasyMock.expect(ctx.getInitParameter(DelegationPolicyResource.MIN_TOKEN_TTL_SEC_PARAM)).andReturn(min).anyTimes();
+ EasyMock.expect(ctx.getInitParameter(DelegationPolicyResource.MAX_TOKEN_TTL_SEC_PARAM)).andReturn(max).anyTimes();
EasyMock.replay(ctx);
final DelegationPolicyResource res = new DelegationPolicyResource();
injectField(res, "servletContext", ctx);
injectField(res, "request", buildRequest(buildPrincipal(OPERATOR)));
res.init();
-
- assertEquals(120, ((Number) readField(res, "minTokenTtlSec")).intValue());
- assertEquals(7200, ((Number) readField(res, "maxTokenTtlSec")).intValue());
- EasyMock.verify(gws, ctx, config);
+ return res;
}
// ---------------------------------------------------------------------------
@@ -1257,12 +1292,20 @@ public class DelegationPolicyResourceTest {
}
private void expectAudit(String registrationId, String outcome, String eventType) {
+ expectAudit(Action.DELEGATION_LIFECYCLE, registrationId, outcome, eventType);
+ }
+
+ private void expectReadAudit(String id, String outcome, String eventType) {
+ expectAudit(Action.ACCESS, id, outcome, eventType);
+ }
+
+ private void expectAudit(String action, String registrationId, String outcome, String eventType) {
mockAuditor.audit(
- EasyMock.eq(Action.DELEGATION_LIFECYCLE),
- EasyMock.eq(registrationId),
- EasyMock.eq(ResourceType.DELEGATION_POLICY),
- EasyMock.eq(outcome),
- EasyMock.contains(eventType));
+ EasyMock.eq(action),
+ EasyMock.eq(registrationId),
+ EasyMock.eq(ResourceType.DELEGATION_POLICY),
+ EasyMock.eq(outcome),
+ EasyMock.contains(eventType));
EasyMock.expectLastCall().once();
}
diff --git a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index 5e892902a..e74df8b9d 100644
--- a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -1425,14 +1425,4 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
return DELEGATION_SERVICE_LIST_MAX_PER_AUTHORITY_DEFAULT;
}
- @Override
- public int getDelegationServiceMinTokenTtlSec() {
- return DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC_DEFAULT;
- }
-
- @Override
- public int getDelegationServiceMaxTokenTtlSec() {
- return DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC_DEFAULT;
- }
-
}
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 6e1e922f0..b2af39e6c 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -183,10 +183,6 @@ public interface GatewayConfig {
int DELEGATION_SERVICE_LIST_MAX_TOTAL_DEFAULT = 10_000;
String DELEGATION_SERVICE_LIST_MAX_PER_AUTHORITY = DELEGATION_SERVICE_PREFIX + "list.max.per.authority";
int DELEGATION_SERVICE_LIST_MAX_PER_AUTHORITY_DEFAULT = 10_000;
- String DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC = DELEGATION_SERVICE_PREFIX + "min.token.ttl.sec";
- int DELEGATION_SERVICE_MIN_TOKEN_TTL_SEC_DEFAULT = 60; // 1 minute
- String DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC = DELEGATION_SERVICE_PREFIX + "max.token.ttl.sec";
- int DELEGATION_SERVICE_MAX_TOKEN_TTL_SEC_DEFAULT = 86400; // 24 hours
// KnoxIDF federated-OP back-channel (token exchange) HTTP client timeouts. Without these an
// unresponsive external OP token endpoint pins the calling request thread indefinitely.
@@ -1315,8 +1311,4 @@ public interface GatewayConfig {
int getDelegationServiceListMaxPerAuthority();
- int getDelegationServiceMinTokenTtlSec();
-
- int getDelegationServiceMaxTokenTtlSec();
-
}
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyService.java
index 02aa237cc..7b33631bc 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyService.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/knoxidf/delegation/DelegationPolicyService.java
@@ -80,4 +80,13 @@ public interface DelegationPolicyService extends Service {
DelegationPolicyList list(String actorAuthorityFilter);
PolicyDecision evaluate(PolicyCheckRequest request);
+
+ /**
+ * @return the gateway-wide default token TTL (seconds) that {@link #evaluate} applies when a
+ * policy does not pin its own tokenTtlSec. Exposed so the admin API can validate this
+ * fallback against its configured [min, max] bounds at startup and fail fast on an
+ * out-of-range value -- otherwise policies stored without an explicit tokenTtlSec would
+ * yield an effective TTL outside the range the API enforces for explicit values.
+ */
+ int getConfiguredTokenTtlSec();
}