From a6c28e79b90b647c606b78660e68f82fea6b6be9 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Tue, 1 Sep 2026 15:37:07 +0300 Subject: [PATCH] Allow an underscore in the mobile app callback url scheme Mobile apps derive the scheme from their package name, which may contain an underscore. It cannot introduce an authority, so accepting it keeps the rule as strong as the RFC 3986 grammar. --- .../security/auth/oauth2/CallbackUrlSchemeValidator.java | 3 ++- .../security/auth/oauth2/CallbackUrlSchemeValidatorTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidator.java b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidator.java index a75af8dd5e..bdb4a6d4ab 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidator.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidator.java @@ -26,7 +26,8 @@ import java.util.regex.Pattern; @Slf4j public class CallbackUrlSchemeValidator { - private static final Pattern SCHEME_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9+.-]*"); + // RFC 3986 scheme grammar, plus '_': mobile apps derive the scheme from their package name, which may contain one + private static final Pattern SCHEME_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9+.\\-_]*"); private static final Set FORBIDDEN_SCHEMES = Set.of("http", "https", "javascript", "data", "file", "vbscript"); private static final int MAX_LOGGED_LENGTH = 128; diff --git a/application/src/test/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidatorTest.java b/application/src/test/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidatorTest.java index 2ba11324ce..aa2eeb7982 100644 --- a/application/src/test/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidatorTest.java +++ b/application/src/test/java/org/thingsboard/server/service/security/auth/oauth2/CallbackUrlSchemeValidatorTest.java @@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class CallbackUrlSchemeValidatorTest { @ParameterizedTest - @ValueSource(strings = {"tbmobile", "tb-mobile.app1", "TbMobile+1"}) + @ValueSource(strings = {"tbmobile", "tb-mobile.app1", "TbMobile+1", "org.mycompany.myapp.auth", "com.my_company.app.auth"}) public void testMobileAppSchemeIsValid(String callbackUrlScheme) { assertThat(CallbackUrlSchemeValidator.isValid(callbackUrlScheme)).isTrue(); }