I need authenticate a user using passport-saml v2.0 and login after the authenticaton callback successful responds to IDP post request.
I’am using React in front-end with flow router and Picker in back-end.
I Start the authentication in client side when i click in a button and this create a window with make a request to /auth/saml.
The code work, and my user is successful added to mongodb, but now, after the userHandler function return the userId and the token i want to use Meteor.loginWithToken to login, but this function don’t work in server side.
The main problem is use the user information retrived by the IDP in callback function and login with that information.
Server side: Code to initiate the authentication using passport js and passport-saml strategy
import { Picker} from 'meteor/meteorhacks:picker';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import passport from 'passport';
import saml from 'passport-saml';
import expressSession from 'express-session';
Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({extended:false}));
Picker.middleware(cookieParser());
Picker.middleware(expressSession({
secret: 'secret',
resave: false,
saveUninitialized: true,
}));
var samlStrategy = new saml.Strategy({
callbackUrl: process.env.ROOT_URL + '/login/callback', //call back in service provider to handle with the IDP response
entryPoint: 'http://localhost:8080/simplesaml/saml2/idp/SSOService.php', //link for IDP
issuer: 'saml-poc', //id da entidade provedora
identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', //formato requisitado pela entidade
decryptionPvk: process.env.CERTPVK,
privateCert: process.env.CERTPVK,
cert: process.env.IDPKEY,
validateInResponseTo: false,
disableRequestedAuthnContext: true,
}, function(profile, done) {
return done(null, profile);
});
passport.use('samlStrategy', samlStrategy);
Picker.middleware(passport.initialize({}));
Picker.middleware(passport.session({}));
//serialize the user
passport.serializeUser(function(user, done) {
console.log('-----------------------------');
console.log('serialize user');
console.log(user);
console.log('-----------------------------');
done(null, user);
});
//deserialize
passport.deserializeUser(function(user, done) {
console.log('-----------------------------');
console.log('deserialize user');
console.log(user);
console.log('-----------------------------');
done(null, user);
});
Picker.route('/auth/saml',
function(params, req, res, next) {
console.log('Start login handler');
passport.authenticate('samlStrategy', {
session: false,
},
function(err, user, info) {
if (err) {
console.log("Error1");
return next(err);
}
if (!user) {
console.log("Error2");
return res.json(401, {
error: 'Auth Error!'
});
}
}
)(req, res, next);
}
);
Picker.route('/auth/callback',
function (params, req, res, next) {
console.log('-----------------------------');
console.log('/Start login callback ');
passport.authenticate('samlStrategy', {
session: false,
},
async function (err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.json(401, {
error: 'Auth Error!'
});
}
const {userId, token} = await userHandler(user);
res.write("<script>window.close();</script>");
res.flushHeaders();
res.end('Sucess');
})(req, res, next);
});
const userHandler = (user) => new Promise((resolve, reject) => {
let usr = Accounts.findUserByEmail(user.email);
const company = "company";
const profile = { name: "Vinicius França" };
const stampedToken = Accounts._generateStampedLoginToken();
if(!usr){
Meteor.call('adminUser_addNewUser', user.email, null, profile, company, "user", undefined, undefined, true, (err,res) => {
if(!res){
SweetAlert('OPS...', 'Error', 'error');
}
Accounts.findUserByEmail(user.email).then((_usr) => {
Accounts._insertLoginToken(_usr._id, stampedToken);
resolve({userId: _usr._id, token: stampedToken});
})
});
} else {
Accounts._clearAllLoginTokens(usr._id);
Accounts._insertLoginToken(usr._id, stampedToken);
resolve({userId: usr._id, token: stampedToken});
}
});
Client side:
logginSAML() {
this.setState({logginSSO: true});
let authWindow = window.open(
window.location.href + "/auth/saml",
"Window SSO",
"resizable=no,scrollbars=yes,status=yes",
"height=1000px",
"width=100px",
"_blank"
);
const _this = this;
window.onunload = window.onbeforeunload = (e) => {
//is not working
//call login with token here
_this.setState({logginSSO: false});
console.log('q loucura man');
e.returnValue = '';
delete e['returnValue'];
};
}