ByteBuddy 变基、合成类型和 OSGi
ByteBuddy rebasing, synthetic types and OSGi
我为 byte-buddy 开发了以下拦截器:
public class SecurityInterceptor() {
@RuntimeType
public static Object intercept(
@SuperCall Callable<Object> supercall,
@This Object target,
@Origin Method method,
@AllArguments Object[] args) {
// Check args and annotations ...
Object obj = supercall.call();
// Post-process obj content ...
}
}
拦截器注册如下:
Unloaded<Object> unloaded = new ByteBuddy()
.rebase(type, classFileLocator)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(SecurityInterceptor.class))
.make();
wovenClass.setBytes(unloaded.getBytes());
这发生在 OSGi 的 WeavingHook
中。问题是 @SuperCall
的变基会改变原始代码
public User getUser(final String s) throws Exception {
return SecurityInterceptor.intercept((Callable)new UsersServiceImpl$auxiliary$xhbBRSr4(this, s),
(Object)this, UsersServiceImpl.cachedValue$nlgHrwy3$sn5qca3, new Object[] { s });
}
其中 UsersServiceImpl$auxiliary$xhbBRSr4
是由 byte-buddy 生成的合成 class:
class UsersServiceImpl$auxiliary$xhbBRSr4 implements Runnable, Callable
{
private UsersServiceImpl argument0;
private String argument1;
@Override
public Object call() throws Exception {
return this.argument0.getUser$originalve6X5gN$accessor$nlgHrwy3(this.argument1);
}
@Override
public void run() {
this.argument0.getUser$originalve6X5gN$accessor$nlgHrwy3(this.argument1);
}
UsersServiceImpl$auxiliary$xhbBRSr4(final UsersServiceImpl argument0, final String argument2) {
this.argument0 = argument0;
this.argument1 = argument2;
}
}
其中 UsersServiceImpl
是正在编织的 class。
所以我需要的是将所有这些合成 classes 添加到 UsersServiceImpl
包的 class space 中(或者通常使合成 classes "accessible" 来自那个包)。这可能吗?
您可以应用的一个技巧是不使用变基,而是在加载代理期间创建自己的 class 加载程序,其中新 class(及其所有合成 classes) 被加载到具有多个父项的 class 加载程序中:
dynamicType
.make()
.load(new MultipleParentClassLoader.Builder(false)
.append(type.getClassLoader(), SecurityInterceptor.class.getClassLoader())
.build());
代理 class 现在将加载到具有多个父级的新 class 加载器中; OSGi 加载器屏蔽通常不为捆绑包所知的任何其他类型,以及安全拦截器的 class 加载器是您的。然而,多父 class 加载器将从两个 class 加载器请求任何类型,从而使两者对代理可见 class.
注意构建器构造函数的 false
参数。这会解封 class 加载程序,使其可能容易受到注入额外 classes 的攻击。我不认为您的代理 classes 对反射攻击敏感,但这是需要考虑的事情。您可以移除标志并为 class 代支付稍高的费用。
最后我用了不同的方法:
Unloaded<Object> unloaded = new ByteBuddy()
.redefine(type, classFileLocator)
.visit(Advice.to(SecurityAdvice.class)
.on(ElementMatchers.isAnnotatedWith(Secured.class)))
.make();
和
public class SecurityAdvice {
@Advice.OnMethodEnter
private static void enter(@Advice.AllArguments Object[] args) {
//...
}
@Advice.OnMethodExit
private static void exit(@Advice.Return(typing = Typing.DYNAMIC) Object value) {
//...
}
}
这只会改变原始 class 的字节码,而不会引入额外的合成类型。
我为 byte-buddy 开发了以下拦截器:
public class SecurityInterceptor() {
@RuntimeType
public static Object intercept(
@SuperCall Callable<Object> supercall,
@This Object target,
@Origin Method method,
@AllArguments Object[] args) {
// Check args and annotations ...
Object obj = supercall.call();
// Post-process obj content ...
}
}
拦截器注册如下:
Unloaded<Object> unloaded = new ByteBuddy()
.rebase(type, classFileLocator)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(SecurityInterceptor.class))
.make();
wovenClass.setBytes(unloaded.getBytes());
这发生在 OSGi 的 WeavingHook
中。问题是 @SuperCall
的变基会改变原始代码
public User getUser(final String s) throws Exception {
return SecurityInterceptor.intercept((Callable)new UsersServiceImpl$auxiliary$xhbBRSr4(this, s),
(Object)this, UsersServiceImpl.cachedValue$nlgHrwy3$sn5qca3, new Object[] { s });
}
其中 UsersServiceImpl$auxiliary$xhbBRSr4
是由 byte-buddy 生成的合成 class:
class UsersServiceImpl$auxiliary$xhbBRSr4 implements Runnable, Callable
{
private UsersServiceImpl argument0;
private String argument1;
@Override
public Object call() throws Exception {
return this.argument0.getUser$originalve6X5gN$accessor$nlgHrwy3(this.argument1);
}
@Override
public void run() {
this.argument0.getUser$originalve6X5gN$accessor$nlgHrwy3(this.argument1);
}
UsersServiceImpl$auxiliary$xhbBRSr4(final UsersServiceImpl argument0, final String argument2) {
this.argument0 = argument0;
this.argument1 = argument2;
}
}
其中 UsersServiceImpl
是正在编织的 class。
所以我需要的是将所有这些合成 classes 添加到 UsersServiceImpl
包的 class space 中(或者通常使合成 classes "accessible" 来自那个包)。这可能吗?
您可以应用的一个技巧是不使用变基,而是在加载代理期间创建自己的 class 加载程序,其中新 class(及其所有合成 classes) 被加载到具有多个父项的 class 加载程序中:
dynamicType
.make()
.load(new MultipleParentClassLoader.Builder(false)
.append(type.getClassLoader(), SecurityInterceptor.class.getClassLoader())
.build());
代理 class 现在将加载到具有多个父级的新 class 加载器中; OSGi 加载器屏蔽通常不为捆绑包所知的任何其他类型,以及安全拦截器的 class 加载器是您的。然而,多父 class 加载器将从两个 class 加载器请求任何类型,从而使两者对代理可见 class.
注意构建器构造函数的 false
参数。这会解封 class 加载程序,使其可能容易受到注入额外 classes 的攻击。我不认为您的代理 classes 对反射攻击敏感,但这是需要考虑的事情。您可以移除标志并为 class 代支付稍高的费用。
最后我用了不同的方法:
Unloaded<Object> unloaded = new ByteBuddy()
.redefine(type, classFileLocator)
.visit(Advice.to(SecurityAdvice.class)
.on(ElementMatchers.isAnnotatedWith(Secured.class)))
.make();
和
public class SecurityAdvice {
@Advice.OnMethodEnter
private static void enter(@Advice.AllArguments Object[] args) {
//...
}
@Advice.OnMethodExit
private static void exit(@Advice.Return(typing = Typing.DYNAMIC) Object value) {
//...
}
}
这只会改变原始 class 的字节码,而不会引入额外的合成类型。