问题
I have the following interceptor developed for 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 ...
}
}
The interceptor is registered as follows:
Unloaded<Object> unloaded = new ByteBuddy()
.rebase(type, classFileLocator)
.method(ElementMatchers.isAnnotatedWith(Secured.class))
.intercept(MethodDelegation.to(SecurityInterceptor.class))
.make();
wovenClass.setBytes(unloaded.getBytes());
and this happens inside a WeavingHook
in OSGi. The problem is that rebasing with @SuperCall
alters the original code as such
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 });
}
where UsersServiceImpl$auxiliary$xhbBRSr4
is a synthetic class that is generated by byte-buddy:
class UsersServiceImpl$auxiliary$xhbBRSr4 implements Runnable, Callable
{
private UsersServiceImpl argument0;
private String argument1;
@Override
public Object call() throws Exception {
return this.argument0.getUser$original$6ve6X5gN$accessor$nlgHrwy3(this.argument1);
}
@Override
public void run() {
this.argument0.getUser$original$6ve6X5gN$accessor$nlgHrwy3(this.argument1);
}
UsersServiceImpl$auxiliary$xhbBRSr4(final UsersServiceImpl argument0, final String argument2) {
this.argument0 = argument0;
this.argument1 = argument2;
}
}
where UsersServiceImpl
is the class being weaved.
So what I need is to add all these synthetic classes in the class space of the UsersServiceImpl
's bundle (or in general make synthetic classes "accessible" from that bundle). Is this possible?
回答1:
One trick you can apply is to not use rebasing but to create your own class loaders during the loading of a proxy where the new class (and all of its synthetic classes) are loaded in a class loader with multiple parents:
dynamicType
.make()
.load(new MultipleParentClassLoader.Builder(false)
.append(type.getClassLoader(), SecurityInterceptor.class.getClassLoader())
.build());
The proxy class will now be loaded in a new class loader that has multiple parents; the OSGi loader that shields any other types not normally known to a bundle and the security interceptor's class loader that is yours. The multiple parent class loader will however request any type from both class loaders, thus making both visible for the proxy class.
Notice the false
argument to the builder's constructor. This unseals the class loader making it potentially vulnerable for injection of additional classes. I don't assume that your proxy classes are sensitive to reflection attacks but it is something to consider. You can remove the flag and pay slightly higher costs for class generation.
回答2:
In the end I used a different approach:
Unloaded<Object> unloaded = new ByteBuddy()
.redefine(type, classFileLocator)
.visit(Advice.to(SecurityAdvice.class)
.on(ElementMatchers.isAnnotatedWith(Secured.class)))
.make();
with
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) {
//...
}
}
this only alters the original class's bytecode without introducing additional synthetic types.
来源:https://stackoverflow.com/questions/58388214/bytebuddy-rebasing-synthetic-types-and-osgi