DEV Community

SSO + Express JS + Passport-saml

Mitesh Kamat on February 10, 2020

Introduction In my previous post, I had mentioned about decoding saml response. Going ahead with that I integrated single-sign-on with m...
Collapse
 
gspagoni profile image
Giampaolo Spagoni

Hello Mitesh, great article
do you have a github repo for all the code?
thanks

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

Thanks for writing. I have a private repo but yet to create a public repo. Once I'm done with it I'll share in this post.

Collapse
 
gspagoni profile image
Giampaolo Spagoni

Hello Mitesh, it's me again. i have another question that maybe you can help me out. i used passport-saml for SSO and it worked. now i have to make a ws trust call to get the token back but i have to pass the Assertion on the header. do you have an example how looks like the assertion or i can i do ? thanks in advance

Thread Thread
 
miteshkamat27 profile image
Mitesh Kamat • Edited

Hi There,

Apologies for late response. Did you try passport-jwt package?
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;

And maybe you can create an options object like:
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); //depends
opts.secretOrKey = config.secretKey;

passport.use(new JwtStrategy(opts,
(jwt_payload, done) => {
console.log('JWT payload', jwt_payload);
}
)));

And if you have specified a login route like this:
router.post('/login', passport.authenticate('saml'), (req, res) => {
var token = jwt.sign({_id: req.user._id}, config.secretKey, {
expiresIn: '1h'
});
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, token: token, status: 'You are successfully logged in !' })
});
Let me know if this is what you are looking for.

Thread Thread
 
gspagoni profile image
Giampaolo Spagoni

Thank you Mitesh
thanks for your reply which is good but it answer partially to my request
what I'm looking for is how to create an RTS to post as soap request including the assertion. I'm not very strong in security so forgive me if I don't use the right terminology. in short, after the SSO I need to make a was trust call passing the RST and once I got the RSTR I need to extract the token which I guess is what you wrote above

thanks for your help
GS

Collapse
 
sripalinm profile image
Sripalinm • Edited

Hi Mitesh, Initially, Thanks a lot for knowledge sharing, could you please share complete code with git location, and could you please share the link, your blog which mentioned decoding saml response.

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

Hi There,
Thanks for writing. This is the post which I am referring to Parsing namespace. Actually, this code is a part of my team project but let me see if I can create a reproducible repo for the same which will be of help.

Collapse
 
raysercast1 profile image
raysercast1

Hi MItesh!! I want to know if you could do a reproducible repo? I'm new as a programmer and I was assigned to create a SP and It would be very helpful if I can use a repo as a guide :). Thank a lot for this post!

Collapse
 
sripalinm profile image
Sripalinm

Hi Mitesh, Really Thanks for the quick and kind response, and If its possible, then it will be the greatest help for me.

Collapse
 
goyaldeeksha profile image
goyal-deeksha

Hi Mitesh,
I am new to SSO. I am creating micro services like users.abc.com, goals.abc.com etc... with separate backend, frontend and database for each.
I have to create SSO so that I will be able to login in all systems with single credentials.
Will you please tell me, passport-saml strategy is the right choice for that and if yes, then how can I achieve that.
And you have something different, then please let me know.

Thanks in advance.

Collapse
 
bankurukodanda profile image
Kodanda • Edited

Hi Mitesh,
small doubt
router.post('/SSO', passport.authenticate('saml', { failureRedirect: '/', failureFlash: true }), function (req, res) {
//Logic
});
control is not coming to inside of this function can you please suggest me what is the issue

My passport code

var passport = require('passport');
var SamlStrategy = require('passport-saml').Strategy;

var users = [];

function findByEmail(email, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
if (user.email === email) {
return fn(null, user);
}
}
return fn(null, null);
}

passport.serializeUser(function(user, done) { //console.log('inside seriliaze');console.log(user.Email);
done(null, user.Email);
});

passport.deserializeUser(function(id, done) { //console.log('deserialized');
findByEmail(id, function (err, user) {
done(err, user);
});
});

passport.use(new SamlStrategy(
{
issuer: "",
path: '/healthCheck',
entryPoint: "
",
cert: "**"
},
function(profile, done) {
//console.log('inside Saml Strategy');console.log(profile.Email);
if (!profile.Email) {
return done(new Error("No email found"), null);
}
process.nextTick(function () {
findByEmail(profile.Email, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
users.push(profile);
return done(null, profile);
}
return done(null, user);
})
});
}, function (err){
console.log(err);
}
));

passport.protected = function protected(req, res, next) {//console.log('inside protected');
if (req.isAuthenticated()) {
return next();
}

res.redirect('/healthCheck');
};

exports = module.exports = passport;

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

Can you try adding a middleware for router.post('/SSO', authMiddleware);

module.exports = function authMiddleware(req, res, next) {
  req.query.RelayState = req.headers.referer;
  console.log("referer", req.headers);
  passport.authenticate('saml')(req, res, next);
}

Enter fullscreen mode Exit fullscreen mode

Check if the control reaches here.
I saw this issue while implementation. As per the official documentation it should work but the control never reaches the success and failure part. So, we have added a middleware to get through this. Let me know if this helps.

Collapse
 
alexbran8 profile image
alexbran8

Hello! thanks for this awesome tutorial! Could you please let me know, if I need to send a XML metadata URL to the idp, how can I achieve this?
I am using the entity_ID of another application(django) which I need to pass to idP?

for django saml the parameter is "entity_id"...

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

Thanks for writing. At the moment I have an xml file with metadata in my local setup, but yes considering different environments we would need to send the xml metadata url to idp to have required metadata. I am yet to implement it for production level. If I figure it out , then I'll post it here. I hope I understood your question so that I can provide you my configuration setup.

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

router.get('/metadata', function(req, res){
  const decryptionCert = //certificate goes here
  res.type('application/xml');
  res.send(strategy.generateServiceProviderMetadata(decryptionCert,decryptionCert));
 }
);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sripalinm profile image
Sripalinm

Could you please let us know what is the "keyConfig" (in app.js) , and how should be the content there,

Collapse
 
raysercast1 profile image
raysercast1

Hi Sripalinm. Could you find out what does keyConfig do and the content in it ?

Collapse
 
miteshkamat27 profile image
Mitesh Kamat

Hi There,
Sorry for late response. KeyConfig is nothing but an object which consists of secret key, token signing algorithm details, etc.

Like:

module.exports = {
    secretKey: 'a@b!#key',
   tokenAlgo: 'aes-128-cbc'
...
}
Collapse
 
bart96b profile image
BART96

«lodash»? Realy? 2020 year!