You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by ad...@apache.org on 2026/10/07 13:08:25 UTC

(polaris) branch main updated: Move credential rotation check from authorizers to a JAX-RS filter (#5706)

This is an automated email from the ASF dual-hosted git repository.

adutra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new a735681d82 Move credential rotation check from authorizers to a JAX-RS filter (#5706)
a735681d82 is described below

commit a735681d82cbfb8b4e71cc446c86da0b4d650302
Author: Alexandre Dutra <ad...@apache.org>
AuthorDate: Wed Oct 7 15:08:19 2026 +0200

    Move credential rotation check from authorizers to a JAX-RS filter (#5706)
    
    The check that blocks principals who must rotate their credentials was
    duplicated in each authorizer implementation. Enforce it once in a
    request filter so it applies regardless of the configured authorizer.
---
 CHANGELOG.md                                       |  10 +-
 .../extension/auth/opa/OpaPolarisAuthorizer.java   |  16 +--
 .../auth/opa/OpaPolarisAuthorizerFactory.java      |   3 +-
 .../auth/opa/OpaPolarisAuthorizerFactoryTest.java  |  27 ++--
 .../auth/opa/OpaPolarisAuthorizerTest.java         | 147 +++------------------
 .../auth/ranger/RangerPolarisAuthorizer.java       |  26 ++--
 .../ranger/RangerPolarisAuthorizerFactory.java     |   9 +-
 .../auth/ranger/RangerPolarisAuthorizerTest.java   |   4 +-
 .../SemanticModelCatalogHandlerAuthzTest.java      |   2 +-
 .../core/auth/AuthorizationPreConditions.java      |  70 ----------
 .../polaris/core/auth/PolarisAuthorizerImpl.java   |   9 --
 .../core/auth/AuthorizationPreConditionsTest.java  | 104 ---------------
 .../core/auth/PolarisAuthorizerImplTest.java       |  44 ++----
 .../service/auth/CredentialRotationFilter.java     |  91 +++++++++++++
 .../auth/DefaultPolarisAuthorizerFactory.java      |   2 +-
 .../polaris/service/config/FilterPriorities.java   |  15 ++-
 .../service/admin/ManagementServiceTest.java       |   2 +-
 .../service/admin/PolarisAuthzTestBase.java        |   2 +-
 .../service/auth/CredentialRotationFilterTest.java | 137 +++++++++++++++++++
 .../AbstractPolarisGenericTableCatalogTest.java    |   2 +-
 .../AbstractIcebergCatalogHandlerAuthzTest.java    | 140 --------------------
 .../AbstractLocalIcebergCatalogViewTest.java       |   2 +-
 .../catalog/policy/AbstractPolicyCatalogTest.java  |   2 +-
 23 files changed, 308 insertions(+), 558 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3cad49e65..87bbe2c9d3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -130,10 +130,12 @@ request adding CHANGELOG notes for breaking (!) changes and possibly other secti
   `deserializeKey`. Previously it counted two units per escaped `0x01`/`0x02` byte against the
   same 500 limit, so a key that had been written successfully (for example 251 bytes of `0x01`)
   could make index deserialization throw and leave the index container unreadable.
-- The OPA authorizer now enforces the credential-rotation pre-condition. With
-  `ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING` enabled, a principal whose credentials
-  were reset but never rotated was refused by the internal and Ranger authorizers but not by OPA.
-  The rotation state is not part of the OPA input document, so a policy could not compensate.
+- The credential-rotation pre-condition is now enforced by a JAX-RS filter instead of by each
+  authorizer. With `ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING` enabled, a principal
+  whose credentials were reset but never rotated can only call the rotate-credentials endpoint,
+  whichever authorizer is configured. Previously the internal and Ranger authorizers enforced it
+  but OPA did not, and the rotation state is not part of the OPA input document, so a policy could
+  not compensate.
 - Re-creating an existing namespace now returns `409 Conflict` instead of `403 Forbidden` when
   `OPTIMIZED_SIBLING_CHECK` is on. Namespace creation checks for an existing namespace before
   validating locations, as table and view creation already do, so the existing namespace's own
diff --git a/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java b/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java
index da91c1a1d2..a7d0646757 100644
--- a/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java
+++ b/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizer.java
@@ -37,10 +37,8 @@ import org.apache.hc.core5.http.ParseException;
 import org.apache.hc.core5.http.io.HttpClientResponseHandler;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.io.entity.StringEntity;
-import org.apache.iceberg.exceptions.ForbiddenException;
 import org.apache.polaris.core.auth.AuthorizationDecision;
 import org.apache.polaris.core.auth.AuthorizationIntent;
-import org.apache.polaris.core.auth.AuthorizationPreConditions;
 import org.apache.polaris.core.auth.AuthorizationRequest;
 import org.apache.polaris.core.auth.AuthorizationState;
 import org.apache.polaris.core.auth.PathSegment;
@@ -55,7 +53,6 @@ import org.apache.polaris.core.auth.RoleAssignmentAuthorizationIntent;
 import org.apache.polaris.core.auth.RootPrivilegeGrantAuthorizationIntent;
 import org.apache.polaris.core.auth.SingleTargetAuthorizationIntent;
 import org.apache.polaris.core.auth.TargetlessAuthorizationIntent;
-import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.extension.auth.opa.model.ImmutableActor;
 import org.apache.polaris.extension.auth.opa.model.ImmutableContext;
 import org.apache.polaris.extension.auth.opa.model.ImmutableOpaAuthorizationInput;
@@ -89,7 +86,6 @@ class OpaPolarisAuthorizer implements PolarisAuthorizer {
   private final ObjectMapper objectMapper;
   private final String requestId;
   private final String realm;
-  private final RealmConfig realmConfig;
 
   /**
    * Public constructor that accepts a complete policy URI and the current realm identifier.
@@ -105,8 +101,6 @@ class OpaPolarisAuthorizer implements PolarisAuthorizer {
    *     the originating HTTP request. Resolved once by the caller since this authorizer is
    *     constructed fresh per request.
    * @param realm The realm identifier (from RealmContext) for isolation in OPA policies.
-   * @param realmConfig The realm configuration, used to evaluate authorization pre-conditions that
-   *     Polaris enforces before consulting OPA.
    */
   public OpaPolarisAuthorizer(
       @NonNull URI policyUri,
@@ -114,8 +108,7 @@ class OpaPolarisAuthorizer implements PolarisAuthorizer {
       @NonNull ObjectMapper objectMapper,
       @Nullable BearerTokenProvider tokenProvider,
       @Nullable String requestId,
-      @NonNull String realm,
-      @NonNull RealmConfig realmConfig) {
+      @NonNull String realm) {
 
     this.policyUri = policyUri;
     this.tokenProvider = tokenProvider;
@@ -123,7 +116,6 @@ class OpaPolarisAuthorizer implements PolarisAuthorizer {
     this.objectMapper = objectMapper;
     this.requestId = requestId;
     this.realm = realm;
-    this.realmConfig = realmConfig;
   }
 
   /**
@@ -144,12 +136,6 @@ class OpaPolarisAuthorizer implements PolarisAuthorizer {
       @NonNull AuthorizationState authzState, @NonNull AuthorizationRequest request) {
     for (AuthorizationIntent intent : request.intents()) {
       PolarisAuthorizableOperation operation = intent.operation();
-      try {
-        AuthorizationPreConditions.checkCredentialRotationRequired(
-            request.principal(), operation, realmConfig);
-      } catch (ForbiddenException e) {
-        return AuthorizationDecision.deny(e.getMessage());
-      }
       List<ResourceEntity> targets;
       List<ResourceEntity> secondaries;
       switch (intent) {
diff --git a/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactory.java b/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactory.java
index e530e864ac..ee3d62c4be 100644
--- a/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactory.java
+++ b/extensions/auth/opa/src/main/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactory.java
@@ -111,8 +111,7 @@ class OpaPolarisAuthorizerFactory implements PolarisAuthorizerFactory {
         objectMapper,
         bearerTokenProvider,
         requestIdSupplier.getRequestId(),
-        realmContext.getRealmIdentifier(),
-        realmConfig);
+        realmContext.getRealmIdentifier());
   }
 
   @PreDestroy
diff --git a/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactoryTest.java b/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactoryTest.java
index 405e6ab79b..c70a6a683d 100644
--- a/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactoryTest.java
+++ b/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerFactoryTest.java
@@ -22,7 +22,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatNoException;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -50,7 +49,6 @@ import org.apache.polaris.core.auth.TargetlessAuthorizationIntent;
 import org.apache.polaris.core.collection.AttributeMap;
 import org.apache.polaris.core.collection.AttributeMap.AttributeKey;
 import org.apache.polaris.core.collection.ImmutableAttributeMap;
-import org.apache.polaris.core.config.FeatureConfiguration;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.context.RealmContext;
 import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
@@ -94,7 +92,7 @@ public class OpaPolarisAuthorizerFactoryTest {
               opaConfig, Clock.systemUTC(), asyncExec, () -> null, realmContext);
 
       // Create authorizer
-      RealmConfig realmConfig = realmConfig(false);
+      RealmConfig realmConfig = mock(RealmConfig.class);
       OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig);
 
       assertThat(authorizer).isNotNull();
@@ -140,7 +138,7 @@ public class OpaPolarisAuthorizerFactoryTest {
               opaConfig, Clock.systemUTC(), asyncExec, () -> null, realmContext);
 
       // Create authorizer
-      RealmConfig realmConfig = realmConfig(false);
+      RealmConfig realmConfig = mock(RealmConfig.class);
       OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig);
 
       assertThat(authorizer).isNotNull();
@@ -187,7 +185,7 @@ public class OpaPolarisAuthorizerFactoryTest {
               opaConfig, Clock.systemUTC(), asyncExec, () -> null, realmContext);
 
       // Create authorizer
-      RealmConfig realmConfig = realmConfig(false);
+      RealmConfig realmConfig = mock(RealmConfig.class);
       OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig);
 
       assertThat(authorizer).isNotNull();
@@ -225,7 +223,8 @@ public class OpaPolarisAuthorizerFactoryTest {
                 opaConfig, Clock.systemUTC(), asyncExec, () -> null, realmContext);
 
         factory.initialize();
-        OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig(false));
+        OpaPolarisAuthorizer authorizer =
+            (OpaPolarisAuthorizer) factory.create(mock(RealmConfig.class));
 
         PolarisPrincipal principal =
             PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
@@ -284,7 +283,8 @@ public class OpaPolarisAuthorizerFactoryTest {
                 opaConfig, Clock.systemUTC(), asyncExec, () -> null, realmContext);
 
         factory.initialize();
-        OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig(false));
+        OpaPolarisAuthorizer authorizer =
+            (OpaPolarisAuthorizer) factory.create(mock(RealmConfig.class));
 
         PolarisPrincipal principal =
             PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
@@ -346,7 +346,7 @@ public class OpaPolarisAuthorizerFactoryTest {
                 realmContext);
         factory.initialize();
 
-        RealmConfig realmConfig = realmConfig(false);
+        RealmConfig realmConfig = mock(RealmConfig.class);
         OpaPolarisAuthorizer authorizer = (OpaPolarisAuthorizer) factory.create(realmConfig);
 
         PolarisPrincipal principal =
@@ -417,7 +417,7 @@ public class OpaPolarisAuthorizerFactoryTest {
 
         factory.initialize();
 
-        RealmConfig realmConfig = realmConfig(false);
+        RealmConfig realmConfig = mock(RealmConfig.class);
         PolarisPrincipal principal =
             PolarisPrincipal.of(
                 "eve",
@@ -517,13 +517,4 @@ public class OpaPolarisAuthorizerFactoryTest {
     server.start();
     return server;
   }
-
-  /** A {@link RealmConfig} answering the credential-rotation flag, as {@code polaris-core} does. */
-  private static RealmConfig realmConfig(boolean enforceCredentialRotation) {
-    RealmConfig realmConfig = mock(RealmConfig.class);
-    when(realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
-        .thenReturn(enforceCredentialRotation);
-    return realmConfig;
-  }
 }
diff --git a/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java b/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java
index e9ed506ee8..c5a14fe437 100644
--- a/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java
+++ b/extensions/auth/opa/src/test/java/org/apache/polaris/extension/auth/opa/OpaPolarisAuthorizerTest.java
@@ -22,7 +22,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatNoException;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -57,7 +56,6 @@ import org.apache.polaris.core.auth.AuthorizationState;
 import org.apache.polaris.core.auth.PathSegment;
 import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
 import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.auth.PolarisPrincipalAttributes;
 import org.apache.polaris.core.auth.PolarisSecurable;
 import org.apache.polaris.core.auth.RenameAuthorizationIntent;
 import org.apache.polaris.core.auth.SingleTargetAuthorizationIntent;
@@ -65,12 +63,9 @@ import org.apache.polaris.core.auth.TargetlessAuthorizationIntent;
 import org.apache.polaris.core.collection.AttributeMap;
 import org.apache.polaris.core.collection.AttributeMap.AttributeKey;
 import org.apache.polaris.core.collection.ImmutableAttributeMap;
-import org.apache.polaris.core.config.FeatureConfiguration;
-import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.entity.PolarisEntity;
 import org.apache.polaris.core.entity.PolarisEntityConstants;
 import org.apache.polaris.core.entity.PolarisEntityType;
-import org.apache.polaris.core.entity.PrincipalEntity;
 import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
 import org.apache.polaris.core.persistence.ResolvedPolarisEntity;
 import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
@@ -101,8 +96,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisPrincipal principal =
           PolarisPrincipal.of(
@@ -164,8 +158,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "prod-realm",
-              realmConfig(false));
+              "prod-realm");
 
       // Set up a realistic principal
       PolarisPrincipal principal =
@@ -310,8 +303,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "analytics-realm",
-              realmConfig(false));
+              "analytics-realm");
 
       // Set up a realistic principal
       PolarisPrincipal principal =
@@ -488,8 +480,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisPrincipal principal =
           PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("admin"));
@@ -545,8 +536,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             tokenProvider,
             null,
-            "test-realm",
-            realmConfig(false));
+            "test-realm");
 
     assertThat(authorizer).isNotNull();
   }
