В каких случаях может понадобиться данный способ
Привет, Хабр! При проектировании интеграционных потоков может возникнуть ситуация, где требуется настроить интеграцию между двумя системами (далее – отправитель и получатель). Обе системы используют REST в качестве протокола для обмена данными. Система получатель требует, чтобы система отправитель присылала данные для авторизации в дефолтном заголовке Authorization. При этом содержимое заголовка Authorization контролирует система отправитель, и его нельзя указать на уровне интеграционной шины. Так как в FESB также требуется авторизация, выходом будет настройка авторизации с кастомным заголовком.
Зачем нужна авторизация на стороне ESB, если получатель все равно проверяет учетные данные?
Если не использовать проверку на стороне ESB и прокидывать запросы до целевой системы, вся нагрузка по аутентификации ляжет на получателя. Проверяя легитимность вызова на уровне FESB мы:
Снижаем нагрузку на целевую систему, поскольку до неё доходят только успешно прошедшие первичную проверку запросы.
Уменьшаем сетевой трафик и задержки за счёт раннего отсечения неавторизованного трафика.
Централизуем политики безопасности на шине, не завися от реализации получателя.
В штатном режиме FESB сама использует заголовок Authorization для внутренней аутентификации, и передать его далее в неизменном виде получателю не получится. Решение - настроить авторизацию через кастомный заголовок (например, FESB_Authorization), в котором отправитель будет передавать учётные данные. Шина проверит их и пропустит запрос дальше, а стандартный Authorization останется свободным для конечного получателя.
В итоге получаем следующую схему взаимодействия систем:

Проблема состоит в том, что модуль также использует заголовок Authorization для авторизации пользователей в шине FESB. Статья посвящена именно тому, как перенастроить FESB на анализ другого заголовка. Данный способ сработает как для всего REST-домена, так и для одной группы методов в рамках домена.
Коротко о том, что потребуется сделать
Для уже настроенных группы методов в REST-домене и СОПСа потребуется выполнить следующие действия:
Отключить авторизацию по группе домена в REST-домене;
Настроить связку СОПС и REST-метода;
В СОПС настроить парсинг кастомного заголовка;
В СОПС настроить проверку сравнения логина и пароля с эталонными;
В СОПС вернуть ошибку при несовпадении логина или пароля.
1. Создание группы доменов и отключение авторизации для неё
Чтобы создать новую группу доменов, требуется перейти в модуль REST, выбрать REST-домен и нажать на кнопку «Добавить группу методов»:

Для создания группы методов потребуется заполнить название, описание и путь. Путь, указанный в группе доменов, будет использоваться в каждом из методов в данной группе доменов. Поэтому мы также будем использовать его для отключения авторизации только для данной группы доменов.

Чтобы отключить авторизацию для конкретной группы доменов, требуется перейти на вкладку Дополнительная конфигурация и открыть объект Аутентификация HTTP (Локальные пользователи), если такой объект есть и настроен для текущего домена.

Примечание
Если объекта Аутентификация HTTP (локальные пользователи) ещё нет в домене, то требуется предварительно его создать и подключить к домену на вкладке Общие настройки → Аутентификация.
В объекте Аутентификация HTTP (Локальные пользователи) требуется перейти на вкладку Настройка путей и добавить правило для отсутствия аутентификации по необходимому фильтру.

