ByteBuddy ребазинг, синтетические типы и OSGi - PullRequest
1 голос
/ 15 октября 2019

У меня есть следующий перехватчик, разработанный для 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());

, и это происходит внутри WeavingHook в OSGi. Проблема в том, что перебазирование с помощью @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 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;
    }
}

, гдеUsersServiceImpl - это класс, который нужно сотворить.

Итак, мне нужно добавить все эти синтетические классы в пространство классов пакета UsersServiceImpl (или вообще сделать синтетические классы "доступными" из этогорасслоение). Это возможно?

Ответы [ 2 ]

0 голосов
/ 17 октября 2019

В конце я использовал другой подход:

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) {
       //...
    }
}

это только изменяет байт-код исходного класса без введения дополнительных синтетических типов.

0 голосов
/ 15 октября 2019

Один прием, который вы можете применить, - это не использовать перебазирование, а создавать собственные загрузчики классов во время загрузки прокси, где новый класс (и все его синтетические классы) загружаются в загрузчик классов с несколькими родителями:

dynamicType
  .make()
  .load(new MultipleParentClassLoader.Builder(false)
    .append(type.getClassLoader(), SecurityInterceptor.class.getClassLoader())
    .build());

Теперь прокси-класс будет загружен в новый загрузчик классов с несколькими родителями;загрузчик OSGi, который защищает любые другие типы, обычно не известные пакету, и загрузчик классов перехватчика безопасности, который принадлежит вам. Однако загрузчик нескольких родительских классов будет запрашивать любой тип из обоих загрузчиков классов, что делает оба видимых для прокси-класса.

Обратите внимание на аргумент false для конструктора компоновщика. Это распечатывает загрузчик классов, делая его потенциально уязвимым для внедрения дополнительных классов. Я не предполагаю, что ваши прокси-классы чувствительны к атакам отражения, но это то, что нужно учитывать. Вы можете убрать флаг и заплатить немного более высокую цену за генерацию класса.

...