@@ -567,8 +557,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             tokenProvider,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -621,8 +610,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             tokenProvider,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -670,8 +658,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false));
+            "test-realm");
     PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(resolutionManifest);
     PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role-1"));
@@ -700,8 +687,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -751,8 +737,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -795,8 +780,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "catalog-realm",
-            realmConfig(false)) {
+            "catalog-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -846,8 +830,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisEntity rootEntity =
           new PolarisEntity.Builder()
@@ -921,8 +904,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisEntity rootEntity =
           new PolarisEntity.Builder()
@@ -992,8 +974,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -1060,8 +1041,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -1149,8 +1129,7 @@ public class OpaPolarisAuthorizerTest {
             JsonMapper.builder().build(),
             null,
             null,
-            "test-realm",
-            realmConfig(false)) {
+            "test-realm") {
           @Override
           <T> T httpClientExecute(
               ClassicHttpRequest request, HttpClientResponseHandler<? extends T> responseHandler)
@@ -1191,8 +1170,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "explicit-realm",
-              realmConfig(false));
+              "explicit-realm");
 
       PolarisPrincipal principal =
           PolarisPrincipal.of("eve", AttributeMap.EMPTY, Set.of("auditor"));
@@ -1235,8 +1213,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "tenant-xyz",
-              realmConfig(false));
+              "tenant-xyz");
 
       PolarisResolutionManifest resolutionManifest = mock(PolarisResolutionManifest.class);
       AuthorizationState authzState = new AuthorizationState(resolutionManifest);
