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

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git


The following commit(s) were added to refs/heads/master by this push:
     new a0e591ad0b JAMES-4195 Validate in introspection that OIDC tokens are 
active (#3139)
a0e591ad0b is described below

commit a0e591ad0b864c5781e1b45c97486de82ab13962
Author: Benoit TELLIER <[email protected]>
AuthorDate: Thu Aug 27 10:03:45 2026 +0700

    JAMES-4195 Validate in introspection that OIDC tokens are active (#3139)
    
    Credit: MopMonk AI [email protected]
---
 .../contract/OidcAuthenticationContract.java       | 26 ++++++++++++++++++++++
 server/protocols/jwt/pom.xml                       |  5 +++++
 .../james/jwt/oidc/OidcEndpointsInfoResolver.java  |  4 ++++
 3 files changed, 35 insertions(+)

diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/OidcAuthenticationContract.java
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/OidcAuthenticationContract.java
index 9d94666729..8438a8d354 100644
--- 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/OidcAuthenticationContract.java
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/OidcAuthenticationContract.java
@@ -253,6 +253,32 @@ public abstract class OidcAuthenticationContract {
             .statusCode(SC_UNAUTHORIZED);
     }
 
+    @Tag(CategoryTags.BASIC_FEATURE)
+    @Test
+    void shouldRejectRevokedToken() {
+        // A revoked token: userinfo still answers, but introspection reports 
the token as inactive (RFC 7662)
+        mockUserInfo(BOB().asString());
+        mockJsonResponse(INTROSPECT_TOKEN_URI_PATH, """
+            {
+              "exp": %d,
+              "scope": "openid email profile",
+              "client_id": "james",
+              "active": false,
+              "aud": "%s",
+              "sub": "james-user",
+              "sid": "%s",
+              "iss": "https://sso.example.com";
+            }""".formatted(TOKEN_EXPIRATION_TIME, primaryAudience(), SID), 
SC_OK);
+
+        given()
+            .headers(getHeadersWith(authHeader))
+            .body(ECHO_REQUEST_OBJECT())
+        .when()
+            .post()
+        .then()
+            .statusCode(SC_UNAUTHORIZED);
+    }
+
     @Tag(CategoryTags.BASIC_FEATURE)
     @Test
     void shouldRejectBadAudience() {
diff --git a/server/protocols/jwt/pom.xml b/server/protocols/jwt/pom.xml
index bf9a8eb452..294bc9877b 100644
--- a/server/protocols/jwt/pom.xml
+++ b/server/protocols/jwt/pom.xml
@@ -48,6 +48,11 @@
             <groupId>${james.groupId}</groupId>
             <artifactId>metrics-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>metrics-tests</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
diff --git 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/oidc/OidcEndpointsInfoResolver.java
 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/oidc/OidcEndpointsInfoResolver.java
index fe539686a0..7a3d56c34e 100644
--- 
a/server/protocols/jwt/src/main/java/org/apache/james/jwt/oidc/OidcEndpointsInfoResolver.java
+++ 
b/server/protocols/jwt/src/main/java/org/apache/james/jwt/oidc/OidcEndpointsInfoResolver.java
@@ -78,6 +78,10 @@ public class OidcEndpointsInfoResolver implements 
TokenInfoResolver {
                 UserinfoResponse userInfo = tokenInfos.getT1();
                 TokenIntrospectionResponse introspectInfo = tokenInfos.getT2();
 
+                if (!introspectInfo.active()) {
+                    return Mono.error(new TokenIntrospectionException("Invalid 
OIDC token: the token is not active"));
+                }
+
                 Username sub = 
Username.of(userInfo.claimByPropertyName(oidcClaim)
                     .orElseThrow(() -> new UserInfoCheckException("Invalid 
OIDC token: userinfo needs to include " + oidcClaim + " claim")));
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to