This is an automated email from the ASF dual-hosted git repository. vgalaxies pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git
The following commit(s) were added to refs/heads/master by this push: new 8c1ee710d feat(server): LoginAPI support token_expire field (#2754) 8c1ee710d is described below commit 8c1ee710d6f7fae26cade37dcf4968b422b108d6 Author: John <sp...@apache.org> AuthorDate: Mon May 5 11:49:12 2025 +0800 feat(server): LoginAPI support token_expire field (#2754) Co-authored-by: imbajin <j...@apache.org> --- .../org/apache/hugegraph/api/auth/LoginAPI.java | 5 +- .../apache/hugegraph/auth/HugeGraphAuthProxy.java | 193 +++++++++++---------- .../org/apache/hugegraph/auth/AuthManager.java | 2 + .../apache/hugegraph/auth/StandardAuthManager.java | 21 ++- .../java/org/apache/hugegraph/core/AuthTest.java | 138 +++++++-------- 5 files changed, 188 insertions(+), 171 deletions(-) diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/LoginAPI.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/LoginAPI.java index 50bf1a78d..5e1bdb636 100644 --- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/LoginAPI.java +++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/auth/LoginAPI.java @@ -70,7 +70,8 @@ public class LoginAPI extends API { checkCreatingBody(jsonLogin); try { - String token = manager.authManager().loginUser(jsonLogin.name, jsonLogin.password); + String token = manager.authManager() + .loginUser(jsonLogin.name, jsonLogin.password, jsonLogin.expire); HugeGraph g = graph(manager, graph); return manager.serializer(g).writeMap(ImmutableMap.of("token", token)); } catch (AuthenticationException e) { @@ -131,6 +132,8 @@ public class LoginAPI extends API { private String name; @JsonProperty("user_password") private String password; + @JsonProperty("token_expire") + private long expire; @Override public void checkCreate(boolean isBatch) { diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java index 63d391279..383504e80 100644 --- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java +++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java @@ -110,15 +110,16 @@ import jakarta.ws.rs.NotAuthorizedException; public final class HugeGraphAuthProxy implements HugeGraph { + private static final Logger LOG = Log.logger(HugeGraphAuthProxy.class); + private static final ThreadLocal<Context> CONTEXTS = new InheritableThreadLocal<>(); + static { HugeGraph.registerTraversalStrategies(HugeGraphAuthProxy.class); } - private static final Logger LOG = Log.logger(HugeGraphAuthProxy.class); private final Cache<Id, UserWithRole> usersRoleCache; private final Cache<Id, RateLimiter> auditLimiters; private final double auditLogMaxRate; - private final HugeGraph hugegraph; private final TaskSchedulerProxy taskScheduler; private final AuthManagerProxy authManager; @@ -141,6 +142,40 @@ public final class HugeGraphAuthProxy implements HugeGraph { LOG.info("Audit log rate limit is {}/s", this.auditLogMaxRate); } + static Context setContext(Context context) { + Context old = CONTEXTS.get(); + CONTEXTS.set(context); + return old; + } + + static void resetContext() { + CONTEXTS.remove(); + } + + private static Context getContext() { + // Return task context first + String taskContext = TaskManager.getContext(); + User user = User.fromJson(taskContext); + if (user != null) { + return new Context(user); + } + + return CONTEXTS.get(); + } + + private static String getContextString() { + Context context = getContext(); + if (context == null) { + return null; + } + return context.user().toJson(); + } + + static void logUser(User user, String path) { + LOG.info("User '{}' login from client [{}] with path '{}'", + user.username(), user.client(), path); + } + @Override public HugeGraph hugegraph() { this.verifyAdminPermission(); @@ -1016,6 +1051,61 @@ public final class HugeGraphAuthProxy implements HugeGraph { return result; } + static class Context { + + private static final Context ADMIN = new Context(User.ADMIN); + + private final User user; + + public Context(User user) { + E.checkNotNull(user, "user"); + this.user = user; + } + + public static Context admin() { + return ADMIN; + } + + public User user() { + return this.user; + } + } + + static class ContextTask implements Runnable { + + private final Runnable runner; + private final Context context; + + public ContextTask(Runnable runner) { + this.context = getContext(); + this.runner = runner; + } + + @Override + public void run() { + setContext(this.context); + try { + this.runner.run(); + } finally { + resetContext(); + } + } + } + + public static class ContextThreadPoolExecutor extends ThreadPoolExecutor { + + public ContextThreadPoolExecutor(int corePoolSize, int maxPoolSize, + ThreadFactory threadFactory) { + super(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), threadFactory); + } + + @Override + public void execute(Runnable command) { + super.execute(new ContextTask(command)); + } + } + class TaskSchedulerProxy implements TaskScheduler { private final TaskScheduler taskScheduler; @@ -1622,8 +1712,14 @@ public final class HugeGraphAuthProxy implements HugeGraph { @Override public String loginUser(String username, String password) { + return this.loginUser(username, password, -1L); + } + + // TODO: the expire haven't been implemented yet + @Override + public String loginUser(String username, String password, long expire) { try { - return this.authManager.loginUser(username, password); + return this.authManager.loginUser(username, password, expire); } catch (AuthenticationException e) { throw new NotAuthorizedException(e.getMessage(), e); } @@ -1841,95 +1937,4 @@ public final class HugeGraphAuthProxy implements HugeGraph { return this.origin.toString(); } } - - private static final ThreadLocal<Context> CONTEXTS = new InheritableThreadLocal<>(); - - protected static Context setContext(Context context) { - Context old = CONTEXTS.get(); - CONTEXTS.set(context); - return old; - } - - protected static void resetContext() { - CONTEXTS.remove(); - } - - protected static Context getContext() { - // Return task context first - String taskContext = TaskManager.getContext(); - User user = User.fromJson(taskContext); - if (user != null) { - return new Context(user); - } - - return CONTEXTS.get(); - } - - protected static String getContextString() { - Context context = getContext(); - if (context == null) { - return null; - } - return context.user().toJson(); - } - - protected static void logUser(User user, String path) { - LOG.info("User '{}' login from client [{}] with path '{}'", - user.username(), user.client(), path); - } - - static class Context { - - private static final Context ADMIN = new Context(User.ADMIN); - - private final User user; - - public Context(User user) { - E.checkNotNull(user, "user"); - this.user = user; - } - - public User user() { - return this.user; - } - - public static Context admin() { - return ADMIN; - } - } - - static class ContextTask implements Runnable { - - private final Runnable runner; - private final Context context; - - public ContextTask(Runnable runner) { - this.context = getContext(); - this.runner = runner; - } - - @Override - public void run() { - setContext(this.context); - try { - this.runner.run(); - } finally { - resetContext(); - } - } - } - - public static class ContextThreadPoolExecutor extends ThreadPoolExecutor { - - public ContextThreadPoolExecutor(int corePoolSize, int maxPoolSize, - ThreadFactory threadFactory) { - super(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>(), threadFactory); - } - - @Override - public void execute(Runnable command) { - super.execute(new ContextTask(command)); - } - } } diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java index 51c72fba4..a2c76d395 100644 --- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java +++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/AuthManager.java @@ -121,6 +121,8 @@ public interface AuthManager { String loginUser(String username, String password) throws AuthenticationException; + String loginUser(String username, String password, long expire) throws AuthenticationException; + void logoutUser(String token); UserWithRole validateUser(String username, String password); diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java index 103c58afc..1ec2711d7 100644 --- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java +++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/auth/StandardAuthManager.java @@ -114,6 +114,13 @@ public class StandardAuthManager implements AuthManager { this.ipWhiteListEnabled = false; } + /** + * Maybe can define an proxy class to choose forward or call local + */ + public static boolean isLocal(AuthManager authManager) { + return authManager instanceof StandardAuthManager; + } + private <V> Cache<Id, V> cache(String prefix, long capacity, long expiredTime) { String name = prefix + "-" + this.graph.name(); @@ -636,6 +643,13 @@ public class StandardAuthManager implements AuthManager { @Override public String loginUser(String username, String password) throws AuthenticationException { + return this.loginUser(username, password, -1L); + } + + // TODO: the expire haven't been implemented yet + @Override + public String loginUser(String username, String password, long expire) + throws AuthenticationException { HugeUser user = this.matchUser(username, password); if (user == null) { String msg = "Incorrect username or password"; @@ -717,13 +731,6 @@ public class StandardAuthManager implements AuthManager { this.ipWhiteListEnabled = status; } - /** - * Maybe can define an proxy class to choose forward or call local - */ - public static boolean isLocal(AuthManager authManager) { - return authManager instanceof StandardAuthManager; - } - public <R> R commit(Callable<R> callable) { this.groups.autoCommit(false); this.access.autoCommit(false); diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java index 1db7af924..60bfdace8 100644 --- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java +++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java @@ -55,6 +55,63 @@ import com.google.common.collect.ImmutableSet; public class AuthTest extends BaseCoreTest { + private static Id makeProjectAndAddGraph(HugeGraph graph, + String projectName, + String graphName) { + HugeProject project = makeProject(projectName, ""); + AuthManager authManager = graph.authManager(); + Id projectId = authManager.createProject(project); + projectId = authManager.projectAddGraphs(projectId, + ImmutableSet.of(graphName)); + Assert.assertNotNull(projectId); + return projectId; + } + + private static HugeProject makeProject(String name, String desc) { + HugeProject project = new HugeProject(name, desc); + project.creator("admin"); + return project; + } + + private static HugeUser makeUser(String name, String password) { + HugeUser user = new HugeUser(name); + user.password(password); + user.creator("admin"); + return user; + } + + private static HugeGroup makeGroup(String name) { + HugeGroup group = new HugeGroup(name); + group.creator("admin"); + return group; + } + + private static HugeTarget makeTarget(String name, String url) { + HugeTarget target = new HugeTarget(name, url); + target.creator("admin"); + return target; + } + + private static HugeTarget makeTarget(String name, String graph, String url, + List<HugeResource> ress) { + HugeTarget target = new HugeTarget(name, graph, url, ress); + target.creator("admin"); + return target; + } + + private static HugeBelong makeBelong(Id user, Id group) { + HugeBelong belong = new HugeBelong(user, group); + belong.creator("admin"); + return belong; + } + + private static HugeAccess makeAccess(Id group, Id target, + HugePermission permission) { + HugeAccess access = new HugeAccess(group, target, permission); + access.creator("admin"); + return access; + } + @After public void clearAll() { HugeGraph graph = graph(); @@ -301,7 +358,7 @@ public class AuthTest extends BaseCoreTest { group = authManager.getGroup(id); Assert.assertEquals("group1", group.name()); - Assert.assertEquals(null, group.description()); + Assert.assertNull(group.description()); Assert.assertEquals(group.create(), group.update()); Assert.assertEquals(ImmutableMap.of("group_name", "group1", @@ -632,7 +689,7 @@ public class AuthTest extends BaseCoreTest { HugeBelong belong = authManager.getBelong(id1); Assert.assertEquals(user, belong.source()); Assert.assertEquals(group1, belong.target()); - Assert.assertEquals(null, belong.description()); + Assert.assertNull(belong.description()); Assert.assertEquals(belong.create(), belong.update()); Map<String, Object> expected = new HashMap<>(); @@ -647,7 +704,7 @@ public class AuthTest extends BaseCoreTest { belong = authManager.getBelong(id2); Assert.assertEquals(user, belong.source()); Assert.assertEquals(group2, belong.target()); - Assert.assertEquals(null, belong.description()); + Assert.assertNull(belong.description()); Assert.assertEquals(belong.create(), belong.update()); expected = new HashMap<>(); @@ -1321,11 +1378,11 @@ public class AuthTest extends BaseCoreTest { authManager.createUser(user); // Login - authManager.loginUser("test", "pass"); + authManager.loginUser("test", "pass", 10080L); // Invalid username or password Assert.assertThrows(AuthenticationException.class, () -> { - authManager.loginUser("huge", "graph"); + authManager.loginUser("huge", "graph", 10080L); }, e -> { Assert.assertContains("Incorrect username or password", e.getMessage()); }); @@ -1338,7 +1395,7 @@ public class AuthTest extends BaseCoreTest { HugeUser user = makeUser("test", StringEncoding.hashPassword("pass")); Id userId = authManager.createUser(user); - String token = authManager.loginUser("test", "pass"); + String token = authManager.loginUser("test", "pass", 10080L); UserWithRole userWithRole; userWithRole = authManager.validateUser(token); @@ -1375,7 +1432,7 @@ public class AuthTest extends BaseCoreTest { Id userId = authManager.createUser(user); // Login - String token = authManager.loginUser("test", "pass"); + String token = authManager.loginUser("test", "pass", 10080L); // Logout Cache<Id, String> tokenCache = Whitebox.getInternalState(authManager, @@ -1500,79 +1557,22 @@ public class AuthTest extends BaseCoreTest { List<HugeProject> projects = authManager.listAllProject(1); Assert.assertNotNull(projects); - Assert.assertTrue(projects.size() == 1); + Assert.assertEquals(1, projects.size()); projects = authManager.listAllProject(-1); Assert.assertNotNull(projects); - Assert.assertTrue(projects.size() == 3); + Assert.assertEquals(3, projects.size()); projects = authManager.listAllProject(3); Assert.assertNotNull(projects); - Assert.assertTrue(projects.size() == 3); + Assert.assertEquals(3, projects.size()); projects = authManager.listAllProject(4); Assert.assertNotNull(projects); - Assert.assertTrue(projects.size() == 3); + Assert.assertEquals(3, projects.size()); projects = authManager.listAllProject(2); Assert.assertNotNull(projects); - Assert.assertTrue(projects.size() == 2); - } - - private static Id makeProjectAndAddGraph(HugeGraph graph, - String projectName, - String graphName) { - HugeProject project = makeProject(projectName, ""); - AuthManager authManager = graph.authManager(); - Id projectId = authManager.createProject(project); - projectId = authManager.projectAddGraphs(projectId, - ImmutableSet.of(graphName)); - Assert.assertNotNull(projectId); - return projectId; - } - - private static HugeProject makeProject(String name, String desc) { - HugeProject project = new HugeProject(name, desc); - project.creator("admin"); - return project; - } - - private static HugeUser makeUser(String name, String password) { - HugeUser user = new HugeUser(name); - user.password(password); - user.creator("admin"); - return user; - } - - private static HugeGroup makeGroup(String name) { - HugeGroup group = new HugeGroup(name); - group.creator("admin"); - return group; - } - - private static HugeTarget makeTarget(String name, String url) { - HugeTarget target = new HugeTarget(name, url); - target.creator("admin"); - return target; - } - - private static HugeTarget makeTarget(String name, String graph, String url, - List<HugeResource> ress) { - HugeTarget target = new HugeTarget(name, graph, url, ress); - target.creator("admin"); - return target; - } - - private static HugeBelong makeBelong(Id user, Id group) { - HugeBelong belong = new HugeBelong(user, group); - belong.creator("admin"); - return belong; - } - - private static HugeAccess makeAccess(Id group, Id target, - HugePermission permission) { - HugeAccess access = new HugeAccess(group, target, permission); - access.creator("admin"); - return access; + Assert.assertEquals(2, projects.size()); } }