passport-saml openidp login "failed to open stream" - passport.js

Up front, I'll state that I am a SAML and Passport novice. I am attempting to use passport-saml in my node.js application for SAML authentication, but am getting a failure attempting to login through OpenIdP (the OpenIdP user configuration I have works correctly with the "passport-saml-example" application). The "login" through passport.authenticate to OpenIdP for my application is failing with the following error:
Exception: Error downloading metadata from "http://192.168.1.11:9050": file_get_contents(http://192.168.1.11:9050): failed to open stream: Connection timed out
Backtrace:
4 /www/openidp.feide.no/simplesamlphp/lib/SimpleSAML/Metadata/MetaDataStorageHandlerDynamicXML.php:235 (SimpleSAML_Metadata_MetaDataStorageHandlerDynamicXML::getMetaData)
3 /www/openidp.feide.no/simplesamlphp/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php:274 (SimpleSAML_Metadata_MetaDataStorageHandler::getMetaData)
2 /www/openidp.feide.no/simplesamlphp/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php:310 (SimpleSAML_Metadata_MetaDataStorageHandler::getMetaDataConfig)
1 /www/openidp.feide.no/simplesamlphp/modules/saml/lib/IdP/SAML2.php:296 (sspmod_saml_IdP_SAML2::receiveAuthnRequest)
0 /www/openidp.feide.no/simplesamlphp/www/saml2/idp/SSOService.php:19 (N/A)
My passport-saml configuration is as follows:
passport : {
strategy : 'saml',
saml : {
entryPoint : 'https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php',
issuer : 'http://192.168.1.11:9050',
callbackUrl : 'http://192.168.1.11:9050/login/callback'
}
},
My route configuration for login is as follows:
// "login" route
app.get("/login",
passport.authenticate(config.passport.strategy, {
successRedirect : "/",
failureRedirect : "/login"
})
);
// "login/callback" route
app.post('/login/callback', function (req, res) {
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/',
failureFlash: true
});
res.redirect('/');
});
Here is the passport middleware setup:
passport.serializeUser(function (user, done) {
db.collection('users').find({email: user.email}).toArray(function (err, result) {
console.log("Passport serialize user: " + user);
if (result.length === 0) {
// User is not in the database, add the user.
var insertData = [{email: user.email, firstName: user.givenName, lastName: user.sn}];
db.collection('users').insert(insertData, function (err, result) {
done(null, insertData);
});
} else {
// User is already in the database, just return their data
done(null, result);
}
});
});
passport.deserializeUser(function (user, done) {
console.log("Passport de-serialize user: " + user);
db.collection('users').find({email: user.email}).toArray(function (err, result) {
console.log("Passport de-serialize result: " + result);
done(null, user);
});
});
passport.use(new SamlStrategy(
{
path : config.passport.saml.callbackUrl,
entryPoint : config.passport.saml.entryPoint,
issuer : config.passport.saml.issuer
},
function (profile, done) {
console.log("Returning SAML authentication: " + profile);
return done(null,
{
id : profile.uid,
email : profile.email,
displayName : profile.cn,
firstName : profile.givenName,
lastName : profile.sn
});
}
));
I believe this is all very similar to the passport-saml-example configurations I have seen; any ideas on what I am missing in this configuration?

Issue was due to problems with the SP registration on the IDP.

Related

Reactjs Passport google oath2.0 failureRedirect does not redirect to frontend but to backend instead

