Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/server-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ on:

jobs:
build-server:
# TODO: we need test & replace it to ubuntu-24.04 or ubuntu-latest
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
env:
USE_STAGE: 'false' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ public String login(@Context GraphManager manager, @PathParam("graph") String gr
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) {
Expand Down Expand Up @@ -131,6 +132,8 @@ private static class JsonLogin implements Checkable {
private String name;
@JsonProperty("user_password")
private String password;
@JsonProperty("token_expire")
private long expire;

@Override
public void checkCreate(boolean isBatch) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,16 @@

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;
Expand All @@ -141,6 +142,40 @@ public HugeGraphAuthProxy(HugeGraph 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();
Expand Down Expand Up @@ -1016,6 +1051,61 @@ else if (ro.type().isGrantOrUser()) {
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;
Expand Down Expand Up @@ -1621,9 +1711,9 @@ public void enabledWhiteIpList(boolean status) {
}

@Override
public String loginUser(String username, String password) {
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);
}
Expand Down Expand Up @@ -1841,95 +1931,4 @@ public String toString() {
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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public interface AuthManager {

RolePermission rolePermission(AuthElement element);

String loginUser(String username, String password) throws AuthenticationException;
String loginUser(String username, String password, long expire) throws AuthenticationException;

void logoutUser(String token);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ public StandardAuthManager(HugeGraphParams graph) {
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();
Expand Down Expand Up @@ -634,7 +641,7 @@ private RolePermission rolePermission(HugeTarget target) {
}

@Override
public String loginUser(String username, String password)
public String loginUser(String username, String password, long expire)
Copy link
Member

@imbajin imbajin Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used? At least we need add a TODO/comment for it

throws AuthenticationException {
HugeUser user = this.matchUser(username, password);
if (user == null) {
Expand Down Expand Up @@ -717,13 +724,6 @@ public void enabledWhiteIpList(boolean status) {
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);
Expand Down
Loading
Loading