@@ -1271,8 +1248,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               "test-id",
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisPrincipal principal =
           PolarisPrincipal.of(
@@ -1322,8 +1298,7 @@ public class OpaPolarisAuthorizerTest {
               JsonMapper.builder().build(),
               null,
               null,
-              "test-realm",
-              realmConfig(false));
+              "test-realm");
 
       PolarisPrincipal principal =
           PolarisPrincipal.of(
@@ -1501,86 +1476,4 @@ public class OpaPolarisAuthorizerTest {
           .isFalse();
     }
   }
-
-  @Test
-  void authorizeRejectsPrincipalThatMustRotateCredentials() {
-    // An unreachable policy URI: contacting OPA at all would surface as a connection failure, so a
-    // clean denial proves the pre-condition is evaluated before OPA is consulted.
-    OpaPolarisAuthorizer authorizer =
-        new OpaPolarisAuthorizer(
-            URI.create("http://127.0.0.1:1/v1/data/polaris/allow"),
-            HttpClients.createDefault(),
-            JsonMapper.builder().build(),
-            null,
-            null,
-            "test-realm",
-            realmConfig(true));
-
-    AuthorizationDecision decision =
-        authorizer.authorize(
-            new AuthorizationState(mock(PolarisResolutionManifest.class)),
-            new AuthorizationRequest(
-                rotationRequiredPrincipal(),
-                authorizationIntents(PolarisAuthorizableOperation.LOAD_TABLE, null, null)));
-
-    assertThat(decision.isAllowed()).isFalse();
-    assertThat(decision.getMessage())
-        .hasValueSatisfying(
-            message -> assertThat(message).contains("must rotate credentials first"));
-  }
-
-  @Test
-  void authorizeAllowsCredentialRotationForPrincipalThatMustRotate() throws Exception {
-    HttpServer server = createServerWithAllowResponse();
-    try {
-      OpaPolarisAuthorizer authorizer =
-          new OpaPolarisAuthorizer(
-              URI.create(
-                  "http://localhost:" + server.getAddress().getPort() + "/v1/data/polaris/allow"),
-              HttpClients.createDefault(),
-              JsonMapper.builder().build(),
-              null,
-              null,
-              "test-realm",
-              realmConfig(true));
-
-      assertThatNoException()
-          .isThrownBy(
-              () ->
-                  authorizer
-                      .authorize(
-                          new AuthorizationState(mock(PolarisResolutionManifest.class)),
-                          new AuthorizationRequest(
-                              rotationRequiredPrincipal(),
-                              authorizationIntents(
-                                  PolarisAuthorizableOperation.ROTATE_CREDENTIALS, null, null)))
-                      .throwIfDenied());
-    } finally {
-      server.stop(0);
-    }
-  }
-
-  /** A principal flagged as needing to rotate its credentials before doing anything else. */
-  private static PolarisPrincipal rotationRequiredPrincipal() {
-    return PolarisPrincipal.of(
-        "alice",
-        ImmutableAttributeMap.builder()
-            .put(
-                PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY,
-                new PrincipalEntity.Builder()
-                    .setName("alice")
-                    .setCredentialRotationRequiredState()
-                    .build())
-            .build(),
-        Set.of("role"));
-  }
-
-  /** A {@link RealmConfig} answering the credential-rotation flag, as {@code polaris-core} does. */
-  private static RealmConfig realmConfig(boolean enforceCredentialRotation) {
-    RealmConfig realmConfig = mock(RealmConfig.class);
-    when(realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
-        .thenReturn(enforceCredentialRotation);
-    return realmConfig;
-  }
 }
diff --git a/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizer.java b/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizer.java
index 267a27fba1..8d2f3ed43b 100644
--- a/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizer.java
+++ b/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizer.java
@@ -26,13 +26,11 @@ import org.apache.iceberg.exceptions.ForbiddenException;
 import org.apache.polaris.core.auth.AuthorizationDecision;
 import org.apache.polaris.core.auth.AuthorizationIntent;
 import org.apache.polaris.core.auth.AuthorizationIntentResolver;
-import org.apache.polaris.core.auth.AuthorizationPreConditions;
 import org.apache.polaris.core.auth.AuthorizationRequest;
 import org.apache.polaris.core.auth.AuthorizationState;
 import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
 import org.apache.polaris.core.auth.PolarisAuthorizer;
 import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.context.RealmContext;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
