How to provide SP metadata to TestShib IdP using passport-saml?

Deadly 提交于 2019-12-08 01:36:51

问题


I have a node.js script, using passport-saml, that simulates an SP. My goal is to connect it to this TestShib IdP but I get the following error: SAML 2 SSO profile is not configured for relying party.

Based on what I read here, I know that I need to provide the SP metadata, but I do not know how. I know that passport-saml has the function: generateServiceProviderMetadata(decryptionCert) and I while I have the certificates required, I do not know how to make it all work.

Also, I want to avoid having to register my SP if that is possible.

Here is my script:

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)
});

Thank you in advance for your help and guidance!


回答1:


I know that passport-saml has the function: generateServiceProviderMetadata(decryptionCert) and I while I have the certificates required, I do not know how to make it all work.

For the sake of completeness, I'll list all the steps needed. But you've already done the first 2 so you can skip them:

  1. Create the cert/key

  2. In your SamlStrategy, define decryptionPvk

    decryptionPvk: fs.readFileSync('./credentials/key.pem', 'utf-8'),
    
  3. Lastly, you can create an endpoint that exposes your metadata (this is the part you're missing)

    app.get('/metadata',
      function(req, res) {
        const decryptionCert = fs.readFileSync('./credentials/cert.pem', 'utf-8');
        res.type('application/xml');
        res.send((myStrategy.generateServiceProviderMetadata(decryptionCert)));
      }
    );
    

    Here's what that would look like reformatted to match the sample code you posted:

    app.get(
        '/metadata',
        function(req, res) {
            res.type('application/xml');
            res.send((saml_strategy.generateServiceProviderMetadata(https_cert)));
        }
    );
    

Once that's done you should be able to access your metadata from the /metadata path.

Also, I want to avoid having to register my SP if that is possible.

I'm not a SAML expert, but you probably won't be able to avoid registration. This would only work with an IdP that was set up to trust all SPs, but that wouldn't make much sense because a key part of SAML is the two-way trust that's established between the IdP and SP.



来源:https://stackoverflow.com/questions/49564161/how-to-provide-sp-metadata-to-testshib-idp-using-passport-saml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!