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

haonan pushed a commit to branch fix_openid
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 0d754c97a4971dd119aa4dbb9799194b61d02281
Author: HTHou <[email protected]>
AuthorDate: Tue Mar 17 10:02:50 2026 +0800

    Reject expired OpenID tokens and add regression test
---
 iotdb-core/node-commons/pom.xml                    |  10 ++
 .../commons/auth/authorizer/OpenIdAuthorizer.java  |   4 +-
 .../auth/authorizer/OpenIdAuthorizerTest.java      | 113 +++++++++++++++++++++
 3 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/iotdb-core/node-commons/pom.xml b/iotdb-core/node-commons/pom.xml
index 24f33d0de8b..9cae757055c 100644
--- a/iotdb-core/node-commons/pom.xml
+++ b/iotdb-core/node-commons/pom.xml
@@ -149,6 +149,16 @@
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>com.nimbusds</groupId>
             <artifactId>oauth2-oidc-sdk</artifactId>
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
index ee66ee5bced..f5f74a87b39 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
@@ -55,6 +55,7 @@ import java.util.UUID;
 public class OpenIdAuthorizer extends BasicAuthorizer {
 
   private static final Logger logger = 
LoggerFactory.getLogger(OpenIdAuthorizer.class);
+  private static final long MAX_CLOCK_SKEW_SECONDS = 300;
   public static final String IOTDB_ADMIN_ROLE_NAME = "iotdb_admin";
   public static final String OPENID_USER_PREFIX = "openid-";
 
@@ -194,8 +195,7 @@ public class OpenIdAuthorizer extends BasicAuthorizer {
 
   private Claims validateToken(String token) {
     return Jwts.parser()
-        // Basically ignore the Expiration Date, if there is any???
-        .clockSkewSeconds(Long.MAX_VALUE / 1000)
+        .clockSkewSeconds(MAX_CLOCK_SKEW_SECONDS)
         .verifyWith(providerKey)
         .build()
         .parseSignedClaims(token)
diff --git 
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizerTest.java
 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizerTest.java
new file mode 100644
index 00000000000..f41645998fe
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizerTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.iotdb.commons.auth.authorizer;
+
+import org.apache.iotdb.commons.conf.CommonConfig;
+import org.apache.iotdb.commons.conf.CommonDescriptor;
+
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import io.jsonwebtoken.Jwts;
+import net.minidev.json.JSONObject;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPublicKey;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+
+public class OpenIdAuthorizerTest {
+
+  private final CommonConfig config = 
CommonDescriptor.getInstance().getConfig();
+
+  private String originalUserFolder;
+  private String originalRoleFolder;
+  private Path baseDir;
+
+  @Before
+  public void setUp() throws IOException {
+    originalUserFolder = config.getUserFolder();
+    originalRoleFolder = config.getRoleFolder();
+
+    baseDir = Files.createTempDirectory("openid-authorizer-test-");
+    
config.setUserFolder(Files.createDirectories(baseDir.resolve("users")).toString());
+    
config.setRoleFolder(Files.createDirectories(baseDir.resolve("roles")).toString());
+  }
+
+  @After
+  public void tearDown() throws IOException {
+    config.setUserFolder(originalUserFolder);
+    config.setRoleFolder(originalRoleFolder);
+
+    if (baseDir != null) {
+      try (java.util.stream.Stream<Path> stream = Files.walk(baseDir)) {
+        stream.sorted(Comparator.reverseOrder()).forEach(this::deleteIfExists);
+      }
+    }
+  }
+
+  @Test
+  public void testExpiredTokenRejectedByLoginAndIsAdmin() throws Exception {
+    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+    keyPairGenerator.initialize(2048);
+    KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+    JSONObject jwk =
+        new JSONObject(
+            new RSAKey.Builder((RSAPublicKey) keyPair.getPublic())
+                .privateKey(keyPair.getPrivate())
+                .keyUse(KeyUse.SIGNATURE)
+                .keyID("expired-token-test-key")
+                .build()
+                .toJSONObject());
+
+    OpenIdAuthorizer authorizer = new OpenIdAuthorizer(jwk);
+    String expiredToken =
+        Jwts.builder()
+            .subject("attacker")
+            .expiration(Date.from(Instant.now().minusSeconds(3600)))
+            .claim(
+                "realm_access",
+                Collections.singletonMap(
+                    "roles", 
Collections.singletonList(OpenIdAuthorizer.IOTDB_ADMIN_ROLE_NAME)))
+            .signWith(keyPair.getPrivate(), Jwts.SIG.RS256)
+            .compact();
+
+    Assert.assertFalse(authorizer.login(expiredToken, "", false));
+    Assert.assertFalse(authorizer.isAdmin(expiredToken));
+  }
+
+  private void deleteIfExists(Path path) {
+    try {
+      Files.deleteIfExists(path);
+    } catch (IOException e) {
+      throw new RuntimeException("Failed to delete test path " + path, e);
+    }
+  }
+}

Reply via email to