This is an automated email from the ASF dual-hosted git repository. imbajin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/hugegraph-toolchain.git
commit dbd72fa0b5ff92d83133613dfd776d1d70147bed Author: dark <[email protected]> AuthorDate: Sat Aug 29 23:11:31 2026 +0800 fix(hubble): limit legacy password retention - retain credentials only for the 1.7 Basic fallback - avoid plaintext passwords in modern token sessions - cover modern and legacy login behavior --- .../hugegraph/controller/auth/LoginController.java | 18 ++++++++++--- .../apache/hugegraph/unit/AuthSecurityTest.java | 30 +++++++++++++++++++++- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/hugegraph-hubble/hubble-be/src/main/java/org/apache/hugegraph/controller/auth/LoginController.java b/hugegraph-hubble/hubble-be/src/main/java/org/apache/hugegraph/controller/auth/LoginController.java index 955909cf4..3cdcf81be 100644 --- a/hugegraph-hubble/hubble-be/src/main/java/org/apache/hugegraph/controller/auth/LoginController.java +++ b/hugegraph-hubble/hubble-be/src/main/java/org/apache/hugegraph/controller/auth/LoginController.java @@ -87,13 +87,21 @@ public class LoginController extends BaseController { try { LoginResult result = this.authenticate(login, pdEnabled, address); Object user; + boolean requiresBasicGremlinAuth; if (!pdEnabled) { user = currentUser(login.name()); + try (HugeClient client = + this.createLoginTokenClient(result.token())) { + requiresBasicGremlinAuth = + client.requiresBasicGremlinAuth(); + } } else { try (HugeClient client = this.createLoginTokenClient(result.token())) { client.assignGraph(PDHugeClientFactory.DEFAULT_GRAPHSPACE, null); + requiresBasicGremlinAuth = + client.requiresBasicGremlinAuth(); UserEntity entity = this.userService.getpersonal( client, login.name()); user = entity; @@ -107,10 +115,12 @@ public class LoginController extends BaseController { // HugeGraph 1.7's Gremlin HTTP channel only accepts Basic auth. // Keep the credential server-side for the session lifetime so // graph queries can use the same identity as REST requests. - this.setSession(Constant.PASSWORD_KEY, login.password()); - this.setSession(Constant.PASSWORD_EXPIRE_AT_KEY, - System.currentTimeMillis() + - TOKEN_EXPIRE_SECONDS * 1000L); + if (requiresBasicGremlinAuth) { + this.setSession(Constant.PASSWORD_KEY, login.password()); + this.setSession(Constant.PASSWORD_EXPIRE_AT_KEY, + System.currentTimeMillis() + + TOKEN_EXPIRE_SECONDS * 1000L); + } return user; } catch (Throwable e) { this.clearAuthSession(); diff --git a/hugegraph-hubble/hubble-be/src/test/java/org/apache/hugegraph/unit/AuthSecurityTest.java b/hugegraph-hubble/hubble-be/src/test/java/org/apache/hugegraph/unit/AuthSecurityTest.java index 86b837b5e..cd3d8f759 100644 --- a/hugegraph-hubble/hubble-be/src/test/java/org/apache/hugegraph/unit/AuthSecurityTest.java +++ b/hugegraph-hubble/hubble-be/src/test/java/org/apache/hugegraph/unit/AuthSecurityTest.java @@ -825,6 +825,7 @@ public class AuthSecurityTest { RequestContextHolder.setRequestAttributes( new ServletRequestAttributes(request)); TestLoginController controller = new TestLoginController(); + controller.basicGremlinAuth = true; HugeConfig config = Mockito.mock(HugeConfig.class); Mockito.when(config.get(HubbleOptions.PD_ENABLED)).thenReturn(false); setField(controller, "config", config); @@ -846,6 +847,29 @@ public class AuthSecurityTest { System.currentTimeMillis()); } + @Test + public void testModernLoginDoesNotRetainPassword() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes( + new ServletRequestAttributes(request)); + TestLoginController controller = new TestLoginController(); + HugeConfig config = Mockito.mock(HugeConfig.class); + Mockito.when(config.get(HubbleOptions.PD_ENABLED)).thenReturn(false); + setField(controller, "config", config); + Login login = new Login(); + login.name("admin"); + login.password("pa"); + + controller.login(login); + + Assert.assertEquals("server-token", request.getSession().getAttribute( + Constant.TOKEN_KEY)); + Assert.assertNull(request.getSession().getAttribute( + Constant.PASSWORD_KEY)); + Assert.assertNull(request.getSession().getAttribute( + Constant.PASSWORD_EXPIRE_AT_KEY)); + } + @Test public void testAuthContextUsesCurrentSessionIdentity() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); @@ -1033,6 +1057,7 @@ public class AuthSecurityTest { private HugeClient userClient; private String validationToken; private LoginAttemptGuard attemptGuard; + private boolean basicGremlinAuth; private TestLoginController() { this.attemptGuard = Mockito.mock(LoginAttemptGuard.class); @@ -1080,7 +1105,10 @@ public class AuthSecurityTest { @Override protected HugeClient createLoginTokenClient(String token) { if (this.userClient == null) { - return super.createLoginTokenClient(token); + HugeClient client = Mockito.mock(HugeClient.class); + Mockito.when(client.requiresBasicGremlinAuth()) + .thenReturn(this.basicGremlinAuth); + return client; } this.validationToken = token; return this.userClient;
