В каких случаях может понадобиться данный способ

Привет, Хабр! При проектировании интеграционных потоков может возникнуть ситуация, где требуется настроить интеграцию между двумя системами (далее – отправитель и получатель). Обе системы используют 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

Примечание

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

В объекте Аутентификация HTTP (Локальные пользователи) требуется перейти на вкладку Настройка путей и добавить правило для отсутствия аутентификации по необходимому фильтру.

Настройка путей
Настройка путей

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

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

2. СОПС и REST-метод и их связка

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

Добавление СОПСа
Добавление СОПСа

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

Точка входа "Ссылка на СОПС"
Точка входа "Ссылка на СОПС"

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

Настройка глобальной ссылки
Настройка глобальной ссылки

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

Добавление логирования
Добавление логирования
Сохранение СОПС
Сохранение СОПС

Далее вернёмся в REST-домен, чтобы настроить REST-метод, передающий сообщения в наш СОПС.

Чтобы создать REST-метод требуется раскрыть группу методов и нажать на кнопку «Добавить метод»:

Добавление метода
Добавление метода

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

Настройка REST-метода
Настройка REST-метода

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.

Если вдруг в статье вы найдете недочеты или предложения по улучшению, напиши, пожалуйста, в комментариях, спасибо!