I am creating a google authentication to my web application wherein users can login through their email when they have status activated while preventing them to login if they has status deactivated. logging in with user status activated is working fine but when it comes to those user with status deactivated, the failureRedirect does not work in redirecting to my landing page.
here is my code for passport.js
function (accessToken, refreshToken, profile, cb) {
const googleEmail = profile._json.email;
const googlePassword = profile._json.family_name;
User.findOne({
'google.google_id': profile.id
}, function(err, user) {
if (err) {
return cb(err);
}
if (!user) {
user = new User({
google: {
google_id: profile.id,
google_mail: googleEmail,
} ,
name: profile.displayName ,
email: googleEmail ,
password: googlePassword ,
avatar: { url: profile._json.picture }
});
user.save(function(err) {
if (err) console.log(err);
return cb(err, user);
});
} else {
if(user.status == "deactivated" ){
return cb( err);
}else{
return cb( err, user);
}
}
});
}
));
my auth.js
...
router.get("/google/callback",passport.authenticate('google', { failureRedirect: '/'}),
function( req, res) {
sendToken(req.user, 200, res)
});
i always get the error 'CANNOT GET /' on the screen with the url http://localhost:4000/ instead of http://localhost:3000/ which is my frontend

object Object error in signup with passport in express

I am using Passport and Express in a NodeJs project.
I have a User model with fields: id, password, and email. When I try to signup it throws this error:
[object Object]
into the form and it doesn't post user data in the database. In the console, it shows
POST /signup 302 -58.
Here's whole passport.js file:
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var configDB = require('./database.js');
var Sequelize = require('sequelize');
var sequelize = new Sequelize(configDB.url);
var User = sequelize.import('../app/models/users');
User.sync();
// load the auth variables
var configAuth = require('./auth'); // use this one for testing
module.exports = function(passport) {
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id).then(function(user){
done(null, user);
}).catch(function(e){
done(e, false);
});
});
=========================================================================
// LOCAL LOGIN =============================================================
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
User.findOne({ where: { email: email }})
.then(function(user) {
if (!user) {
done(null, false, req.flash('loginMessage', 'Unknown user'));
} else if (!user.validPassword(password)) {
done(null, false, req.flash('loginMessage', 'Wrong password'));
} else {
done(null, user);
}
})
.catch(function(e) {
done(null, false, req.flash('loginMessage',e.name + " " + e.message));
});
}));
=========================================================================
// LOCAL SIGNUP ============================================================
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, email, password, done) {
// Whether we're signing up or connecting an account, we'll need
// to know if the email address is in use.
User.findOne({ where: { email: email }})
.then(function(existingUser) {
// check to see if there's already a user with that email
if (existingUser)
return done(null, false, req.flash('error', 'That email is already taken.'));
// If we're logged in, we're connecting a new local account.
if(req.user) {
var user = req.user;
user.email = email;
user.password = User.generateHash(password);
user.save().catch(function (err) {
throw err;
}).then (function() {
done(null, user);
});
}
// We're not logged in, so we're creating a brand new user.
else {
// create the user
var newUser = User.build ({email: email, password: User.generateHash(password)});
newUser.save().then(function() {done (null, newUser);}).catch(function(err) { done(null, false, req.flash('error', err));});
}
})
.catch(function (e) {
done(null, false, req.flash('loginMessage',e.name + " " + e.message));
})
}));
And in routes.js
// locally --------------------------------
// LOGIN ===============================
// show the login form
app.get('/login', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// SIGNUP =================================
// show the signup form
app.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('loginMessage') });
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
Thanks in advance.
I found the solution!!! It was simpler than I thought, just a carelessness.
In user model I defined password field:
password: {
type: DataTypes.STRING(25),
allowNull: true,
defaultValue: ''
},
And after encryption, this field length was too small to storage the value. So I changed it for 255.

Passport-facebook : 'cannot get /auth/facebook/callback?code= {callback_code}

