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

Руководство по внедрению SAML/ADFS node.js?

Я хотел бы предисловие к этому, сказав, что до сих пор я даже не был свидетелем SAML, а тем более разработал стратегию SSO, связанную с этим. Это, в сочетании с тем, что я едва делал node в течение года, делает славный новичок сэндвич. В настоящее время у меня есть клиент, который использует SAML и ADFS в качестве своего поставщика единого входа. Я уже использую pass.js для локальных логинов, поэтому использование паспорт-saml, похоже, является способом реализации SSO с использованием SAML/ADFS. При выполнении моих исследований я нашел пару различных руководств по внедрению, но, поскольку я буквально ничего не знаю об этом процессе, я мог бы использовать несколько указателей.

В документации паспорт-saml я нашел следующее для стратегии, проверенной для работы с ADFS (согласно документам):

{
  entryPoint: 'https://ad.example.net/adfs/ls/',
  issuer: 'https://your-app.example.net/login/callback',
  callbackUrl: 'https://your-app.example.net/login/callback',
  cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==',
  identifierFormat: null
}

Я полагаю, что мой главный вопрос: откуда этот сертификат? Это сертификат, который я генерирую на своем сервере через SSL? Предоставляет ли провайдер это?

В моих поисках я также нашел это: https://github.com/auth0/passport-wsfed-saml2, который основан на паспорт-saml. Для ADFS предлагается следующая конфигурация:

{
  path: '/login/callback',
  realm: 'urn:node:app',
  homeRealm: '', // optionally specify an identity provider 
  identityProviderUrl: 'https://auth10-dev.accesscontrol.windows.net/v2/wsfederation',
  cert: 'MIIDFjCCAf6gAwIBAgIQDRRprj9lv5 ... ='
}

В этом примере объект пути очевиден, и мой провайдер уже предоставил мне providerURL. Но царство не имеет для меня никакого смысла, и там этот штопать cert снова.

Может ли кто-нибудь предоставить мне способ "объяснять-как-я-пять" для реализации SOML/ADFS SSO на сайте node.js? Или помочь мне сделать головы или хвосты объектов аргументов, запрошенных двумя решениями, которые я изложил? Очень ценится заранее!

4b9b3361

Ответ 1

Недавно я прошел один и тот же процесс: никогда не слышал о SAML, мне нужно было включить веб-приложение для аутентификации через SAML с OneLogin в качестве поставщика удостоверений (вместо Active Directory).

Во время реализации я активно использовал документацию OneLogin и библиотеку passport-saml, оба из которых я рекомендую, хотя я не связан ни с одним из них.

Я понял, что путаница трижды:

(1) как работает SAML,

(2) как библиотека passport-saml работает в узле, и

(3) как настроить поставщика удостоверений (OneLogin, Active Directory или иначе). Ниже следует моя попытка объяснения "объяснения как я-пять".

SAML

Язык разметки безопасности (SAML) - это стандарт XML, который позволяет пользователям регистрироваться на основе их сеанса браузера. Там много, но в основном, это позволяет упростить процесс аутентификации. Пользователь может нажать кнопку, а не отправить форму с именем пользователя и паролем.

Способ работы SAML немного связан. Я нашел этот обзор от OneLogin и сопровождающей диаграммы полезными:

SAML SSO flow, OneLogin.com