В данном случае был добавлен последний пункт. Он разрешает не проходить аутентификацию (зелёный замок) по всем методам (*) для пути /habr/*. Для этого необходимо снять флаг "Аутентифицировать".

После выполнения всех настроек все методы, которые мы в дальнейшем создадим в указанной группе доменов, не будут проверять авторизацию перед тем, как продолжить выполнение в точке обработки. Перейдём непосредственно к созданию метода и точки обработки.
2. СОПС и REST-метод и их связка
Прежде чем создавать REST-метод в только что созданной группе методов требуется создать точку обработки, то есть СОПС. Чтобы это сделать, требуется перейти в модуль Интеграционный брокер, создать или открыть один из доменов и нажать на кнопку «Добавить СОПС»:

В созданном СОПС укажем точку входа «Ссылка на СОПС»:

Зададим ссылке имя (в нашем случае используем «Habr_Auth») и обязательно отметим галочкой настройку «Глобальная», чтобы сделать ссылку видимой вне домена:

Основные обработчики мы будем создавать позднее, в данный момент ограничимся созданием обработчика «Логирование» и сохраним СОПС:


Далее вернёмся в REST-домен, чтобы настроить REST-метод, передающий сообщения в наш СОПС.
Чтобы создать REST-метод требуется раскрыть группу методов и нажать на кнопку «Добавить метод»:

В методе требуется указать имя, путь к методу, HTTP метод и точку обработки – СОПС, который мы создали ранее:

3. Настройка парсинга кастомного заголовка в СОПС
Все дальнейшие настройки будут производиться в СОПС, созданном на предыдущем шаге. Помните, что настройку потребуется произвести во всех СОПС, на которые ведут методы в группе методов REST-домена.
Прежде чем делать парсинг заголовка, требуется определиться с форматом данных в самом заголовке. В рамках статьи мы возьмём формат «логин:пароль», закодированные в base64. Данный подход используется в стандартном заголовке Authorization, но мы исключим из него строку «Basic», чтобы упростить себе задачу.
Вариативность: связка "логин:пароль" приведена для примера. При необходимости можно использовать bearer-токен, точно так же закодированный и переданный в кастомном заголовке. Логика парсинга при этом изменится минимально. Вместо разделения по ":" вы просто получите строку токена и сверите ее с эталонным значением
Итак, будем принимать следующий заголовок:
FESB_Authorization: bG9naW46cGFzc3dvcmQ=
Для удобства дальнейшего сравнения переданных логина и пароля в рамках СОПС рекомендуется поместить их в соответствующие заголовки. Будем использовать точку обработки «Установка заголовков» и установим заголовки login и pass, для которых укажем код на языке groovy:
new String(Base64.decoder.decode(request.headers.FESB_Authorization)).split(":")[0] new String(Base64.decoder.decode(request.headers.FESB_Authorization)).split(":")[1]

Приведённый код получает доступ к заголовку FESB_Authorization, декодирует его с использованием класса Base64, конвертирует результат в строку. После чего полученную строку разбивает на массив из двух строк по символу «:» и выбирает нулевой или первый элемент в зависимости от устанавливаемого заголовка.
4. Настройка сравнения логина и пароля с эталонными
Чтобы выполнить сравнение логина и пароля с некими эталонными значениями, требуется настроить те самые эталонные значения в виде констант домена следующим образом:

После этого необходимо настроить точку обработки «Фильтр». В условии необходимо прописать проверку на соответствие логина и пароля. В тестовом примере условие выглядит следующим образом:

${header.login} != ${properties:login} || ${header.pass} != ${properties:pass}
5. Настройка возврата ошибки 401 в случае несовпадения логина или пароля
При несовпадении логина или пароля требуется остановить обработку сообщения в СОПС с использованием шага «Прекратить обработку» (не требует настройки). Но при использовании только этого шага пользователь получит код 200, т.к. технически никакой ошибки не возникло, просто выполнилось условие сравнения.
Чтобы пользователь в системе отправителе получил код ошибки 401, требуется в ветку «Фильтра» с невыполненным условием добавить установку системного заголовка CamelHttpResponseCode, в качестве значения устанавливаем 401.
Внимание
Требуется устанавливать именно системный заголовок, добавляющийся по кнопке «Добавить системный заголовок». При установке обычного заголовка отправитель по-прежнему получит код 200.


Таким образом, фильтр будет выглядеть так:

При дальнейшей обработке сообщения может быть нецелесообразным хранение логина и пароля в открытом виде в заголовках. Поэтому в ветке «Иначе» стоит настроить их удаление с использованием точки обработки «Очистить заголовки» следующим образом:

6. Делаем универсальное решение
Описанный выше подход хорошо работает, но если у нас будет несколько REST-методов, которые ссылаются на разные СОПС, дублировать шаги аутентификации в каждом из них будет неудобно. Для этого логику можно немного модернизировать и сделать универсальной, для этого:
Оставьте в
Habr_Authтолько шаги аутентификации (установка заголовков, фильтр, возврат 401) без финальной бизнес-логики. Убедитесь, что в точке входа «Ссылка на СОПС» включена глобальная видимость.В СОПС, куда приходят REST-запросы, первым шагом вставьте точку обработки Ссылка на СОПС (или Вызов СОПС) и укажите глобальную ссылку
Habr_Auth. Она проверит учётные данные и либо прервёт обработку с 401, либо вернёт сообщение в основной поток, где вы уже реализуете целевую логику.Таким образом, любые изменения в алгоритме аутентификации достаточно внести один раз в
Habr_Auth, и они сразу применятся ко всем вызывающим СОПС.
Проверка работы
Дальше вам только остается вызвать REST-метод из любого инструмента для отладки: Postman, SOAP UI. В заголовках установить наш кастомный заголовок FESB_Authorization с нужным значением в base64
Заключение
Теперь вы можете гибко управлять авторизацией для отдельных групп REST-методов, не затрагивая стандартный механизм заголовка Authorization.
Если вдруг в статье вы найдете недочеты или предложения по улучшению, напиши, пожалуйста, в комментариях, спасибо!