I'm incorporating Facebook authentication in my app using Passport with Node and Express, and MySQL db (using Bookshelf.js ORM). When I go to log in using Facebook, after entering my Facebook credentials, I get the error 'cannot get /auth/facebook/callback?code= {callback_code}'. I've tried the following solutions I found on stackoverflow: 1, 2, 3, 4
And this outside post: 5
None of these have worked.
In my FB app account, I've set 'Valid OAuth redirect URIs' inside of Client OAuth Settings to 'localhost:8080/auth/facebook/callback', App Domain to 'localhost', and Site URL to 'localhost:8080/'.
Below is my code. Any help is much appreciated!
Routes:
module.exports = function (apiRouter, passport) {
apiRouter.get('/events', isLoggedIn, eventController.getAllEvents);
apiRouter.post('/events', eventController.addEvent);
apiRouter.get('/auth/facebook', passport.authenticate('facebook', {scope : ['email ', 'public_profile', 'user_friends']}));
apiRouter.get('/auth/facebook/callback',
passport.authenticate('facebook', {failureRedirect: '/'}))
};
passport config:
passport.use(new FacebookStrategy({
clientID : configAuth.facebookAuth.clientID,
clientSecret : configAuth.facebookAuth.clientSecret,
callbackURL : 'http://localhost:8080/auth/facebook/callback'
},
function(token, refreshToken, profile, done) {
console.log('looking for user from fb');
process.nextTick(function() {
console.log('looking for user from fb inside async');
new User({ 'facebook_id' : profile.id })
.fetch()
.then(function(userModel) {
if (userModel) {
return userModel;
} else {
new User({
facebook_token: token,
first_name: profile.name.givenName,
last_name: profile.name.familyName
}).save()
.then(function(model) {
console.log('New user saved', model);
done(null, model);
},function(error) {
console.log('Error saving new user: ', error);
done(error);
});
}
done(null, userModel);
}, function(error) {
console.log('Error: ', error);
done(error);
});
});
}));

Req.User values Default to 1st record in DB after Oauth Authentictation Redirect