@@ -62,20 +60,15 @@ public class RangerPolarisAuthorizer implements PolarisAuthorizer {
 
   private final RangerEmbeddedAuthorizer authorizer;
   private final String serviceName;
-  private RealmContext realmContext;
-  private String realmConextIdentifier;
-  private final RealmConfig realmConfig;
+  private String realmContextIdentifier;
 
-  public RangerPolarisAuthorizer(
-      RangerEmbeddedAuthorizer authorizer, String serviceName, RealmConfig realmConfig) {
+  public RangerPolarisAuthorizer(RangerEmbeddedAuthorizer authorizer, String serviceName) {
     this.authorizer = authorizer;
     this.serviceName = serviceName;
-    this.realmConfig = realmConfig;
   }
 
-  public void setRealmContext(RealmContext aRealmContext) {
-    this.realmContext = aRealmContext;
-    this.realmConextIdentifier = aRealmContext.getRealmIdentifier();
+  public void setRealmContext(RealmContext realmContext) {
+    this.realmContextIdentifier = realmContext.getRealmIdentifier();
   }
 
   /**
@@ -161,9 +154,6 @@ public class RangerPolarisAuthorizer implements PolarisAuthorizer {
     }
 
     try {
-      AuthorizationPreConditions.checkCredentialRotationRequired(
-          polarisPrincipal, authzOp, realmConfig);
-
       if (!isAccessAuthorized(polarisPrincipal, authzOp, targets, secondaries)) {
         throw new ForbiddenException(
             RANGER_AUTH_FAILED_ERROR, polarisPrincipal.getName(), authzOp.name());
@@ -197,12 +187,12 @@ public class RangerPolarisAuthorizer implements PolarisAuthorizer {
       for (PolarisResolvedPathWrapper target : targets) {
         accessInfos.add(
             RangerUtils.toAccessInfo(
-                target, authzOp, semantics.targetPrivileges(), realmConextIdentifier));
+                target, authzOp, semantics.targetPrivileges(), realmContextIdentifier));
       }
     } else if (isTargetSpecified) {
       LOG.warn(
           "No privileges specified for target authorization. Ignoring target {}, op: {}, user: {}",
-          RangerUtils.toResourcePath(targets, realmConextIdentifier),
+          RangerUtils.toResourcePath(targets, realmContextIdentifier),
           authzOp.name(),
           principal.getName());
     }
@@ -217,12 +207,12 @@ public class RangerPolarisAuthorizer implements PolarisAuthorizer {
       for (PolarisResolvedPathWrapper secondary : secondaries) {
         accessInfos.add(
             RangerUtils.toAccessInfo(
-                secondary, authzOp, semantics.secondaryPrivileges(), realmConextIdentifier));
+                secondary, authzOp, semantics.secondaryPrivileges(), realmContextIdentifier));
       }
     } else if (isSecondarySpecified) {
       LOG.warn(
           "No privileges specified for secondary authorization. Ignoring secondaries {}, op: {}, user: {}",
-          RangerUtils.toResourcePath(secondaries, realmConextIdentifier),
+          RangerUtils.toResourcePath(secondaries, realmContextIdentifier),
           authzOp.name(),
           principal.getName());
     }
diff --git a/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerFactory.java b/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerFactory.java
index d1787cd994..2bdcbd4cd3 100644
--- a/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerFactory.java
+++ b/extensions/auth/ranger/src/main/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerFactory.java
@@ -39,14 +39,13 @@ public class RangerPolarisAuthorizerFactory implements PolarisAuthorizerFactory
   private static final String ERR_AUTHORIZER_FACTORY_NOT_INITIALIZED =
       "Ranger authorizer factory was not initialized successfully";
 
-  private final RangerPolarisAuthorizerConfig config;
-  private RangerEmbeddedAuthorizer authorizer;
-  private String serviceName;
+  private final RangerEmbeddedAuthorizer authorizer;
+  private final String serviceName;
+
   @Inject private RealmContext realmContext;
 
   @Inject
   RangerPolarisAuthorizerFactory(RangerPolarisAuthorizerConfig config) {
-    this.config = config;
     config.validate();
     LOG.info("Initializing RangerAuthorizer");
     try {
@@ -71,7 +70,7 @@ public class RangerPolarisAuthorizerFactory implements PolarisAuthorizerFactory
     }
 
     RangerPolarisAuthorizer polarisAuthorizer =
-        new RangerPolarisAuthorizer(authorizer, serviceName, realmConfig);
+        new RangerPolarisAuthorizer(authorizer, serviceName);
 
     if (realmContext != null) {
       polarisAuthorizer.setRealmContext(realmContext);
diff --git a/extensions/auth/ranger/src/test/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerTest.java b/extensions/auth/ranger/src/test/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerTest.java
index 3166b2f7f5..9118af8363 100644
--- a/extensions/auth/ranger/src/test/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerTest.java
+++ b/extensions/auth/ranger/src/test/java/org/apache/polaris/extension/auth/ranger/RangerPolarisAuthorizerTest.java
@@ -211,7 +211,7 @@ public class RangerPolarisAuthorizerTest {
   void authorizeUsesIntentResolvedTarget() throws Exception {
     RangerEmbeddedAuthorizer embeddedAuthorizer = mock(RangerEmbeddedAuthorizer.class);
     RangerPolarisAuthorizer authorizer =
-        new RangerPolarisAuthorizer(embeddedAuthorizer, "dev_polaris", createRealmConfig());
+        new RangerPolarisAuthorizer(embeddedAuthorizer, "dev_polaris");
     authorizer.setRealmContext(createRealmContext());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     PolarisResolvedPathWrapper tablePath =
@@ -264,7 +264,7 @@ public class RangerPolarisAuthorizerTest {
   void authorizeReturnsDenyDecisionWhenRangerDenies() throws Exception {
     RangerEmbeddedAuthorizer embeddedAuthorizer = mock(RangerEmbeddedAuthorizer.class);
     RangerPolarisAuthorizer authorizer =
-        new RangerPolarisAuthorizer(embeddedAuthorizer, "dev_polaris", createRealmConfig());
+        new RangerPolarisAuthorizer(embeddedAuthorizer, "dev_polaris");
     authorizer.setRealmContext(createRealmContext());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     PolarisResolvedPathWrapper catalogPath =
diff --git a/extensions/semantic-models/src/test/java/org/apache/polaris/service/catalog/semanticmodel/SemanticModelCatalogHandlerAuthzTest.java b/extensions/semantic-models/src/test/java/org/apache/polaris/service/catalog/semanticmodel/SemanticModelCatalogHandlerAuthzTest.java
index d7b6b0178a..d87989736c 100644
--- a/extensions/semantic-models/src/test/java/org/apache/polaris/service/catalog/semanticmodel/SemanticModelCatalogHandlerAuthzTest.java
+++ b/extensions/semantic-models/src/test/java/org/apache/polaris/service/catalog/semanticmodel/SemanticModelCatalogHandlerAuthzTest.java
@@ -420,7 +420,7 @@ class SemanticModelCatalogHandlerAuthzTest extends AbstractSemanticModelCatalogH
         .callContext(services.newCallContext())
         .resolutionManifestFactory(services.resolutionManifestFactory())
         .metaStoreManager(services.metaStoreManager())
-        .authorizer(new PolarisAuthorizerImpl(services.realmConfig()))
+        .authorizer(new PolarisAuthorizerImpl())
         .build();
   }
 }
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/auth/AuthorizationPreConditions.java b/polaris-core/src/main/java/org/apache/polaris/core/auth/AuthorizationPreConditions.java
deleted file mode 100644
index 6d1cddd566..0000000000
--- a/polaris-core/src/main/java/org/apache/polaris/core/auth/AuthorizationPreConditions.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.polaris.core.auth;
-
-import org.apache.iceberg.exceptions.ForbiddenException;
-import org.apache.polaris.core.config.FeatureConfiguration;
-import org.apache.polaris.core.config.RealmConfig;
-import org.apache.polaris.core.entity.PolarisEntityConstants;
-import org.apache.polaris.core.entity.PrincipalEntity;
-
-/**
- * Common pre-condition checks shared across authorizer implementations for credential-related
- * operations.
- */
-public final class AuthorizationPreConditions {
-
-  private AuthorizationPreConditions() {}
-
-  /**
-   * Checks whether the principal is required to rotate credentials before performing the requested
-   * operation. If the principal has the {@code PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE}
-   * property set, only {@link PolarisAuthorizableOperation#ROTATE_CREDENTIALS} is allowed.
-   *
-   * @param polarisPrincipal the principal attempting the operation
-   * @param authzOp the operation being attempted
-   * @param realmConfig the realm config, used to read the enforcement feature flag
-   * @throws ForbiddenException if the principal must rotate credentials first
-   */
-  public static void checkCredentialRotationRequired(
-      PolarisPrincipal polarisPrincipal,
-      PolarisAuthorizableOperation authzOp,
-      RealmConfig realmConfig) {
-    if (realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING)
-        && authzOp != PolarisAuthorizableOperation.ROTATE_CREDENTIALS
-        && mustRotateCredentials(polarisPrincipal)) {
-      throw new ForbiddenException(
-          "Principal '%s' is not authorized for op %s because it must rotate credentials first",
-          polarisPrincipal.getName(), authzOp);
-    }
-  }
-
-  private static boolean mustRotateCredentials(PolarisPrincipal principal) {
-    return principal
-        .getAttributes()
-        .getOptional(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY)
-        .map(PrincipalEntity::getInternalPropertiesAsMap)
-        .map(
-            map ->
-                map.containsKey(
-                    PolarisEntityConstants.PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE))
-        .orElse(false);
-  }
-}
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
index 24c9a34ad2..622b9b8b38 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
@@ -142,7 +142,6 @@ import org.apache.iceberg.exceptions.ForbiddenException;
 import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.AuthorizationIntentResolver.ResolvedIntent;
 import org.apache.polaris.core.auth.RbacOperationSemantics.ResolvedPathRooting;
-import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisEntityCore;
 import org.apache.polaris.core.entity.PolarisGrantRecord;
@@ -795,12 +794,6 @@ public class PolarisAuthorizerImpl implements PolarisAuthorizer {
         : EnumSet.of(privilege);
   }
 
-  private final RealmConfig realmConfig;
-
-  public PolarisAuthorizerImpl(RealmConfig realmConfig) {
-    this.realmConfig = realmConfig;
-  }
-
   @Override
   public void resolveAuthorizationInputs(
       @NonNull AuthorizationState authzState, @NonNull AuthorizationRequest request) {
@@ -872,8 +865,6 @@ public class PolarisAuthorizerImpl implements PolarisAuthorizer {
       @NonNull Set<PolarisBaseEntity> activatedEntities,
       @NonNull PolarisAuthorizableOperation authzOp,
       @NonNull ResolvedIntent resolvedIntent) {
-    AuthorizationPreConditions.checkCredentialRotationRequired(
-        polarisPrincipal, authzOp, realmConfig);
     boolean isRoot = getRootPrincipalName().equals(polarisPrincipal.getName());
     if (authzOp == PolarisAuthorizableOperation.RESET_CREDENTIALS) {
       if (!isRoot) {
diff --git a/polaris-core/src/test/java/org/apache/polaris/core/auth/AuthorizationPreConditionsTest.java b/polaris-core/src/test/java/org/apache/polaris/core/auth/AuthorizationPreConditionsTest.java
deleted file mode 100644
index 0ffda57fd4..0000000000
--- a/polaris-core/src/test/java/org/apache/polaris/core/auth/AuthorizationPreConditionsTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.polaris.core.auth;
-
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Set;
-import org.apache.iceberg.exceptions.ForbiddenException;
-import org.apache.polaris.core.collection.AttributeMap;
-import org.apache.polaris.core.collection.ImmutableAttributeMap;
-import org.apache.polaris.core.config.FeatureConfiguration;
-import org.apache.polaris.core.config.RealmConfig;
-import org.apache.polaris.core.entity.PrincipalEntity;
-import org.junit.jupiter.api.Test;
-
-public class AuthorizationPreConditionsTest {
-
-  private static final PolarisPrincipal PRINCIPAL =
-      PolarisPrincipal.of(
-          "alice",
-          ImmutableAttributeMap.builder()
-              .put(
-                  PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY,
-                  new PrincipalEntity.Builder()
-                      .setName("alice")
-                      .setCredentialRotationRequiredState()
-                      .build())
-              .build(),
-          Set.of("role"));
-
-  private static RealmConfig realmConfigWithEnforcement(boolean enforce) {
-    RealmConfig realmConfig = mock(RealmConfig.class);
-    when(realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
-        .thenReturn(enforce);
-    return realmConfig;
-  }
-
-  @Test
-  public void testFlagOff_noException() {
-    assertThatCode(
-            () ->
-                AuthorizationPreConditions.checkCredentialRotationRequired(
-                    PRINCIPAL,
-                    PolarisAuthorizableOperation.LIST_CATALOGS,
-                    realmConfigWithEnforcement(false)))
-        .doesNotThrowAnyException();
-  }
-
-  @Test
-  public void testFlagOn_rotateCredentialsOp_noException() {
-    assertThatCode(
-            () ->
-                AuthorizationPreConditions.checkCredentialRotationRequired(
-                    PRINCIPAL,
-                    PolarisAuthorizableOperation.ROTATE_CREDENTIALS,
-                    realmConfigWithEnforcement(true)))
-        .doesNotThrowAnyException();
-  }
-
-  @Test
-  public void testFlagOn_nonRotationOp_propertySet_throwsForbidden() {
-    assertThatThrownBy(
-            () ->
-                AuthorizationPreConditions.checkCredentialRotationRequired(
-                    PRINCIPAL,
-                    PolarisAuthorizableOperation.LIST_CATALOGS,
-                    realmConfigWithEnforcement(true)))
-        .isInstanceOf(ForbiddenException.class)
-        .hasMessageContaining("must rotate credentials");
-  }
-
-  @Test
-  public void testFlagOn_nonRotationOp_propertyNotSet_noException() {
-    PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role"));
-
-    assertThatCode(
-            () ->
-                AuthorizationPreConditions.checkCredentialRotationRequired(
-                    principal,
-                    PolarisAuthorizableOperation.LIST_CATALOGS,
-                    realmConfigWithEnforcement(true)))
-        .doesNotThrowAnyException();
-  }
-}
diff --git a/polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java b/polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java
index 2fb0290d83..103c36328b 100644
--- a/polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java
+++ b/polaris-core/src/test/java/org/apache/polaris/core/auth/PolarisAuthorizerImplTest.java
@@ -35,8 +35,6 @@ import java.util.Set;
 import org.apache.iceberg.exceptions.ForbiddenException;
 import org.apache.polaris.core.auth.AuthorizationIntentResolver.ResolvedIntent;
 import org.apache.polaris.core.collection.AttributeMap;
-import org.apache.polaris.core.config.FeatureConfiguration;
-import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.entity.PolarisEntity;
 import org.apache.polaris.core.entity.PolarisEntitySubType;
 import org.apache.polaris.core.entity.PolarisEntityType;
@@ -52,14 +50,6 @@ import org.mockito.ArgumentMatchers;
 
 public class PolarisAuthorizerImplTest {
 
-  private static RealmConfig realmConfig() {
-    RealmConfig realmConfig = mock(RealmConfig.class);
-    when(realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
-        .thenReturn(false);
-    return realmConfig;
-  }
-
   @ParameterizedTest
   @EnumSource(PolarisPrivilege.class)
   void subsumingPrivilegesOf(PolarisPrivilege privilege) {
@@ -74,7 +64,7 @@ public class PolarisAuthorizerImplTest {
 
   @Test
   void resolveAuthorizationInputsResolvesAll() {
-    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl(realmConfig());
+    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl();
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("role"));
@@ -95,7 +85,7 @@ public class PolarisAuthorizerImplTest {
   void authorizeUsesRootTargetForRootGrantRequestWithoutPrimaryTarget() {
     // Verify that new authorize SPI call without primary target uses root_container
     // for resolution and authorization
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper rootWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -138,7 +128,7 @@ public class PolarisAuthorizerImplTest {
   void authorizeUsesRootTargetForListCatalogsRequestWithoutPrimaryTarget() {
     // Verify that new authorize SPI call without primary target uses root_container
     // for resolution and authorization
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper rootWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -174,7 +164,7 @@ public class PolarisAuthorizerImplTest {
   void authorizeResolvesNamespaceTargetUsingCatalog() {
     // Verify authorize call that includes Catalog name in the PolarisSecurable
     // successfully resolves the correct namespace
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper namespaceWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -217,7 +207,7 @@ public class PolarisAuthorizerImplTest {
 
   @Test
   void authorizeSingleOperationMultiIntentRequestEvaluatesSequentially() {
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper firstCatalogWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -267,7 +257,7 @@ public class PolarisAuthorizerImplTest {
 
   @Test
   void authorizeUpdateTableMultiIntentRequestEvaluatesSequentially() {
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper tableWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -329,7 +319,7 @@ public class PolarisAuthorizerImplTest {
 
   @Test
   void authorizeReturnsDenyDecision() {
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfig()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
     AuthorizationState authzState = new AuthorizationState(manifest);
     PolarisResolvedPathWrapper catalogWrapper = mock(PolarisResolvedPathWrapper.class);
@@ -364,7 +354,7 @@ public class PolarisAuthorizerImplTest {
 
   @Test
   void authorizeLogsMissingPrivilegeDetailsServerSide() {
-    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl(realmConfigWithDefaults());
+    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl();
     PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("reader"));
     PolarisResolvedPathWrapper namespace = resolvedPath(namespaceEntity("ns1"));
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
@@ -401,7 +391,7 @@ public class PolarisAuthorizerImplTest {
     // CREATE_TABLE_DIRECT_WITH_WRITE_DELEGATION requires both TABLE_CREATE and TABLE_WRITE_DATA
     // on the target namespace. With no grants at all, both should be logged server-side but NOT
     // exposed in the client-facing exception.
-    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl(realmConfigWithDefaults());
+    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl();
     PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("reader"));
     PolarisResolvedPathWrapper namespace = resolvedPath(namespaceEntity("ns1"));
     PolarisResolutionManifest manifest = mock(PolarisResolutionManifest.class);
@@ -437,7 +427,7 @@ public class PolarisAuthorizerImplTest {
     // RENAME_TABLE: target privilege TABLE_DROP on the existing table; secondary privileges
     // TABLE_LIST and TABLE_CREATE on the destination namespace. Secondary details must NOT
     // appear in the client-facing exception.
-    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl(realmConfigWithDefaults());
+    PolarisAuthorizerImpl authorizer = new PolarisAuthorizerImpl();
     PolarisPrincipal principal = PolarisPrincipal.of("alice", AttributeMap.EMPTY, Set.of("reader"));
     PolarisResolvedPathWrapper srcTable = resolvedPath(tableEntity("src_t"));
     PolarisResolvedPathWrapper dstNamespace = resolvedPath(namespaceEntity("dst_ns"));
@@ -483,7 +473,7 @@ public class PolarisAuthorizerImplTest {
   void findMissingPrivilegesReturnsEmptyWhenNothingRequiredFails() {
     // When the authorizer would say "yes", the helper must return an empty list — this is the
     // invariant relied on by isAuthorized.
-    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl(realmConfigWithDefaults()));
+    PolarisAuthorizerImpl authorizer = spy(new PolarisAuthorizerImpl());
     PolarisResolvedPathWrapper namespace = resolvedPath(namespaceEntity("ns1"));
     // Stub hasTransitivePrivilege to always return true so we exercise the empty-result branch
     // of findMissingPrivileges without rebuilding a full grant graph.
@@ -542,16 +532,4 @@ public class PolarisAuthorizerImplTest {
         .setName(name)
         .build();
   }
-
-  private static RealmConfig realmConfigWithDefaults() {
-    // The credential-rotation-required gate auto-unboxes a Boolean from RealmConfig.getConfig;
-    // Mockito's default null answer would NPE before we ever reach the authorization logic.
-    // Returning false (the production default for the configuration flag) sends control through
-    // to findMissingPrivileges, which is what we want to exercise.
-    RealmConfig realmConfig = mock(RealmConfig.class);
-    when(realmConfig.getConfig(
-            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
-        .thenReturn(false);
-    return realmConfig;
-  }
 }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/auth/CredentialRotationFilter.java b/runtime/service/src/main/java/org/apache/polaris/service/auth/CredentialRotationFilter.java
new file mode 100644
index 0000000000..cda73b9318
--- /dev/null
+++ b/runtime/service/src/main/java/org/apache/polaris/service/auth/CredentialRotationFilter.java
@@ -0,0 +1,91 @@
+/*
+ * 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.polaris.service.auth;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.SecurityContext;
+import java.lang.reflect.Method;
+import org.apache.iceberg.exceptions.ForbiddenException;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.auth.PolarisPrincipalAttributes;
+import org.apache.polaris.core.config.FeatureConfiguration;
+import org.apache.polaris.core.config.RealmConfig;
+import org.apache.polaris.core.context.RealmContext;
+import org.apache.polaris.core.entity.PolarisEntityConstants;
+import org.apache.polaris.core.entity.PrincipalEntity;
+import org.apache.polaris.service.admin.api.PolarisPrincipalsApi;
+import org.apache.polaris.service.config.FilterPriorities;
+import org.jboss.resteasy.reactive.server.ServerRequestFilter;
+
+/**
+ * Rejects every request made by a principal that must rotate its credentials first, except the
+ * request that rotates them. The check is independent of the configured authorizer.
+ *
+ * <p>The check is only active when {@link
+ * FeatureConfiguration#ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING} is enabled.
+ */
+public class CredentialRotationFilter {
+
+  /** The generated resource method for the rotate-credentials endpoint. */
+  static final Method ROTATE_CREDENTIALS = rotateCredentialsMethod();
+
+  @Inject RealmConfig realmConfig;
+
+  @ServerRequestFilter(priority = FilterPriorities.CREDENTIAL_ROTATION_FILTER)
+  public void checkCredentialRotationRequired(
+      ContainerRequestContext requestContext, ResourceInfo resourceInfo) {
+    if (requestContext.getSecurityContext().getUserPrincipal() instanceof PolarisPrincipal principal
+        && mustRotateCredentials(principal)
+        && realmConfig.getConfig(
+            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING)
+        && !isRotateCredentials(resourceInfo)) {
+      throw new ForbiddenException(
+          "Principal '%s' is not authorized because it must rotate credentials first",
+          principal.getName());
+    }
+  }
+
+  private static boolean isRotateCredentials(ResourceInfo resourceInfo) {
+    return ROTATE_CREDENTIALS.equals(resourceInfo.getResourceMethod());
+  }
+
+  private static Method rotateCredentialsMethod() {
+    try {
+      // The method name is derived from the OpenAPI spec operationId
+      return PolarisPrincipalsApi.class.getMethod(
+          "rotateCredentials", String.class, RealmContext.class, SecurityContext.class);
+    } catch (NoSuchMethodException e) {
+      throw new IllegalStateException("Cannot find the rotate-credentials resource method", e);
+    }
+  }
+
+  private static boolean mustRotateCredentials(PolarisPrincipal principal) {
+    return principal
+        .getAttributes()
+        .getOptional(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY)
+        .map(PrincipalEntity::getInternalPropertiesAsMap)
+        .map(
+            map ->
+                map.containsKey(
+                    PolarisEntityConstants.PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE))
+        .orElse(false);
+  }
+}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultPolarisAuthorizerFactory.java b/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultPolarisAuthorizerFactory.java
index 7f11b9ce10..b1bece3ccb 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultPolarisAuthorizerFactory.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultPolarisAuthorizerFactory.java
@@ -32,6 +32,6 @@ class DefaultPolarisAuthorizerFactory implements PolarisAuthorizerFactory {
 
   @Override
   public PolarisAuthorizer create(RealmConfig realmConfig) {
-    return new PolarisAuthorizerImpl(realmConfig);
+    return new PolarisAuthorizerImpl();
   }
 }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/config/FilterPriorities.java b/runtime/service/src/main/java/org/apache/polaris/service/config/FilterPriorities.java
index 66414d1d40..fdd04997f2 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/config/FilterPriorities.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/config/FilterPriorities.java
@@ -21,10 +21,17 @@ package org.apache.polaris.service.config;
 import jakarta.ws.rs.Priorities;
 
 public final class FilterPriorities {
+
+  // Pre-Authentication filters
+
   public static final int REQUEST_ID_FILTER = Priorities.AUTHENTICATION - 101;
-  public static final int REALM_CONTEXT_FILTER = REQUEST_ID_FILTER + 1;
+  public static final int REALM_CONTEXT_FILTER = Priorities.AUTHENTICATION - 100;
+  public static final int MDC_FILTER = Priorities.AUTHENTICATION - 99;
+  public static final int TRACING_FILTER = Priorities.AUTHENTICATION - 98;
+  public static final int IDEMPOTENCY_KEY_FILTER = Priorities.AUTHENTICATION - 97;
+
+  // Post-Authentication filters
+
+  public static final int CREDENTIAL_ROTATION_FILTER = Priorities.AUTHORIZATION;
   public static final int RATE_LIMITER_FILTER = Priorities.USER;
-  public static final int MDC_FILTER = REALM_CONTEXT_FILTER + 1;
-  public static final int TRACING_FILTER = REALM_CONTEXT_FILTER + 2;
-  public static final int IDEMPOTENCY_KEY_FILTER = REALM_CONTEXT_FILTER + 3;
 }
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/admin/ManagementServiceTest.java b/runtime/service/src/test/java/org/apache/polaris/service/admin/ManagementServiceTest.java
index fde669bd08..05ea435a10 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/admin/ManagementServiceTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/admin/ManagementServiceTest.java
@@ -395,7 +395,7 @@ public class ManagementServiceTest {
         new UnsafeInMemorySecretsManager(),
         new DefaultServiceIdentityProvider(),
         principal,
-        new PolarisAuthorizerImpl(services.realmConfig()),
+        new PolarisAuthorizerImpl(),
         ReservedProperties.NONE,
         services.vendingMechanisms());
   }
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
index db0cc28c5d..438041f5c8 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAuthzTestBase.java
@@ -223,7 +223,7 @@ public abstract class PolarisAuthzTestBase {
     QuarkusMock.installMockForType(realmContext, RealmContext.class);
     polarisContext = callContext.getPolarisCallContext();
 
-    polarisAuthorizer = new PolarisAuthorizerImpl(realmConfig);
+    polarisAuthorizer = new PolarisAuthorizerImpl();
 
     PrincipalEntity rootPrincipal =
         metaStoreManager.findRootPrincipal(polarisContext).orElseThrow();
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/auth/CredentialRotationFilterTest.java b/runtime/service/src/test/java/org/apache/polaris/service/auth/CredentialRotationFilterTest.java
new file mode 100644
index 0000000000..963003478e
--- /dev/null
+++ b/runtime/service/src/test/java/org/apache/polaris/service/auth/CredentialRotationFilterTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.polaris.service.auth;
+
+import static org.apache.polaris.service.auth.CredentialRotationFilter.ROTATE_CREDENTIALS;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.SecurityContext;
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Set;
+import org.apache.iceberg.exceptions.ForbiddenException;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.auth.PolarisPrincipalAttributes;
+import org.apache.polaris.core.collection.AttributeMap;
+import org.apache.polaris.core.collection.ImmutableAttributeMap;
+import org.apache.polaris.core.config.FeatureConfiguration;
+import org.apache.polaris.core.config.RealmConfig;
+import org.apache.polaris.core.entity.PrincipalEntity;
+import org.apache.polaris.service.admin.api.PolarisPrincipalsApi;
+import org.junit.jupiter.api.Test;
+
+class CredentialRotationFilterTest {
+
+  private static final PolarisPrincipal MUST_ROTATE =
+      PolarisPrincipal.of(
+          "alice",
+          ImmutableAttributeMap.builder()
+              .put(
+                  PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY,
+                  new PrincipalEntity.Builder()
+                      .setName("alice")
+                      .setCredentialRotationRequiredState()
+                      .build())
+              .build(),
+          Set.of("role"));
+
+  private static final PolarisPrincipal REGULAR =
+      PolarisPrincipal.of("bob", AttributeMap.EMPTY, Set.of("role"));
+
+  @Test
+  void rejectsOtherEndpoints() {
+    assertThatThrownBy(() -> filter(true, MUST_ROTATE, listPrincipals()))
+        .isInstanceOf(ForbiddenException.class)
+        .hasMessageContaining("must rotate credentials first");
+  }
+
+  @Test
+  void allowsRotateCredentialsEndpoint() {
+    assertThatCode(() -> filter(true, MUST_ROTATE, ROTATE_CREDENTIALS)).doesNotThrowAnyException();
+  }
+
+  @Test
+  void allowsWhenEnforcementDisabled() {
+    assertThatCode(() -> filter(false, MUST_ROTATE, listPrincipals())).doesNotThrowAnyException();
+  }
+
+  @Test
+  void allowsPrincipalThatDoesNotNeedToRotate() {
+    assertThatCode(() -> filter(true, REGULAR, listPrincipals())).doesNotThrowAnyException();
+  }
+
+  @Test
+  void ignoresNonPolarisPrincipal() {
+    ContainerRequestContext requestContext = requestContext(mock(Principal.class));
+    assertThatCode(() -> newFilter(true).checkCredentialRotationRequired(requestContext, null))
+        .doesNotThrowAnyException();
+  }
+
+  @Test
+  void ignoresUnauthenticatedRequests() {
+    ContainerRequestContext requestContext = requestContext(null);
+    assertThatCode(() -> newFilter(true).checkCredentialRotationRequired(requestContext, null))
+        .doesNotThrowAnyException();
+  }
+
+  @Test
+  void doesNotInspectResourceWhenEnforcementDisabled() {
+    ContainerRequestContext requestContext = requestContext(MUST_ROTATE);
+    assertThatCode(() -> newFilter(false).checkCredentialRotationRequired(requestContext, null))
+        .doesNotThrowAnyException();
+  }
+
+  private static CredentialRotationFilter newFilter(boolean enforce) {
+    RealmConfig realmConfig = mock(RealmConfig.class);
+    when(realmConfig.getConfig(
+            FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING))
+        .thenReturn(enforce);
+    CredentialRotationFilter filter = new CredentialRotationFilter();
+    filter.realmConfig = realmConfig;
+    return filter;
+  }
+
+  private static Method listPrincipals() {
+    return Arrays.stream(PolarisPrincipalsApi.class.getMethods())
+        .filter(m -> m.getName().equals("listPrincipals"))
+        .findFirst()
+        .orElseThrow();
+  }
+
+  private static void filter(boolean enforce, PolarisPrincipal principal, Method method) {
+    ResourceInfo resourceInfo = mock(ResourceInfo.class);
+    when(resourceInfo.getResourceClass()).thenAnswer(i -> PolarisPrincipalsApi.class);
+    when(resourceInfo.getResourceMethod()).thenReturn(method);
+    newFilter(enforce).checkCredentialRotationRequired(requestContext(principal), resourceInfo);
+  }
+
+  private static ContainerRequestContext requestContext(Principal principal) {
+    SecurityContext securityContext = mock(SecurityContext.class);
+    when(securityContext.getUserPrincipal()).thenReturn(principal);
+    ContainerRequestContext requestContext = mock(ContainerRequestContext.class);
+    when(requestContext.getSecurityContext()).thenReturn(securityContext);
+    return requestContext;
+  }
+}
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
index 03081e2988..5989e6801d 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/AbstractPolarisGenericTableCatalogTest.java
@@ -169,7 +169,7 @@ public abstract class AbstractPolarisGenericTableCatalogTest {
             Set.of());
     polarisPrincipalHolder.set(authenticatedRoot);
 
-    PolarisAuthorizer authorizer = new PolarisAuthorizerImpl(realmConfig);
+    PolarisAuthorizer authorizer = new PolarisAuthorizerImpl();
     ReservedProperties reservedProperties = ReservedProperties.NONE;
 
     adminService =
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
index 7e5259a1f5..6bf5e2868b 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
@@ -23,14 +23,12 @@ import static org.apache.polaris.service.catalog.AccessDelegationMode.VENDED_CRE
 import com.google.common.collect.ImmutableMap;
 import jakarta.inject.Inject;
 import java.time.Duration;
-import java.time.Instant;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
-import java.util.function.Supplier;
 import java.util.stream.Stream;
 import org.apache.iceberg.CatalogProperties;
 import org.apache.iceberg.CatalogUtil;
@@ -67,7 +65,6 @@ import org.apache.iceberg.view.ImmutableSQLViewRepresentation;
 import org.apache.iceberg.view.ImmutableViewVersion;
 import org.apache.polaris.core.admin.model.CreateCatalogRequest;
 import org.apache.polaris.core.admin.model.FileStorageConfigInfo;
-import org.apache.polaris.core.admin.model.PrincipalWithCredentialsCredentials;
 import org.apache.polaris.core.admin.model.StorageConfigInfo;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.auth.PolarisPrincipalAttributes;
@@ -80,8 +77,6 @@ import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.CatalogEntity;
 import org.apache.polaris.core.entity.CatalogRoleEntity;
 import org.apache.polaris.core.entity.PolarisPrivilege;
-import org.apache.polaris.core.entity.PrincipalEntity;
-import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult;
 import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
 import org.apache.polaris.service.admin.PolarisAuthzTestBase;
 import org.apache.polaris.service.admin.PolarisAuthzTestsFactory;
@@ -172,141 +167,6 @@ public abstract class AbstractIcebergCatalogHandlerAuthzTest extends PolarisAuth
         .createTests();
   }
 
-  @TestFactory
-  Stream<DynamicNode> testInsufficientPermissionsPriorToSecretRotation() {
-    String principalName = "all_the_powers";
-    CreatePrincipalResult newPrincipal =
-        metaStoreManager.createPrincipal(
-            callContext.getPolarisCallContext(),
-            new PrincipalEntity.Builder()
-                .setName(principalName)
-                .setCreateTimestamp(Instant.now().toEpochMilli())
-                .setCredentialRotationRequiredState()
-                .build());
-    newRootAdminService().assignPrincipalRole(principalName, PRINCIPAL_ROLE1);
-    newRootAdminService().assignPrincipalRole(principalName, PRINCIPAL_ROLE2);
-
-    PrincipalEntity principalEntity = newPrincipal.getPrincipal();
-    PolarisPrincipal authenticatedPrincipal =
-        PolarisPrincipal.of(
-            principalEntity.getName(),
-            ImmutableAttributeMap.builder()
-                .put(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY, principalEntity)
-                .build(),
-            Set.of(PRINCIPAL_ROLE1, PRINCIPAL_ROLE2));
-
-    Supplier<IcebergCatalogHandler> handler =
-        () ->
-            ImmutableIcebergCatalogHandler.builder()
-                .from(
-                    icebergCatalogHandlerFactory.createHandler(
-                        CATALOG_NAME, authenticatedPrincipal))
-                .build();
-
-    // a variety of actions are all disallowed because the principal's credentials must be rotated
-
-    Namespace ns3 = Namespace.of("ns3");
-    Stream<DynamicNode> beforeRotationTests =
-        Stream.of(
-                authzTestsBuilder("listNamespaces (before rotation)")
-                    .action(() -> handler.get().listNamespaces(Namespace.of(), null, null))
-                    .principalName(principalName)
-                    .shouldFailWithAnyPrivilege()
-                    .createTests(),
-                authzTestsBuilder("createNamespace (before rotation)")
-                    .action(
-                        () ->
-                            handler
-                                .get()
-                                .createNamespace(
-                                    CreateNamespaceRequest.builder().withNamespace(ns3).build()))
-                    .principalName(principalName)
-                    .shouldFailWithAnyPrivilege()
-                    .createTests(),
-                authzTestsBuilder("listTables (before rotation)")
-                    .action(() -> handler.get().listTables(NS1, null, null))
-                    .principalName(principalName)
-                    .shouldFailWithAnyPrivilege()
-                    .createTests())
-            .flatMap(s -> s);
-
-    // Rotate credentials and create refreshed wrapper
-    PrincipalWithCredentialsCredentials credentials =
-        new PrincipalWithCredentialsCredentials(
-            newPrincipal.getPrincipalSecrets().getPrincipalClientId(),
-            newPrincipal.getPrincipalSecrets().getMainSecret());
-    PrincipalEntity refreshPrincipal =
-        rotateAndRefreshPrincipal(
-            metaStoreManager, principalName, credentials, callContext.getPolarisCallContext());
-    PolarisPrincipal authenticatedPrincipal1 =
-        PolarisPrincipal.of(
-            refreshPrincipal.getName(),
-            ImmutableAttributeMap.builder()
-                .put(PolarisPrincipalAttributes.PRINCIPAL_ENTITY_ATTRIBUTE_KEY, refreshPrincipal)
-                .build(),
-            Set.of(PRINCIPAL_ROLE1, PRINCIPAL_ROLE2));
-
-    Supplier<IcebergCatalogHandler> refreshedWrapper =
-        () ->
-            ImmutableIcebergCatalogHandler.builder()
-                .from(
-                    icebergCatalogHandlerFactory.createHandler(
-                        CATALOG_NAME, authenticatedPrincipal1))
-                .polarisPrincipal(authenticatedPrincipal1)
-                .build();
-
-    // Grant NAMESPACE_DROP to CATALOG_ROLE2 so cleanup can work
-    assertSuccess(
-        newRootAdminService()
-            .grantPrivilegeOnCatalogToRole(
-                CATALOG_NAME, CATALOG_ROLE2, PolarisPrivilege.NAMESPACE_DROP));
-
-    // Tests after credential rotation - actions should succeed with proper privileges
-    Stream<DynamicNode> afterRotationTests =
-        Stream.of(
-                authzTestsBuilder("listNamespaces (after rotation)")
-                    .action(() -> refreshedWrapper.get().listNamespaces(Namespace.of(), null, null))
-                    .principalName(principalName)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_LIST)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_CREATE)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_READ_PROPERTIES)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_WRITE_PROPERTIES)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_FULL_METADATA)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_CONTENT)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_METADATA)
-                    .createTests(),
-                authzTestsBuilder("createNamespace (after rotation)")
-                    .action(
-                        () ->
-                            refreshedWrapper
-                                .get()
-                                .createNamespace(
-                                    CreateNamespaceRequest.builder().withNamespace(ns3).build()))
-                    .cleanupAction(() -> newHandler(Set.of(PRINCIPAL_ROLE2)).dropNamespace(ns3))
-                    .principalName(principalName)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_CREATE)
-                    .shouldPassWith(PolarisPrivilege.NAMESPACE_FULL_METADATA)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_CONTENT)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_METADATA)
-                    .createTests(),
-                authzTestsBuilder("listTables (after rotation)")
-                    .action(() -> refreshedWrapper.get().listTables(NS1, null, null))
-                    .principalName(principalName)
-                    .shouldPassWith(PolarisPrivilege.TABLE_LIST)
-                    .shouldPassWith(PolarisPrivilege.TABLE_CREATE)
-                    .shouldPassWith(PolarisPrivilege.TABLE_READ_PROPERTIES)
-                    .shouldPassWith(PolarisPrivilege.TABLE_WRITE_PROPERTIES)
-                    .shouldPassWith(PolarisPrivilege.TABLE_READ_DATA)
-                    .shouldPassWith(PolarisPrivilege.TABLE_WRITE_DATA)
-                    .shouldPassWith(PolarisPrivilege.TABLE_FULL_METADATA)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_CONTENT)
-                    .shouldPassWith(PolarisPrivilege.CATALOG_MANAGE_METADATA)
-                    .createTests())
-            .flatMap(s -> s);
-
-    return Stream.concat(beforeRotationTests, afterRotationTests);
-  }
-
   @Test
   public void testListNamespacesCatalogLevelWithPrincipalRoleActivation() {
     // Grant catalog-level privilege to CATALOG_ROLE1
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogViewTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogViewTest.java
index c1bd488a91..9370bc2f18 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogViewTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractLocalIcebergCatalogViewTest.java
@@ -178,7 +178,7 @@ public abstract class AbstractLocalIcebergCatalogViewTest
                 .build(),
             Set.of());
 
-    authorizer = new PolarisAuthorizerImpl(realmConfig);
+    authorizer = new PolarisAuthorizerImpl();
     reservedProperties = ReservedProperties.NONE;
 
     newAdminService()
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
index aea0b8c235..491a84b824 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/AbstractPolicyCatalogTest.java
@@ -194,7 +194,7 @@ public abstract class AbstractPolicyCatalogTest {
             Set.of());
     polarisPrincipalHolder.set(authenticatedRoot);
 
-    PolarisAuthorizer authorizer = new PolarisAuthorizerImpl(realmConfig);
+    PolarisAuthorizer authorizer = new PolarisAuthorizerImpl();
     ReservedProperties reservedProperties = ReservedProperties.NONE;
 
     adminService =