This is an automated email from the ASF dual-hosted git repository.
dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new fcf0c98c34 fix: JWT plugin throws ArrayIndexOutOfBoundsException on
malformed Authorization header (#6450)
fcf0c98c34 is described below
commit fcf0c98c34a22891eddeebbb0dfee99c27524c31
Author: wy471x <[email protected]>
AuthorDate: Fri Jul 31 17:43:47 2026 +0800
fix: JWT plugin throws ArrayIndexOutOfBoundsException on malformed
Authorization header (#6450)
Use strict startsWith("Bearer ") check instead of contains("Bearer") and
handle empty tokens gracefully instead of accessing split[1] directly.
Co-authored-by: Claude Opus 4.7 <[email protected]>
Co-authored-by: aias00 <[email protected]>
Co-authored-by: xiaoyu <[email protected]>
Co-authored-by: Liming Deng <[email protected]>
---
.../org/apache/shenyu/plugin/jwt/JwtPlugin.java | 16 +++---
.../apache/shenyu/plugin/jwt/JwtPluginTest.java | 62 ++++++++++++++++++++++
2 files changed, 71 insertions(+), 7 deletions(-)
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/JwtPlugin.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/JwtPlugin.java
index 66847f6d2d..fff40be284 100644
---
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/JwtPlugin.java
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/main/java/org/apache/shenyu/plugin/jwt/JwtPlugin.java
@@ -98,19 +98,21 @@ public class JwtPlugin extends AbstractShenyuPlugin {
* @return the authorization after processing
*/
private String compatible(final String token, final String authorization) {
- String finalAuthorization;
if (StringUtils.isNotEmpty(token)) {
- finalAuthorization = token;
- } else if (StringUtils.isNotEmpty(authorization)) {
- finalAuthorization = authorization;
- } else {
+ return token;
+ }
+ if (StringUtils.isEmpty(authorization)) {
return null;
}
- return isAuth2(finalAuthorization) ? finalAuthorization.split(" ")[1]
: finalAuthorization;
+ if (isAuth2(authorization)) {
+ String jwtToken =
authorization.substring(AUTH2_TOKEN.length()).trim();
+ return StringUtils.isEmpty(jwtToken) ? null : jwtToken;
+ }
+ return authorization;
}
private boolean isAuth2(final String authorization) {
- return authorization.contains(AUTH2_TOKEN);
+ return authorization.startsWith(AUTH2_TOKEN + " ");
}
/**
diff --git
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/JwtPluginTest.java
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/JwtPluginTest.java
index 3c2daf4261..21e5a8d547 100644
---
a/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/JwtPluginTest.java
+++
b/shenyu-plugin/shenyu-plugin-security/shenyu-plugin-jwt/src/test/java/org/apache/shenyu/plugin/jwt/JwtPluginTest.java
@@ -46,6 +46,7 @@ import java.util.Map;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -133,6 +134,67 @@ public final class JwtPluginTest {
Assertions.assertEquals(PluginEnum.JWT.getCode(), result);
}
+ @Test
+ public void testBearerWithoutToken() {
+ ServerWebExchange exchange =
MockServerWebExchange.from(MockServerHttpRequest
+ .get("localhost")
+ .header("Authorization", "Bearer")
+ .build());
+
+ Mono<Void> mono = jwtPluginUnderTest.doExecute(exchange, chain,
selectorData, ruleData);
+ StepVerifier.create(mono).expectSubscription().verifyComplete();
+ verify(chain, never()).execute(any());
+ }
+
+ @Test
+ public void testAuthorizationNotBearerPrefix() {
+ ServerWebExchange exchange =
MockServerWebExchange.from(MockServerHttpRequest
+ .get("localhost")
+ .header("Authorization", "fooBearerbar")
+ .build());
+
+ Mono<Void> mono = jwtPluginUnderTest.doExecute(exchange, chain,
selectorData, ruleData);
+ StepVerifier.create(mono).expectSubscription().verifyComplete();
+ verify(chain, never()).execute(any());
+ }
+
+ @Test
+ public void testBearerWithWhitespaceOnlyToken() {
+ ServerWebExchange exchange =
MockServerWebExchange.from(MockServerHttpRequest
+ .get("localhost")
+ .header("Authorization", "Bearer ")
+ .build());
+
+ Mono<Void> mono = jwtPluginUnderTest.doExecute(exchange, chain,
selectorData, ruleData);
+ StepVerifier.create(mono).expectSubscription().verifyComplete();
+ verify(chain, never()).execute(any());
+ }
+
+ @Test
+ public void testValidBearerAuthorization() {
+
ruleData.setHandle("{\"converter\":[{\"jwtVal\":\"userId\",\"headerVal\":\"id\"}]}");
+ jwtPluginDataHandlerUnderTest.handlerRule(ruleData);
+ when(chain.execute(any())).thenReturn(Mono.empty());
+
+ final String secreteKey = "shenyu-test-shenyu-test-shenyu-test";
+ Map<String, Object> map = ImmutableMap.<String,
Object>builder().put("userId", 1).build();
+ String jwtToken = Jwts.builder()
+ .claims(map)
+ .issuedAt(new Date(1636371125000L))
+ .expiration(new Date(new Date().getTime() + 10000L))
+
.signWith(Keys.hmacShaKeyFor(secreteKey.getBytes(StandardCharsets.UTF_8)))
+ .compact();
+
+ ServerWebExchange exchange =
MockServerWebExchange.from(MockServerHttpRequest
+ .get("localhost")
+ .header("Authorization", "Bearer " + jwtToken)
+ .build());
+
+ Mono<Void> mono = jwtPluginUnderTest.doExecute(exchange, chain,
selectorData, ruleData);
+ StepVerifier.create(mono).expectSubscription().verifyComplete();
+ verify(chain).execute(any());
+ }
+
private void initContext() {
ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
when(context.getBean(ShenyuResult.class)).thenReturn(new
DefaultShenyuResult());