我有一个 node.js
脚本,使用 passport-saml 来模拟 SP。我的目标是将其连接到此 TestShib IdP,但出现以下错误: SAML 2 SSO 配置文件未配置为依赖方 。
根据我阅读的内容 here ,我知道我需要提供 SP 元数据,但我不知道如何提供。我知道passport-saml 具有以下功能:generateServiceProviderMetadata(decryptionCert)
和我虽然拥有所需的证书,但我不知道如何使其全部工作。
另外,如果可能的话,我想避免必须注册我的 SP。
这是我的脚本:
const https = require('https');
const fs = require('fs');
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const passport = require('passport');
const saml = require('passport-saml');
/*
---------------------------------------------------------------------------------------------------
-- certificates
---------------------------------------------------------------------------------------------------
*/
// for https server
const https_cert = fs.readFileSync('certificate.pem', 'utf-8');
const https_pvk = fs.readFileSync('privatekey.pem', 'utf-8');
// from idp's metadata
const idp_cert_1 = 'MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryhm3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEmlGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBnxoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTHot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQIDAQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQwEoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzROZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QPdRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOTMVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhORkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqXMLRKhDgdmA==';
const idp_cert_2 = 'MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryhm3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEmlGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBnxoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTHot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQIDAQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQwEoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzROZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QPdRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOTMVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhORkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqXMLRKhDgdmA==';
/*
---------------------------------------------------------------------------------------------------
-- passport-saml setup
---------------------------------------------------------------------------------------------------
*/
const saml_strategy = new saml.Strategy(
{
'callbackUrl': 'https://localhost:44300/login/callback',
'entryPoint': 'https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO',
'issuer': 'https://localhost:44300',
'decryptionPvk': https_pvk,
'cert': [idp_cert_1, idp_cert_2]
},
function (profile, done)
{
console.log('passport.use() profile: %s \n', JSON.stringify(profile));
return done(
null,
{
'nameIDFormat': profile.nameIDFormat,
'nameID': profile.nameID
}
);
}
);
passport.serializeUser(function (user, done) {
console.log('passport.serializeUser() user: %s \n', JSON.stringify(user));
done(null, user);
});
passport.deserializeUser(function (user, done) {
console.log('passport.deserializeUser() user: %s \n', JSON.stringify(user));
done(null, user);
});
passport.use(saml_strategy);
/*
---------------------------------------------------------------------------------------------------
-- express setup
---------------------------------------------------------------------------------------------------
*/
const app = express();
// configure view engine to render EJS templates
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// additional settings for logging and parsing
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({'extended': true}));
app.use(session({ 'secret': 'this-is-secret', 'resave': false, 'saveUninitialized': false }));
// initialize Passport and restore authentication state, if any, from the session
app.use(passport.initialize());
app.use(passport.session());
/*
---------------------------------------------------------------------------------------------------
-- routes
---------------------------------------------------------------------------------------------------
*/
app.get(
'/',
function (req, res) {
if (req.isAuthenticated()) {
console.log('GET [/] user authenticated! req.user: %s \n', JSON.stringify(req.user));
res.render('home', { 'user': req.user });
} else {
console.log('GET [/] user not authenticated! \n');
res.render('home', { 'user': null });
}
}
);
app.get(
'/login',
passport.authenticate('saml', { 'successRedirect': '/', 'failureRedirect': '/login' })
);
app.post(
'/login/callback',
passport.authenticate('saml', { 'failureRedirect': '/', 'failureFlash': true }),
function(req, res) {
console.log('POST [/login] \n');
res.redirect('/');
}
);
app.get(
'/profile',
function(req, res){
if (req.isAuthenticated()) {
console.log('GET [/profile] user authenticated! req.user: %s \n', JSON.stringify(req.user));
res.render('profile', { 'user': req.user });
} else {
console.log('GET [/profile] user not authenticated! \n');
res.redirect('/login');
}
}
);
app.get(
'/logout',
function(req, res) {
console.log('GET [/logout] \n');
passport._strategy('saml').logout(
req,
function(err, requestUrl) {
req.logout();
res.redirect('/');
}
);
}
);
/*
---------------------------------------------------------------------------------------------------
-- start https server
---------------------------------------------------------------------------------------------------
*/
const server = https.createServer({
'key': https_pvk,
'cert': https_cert
}, app);
server.listen(44300, function() {
console.log('Listening on https://localhost:%d', server.address().port)
});
在此先感谢您的帮助和指导!
最佳答案
为了完整起见,我将列出所需的所有步骤。但是您已经完成了前 2 个,因此您可以跳过它们:
decryptionPvk
decryptionPvk: fs.readFileSync('./credentials/key.pem', 'utf-8'),
app.get('/metadata',
function(req, res) {
const decryptionCert = fs.readFileSync('./credentials/cert.pem', 'utf-8');
res.type('application/xml');
res.send((myStrategy.generateServiceProviderMetadata(decryptionCert)));
}
);
这是重新格式化以匹配您发布的示例代码的样子:
app.get(
'/metadata',
function(req, res) {
res.type('application/xml');
res.send((saml_strategy.generateServiceProviderMetadata(https_cert)));
}
);
完成后,您应该能够从/metadata 路径访问您的元数据。
我不是 SAML 专家,但您可能无法避免注册。这仅适用于设置为信任所有 SP 的 IdP,但这没有多大意义,因为 SAML 的一个关键部分是在 IdP 和 SP 之间建立的双向信任。
关于node.js - 如何使用passport-saml向TestShib IdP提供SP元数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49564161/