after a successful authentication with Passport.js, I want a redirect to the user's profile page. However, after the redirect, the value of req.user is set to the first record of the database. So all users see user /1's profile page, instead of the intended page, let's say /33.
How can I keep the information of the session and req.user consistent during a redirect?
The web app is express.js 4.0, and sequelize.js 2.0, and postgres 9.4. Full code is here: https://github.com/skilbjo/dropkey
routes.js file
// Users ==========================
app.route('/users/:id([0-9]+)')
.get(function(req, res) {
controller.users.show(req, res, model);
});
// Dropbox
app.route('/auth/dropbox')
.get( passport.authenticate('dropbox-oauth2') );
app.route('/auth/dropbox/callback')
.get(function(req, res) { passport.authenticate('dropbox-oauth2')(req, res, function() {
res.redirect('/users/' + req.user[0].dataValues.UserId)(req);
});
});
passport.js file
passport.serializeUser(function(user, done) {
return done(null, user);
});
passport.deserializeUser(function(id, done) {
User.find(id)
.complete(function(err, user) {
return done(err, user);
});
});
// Dropbox
passport.use(new DropboxOAuth2Strategy({
clientID : process.env.DROPBOX_KEY,
clientSecret : process.env.DROPBOX_SECRET,
callbackURL : process.env.DROPBOX_CALLBACK
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({where: {
DropboxId: profile.id,
DropboxToken: accessToken,
Name: profile.displayName,
Email: profile.emails[0].value
}})
.complete(function(err, user) {
if (err) return done(err);
if (user) {
return done(null, user);
}
});
}
logs
GET /auth/dropbox 302 3.727 ms - 0
Executing: SELECT "UserId", "DropboxId", "DropboxToken", "Name", "Email" FROM "User" AS "User" WHERE "User"."DropboxId" = // blah blah
[
{ dataValues:
{
UserId: 33, // this is correct
DropboxId: //correct,
DropboxToken: //correct
}
}
]
that's all correct... but then on the redirect, even though the endpoint is /33 (not /1), and the information passed as the req.user is for user 1
logs
GET /auth/dropbox/callback?code=OTsdk-213 302 1266.986 ms - 74
Executing (default): SELECT "UserId", "DropboxId", "DropboxToken", "Name", "Email" FROM "User" AS "User";
[
{ dataValues:
{
UserId: 1, // not the correct user!
DropboxId: // information for user /1, when I want /33
DropboxToken: // information for user /1, when I want /33
}
}
]
I think it's possible your issue might have something to do with the serializeUser function I see in your github:
https://github.com/skilbjo/dropkey/blob/6ef79bbd/lib/config/passport.js#L8
passport.serializeUser(function(user, done) {
return done(null, user);
});
passport.deserializeUser(function(id, done) {
User.find(id)
.complete(function(err, user) {
return done(err, user);
});
});
You're de-serializing from an id, but what you're serializing is the user object. You might try serializing like this instead:
passport.serializeUser(function(user, done) {
return done(null, user.UserId);
});
Another thing that I can't wrap my head around is this code here:
passport.authenticate('dropbox-oauth2')(req, res, function() {
res.redirect('/users/' + req.user[0].dataValues.UserId)(req);
});
From what I understand, the express res.redirect method returns undefined, so I'm not sure what's going on by calling it like a function the way you are.
A friend gave me an excellent suggestion: try it on a small app, remove all complexity, and then start building complexity on from that. That way helped to solve the problem here. The issue is to be really careful what you serialize, deserialize, and the general attributes that live in req.user and how you use them...
passport.js
passport.serializeUser(function(user, done) {
done(null, user[0].UserId);
});
passport.deserializeUser(function(UserId, done) {
User.find(UserId)
.complete(function(err, user) {
return done(err, user);
});
});
users.js controller
exports.show = function(req, res, model) {
model.user
.find(req.user.dataValues.UserId) // <<--- this is where I believe the issue was
.then(function(err, user) {
res.render('users/profile', {
name : req.user.Name,
email : req.user.Email
});
});
};

How to properly set the server login code?

I'm trying to set up a login page using passport-local this way, but it wouldn't work:
node server side:
// mongoose
var User = mongoose.model('User', userSchema);
User.find({}).exec(function(err, collection){
if(collection.length === 0) {
User.create({identifiant: '123', motDePasse: '123'});
}
});
// passport-local
passport.use(new LocalStrategy(
function(identifiant, motDePasse, done) {
console.log(identifiant); // It's not logging
User.findOne({identifiant:identifiant}).exec(function(err, user) {
if(user) {
return done(null, user);
} else {
return done(null, false);
}
})
}
));
passport.serializeUser(function(user, done) {
if(user) {
done(null, user._id);
}
});
passport.deserializeUser(function(id, done) {
User.findOne({_id:id}).exec(function(err, user) {
if(user) {
return done(null, user);
} else {
return done(null, false);
}
})
});
// route
app.post('/connexion', function(req, res, next){
var auth = passport.authenticate('local', function(err, user) {
if(err) {return next(err);}
if(!user) {res.send({success: false});}
req.logIn(user, function(err) {
if(err) {return next(err);}
res.send({success: true, user: user});
})
});
auth(req, res, next);
});
angular client:
app.controller('uAsideLoginCtrl', function($scope, $http, uIdentity, uNotifier){
$scope.identity = uIdentity;
$scope.signin = function(identifiant, motDePasse){
$http.post('/connexion', {identifiant: identifiant, motDePasse: motDePasse}).then(function(res){
if(res.data.success) {
uIdentity.currentUser = res.data.user;
uNotifier.success("Vous ĂȘtes maintenant connectĂ©!");
} else {
uNotifier.error("L'identifiant ou le mot-de-passe est incorrecte.");
}
});
};
});
Here is the mongodb's user row :
{ "_id" : ObjectId("53df7b3b769827786b32dafe"), "identifiant" : "123", "motDePasse" : "123", "__v" : 0 }
I think that it's comming from LocalStrategy. I'm not getting the result of the console.log.
Any brilliant idea, please?
What's wrong, please ?
The problem's not within the code you showed. My guess is that the parameters used in your request to /connexion (I assume it's a regular form with a POST method) are misnamed, because you set custom field names.
From Passport's official docs :
By default, LocalStrategy expects to find credentials in parameters named username and password. If your site prefers to name these fields differently, options are available to change the defaults.
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'passwd'
},
function(username, password, done) {
// ...
}
));
But your name rings a bell, didn't you ask a similar question yesterday, we helped you, and you deleted your post after that ?

Resources