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

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


The following commit(s) were added to refs/heads/main by this push:
     new f8d7523b0d [#12095] feat(auth): parse X-Gravitino-Active-Roles into 
the request path (#12096)
f8d7523b0d is described below

commit f8d7523b0d9a7fabdef6ee65c683b3484f997eda
Author: Bharath Krishna <[email protected]>
AuthorDate: Wed Jul 22 22:23:23 2026 -0700

    [#12095] feat(auth): parse X-Gravitino-Active-Roles into the request path 
(#12096)
    
    ### What changes were proposed in this pull request?
    
    Parse the `X-Gravitino-Active-Roles` header and carry the declared
    active roles on the `UserPrincipal`, so the narrowing from #11967 takes
    effect.
    
    - `UserPrincipal`: carry an immutable `ActiveRoles` (defaults to `ALL`)
    alongside the existing per-request `accessToken`; `withActiveRoles()`
    attaches the parsed value.
    - `AuthenticationFilter`: parse the header after authentication and
    attach it to the principal. A malformed value maps to `400` (the Lance
    filter maps the same).
    - `AuthorizationRequestContext`: read `activeRoles` from the current
    `UserPrincipal`, so every authorization decision uses the request's
    declaration.
    
    Membership validation (`403` for an unheld role) is metalake-scoped and
    follows in a later PR. Part of #11965.
    
    ### Why are the changes needed?
    
    #11967 added the narrowing enforcement, but nothing populated the active
    roles, so it never activated. This wires the header through the request
    path.
    
    ### Does this PR introduce any user-facing change?
    
    Yes, additive and backward compatible. A request may send
    `X-Gravitino-Active-Roles: <role>[,<role>] | ALL | NONE` to narrow the
    roles used for authorization; a malformed value returns `400`. An absent
    header behaves as before (`ALL`).
    
    ### How was this patch tested?
    
    New unit tests for `UserPrincipal.withActiveRoles`, the filter's header
    parsing (valid / absent / malformed → `400`), and
    `AuthorizationRequestContext` reading the active roles from the
    principal. Verified with the module `test` and `spotlessCheck` tasks for
    `core`, `server-common`, and `lance-rest-server`.
---
 .../java/org/apache/gravitino/UserPrincipal.java   | 32 +++++++++
 .../authorization/AuthorizationRequestContext.java | 16 ++++-
 .../TestAuthorizationRequestContext.java           | 17 +++++
 .../iceberg/service/IcebergExceptionMapper.java    |  1 +
 .../service/TestIcebergAuthenticationFilter.java   | 20 ++++++
 .../lance/service/LanceAuthenticationFilter.java   |  7 ++
 .../authentication/AuthenticationFilter.java       | 20 +++++-
 .../authentication/TestAuthenticationFilter.java   | 80 ++++++++++++++++++++++
 8 files changed, 189 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/apache/gravitino/UserPrincipal.java 
b/core/src/main/java/org/apache/gravitino/UserPrincipal.java
index e3980720eb..cb3885a017 100644
--- a/core/src/main/java/org/apache/gravitino/UserPrincipal.java
+++ b/core/src/main/java/org/apache/gravitino/UserPrincipal.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import javax.annotation.Nullable;
+import org.apache.gravitino.auth.ActiveRoles;
 
 /**
  * A simple implementation of Principal that holds a username, optional group 
membership, and
@@ -38,6 +39,7 @@ public class UserPrincipal implements Principal {
   private final String username;
   private final List<UserGroup> groups;
   @Nullable private final String accessToken;
+  private final ActiveRoles activeRoles;
 
   /**
    * Constructs a UserPrincipal with the given username.
@@ -80,6 +82,14 @@ public class UserPrincipal implements Principal {
    */
   public UserPrincipal(
       final String username, final List<UserGroup> groups, @Nullable final 
String accessToken) {
+    this(username, groups, accessToken, ActiveRoles.all());
+  }
+
+  private UserPrincipal(
+      final String username,
+      final List<UserGroup> groups,
+      @Nullable final String accessToken,
+      final ActiveRoles activeRoles) {
     Preconditions.checkArgument(username != null, "UserPrincipal must have the 
username");
     this.username = username;
     this.groups =
@@ -87,6 +97,7 @@ public class UserPrincipal implements Principal {
             ? Collections.unmodifiableList(new ArrayList<>(groups))
             : Collections.emptyList();
     this.accessToken = accessToken;
+    this.activeRoles = Objects.requireNonNull(activeRoles, "activeRoles must 
not be null");
   }
 
   /**
@@ -113,6 +124,27 @@ public class UserPrincipal implements Principal {
     return groups;
   }
 
+  /**
+   * Returns the roles the caller declared active for this request (role 
assumption); {@link
+   * ActiveRoles#all()} when none was declared.
+   *
+   * @return the active-role declaration
+   */
+  public ActiveRoles getActiveRoles() {
+    return activeRoles;
+  }
+
+  /**
+   * Returns a copy of this principal carrying the given active-role 
declaration, keeping the same
+   * identity.
+   *
+   * @param activeRoles the active-role declaration to attach
+   * @return a new principal with the same identity and the given active roles
+   */
+  public UserPrincipal withActiveRoles(final ActiveRoles activeRoles) {
+    return new UserPrincipal(username, groups, accessToken, activeRoles);
+  }
+
   @Override
   public int hashCode() {
     return Objects.hash(username, groups);
diff --git 
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationRequestContext.java
 
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationRequestContext.java
index d676f101b5..dc30ae58d0 100644
--- 
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationRequestContext.java
+++ 
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationRequestContext.java
@@ -30,11 +30,13 @@ import lombok.AllArgsConstructor;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.UserPrincipal;
 import org.apache.gravitino.auth.ActiveRoles;
 import org.apache.gravitino.storage.relational.po.auth.GroupUpdatedAt;
 import org.apache.gravitino.storage.relational.po.auth.OwnerInfo;
 import org.apache.gravitino.storage.relational.po.auth.RoleUpdatedAt;
 import org.apache.gravitino.storage.relational.po.auth.UserUpdatedAt;
+import org.apache.gravitino.utils.PrincipalUtils;
 
 /**
  * Per-HTTP-request scratchpad shared by {@link GravitinoAuthorizer} calls. A 
fresh instance is
@@ -86,10 +88,18 @@ public class AuthorizationRequestContext {
   private volatile String originalAuthorizationExpression;
 
   /**
-   * The roles the caller has declared active for this request (role 
assumption). Defaults to {@link
-   * ActiveRoles#all()}, which evaluates every role the caller holds (no 
narrowing).
+   * The roles the caller has declared active for this request (role 
assumption). Read from the
+   * current {@link UserPrincipal}; defaults to {@link ActiveRoles#all()} (no 
narrowing) when the
+   * caller declared none.
    */
-  private volatile ActiveRoles activeRoles = ActiveRoles.all();
+  private volatile ActiveRoles activeRoles = currentPrincipalActiveRoles();
+
+  private static ActiveRoles currentPrincipalActiveRoles() {
+    Principal principal = PrincipalUtils.getCurrentPrincipal();
+    return principal instanceof UserPrincipal
+        ? ((UserPrincipal) principal).getActiveRoles()
+        : ActiveRoles.all();
+  }
 
   /**
    * check allow
diff --git 
a/core/src/test/java/org/apache/gravitino/authorization/TestAuthorizationRequestContext.java
 
b/core/src/test/java/org/apache/gravitino/authorization/TestAuthorizationRequestContext.java
index e4ef672bcc..313d490eac 100644
--- 
a/core/src/test/java/org/apache/gravitino/authorization/TestAuthorizationRequestContext.java
+++ 
b/core/src/test/java/org/apache/gravitino/authorization/TestAuthorizationRequestContext.java
@@ -23,13 +23,17 @@ import static 
org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.util.Arrays;
 import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.gravitino.UserPrincipal;
+import org.apache.gravitino.auth.ActiveRoles;
 import org.apache.gravitino.storage.relational.po.auth.GroupUpdatedAt;
 import org.apache.gravitino.storage.relational.po.auth.OwnerInfo;
 import org.apache.gravitino.storage.relational.po.auth.UserUpdatedAt;
+import org.apache.gravitino.utils.PrincipalUtils;
 import org.junit.jupiter.api.Test;
 
 public class TestAuthorizationRequestContext {
@@ -327,4 +331,17 @@ public class TestAuthorizationRequestContext {
     context.setOriginalAuthorizationExpression("OWNER && HAS_PRIVILEGE");
     assertEquals("OWNER && HAS_PRIVILEGE", 
context.getOriginalAuthorizationExpression());
   }
+
+  @Test
+  public void testActiveRolesInitializedFromPrincipal() throws Exception {
+    // With no active roles on the current principal, a new context defaults 
to ALL (no narrowing).
+    assertEquals(ActiveRoles.all(), new 
AuthorizationRequestContext().getActiveRoles());
+
+    // A new context picks up the active roles carried by the current 
UserPrincipal.
+    ActiveRoles named = ActiveRoles.of(Arrays.asList("analyst"));
+    UserPrincipal principal = new 
UserPrincipal("tester").withActiveRoles(named);
+    ActiveRoles seen =
+        PrincipalUtils.doAs(principal, () -> new 
AuthorizationRequestContext().getActiveRoles());
+    assertEquals(named, seen);
+  }
 }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergExceptionMapper.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergExceptionMapper.java
index daaf1db3aa..dd00b9c4b6 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergExceptionMapper.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/IcebergExceptionMapper.java
@@ -57,6 +57,7 @@ public class IcebergExceptionMapper implements 
ExceptionMapper<Exception> {
   private static final Map<Class<? extends Exception>, Integer> 
EXCEPTION_ERROR_CODES =
       ImmutableMap.<Class<? extends Exception>, Integer>builder()
           .put(IllegalArgumentException.class, 400)
+          .put(BadRequestException.class, 400)
           .put(ValidationException.class, 400)
           .put(IllegalNameIdentifierException.class, 400)
           .put(NamespaceNotEmptyException.class, 409)
diff --git 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergAuthenticationFilter.java
 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergAuthenticationFilter.java
index 8f73cdf4d0..4dbd5e1292 100644
--- 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergAuthenticationFilter.java
+++ 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/TestIcebergAuthenticationFilter.java
@@ -28,6 +28,7 @@ import java.io.StringWriter;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.gravitino.auth.IllegalActiveRolesException;
 import org.apache.gravitino.exceptions.TokenExpiredException;
 import org.apache.gravitino.exceptions.UnauthorizedException;
 import org.apache.iceberg.rest.responses.ErrorResponse;
@@ -107,6 +108,25 @@ public class TestIcebergAuthenticationFilter {
     Assertions.assertEquals("The provided credentials did not support", 
errorResponse.message());
   }
 
+  @Test
+  public void testIllegalActiveRolesReturnsBadRequest() throws Exception {
+    IcebergAuthenticationFilter filter = new IcebergAuthenticationFilter();
+
+    HttpServletResponse response = mock(HttpServletResponse.class);
+    StringWriter stringWriter = new StringWriter();
+    PrintWriter printWriter = new PrintWriter(stringWriter);
+    when(response.getWriter()).thenReturn(printWriter);
+
+    filter.sendAuthErrorResponse(
+        response, new IllegalActiveRolesException("malformed active-roles 
header"));
+
+    verify(response).setStatus(HttpServletResponse.SC_BAD_REQUEST);
+
+    printWriter.flush();
+    ErrorResponse errorResponse = MAPPER.readValue(stringWriter.toString(), 
ErrorResponse.class);
+    Assertions.assertEquals(400, errorResponse.code());
+  }
+
   @Test
   public void testInternalServerErrorReturnsJson() throws Exception {
     IcebergAuthenticationFilter filter = new IcebergAuthenticationFilter();
diff --git 
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/LanceAuthenticationFilter.java
 
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/LanceAuthenticationFilter.java
index 51aea85524..45cebe3852 100644
--- 
a/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/LanceAuthenticationFilter.java
+++ 
b/lance/lance-rest-server/src/main/java/org/apache/gravitino/lance/service/LanceAuthenticationFilter.java
@@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.gravitino.auth.IllegalActiveRolesException;
 import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.UnauthorizedException;
 import org.apache.gravitino.server.authentication.AuthenticationFilter;
@@ -66,6 +67,12 @@ public class LanceAuthenticationFilter extends 
AuthenticationFilter {
       if (message == null || message.isEmpty()) {
         message = "Access denied";
       }
+    } else if (exception instanceof IllegalActiveRolesException) {
+      status = HttpServletResponse.SC_BAD_REQUEST;
+      message = exception.getMessage();
+      if (message == null || message.isEmpty()) {
+        message = "Bad request";
+      }
     } else {
       status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
       LOG.error("Authentication failure", exception);
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
index e8b100af22..8fa379922b 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
@@ -32,7 +32,11 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.gravitino.UserPrincipal;
+import org.apache.gravitino.auth.ActiveRoles;
+import org.apache.gravitino.auth.ActiveRolesParser;
 import org.apache.gravitino.auth.AuthConstants;
+import org.apache.gravitino.auth.IllegalActiveRolesException;
 import org.apache.gravitino.dto.responses.ErrorResponse;
 import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.UnauthorizedException;
@@ -92,7 +96,6 @@ public class AuthenticationFilter implements Filter {
         if (authenticator.supportsToken(authData) && 
authenticator.isDataFromToken()) {
           principal = authenticator.authenticateToken(authData);
           if (principal != null) {
-            
request.setAttribute(AuthConstants.AUTHENTICATED_PRINCIPAL_ATTRIBUTE_NAME, 
principal);
             break;
           }
         }
@@ -100,6 +103,16 @@ public class AuthenticationFilter implements Filter {
       if (principal == null) {
         throw new UnauthorizedException("The provided credentials did not 
support");
       }
+      // Role assumption: parse the header (syntactic only; malformed -> 400) 
and, only when
+      // narrowed, attach the roles to the principal. Membership 403 is 
checked later.
+      ActiveRoles activeRoles =
+          
ActiveRolesParser.parse(req.getHeader(AuthConstants.X_GRAVITINO_ACTIVE_ROLES_HEADER));
+      if (!activeRoles.isAll() && principal instanceof UserPrincipal) {
+        principal = ((UserPrincipal) principal).withActiveRoles(activeRoles);
+      }
+      // Publish the finalized principal (already carrying any narrowed roles) 
so downstream
+      // re-binds from the attribute (e.g. Utils.doAs) see the same identity 
and roles.
+      
request.setAttribute(AuthConstants.AUTHENTICATED_PRINCIPAL_ATTRIBUTE_NAME, 
principal);
       PrincipalUtils.doAs(
           principal,
           () -> {
@@ -146,6 +159,11 @@ public class AuthenticationFilter implements Filter {
     } else if (exception instanceof ForbiddenException) {
       httpStatus = HttpServletResponse.SC_FORBIDDEN;
       errorResponse = ErrorResponse.forbidden(exception.getMessage(), 
exception);
+    } else if (exception instanceof IllegalActiveRolesException) {
+      httpStatus = HttpServletResponse.SC_BAD_REQUEST;
+      errorResponse =
+          ErrorResponse.illegalArguments(
+              exception.getClass().getSimpleName(), exception.getMessage(), 
exception);
     } else {
       httpStatus = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
       errorResponse = ErrorResponse.internalError(exception.getMessage(), 
exception);
diff --git 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
index fa8a01bc40..8af1b58fed 100644
--- 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
+++ 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
@@ -32,18 +32,23 @@ import com.google.common.collect.Lists;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.security.Principal;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Vector;
+import java.util.concurrent.atomic.AtomicReference;
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.gravitino.UserPrincipal;
+import org.apache.gravitino.auth.ActiveRoles;
 import org.apache.gravitino.auth.AuthConstants;
 import org.apache.gravitino.dto.responses.ErrorResponse;
 import org.apache.gravitino.exceptions.ForbiddenException;
 import org.apache.gravitino.exceptions.UnauthorizedException;
 import org.apache.gravitino.server.web.ObjectMapperProvider;
+import org.apache.gravitino.utils.PrincipalUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -66,6 +71,81 @@ public class TestAuthenticationFilter {
     verify(mockResponse, never()).sendError(anyInt(), anyString());
   }
 
+  @Test
+  public void testDoFilterSetsActiveRolesFromHeader() throws ServletException, 
IOException {
+    Authenticator authenticator = mock(Authenticator.class);
+    AuthenticationFilter filter = new 
AuthenticationFilter(Lists.newArrayList(authenticator));
+    HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+    when(mockRequest.getHeaders(AuthConstants.HTTP_HEADER_AUTHORIZATION))
+        .thenReturn(new 
Vector<>(Collections.singletonList("user")).elements());
+    when(mockRequest.getHeader(AuthConstants.X_GRAVITINO_ACTIVE_ROLES_HEADER))
+        .thenReturn("analyst,reader");
+    when(authenticator.supportsToken(any())).thenReturn(true);
+    when(authenticator.isDataFromToken()).thenReturn(true);
+    when(authenticator.authenticateToken(any())).thenReturn(new 
UserPrincipal("user"));
+
+    // The active roles must be visible on the principal to the downstream 
chain (where
+    // authorization runs).
+    AtomicReference<Principal> seenDuringChain = new AtomicReference<>();
+    FilterChain capturingChain =
+        (req, resp) -> 
seenDuringChain.set(PrincipalUtils.getCurrentPrincipal());
+    filter.doFilter(mockRequest, mockResponse, capturingChain);
+
+    Assertions.assertInstanceOf(UserPrincipal.class, seenDuringChain.get());
+    Assertions.assertEquals(
+        ActiveRoles.of(Arrays.asList("analyst", "reader")),
+        ((UserPrincipal) seenDuringChain.get()).getActiveRoles());
+  }
+
+  @Test
+  public void testDoFilterDefaultsToAllWhenHeaderAbsent() throws 
ServletException, IOException {
+    Authenticator authenticator = mock(Authenticator.class);
+    AuthenticationFilter filter = new 
AuthenticationFilter(Lists.newArrayList(authenticator));
+    HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+    when(mockRequest.getHeaders(AuthConstants.HTTP_HEADER_AUTHORIZATION))
+        .thenReturn(new 
Vector<>(Collections.singletonList("user")).elements());
+    when(authenticator.supportsToken(any())).thenReturn(true);
+    when(authenticator.isDataFromToken()).thenReturn(true);
+    when(authenticator.authenticateToken(any())).thenReturn(new 
UserPrincipal("user"));
+
+    AtomicReference<Principal> seenDuringChain = new AtomicReference<>();
+    FilterChain capturingChain =
+        (req, resp) -> 
seenDuringChain.set(PrincipalUtils.getCurrentPrincipal());
+    filter.doFilter(mockRequest, mockResponse, capturingChain);
+
+    // No header means today's behavior: every role the caller holds is active.
+    Assertions.assertInstanceOf(UserPrincipal.class, seenDuringChain.get());
+    Assertions.assertEquals(
+        ActiveRoles.all(), ((UserPrincipal) 
seenDuringChain.get()).getActiveRoles());
+  }
+
+  @Test
+  public void testDoFilterRejectsMalformedActiveRolesHeader() throws 
ServletException, IOException {
+    Authenticator authenticator = mock(Authenticator.class);
+    AuthenticationFilter filter = new 
AuthenticationFilter(Lists.newArrayList(authenticator));
+    FilterChain mockChain = mock(FilterChain.class);
+    HttpServletRequest mockRequest = mock(HttpServletRequest.class);
+    HttpServletResponse mockResponse = mock(HttpServletResponse.class);
+    StringWriter stringWriter = new StringWriter();
+    PrintWriter printWriter = new PrintWriter(stringWriter);
+    when(mockResponse.getWriter()).thenReturn(printWriter);
+    when(mockRequest.getHeaders(AuthConstants.HTTP_HEADER_AUTHORIZATION))
+        .thenReturn(new 
Vector<>(Collections.singletonList("user")).elements());
+    // A reserved keyword combined with a role name is syntactically invalid.
+    when(mockRequest.getHeader(AuthConstants.X_GRAVITINO_ACTIVE_ROLES_HEADER))
+        .thenReturn("ALL,analyst");
+    when(authenticator.supportsToken(any())).thenReturn(true);
+    when(authenticator.isDataFromToken()).thenReturn(true);
+    when(authenticator.authenticateToken(any())).thenReturn(new 
UserPrincipal("user"));
+
+    filter.doFilter(mockRequest, mockResponse, mockChain);
+
+    verify(mockResponse).setStatus(HttpServletResponse.SC_BAD_REQUEST);
+    verify(mockChain, never()).doFilter(any(), any());
+  }
+
   @Test
   public void testDoFilterWithException() throws ServletException, IOException 
{
     Authenticator authenticator = mock(Authenticator.class);

Reply via email to