I am able to authenticate via LDAP, but I can't seem to figure out how to catch an error when a user enters an invalid username/password. I have failureRedirect and other stuff setup, but it doesn't get to that step in the authenticate function when an error does occur. I have tried putting in try catch functions with no luck either.
Here is the link to the authentication strategy being used:
https://www.npmjs.com/package/passport-activedirectory
front end -I have tried changing the {{#if error}} to {{#if failWithError}} as well.
{{#if error}}
<div class="alert alert-danger">
Warning! {{error}}
</div>
{{/if}}
**error message that is displayed to the user **
InvalidCredentialsError: 80090308: LdapErr: DSID-0C0903C5, comment: AcceptSecurityContext error, data 52e, v2580
at messageCallback (d:\........\node_modules\ldapjs\lib\client\client.js:1419:45)
at Parser.onMessage (d:\........\node_modules\ldapjs\lib\client\client.js:1089:14)
at emitOne (events.js:96:13)
at Parser.emit (events.js:188:7)
at Parser.write (d:\........\node_modules\ldapjs\lib\messages\parser.js:111:8)
at Socket.onData (d:\........\node_modules\ldapjs\lib\client\client.js:1076:22)
at emitOne (events.js:96:13)
at Socket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:176:18)
at Socket.Readable.push (_stream_readable.js:134:10)
block of code in ..\node_modules\ldapjs\lib\client\client.js line 1419
if (expect.indexOf(msg.status) === -1) {
return sendResult('error', errors.getError(msg));
}
auth.js
module.exports = function(app,passport) {
let opts = {
failWithError: true,
failureRedirect: '/',
successRedirect: '/dashboard',
failureFlash: true
};
app.post('/login', passport.authenticate('ActiveDirectory', opts), function(req, res) {
res.json(req.user);
}, function(err) {
if (err) res.status(401).send('Not Authenticated');
});
};
passport.js
module.exports = function(passport) {
var ActiveDirectoryStrategy = require('passport-activedirectory');
passport.serializeUser(function (user, done) { done(null, user); });
passport.deserializeUser(function (user, done) { done(null, user); });
passport.use(new ActiveDirectoryStrategy({
integrated: false,
passReqToCallback: true,
ldap: {
url: 'ldap://a.b.awesome:389',
baseDN: 'DC=a,DC=b,DC=awesome',
bindDN: 'CN=rando user,OU=users,DC=a,DC=b,DC=awesome',
bindCredentials: 'ASecret',
searchBase: 'OU=users,DC=a,DC=b,DC=awesome',
searchFilter: '(sAMAccountName={{username}})',
attributes: ['dn', 'displayName', 'givenName', 'sn', 'title', 'userPrincipalName', 'sAMAccountName', 'mail', 'description', 'memberOf'],
logging: {
name: 'ActiveDirectory',
streams: [
{ level: 'debug',
stream: process.stdout }
]
}
}
}, function (req, profile, ad, done) {
ad.isUserMemberOf(profile._json.dn, '123', function (err, isMember) {
if (err) return done(err);
return done (null, profile)
})
}));
};
So I was able to 'catch' the error and no longer display the error message to user.
However, express handlebars does not want to display my custom error message, I may be doing that wrong.
The answer for catching the error:
https://github.com/bhoriuchi/passport-activedirectory/issues/4
auth.js
app.post('/login', passport.authenticate('ActiveDirectory', opts), function(req, res) {
res.json(req.user);
}, function(err, req, res, next) {
let statusCode = /InvalidCredentialsError/.test(err.stack)
? res.redirect('/') && res.send( {error: 'Invalid Credentials!'} )
: 500;
return res.status(statusCode)
});
EDIT
I also figured out how to send data to the front end to be displayed in a nice manner.
new auth.js
app.post('/login', passport.authenticate('ActiveDirectory', opts), function(req, res) {
res.json(req.user);
}, function(err, req, res, next) {
let statusCode = /InvalidCredentialsError/.test(err.stack)
? res.render('login', {failWithError: true, error: 'Invalid Username or Password!'})
: res.status(500);
return statusCode
});
front end .hbs
{{#if failWithError}}
<div class="alert alert-danger">
<strong>Error!</strong> {{error}}
</div>
{{/if}}
I used your solution for a bit, but I think this works better IMO:
router.post('/login', (req, res, next) => {
passport.authenticate('ActiveDirectory', opts, (err, user, info) => {
if (err) {
return next(err)
}
if (! user) {
return res.redirect('/login')
}
req.login(user, (err) => {
if(err) {
return next(err)
}
return res.json(req.user)
})
}) (req, res, next)
})
Related
I want to log in with ajax.
I want user information to be recorded in the request parameter.
But when I do it with ajax, user information is not registered in the request parameter.
so req.user --> undefined
he's turning.
How can I solve this?
local auth passport codes:
const LocalStrategy = require("passport-local").Strategy;
const passport = require("passport");
const bcrypt = require("bcrypt");
const User = require("../models/User");
passport.use(
"user-login",
new LocalStrategy(
{
usernameField: "email",
},
(email, password, done) => {
User.findOne(
{
email,
},
(err, user) => {
if (err) return done(err, null, "Bir hata olustu");
if (!user) {
return done(null, false, "Böyle bir email yok.");
}
bcrypt.compare(password, user.password, (err, res) => {
if (res) {
return done(null, user, "Başarıyla giriş yapıldı.");
} else {
return done(null, false, "Yanlış şifre girildi");
}
});
}
);
}
)
);
passport.serializeUser(function (user, done) {
console.log(user);
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
console.log(user);
done(err, user);
});
});
router:
module.exports.postLogin = async (req, res, next) => {
passport.authenticate("user-login", {
successRedirect: "/",
failureRedirect: "/users/login",
failureFlash: true,
successFlash: true,
})(req, res, next);
}
app.js middleware
app.use((req, res, next) => {
console.log(req.user);
next();
});
print:
POST /admin/login 302 2304.994 ms - 23
{
_id: 5fb8fa8c26cdfc239c4276b9,
username: 'tolgaand',
password: '$2b$10$XhifEgbN4mEiCGPvm/dF5.zHYlEPZW3Jhibjm4ABuhEeRJ34psYsu',
name: 'Tolga',
lastName: 'Çağlayan',
title: 'Javascript Geliştiricisi',
about: "mongodb'ye bağlandım olley",
phone: '+90 534 393 6238',
email: 'tolgaand#yandex.com',
location: 'İstanbul / Türkiye',
available: 'Müsait',
permission: 0,
__v: 0
}
{}
router with ajax (i want)
module.exports.postLogin = async (req, res, next) => {
passport.authenticate("user-login", (error, user, info) => {
if (error) {
return res.json({ success: false, message: info.message });
}
if (!user) {
return res.json({ success: false, message: info });
}
res.json({ success: true, message: info, user });
})(req, res, next);
};
print:
POST /admin/login 200 998.327 ms - 446
undefined
{}
how can I do this with jquery / ajax?
instead of undefined, I just want user information to be registered as above.
I'm trying to secure an API endpoint on a node.js express app that uses passport.
This is my route:
router.post('/api/devices', authController.isAuthorized, catchErrors(deviceController.getDevicesAPI));
This is my authorization method:
exports.isAuthorized = (req, res, next) => {
passport.authenticate('local', {session: false}, (err, user, info) => {
if (err || !user) {
return res.json({ message: 'Something is not right ', err, info });
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
next();
});
})(req, res);
};
From Postman or a separate local server, I get the response:
{
"message": "Something is not right ",
"err": null,
"info": {
"message": "Missing credentials"
}
}
This is the Postman configuration:
What am I missing?
How is your local strategy configured? It seems like a database query problem
As the sample in http://www.passportjs.org/docs/username-password/, please see my comments below
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) { //<--- Here is where you pass the UN&PASS
User.findOne({ username: username }, function(err, user) { //<--- Here is the sample code that should find you a user
if (err) { return done(err); } //<--- Here could be where the response is coming from
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user); //<--- Here is the sample code that should let you return that user
});
}
));
I finally dug it out from here. User.authenticate() is the method I was looking for.
exports.isAuthorized = async (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
const user = await User.findOne({ email: username });
if (!user) {
res.sendStatus(403);
return;
}
user.authenticate(password, function(err, result) {
if (result) {
next();
return;
}
res.sendStatus(403);
});
};
I have built a mini CMS system using Node Js, Express, Mongoose and Passport.js.
When the client is loging out, I get this error in the console: 'Cannot read property 'id' of null', the error comes from the PrivateThread.find().lean().then()...
// Pass User Data To Template
function sendUserData(req, res, next) {
if (req.isAuthenticated()) {
User.findById(req.user.id, doNotSend).then(user => {
switch(true) {
case user.banned:
req.logOut();
flashRedirect(req, res, '/login', 'res-err', 'Some message');
break;
case !user.activated:
req.logOut();
flashRedirect(req, res, '/login', 'res-err', 'Somem message');
break;
default:
res.locals.foundUser = user;
PrivateThread.find({ participants: req.user.id }).lean().then(foundThreads => {
let notifications = foundThreads.filter(thread => !thread.readBy.toString().includes(req.user.id));
res.locals.notifications = notifications.length;
});
next();
}
})
.catch((err) => res.send(err));
} else {
next();
}
}
This is the logout route:
router.get('/logout', (req, res) => {
req.logOut();
res.redirect('/');
});
I'm only getting the error when the client is loging out through the logout page.
When configuring passport using Express and NodeJS, I am throwing an error if the user has an invalid email address. After this error I would like to redirect to a failure page giving them instructions on how to log in correctly. Is there are a better way to do this? If not, how would I go about catching the error in some fashion and redirecting to a new page.
passport.use(new GoogleStrategy({
clientID : auth.googleAuth.clientID,
/* Settings redacted for brevity */
},
function(token, refreshToken, profile, done) {
User.findOne(
{
"google.id" : profile.id
},
function(err, user) {
if (err) return done(err)
if (user) return done(null, user)
else {
if (email.indexOf("lsmsa.edu") > -1) {
// Code redacted for brevity
} else {
done(new Error("Invalid email address"))
}
}
}
)
}))
I think you can use this:
Redirects
A redirect is commonly issued after authenticating a request.
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
In this case, the redirect options override the default behavior. Upon
successful authentication, the user will be redirected to the home
page. If authentication fails, the user will be redirected back to the
login page for another attempt.
Or this:
Custom Callback
If the built-in options are not sufficient for handling an
authentication request, a custom callback can be provided to allow the
application to handle success or failure.
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
Please read the document:
https://www.passportjs.org/concepts/authentication/downloads/html/#middleware
Note: I quite like BlackMamba's answer as well, adding the custom callback / redirect is a perfectly acceptable option.
Simply add your own error handling middleware to Express:
passport.use(new GoogleStrategy({
clientID : auth.googleAuth.clientID,
/* Settings redacted for brevity */
},
function(token, refreshToken, profile, done) {
User.findOne({
"google.id" : profile.id
},
function(err, user) {
if (err) return done(err)
if (user) return done(null, user)
else {
if (email.indexOf("lsmsa.edu") > -1) {
} else {
// Throw a new error with identifier:
done(throw {
type: "invalid_email_address",
code: 401,
profileId: profile.id
}));
}
}
}
)
}));
// The error handling middleware:
app.use(function(e, req, res, next) {
if (e.type === "invalid_email_address") {
res.status(e.code).json({
error: {
msg: "Unauthorized access",
user: e.profileId
}
});
}
});
You'll notice I modified this answer a little bit with a more robust error composition. I've defined the code property of the error to match the applicable HTTP status code -- in this case, 401:
// callback
done(throw {
// just a custom object with whatever properties you want/need
type: "invalid_email_address",
code: 401,
profileId: profile.id
}));
In the error handling, we simply check the type is invalid_email_address (you can make it whatever you want, but it should be consistent across your app) and then write the error out using the "code" as the HTTP status code:
// e is the error object, and code is the custom property we defined
res.status(e.code).json({
error: {
msg: "Unauthorized access",
user: e.profileId
}
});
Here's a self-contained working example with a redirect:
var express = require('express');
var app = express();
app.all('*', function(req, res) {
throw {type: "unauthorized", code: 401}
})
app.use(function(e, req, res, next) {
console.log(e);
if (e.code === 401) {
res.redirect("/login")
} else {
res.status(500).json({error: e.type});
}
});
app.listen(9000);
I am integrating SailsJS and Passport. I have a fairly simply controller but during the "process" method where I process the login I get the following error:
TypeError: Object #<Object> has no method 'authenticate'
You can see in the controller I am calling the passport.authenticate() method, according to docs this should exist.
LoginController.js
module.exports = {
login: function(req, res) {
res.view("login",{});
},
process: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if( (err)||(!user) ) {
return res.send({
message: 'login failed'
});
res.send(err);
}
req.logIn(user, function(err) {
if(err) res.send(err);
return res.send({
message: 'login successful'
});
});
}) (req, res);
},
logout: function(req, res) {
req.logOut();
res.send('logout successful');
}
};
#idbehold got this one, I wasn't requiring passport any where.