Диаграмма представляет собой следующий процесс:

  1. Пользователь нажимает кнопку для аутентификации для определенного приложения (иногда называемого поставщиком услуг) с использованием SAML. Выполняется запрос (к узлу или иным образом) для создания запроса авторизации SAML.
  2. Построен запрос авторизации. Этот запрос авторизации представляет собой XML (см. Больше на OneLogin), закодированный и/или зашифрованный и добавленный к URL-адресу в качестве параметра запроса. Узел перенаправляет браузер на этот URL (что-то вроде https://domain.onelogin.com/trust/saml2/http-post/sso/123456?SAMLRequest=...encodedXML...).
  3. OneLogin, как поставщик удостоверений, определяет из сеанса браузера, был ли пользователь уже зарегистрирован. Если нет, пользователю будет предложена форма входа в систему OneLogin. Если это так, браузер отправляет ответ SAML обратно на приложение (поставщик услуг). Этот ответ SAML (опять XML) включает в себя определенные свойства пользователя, такие как NameID.
  4. Назад в узле, приложение проверяет ответ SAML и завершает проверку подлинности.

Узел и passport-saml

Passport.js является промежуточным программным обеспечением аутентификации для узла. Это требует стратегии, которая может быть чем-то вроде passport-local или, в нашем случае, passport-saml.

Поскольку стратегия passport-local позволяет использовать аутентификацию Passport с использованием имени пользователя/пароля, стратегия passport-saml включает аутентификацию Passport с использованием сеанса браузера и настраиваемых значений идентификатора поставщика.

В то время как passport-saml хорошо служил моим целям, его документы были трудно прояснить. Пример конфигурации не работает из-за того, что провайдер идентификации OpenIdp неактивен и существует множество настраиваемых параметров.

Основной вопрос, о котором я заботился: entryPoint и path (или callbackURL). Мне нужны только эти два, которые делают следующее:

  • entryPoint - это URL-адрес для перенаправления с запросом авторизации (см. № 2 выше).
  • path/callbackURL задает URL/маршрут в узле для ответа SAML на POSTED (см. № 3 выше).

Там множество других параметров, которые важны и ценны, но можно настроить SAML SSO, используя только эти два.

Конфигурация поставщика удостоверений

Наконец, сам поставщик удостоверений должен быть настроен так, что, учитывая запрос авторизации SAML, он знает, куда отправить ответ SAML. В случае OneLogin это означает настройку ACS (Consumer) URL и ACS (Consumer) URL Validator, оба из которых должны соответствовать path/callbackURL настроенному для паспорта-saml.

Другие вещи могут быть настроены (для поддержки выхода из системы и других функций), но это минимальный минимум для аутентификации.


Резюме

В исходный вопрос было две части: (1) как реализовать интеграцию SAML/ADFS и (2) руководство по внедрению SAML node.js на высоком уровне. Этот ответ касается второго.

Что касается конкретной интеграции с Active Directory, я рекомендую документы паспорт-saml в ADFS, имея в виду, что есть две части: настройка паспорта-saml для использования поставщика идентификации ADFS и настройка сервера ADFS для ответа на узел.

Ответ 2

Возможно, я ошибаюсь, но я думаю, что это происходит с серверов XML ADFS, найденных в https://servername/FederationMetadata/2007-06/FederationMetadata.xml.

Вытащите сертификат X509. У меня такие же проблемы, и я собираюсь попробовать следующее.

Ответ 3

Здесь альтернативное решение, использующее библиотеку saml2.js

var saml2 = require('saml2-js');
var fs = require('fs');
var express = require('express');
var https = require('https');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
  extended: true
}));
// Create service provider
var sp_options = {
  entity_id: "https://localhost:44301/",
  private_key: fs.readFileSync("key.pem").toString(),
  certificate: fs.readFileSync("certificate.crt").toString(),
  assert_endpoint: "https://localhost:44301/assert",

  force_authn: true,
  auth_context: { comparison: "minimum", class_refs: ["urn:oasis:names:tc:SAML:2.0:ac:classes:password"] },
  nameid_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
  sign_get_request: false,
  allow_unencrypted_assertion: true
};
var sp = new saml2.ServiceProvider(sp_options);
// Create identity provider
var idp_options = {
  sso_login_url: "https://mmusmaadfs.company.com/adfs/ls/",
  sso_logout_url: "https://mmusmaadfs.company.com/adfs/ls/",
  certificates: [fs.readFileSync("./2018ADFSSigningBase64Cert.cer").toString()],
  force_authn: true,
  sign_get_request: false,
  allow_unencrypted_assertion: true
};
var idp = new saml2.IdentityProvider(idp_options);
// ------ Define express endpoints ------
// Endpoint to retrieve metadata
app.get("/metadata.xml", function(req, res) {
  res.type('application/xml');
  res.send(sp.create_metadata());
});
// Starting point for login
app.get("/login", function(req, res) {
  sp.create_login_request_url(idp, {}, function(err, login_url, request_id) {
    if (err != null)
      return res.send(500);
    res.redirect(login_url);
  });
});
// Assert endpoint for when login completes
app.post("/assert", function(req, res) {  
  var options = {request_body: req.body};
  sp.post_assert(idp, options, function(err, saml_response) {
    if (err != null){
      console.log("got here");
      console.log(err);
      return res.send(err);  
    }
    // Save name_id and session_index for logout
    // Note:  In practice these should be saved in the user session, not globally.
    name_id = saml_response.user.name_id;
    session_index = saml_response.user.session_index;
    res.send("Hello " +name_id +".");
    //res.send("Hello #{saml_response.user.name_id}!");
  });
});
// Starting point for logout
app.get("/logout", function(req, res) {
  var options = {
    name_id: name_id,
    session_index: session_index
  };
  sp.create_logout_request_url(idp, options, function(err, logout_url) {
    if (err != null)
      return res.send(500);
    res.redirect(logout_url);
  });
});
var httpsOptions = {
  key: fs.readFileSync('./key.pem')
    , cert: fs.readFileSync('./certificate.crt')
}
var httpsServer = https.createServer(httpsOptions, app);
// app.listen(44301,console.log("App on 44301"));
httpsServer.listen(44301,console.log("App on 44301"));