diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/log/Sensitive.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/log/Sensitive.java new file mode 100644 index 00000000000..6870938396e --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/log/Sensitive.java @@ -0,0 +1,14 @@ +package io.cloudbeaver.model.log; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a field or method as sensitive, so its value won't be logged. + */ +@Target(value = {ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Sensitive { +} diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java index 002d522aa41..47914d130b0 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLEndpoint.java @@ -246,14 +246,14 @@ private void executeQuery( if (operationName != null) { contextBuilder.operationName(operationName); } - String sessionId = GraphQLLoggerUtil.getSmSessionId(request); +// String sessionId = GraphQLLoggerUtil.getSmSessionId(request); String userId = GraphQLLoggerUtil.getUserId(request); - String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, variables); - if (operationName != null) { - log.debug("API > " + operationName + loggerMessage); - } else if (DEBUG) { - log.debug("API > " + query + loggerMessage); - } +// String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, variables); +// if (operationName != null) { +// log.debug("API > " + operationName + loggerMessage); +// } else if (DEBUG) { +// log.debug("API > " + query + loggerMessage); +// } LocalDateTime startTime = LocalDateTime.now(); ExecutionInput executionInput = contextBuilder.build(); ExecutionResult executionResult = null; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLLoggerUtil.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLLoggerUtil.java index 98655c05bfc..e8037991147 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLLoggerUtil.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/graphql/GraphQLLoggerUtil.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.server.graphql; +import io.cloudbeaver.model.log.Sensitive; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.server.WebAppUtils; import io.cloudbeaver.server.WebApplication; @@ -23,7 +24,9 @@ import org.jkiss.code.Nullable; import org.jkiss.utils.CommonUtils; -import java.util.Map; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.Set; public class GraphQLLoggerUtil { @@ -63,43 +66,63 @@ public static WebSession getWebSession(HttpServletRequest request) { .findWebSession(request); } - public static String buildLoggerMessage(String sessionId, String userId, Map variables) { + public static String buildLoggerMessage(String sessionId, String userId, Method method, Object[] args) { StringBuilder loggerMessage = new StringBuilder(" [user: ").append(userId) .append(", sessionId: ").append(sessionId).append("]"); - if (WebAppUtils.getWebPlatform().getPreferenceStore().getBoolean(LOG_API_GRAPHQL_DEBUG_PARAMETER) - && variables != null +// if (WebAppUtils.getWebPlatform().getPreferenceStore().getBoolean(LOG_API_GRAPHQL_DEBUG_PARAMETER) + if (true ) { loggerMessage.append(" [variables] "); - String parsedVariables = parseVarialbes(variables); + String parsedVariables = maskArgsToString(method, args); if (CommonUtils.isNotEmpty(parsedVariables)) { - loggerMessage.append(parseVarialbes(variables)); + loggerMessage.append(parsedVariables); } } return loggerMessage.toString(); } - private static String parseVarialbes(Map map) { - StringBuilder result = new StringBuilder(); + public static String maskArgsToString(Method method, Object[] args) { + StringBuilder sb = new StringBuilder(); + Parameter[] params = method.getParameters(); - for (Map.Entry entry : map.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); + for (int i = 0; i < params.length; i++) { + //fixme can't get real parameter names without -parameters compiler option + String name = params[i].getName(); + Object value = (args != null && i < args.length) ? args[i] : null; - boolean isProhibited = PROHIBITED_VARIABLES.stream() - .anyMatch(prohibitedKey -> key.toLowerCase().contains(prohibitedKey.toLowerCase())); + sb.append(name).append(": "); - if (isProhibited) { - result.append(key).append(": ").append("******** "); - continue; - } - - if (value instanceof Map) { - result.append(parseVarialbes((Map) value)); + if (params[i].isAnnotationPresent(Sensitive.class)) { + sb.append("**** "); + } else if (value != null && !isSimple(value.getClass())) { + sb.append("{ "); + for (Field field : value.getClass().getDeclaredFields()) { + field.setAccessible(true); + sb.append(field.getName()).append(": "); + try { + if (field.isAnnotationPresent(Sensitive.class)) { + sb.append("**** "); + } else { + sb.append(field.get(value)).append(" "); + } + } catch (IllegalAccessException e) { + sb.append(" "); + } + } + sb.append("} "); } else { - result.append(key).append(": ").append(value).append(" "); + sb.append(value).append(" "); } } - return result.toString().trim(); + return sb.toString().trim(); + } + + private static boolean isSimple(Class cls) { + return cls.isPrimitive() + || Number.class.isAssignableFrom(cls) + || CharSequence.class.isAssignableFrom(cls) + || Boolean.class.equals(cls) + || Enum.class.isAssignableFrom(cls); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 7f0fe160679..9e0de40bcc9 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -27,9 +27,11 @@ import io.cloudbeaver.model.session.WebSessionProvider; import io.cloudbeaver.server.WebAppUtils; import io.cloudbeaver.server.graphql.GraphQLEndpoint; +import io.cloudbeaver.server.graphql.GraphQLLoggerUtil; import io.cloudbeaver.service.security.SMUtils; import io.cloudbeaver.utils.ServletAppUtils; import io.cloudbeaver.utils.WebDataSourceUtils; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -327,16 +329,26 @@ private void checkActionPermissions(@NotNull Method method, @NotNull WebAction w } } } + // Perform any checks before action call + protected void beforeWebActionCall(WebAction webAction, Method method, Object[] args) throws DBException { - } + HttpServletRequest request = this.env.getGraphQlContext().get("request"); + String sessionId = GraphQLLoggerUtil.getSmSessionId(request); + String userId = GraphQLLoggerUtil.getUserId(request); - // Perform any checks before action call - protected void beforeWebActionCall(WebAction webAction, Method method, Object[] args) throws DBException { - setLogContext(method, args); - } + String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, method, args); + + if (method.getName() != null) { + log.debug("API > " + method.getName() + loggerMessage); + } + + setLogContext(method, args); + } + + protected void afterWebActionCall(WebAction webAction, Method method, Object[] args) throws DBException { + Log.setContext(null); + } - protected void afterWebActionCall(WebAction webAction, Method method, Object[] args) throws DBException { - Log.setContext(null); } protected void setLogContext(Method method, Object[] args) {