Неверное состояние на лазурном, но работает локально
У меня есть клиент Azure Active Directory, с которым я хочу пройти аутентификацию из своего приложения Node.js, работающего в экземпляре службы приложений Azure. Для этого я использую passportjs и passport-azure-ad.
Локально все отлично работает. Я могу пройти проверку подлинности с клиентом Azure AD, и он вернется на мою страницу правильно. Однако в Azure происходит сбой с ошибкой:
authentication failed due to: In collectInfoFromReq: invalid state received in the request
Моя конфигурация точно такая же (кроме redirectUrl), что я использую тот же клиент для локального тестирования, как и в Azure, но все равно не удается. Я настроил правильные URL-адреса ответа, и аутентификация возвращается к моему приложению.
Вот мой конфиг:
{
identityMetadata: `https://login.microsoftonline.com/${tenantId}/.well-known/openid-configuration`,
clientID: `${clientId}`,
responseType: 'id_token',
responseMode: 'form_post',
redirectUrl: 'https://localhost:3000/auth/oidc/return',
allowHttpForRedirectUrl: false,
scope: [ 'openid' ],
isB2C: false,
passReqToCallback: true,
loggingLevel: 'info'
}
Я использую стратегию OIDC.
Мое промежуточное ПО аутентификации:
passport.authenticate('azuread-openidconnect', {
response: res,
failureRedirect: '/auth/error',
customState: '/'
});
Я сравнил закодированное состояние на authorize
request против возвращенного ответа, и они отличаются так же локально, как и в Azure, однако Azure - единственная жалоба. Примеры того, как различаются состояния:
Azure:
Request state: CUSTOMEwAuZcY7VypgbKQlwlUHwyO18lnzaYGt%20
Response state: CUSTOMEwAuZcY7VypgbKQlwlUHwyO18lnzaYGt
localhost:
Request state: CUSTOMTAYOz2pBQt332oKkJDGqRKs_wAo90Pny%2F
Response state: CUSTOMTAYOz2pBQt332oKkJDGqRKs_wAo90Pny/
Я также попытался полностью удалить customState, но все равно не получилось.
Кто-нибудь знает, что здесь происходит? Я неправильно его настраиваю?
Изменить: Похоже, что это не может быть проблемой с passport-azure-ad. Я еще не уверен, но некоторая отладка показала, что в запросе на вход в мое приложение нет заголовка set-cookie. Сеанс создан, но файл cookie не установлен, поэтому возвращающий ответ не может найти информацию о сеансе, включая состояние, и сравнить их. В результате он сообщает о недопустимом состоянии, поскольку не может получить данные из сеанса.
2 ответа
Оказывается, проблема была в том, что сеанс никогда не создавался должным образом, поэтому не было состояния для process-azure-ad
сравнивать. Причиной этого было то, что я настроил express-session
использовать безопасные сеансовые файлы cookie при условии, что, поскольку я подключался через адрес https://...azurewebsites.net, соединение было безопасным. Технически это не так, хотя.
Azure запускает балансировщик нагрузки перед веб-приложением, эффективно проксируя подключения извне к моему приложению. Этот прокси-сервер обеспечивает безопасное соединение, после чего трафик направляется в мое приложение в незашифрованном виде.
Browser -(HTTPS)> Load balancer -(HTTP)> Application
В результате узел не сообщил о безопасном соединении, если не задан параметр конфигурации. trust proxy
:
app.set('trust proxy', true);
Когда эта опция установлена, экспресс проверит X-Forwarded-Proto
заголовок, для которого был использован протокол для подключения к прокси-серверу (в данном случае балансировщик нагрузки). Этот заголовок содержит http или https в зависимости от протокола соединения.
Однако для Azure этого еще недостаточно. Балансировщик нагрузки Azure не устанавливает X-Forwarded-Proto
заголовок тоже. Вместо этого он использует x-arr-ssl
, Это не большая проблема, хотя, поскольку iisnode (среда выполнения, которую я использую для запуска узла в IIS в Azure), имеет опцию под названием enableXFF
это обновит X-Forwarded-Proto
заголовок на основе внешнего протокола соединения. Установка обоих этих параметров позволяет express-session
установить безопасный cookie, сохраняя сеанс и позволяя passport-azure-ad
хранить и сравнивать информацию о состоянии аутентификации.
PS: Большое спасибо блогу Скотта Смита + комментарии за предоставление ответа: http://scottksmith.com/blog/2014/08/22/using-secure-cookies-in-node-on-azure/
Это известная проблема кодирования с модулем passport-azure-ad
, Увидеть:
"State" gets encoded and causes "collectInfoFromReq: invalid state received" #309
"invalid state received in the request" causing infinite loop on Login #247
Вы можете обновить версию модуля до v3.0.7
или более новый, чтобы исправить это.