Подтвердить что ты не робот

Как мне перенаправить обратно на первоначально запрошенный URL-адрес после аутентификации с помощью паспорт-saml?

Извините, если это вопрос о головной стороне, но у меня возникли проблемы с пониманием того, как я могу перенаправить клиентский браузер обратно на любой URL-адрес, который был первоначально запрошен после успешной проверки подлинности с нашим поставщиком идентификации SAML (IdP). Я использую последние версии паспорт-saml, паспорт и экспресс.

Например, скажем, что клиент изначально запросил /foo/bar из ссылки на другой незащищенной странице, но поскольку это защищенный ресурс, я отвечаю перенаправлением на /login, где я вызываю passport.authenticate('saml').

app.get('/login', passport.authenticate('saml'));

function ensureAuth(req, res, next) {
    if (req.user.isAuthenticated()) {return next();}
    else {res.redirect('/login');}
}

app.get('/foo/bar', ensureAuth, function(req, res) {
    ...
});

Этот вызов перенаправит браузер на мою страницу входа в систему IdP, и после успешной проверки подлинности IdP POST вернутся к моему маршруту /login/callback. В этом маршруте я снова использую passport.authenticate(saml) для проверки ответа SAML, и, если все это хорошо, я затем перенаправляю браузер обратно к запрашиваемому ресурсу... но откуда я знаю, что это за запрошенный ресурс? Поскольку это обратный вызов POST, я потерял любое состояние, связанное с исходным запросом.

app.post('/login/callback', passport.authenticate('saml'), function(req, res) {
    res.redirect('...can I know which url to redirect back to?...');
});

Пример в паспорт-saml readme просто показывает жестко закодированное перенаправление на корневой ресурс, но я бы хотел перенаправить обратно в первоначально запрошенную URL (/foo/bar).

Могу ли я отправить URL-адрес или какое-либо другое значение в IdP, который будет возвращаться в ответ на ответ SAML? И если да, то как я могу получить доступ к нему в моем маршруте /login/callback?

Или есть ли какой-то лучший способ выразить/паспорт, чтобы я этого не делал?

Любая помощь, которую вы можете предоставить, будет оценена по достоинству!

4b9b3361

Ответ 1

Могу ли я отправить URL-адрес или другое значение в IdP, который получит с округлением и возвратом в ответ SAML? И если да, то как можно Я обращаюсь к нему в моем/логином/обратном вызове?

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

Вот что спецификации SAML должно сказать:

3.1.1 Использование RelayState

Некоторые привязки определяют механизм RelayState для сохранения и передачу информации о состоянии. Когда такой механизм используется в передачу сообщения запроса в качестве начального шага протокола SAML, оно устанавливает требования к выбору и использованию привязки впоследствии используется для передачи ответа. А именно, если запрос SAML сообщение сопровождается данными RelayState, затем ответчик SAML ДОЛЖЕН вернуть ответ протокола SAML, используя привязку, которая также поддерживает механизм RelayState, и он ДОЛЖЕН разместить точное Данные RelayState, полученные с запросом, в соответствующий Параметр RelayState в ответе.

Чтобы использовать это с паспорт-saml, вы должны добавить его как значение additionalParams. В приведенном ниже коде показано, что это происходит.

saml = new SamlStrategy
    path: appConfig.passport.saml.path
    decryptionPvk: fs.readFileSync(appConfig.passport.saml.privateKeyFile)
    issuer: appConfig.passport.saml.issuer
    identifierFormat: tenant.strategy.identifierFormat
    entryPoint: tenant.strategy.entryPoint
    additionalParams:{'RelayState':tenant.key}
    ,
    (profile, next) -> 
        # get the user from the profile

Приведенный выше код представляет собой реализацию multi-tenant saml, поэтому я отправляю свой tenant.key в качестве параметра RelayState. Затем я извлекаю это значение из тела POSTed return из IdP и использую его для восстановления всего состояния, в котором я нуждаюсь.

getTenantKey: (req, next) ->
    key = req.body?.RelayState ? routes.match(req.path).params.tenentKey
    next null, key

Ваше дело может быть проще. Вероятно, вы захотите сохранить URL-адрес конечного адресата в кеше, ограниченном временем, а затем отправить ключ кэша в качестве параметра RelayState.

Для чего вы можете избежать использования RelayState вообще, если вы просто используете исходный идентификатор запроса SAML в качестве ключа кеша. Это значение всегда отправляется вам через поле InResponseTo.

Ответ 2

Если вы хотите указать RelayState для каждого запроса, вы могли бы подумать, что можете сделать:

passport.authenticate('saml', { additionalParams: { RelayState: "foo" } })

Но это не работает. Если вы посмотрите на реализацию: https://github.com/bergie/passport-saml/blob/6d1215bf96e9e352c25e92d282cba513ed8e876c/lib/passport-saml/saml.js#L326, вы увидите, что дополненияParams взяты из исходных параметров конфигурации ИЛИ из объекта req ( но не из параметров для запроса).

Но, к счастью, стратегия Passport SAML делает этот запрос:

var RelayState = req.query && req.query.RelayState || req.body && req.body.RelayState;

Затем он просматривает параметры конфигурации для дополнительных (глобальных) дополнительных параметров.

Итак, если вы хотите указать RelayParams для каждого запроса, вам нужно загрузить их в req до вызова авторизации. В моем случае я делаю что-то подобное внутри обработчика маршрута:

req.query.RelayState = req.params.redirect_to;
passport.authenticate('saml')(req, res, next);

Затем, когда перенаправленный запрос возвращается из SAML IdP, вы должны иметь возможность использовать req.body.RelayParams для доступа к вашему состоянию для каждого запроса.

Обратите внимание, что если ваше значение RelayParams является объектом, вам может потребоваться использовать JSON.stringify для его кодирования в RelayParams и JSON.parse для его декодирования (я должен был сделать это в моем случае).