如何使用passport-saml向TestShib IdP提供SP元数据?

时间:2018-03-29 20:02:57

标签: node.js shibboleth passport-saml

我有node.js脚本,使用passport-saml来模拟SP。我的目标是将其连接到此TestShib IdP,但我收到以下错误: SAML 2 SSO配置文件未配置为依赖方

根据我读到的here,我知道我需要提供SP元数据,但我不知道如何。我知道护照-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)
});

提前感谢您的帮助和指导!

1 个答案:

答案 0 :(得分:1)

  

我知道护照-saml具有以下功能:generateServiceProviderMetadata(decryptionCert)我在获得所需证书的同时,我不知道如何使其全部工作。

为了完整起见,我将列出所需的所有步骤。但是你已经完成了前2个,所以你可以跳过它们:

  1. Create the cert/key

  2. 在您的SamlStrategy中,定义decryptionPvk

    decryptionPvk: fs.readFileSync('./credentials/key.pem', 'utf-8'),
    
  3. 最后,您可以创建一个公开元数据的端点(这是您缺少的部分)

    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)));
        }
    );
    
  4. 完成后,您应该能够从/ metadata路径访问元数据。

      

    另外,如果可能的话,我想避免注册我的SP。

    我不是SAML专家,但您可能无法避免注册。这只适用于设置为信任所有SP的IdP,但这没有多大意义,因为SAML的关键部分是在IdP和SP之间建立的双向信任。