Logout using passport-saml: req.logout () or Strategy.logout () or both?
I have a question regarding the correct way to log out a user when using passport-saml for authentication.
An example script with passport-saml shows the logout as follows:
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
From what I can tell, this will end the local passport session, but it doesn't seem to be sending a logout request to the SAML IdP. When the user makes another login, it redirects to the IdP, but immediately redirects back with the authenticated user. Is there a way to log out of the IdP system so that the user will re-enter their password when they log into my site? I have seen other sites that use our IdP, so I think it is possible.
In passport-saml-code, I noticed that there is a method logout()
on the Strategy-saml file object that doesn't appear to be called req.logout()
. So I tried to switch the code to this:
app.get('/logout', function(req, res) {
//strategy is a ref to passport-saml Strategy instance
strategy.logout(req, function(){
req.logout();
res.redirect('/');
});
});
But I got this error deep in XMLNode.js
Error: Could not create any elements with: [object Object]
at XMLElement.module.exports.XMLNode.element (/.../node_modules/passport-saml/node_modules/xmlbuilder/lib/XMLNode.js:74:15)
at XMLElement.module.exports.XMLNode.element (/.../node_modules/passport-saml/node_modules/xmlbuilder/lib/XMLNode.js:54:25)
at XMLElement.module.exports.XMLNode.element (/.../node_modules/passport-saml/node_modules/xmlbuilder/lib/XMLNode.js:54:25)
at new XMLBuilder (/.../node_modules/passport-saml/node_modules/xmlbuilder/lib/XMLBuilder.js:27:19)
at Object.module.exports.create (/.../node_modules/passport-saml/node_modules/xmlbuilder/lib/index.js:11:12)
at SAML.generateLogoutRequest (/.../node_modules/passport-saml/lib/passport-saml/saml.js:169:21)
Am I not calling this method correctly? Or should I not directly access this method and instead use a different method?
I see that in generateLogoutRequest()
it is referring to two properties req.user
that I am not sure about:
'saml:NameID' : {
'@Format': req.user.nameIDFormat,
'#text': req.user.nameID
}
If these properties are not present, will this result in this error? If so, my guess is that maybe I need to make sure these properties are added to the user object that is returned from the validation callback function?
Thanks for any help anyone can provide on this.
source to share
Yes, adding the nameIDFormat and nameID to the user will fix the problem.
- To enable logout, you must configure the logoutURL parameter in your strategy.
logoutUrl: 'http://example.org/simplesaml/saml2/idp/SingleLogoutService.php',
The exit method in the strategy does not actually send the request. the callback function is called with a request as a parameter.
To start the logout process:
passport.logoutSaml = function(req, res) {
//Here add the nameID and nameIDFormat to the user if you stored it someplace.
req.user.nameID = req.user.saml.nameID;
req.user.nameIDFormat = req.user.saml.nameIDFormat;
samlStrategy.logout(req, function(err, request){
if(!err){
//redirect to the IdP Logout URL
res.redirect(request);
}
});
};
edit: nameId and nameIdFormat should be saved somewhere on successful login
var samlStrategy = new SamlStrategy(
{
callbackUrl: 'https://mydomain/auth/saml/callback',
entryPoint: 'https://authprovider/endpoint',
logoutUrl: 'https://authprovider/logoutEndPoint',
issuer: 'passport-saml'
},
function(profile, done) {
//Here save the nameId and nameIDFormat somewhere
user.saml = {};
user.saml.nameID = profile.nameID;
user.saml.nameIDFormat = profile.nameIDFormat;
//Do save
});
});
- You will also need to create an endpoint for the exit callback:
This URL needs to be configured in your SP metadata in your IdP configuration. The IdP will be redirected to this URL after logging out.
in your routes:
app.post('/auth/saml/logout/callback', passport.logoutSamlCallback);
In the configuration of your passport:
passport.logoutSamlCallback = function(req, res){
req.logout();
res.redirect('/');
}
source to share