I'm trying to get the data from LDAP and I'm getting it successfully but it's not written into variable so then after the code is executed I can make some checks on the data.
var server = LdapJS.createClient({
url: LdapConf.server.url,
tlsOptions: LdapConf.server.tlsOptions
});
server.bind(LdapConf.server.bindDN, LdapConf.server.bindCredentials, function(err) {
if (err) {
return done(err);
}
});
var SearchOtps = {
filter: '(uid=' + username + ')',
scope: 'one',
};
var UserSearch = server.search(LdapConf.server.searchBase, SearchOtps, function(err, res) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
return (JSON.stringify(entry.object));
});
res.on('searchReference', function(referral) {
//console.log('referral: ' + referral.uris.join());
});
res.on('error', function(err) {
//console.error('error: ' + err.message);
});
res.on('end', function(result) {
//console.log('status: ' + result.status);
});
});
console.log(UserSearch);
I just do not know how to stop further code execution while it's waiting for the return of the LDAP search.
Server Started
undefined
You could do a function that returns it in promise.
function UserSearch(server,LdapConf, SearchOtps) {
return new Promise(function(resolve,reject) {
server.search(LdapConf.server.searchBase, SearchOtps, function(err, res) {
res.on('searchEntry', function(entry) {
console.log('entry: ' + JSON.stringify(entry.object));
resolve(JSON.stringify(entry.object)));
});
res.on('searchReference', function(referral) {
//console.log('referral: ' + referral.uris.join());
});
res.on('error', function(err) {
reject()
});
res.on('end', function(result) {
//console.log('status: ' + result.status);
});
});
}
}
UserSearch(server,LdapConf, SearchOtps)
.then(function(res) {
console.log(res)
})
Related
Facebook.create executes before fbUtils.getLongTermToken finishes retrieving the long term token. This is causing validation issues when trying to create the user. Do I need to use promises to manage the asynchronous execution that's happening here?
var userData = req.body;
userData.email = userData.email.toLowerCase();
userData.fbAuthToken = fbUtils.getLongTermToken(userData.fbAuthToken);
FacebookUser.create(userData, function (err, fbUser) {
console.log(userData.fbAuthToken);
if (err) {
console.log(err.message);
if (err.toString().indexOf('E11000') > -1) {
err = new Error('Email already exists.');
}
res.status(400);
return res.sendStatus({reason: err.toString()});
} else {
res.send('success');
}
});
Here's the code for fbUtils.getLongTermToken:
getLongTermToken: function (token) {
var options = {
host: 'graph.facebook.com',
path: '/oauth/access_token?grant_type=fb_exchange_token'
+ '&client_id=' + CONSTANTS.FACEBOOK_APP_ID
+ '&client_secret=' + CONSTANTS.FACEBOOK_APP_SECRET
+ '&fb_exchange_token=' + token
};
var str = '';
http.get(options, function (res) {
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
console.log(str);
console.log(fbUtils.parseToken(str));
return fbUtils.parseToken(str);
});
}).on('error', function(err) {
console.log('longterm error: ' + err.message);
});
return str;
}
You need to update getLongTermToken to take a callback too, which will be called when the token retrieval is complete. For example:
getLongTermToken: function (token, cb) {
var options = {
host: 'graph.facebook.com',
path: '/oauth/access_token?grant_type=fb_exchange_token'
+ '&client_id=' + CONSTANTS.FACEBOOK_APP_ID
+ '&client_secret=' + CONSTANTS.FACEBOOK_APP_SECRET
+ '&fb_exchange_token=' + token
};
var str = '';
http.get(options, function (res) {
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
console.log(str);
console.log(fbUtils.parseToken(str));
return cb(fbUtils.parseToken(str));
});
}).on('error', function(err) {
console.log('longterm error: ' + err.message);
});
}
Then you need to update your calling code to wait for this token:
var userData = req.body;
userData.email = userData.email.toLowerCase();
fbUtils.getLongTermToken(userData.fbAuthToken, function (token) {
userData.fbAuthToken = token;
FacebookUser.create(userData, function (err, fbUser) {
console.log(userData.fbAuthToken);
if (err) {
console.log(err.message);
if (err.toString().indexOf('E11000') > -1) {
err = new Error('Email already exists.');
}
res.status(400);
return res.sendStatus({reason: err.toString()});
} else {
res.send('success');
}
});
});
Because fbUtils.getLongTermToken is async, Facebook.create should be called in its callback, after the token is retrieved and parsed.
getLongTermToken: function (token) {
var options = {
host: 'graph.facebook.com',
path: '/oauth/access_token?grant_type=fb_exchange_token'
+ '&client_id=' + CONSTANTS.FACEBOOK_APP_ID
+ '&client_secret=' + CONSTANTS.FACEBOOK_APP_SECRET
+ '&fb_exchange_token=' + token
};
var str = '';
http.get(options, function (res) {
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
console.log(str);
console.log(fbUtils.parseToken(str));
var parsedToken = fbUtils.parseToken(str);
// The earliest point where the token can be used
Facebook.create(...);
return parsedToken;
});
}).on('error', function(err) {
console.log('longterm error: ' + err.message);
});
return str;
}
failing to find any info on the matter.
I need to query an active directory server with a specified group name, and to receive back all the users it contains.
Then i can iterate through those users and use their first&last name + email + phone + accountname.
Is all that possible using Node.js?
Can someone liberate me from this headache?
Using this link:
https://www.npmjs.com/package/activedirectory#getUsersForGroup
var groupName = 'Employees';
var ad = new ActiveDirectory(config);
ad.getUsersForGroup(groupName, function(err, users) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (! users) console.log('Group: ' + groupName + ' not found.');
else {
console.log(JSON.stringify(users));
}
});
The other solution posted is for ActiveDirectory, as a more general answer, you need a query which will return the "member" attribute from a group.
I was able to accomplish this using ldapjs
import ldap from 'ldapjs'
const client = ldap.createClient({ url: ['ldap://localhost:389'] })
client.on('error', (err) => { console.log(err) } )
client.bind("cn=admin,dc=example,dc=com", "password", (err) => {console.log(err)})
function logCallback(err,res) {
if(!res) {
console.log(err)
return
}
res.on('searchRequest', (searchRequest) => {
console.log('searchRequest: ', searchRequest.messageID);
});
res.on('searchEntry', (entry) => {
console.log('entry: ' + JSON.stringify(entry.object));
});
res.on('searchReference', (referral) => {
console.log('referral: ' + referral.uris.join());
});
res.on('error', (err) => {
console.error('error: ' + err.message);
});
res.on('end', (result) => {
console.log('status: ' + result?.status);
});
}
client.search("dc=example,dc=com",{filter:"(&(objectclass=groupofnames)(cn=users))",scope:"sub"},logCallback)
> searchRequest: 8
entry: {"dn":"cn=users,ou=Groups,dc=example,dc=com","controls":[],"cn":"users","description":"All Users","member":["uid=user,ou=Users,dc=example,dc=com","uid=user1,ou=Users,dc=example,dc=com","uid=user2,ou=Users,dc=example,dc=com"],"objectClass":["groupOfNames","top"]}
status: 0
The return value has a field "member" with a list of all users in the group.
exports.getUserLists = (req, res) => {
var ActiveDirectory = require('activedirectory');
var ad = new ActiveDirectory({
url: 'domainName.com',
baseDN: 'dc=domain,dc=com',
});
var opts = {
includeMembership: ['user'], // can use 'all','group','user'
baseDN: 'cn=users,cn=accounts,dc=domain,dc=com',
includeDeleted: false
};
ad.find(opts, function (err, results) {
if ((err) || (!results)) {
res.send('ERROR: ' + JSON.stringify(err));
return;
}
res.send(JSON.stringify(results))
});
I believe i have a problem with the Syntax.
By the Function xx the return is undefined :(.
Here the Problem in one File.
var Client = require('mariasql');
var inspect = require('util').inspect;
var c = new Client();
c.connect({
host: '127.0.0.1',
user: 'root',
password: '38nudel5nu',
db: 'artikel2'
});
var login = function(){
console.log("LOGIN\n");
c.on('connect', function() {
console.log('Client connected');
})
.on('error', function(err) {
console.log('Client error: ' + err);
})
.on('close', function(hadError) {
console.log('Client closed');
});
}
var end = function(){
console.log("EXIT");
c.end();
}
login();
var xx = function(){
c.query("SELECT COUNT(ArtikelID) AS Count FROM artikel")
.on('result', function(res) {
res.on('row', function(row) {
return "YOLO";
})
.on('error', function(err) {
})
.on('end', function(info) {
});
})
.on('end', function() {
});
}
var autohaus = xx();
console.log("\n\n --> " + autohaus);
And here is the Output:
[cseipel#myhost testumgebung]$ node skript.js LOGIN
--> undefined Client connected
You're using an asynchronous function as if it were synchronous. That's not going to work. You need to pass in a callback to your ArtikelCount function and call the callback once you have the results you want (the typical convention for callbacks is to have the first argument be an error if an error occurred, otherwise it should be null).
Example:
var ArtikelCount = function(cb) {
var count,
error;
c.query('SELECT COUNT(ArtikelID) AS Count FROM artikel')
.on('result', function(res) {
res.on('row', function(row) {
count = row.Count;
})
.on('error', function(err) {
console.log('Result error: ' + inspect(err));
error = err;
})
.on('end', function(info) {
console.log('Result finished successfully');
});
})
.on('end', function() {
console.log('Done with all results');
cb(error, count);
});
}
Then use it like:
wc.ArtikelCount(function(err, count) {
if (err)
throw err;
else
console.log('Row count', count);
});
I'm trying to read the body of an e-mail that is retrieved with node js. I'm using this npm module: https://github.com/mscdex/node-imap
And I can get pretty much all the information of the email, except reading the content of the body.
Any ideas?
Thanks,
You can use this code to fetch email body and mark it as seen
var Imap = require("imap");
var MailParser = require("mailparser").MailParser;
var Promise = require("bluebird");
Promise.longStackTraces();
var imapConfig = {
user: 'USERNAME',
password: 'PASSWORD',
host: 'HOST',
port: 993,
tls: true
};
var imap = new Imap(imapConfig);
Promise.promisifyAll(imap);
imap.once("ready", execute);
imap.once("error", function(err) {
log.error("Connection error: " + err.stack);
});
imap.connect();
function execute() {
imap.openBox("INBOX", false, function(err, mailBox) {
if (err) {
console.error(err);
return;
}
imap.search(["UNSEEN"], function(err, results) {
if(!results || !results.length){console.log("No unread mails");imap.end();return;}
/* mark as seen
imap.setFlags(results, ['\\Seen'], function(err) {
if (!err) {
console.log("marked as read");
} else {
console.log(JSON.stringify(err, null, 2));
}
});*/
var f = imap.fetch(results, { bodies: "" });
f.on("message", processMessage);
f.once("error", function(err) {
return Promise.reject(err);
});
f.once("end", function() {
console.log("Done fetching all unseen messages.");
imap.end();
});
});
});
}
function processMessage(msg, seqno) {
console.log("Processing msg #" + seqno);
// console.log(msg);
var parser = new MailParser();
parser.on("headers", function(headers) {
console.log("Header: " + JSON.stringify(headers));
});
parser.on('data', data => {
if (data.type === 'text') {
console.log(seqno);
console.log(data.text); /* data.html*/
}
// if (data.type === 'attachment') {
// console.log(data.filename);
// data.content.pipe(process.stdout);
// // data.content.on('end', () => data.release());
// }
});
msg.on("body", function(stream) {
stream.on("data", function(chunk) {
parser.write(chunk.toString("utf8"));
});
});
msg.once("end", function() {
// console.log("Finished msg #" + seqno);
parser.end();
});
}
hope this code will help you :)
The Body of the message is in the spot where i have console.log("BUFFER", buffer)
I'm using node-imap npm module
imap.once('ready', function() {
openInbox(function(err, box) {
if (err) throw err;
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM)','TEXT'] });
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] found, %d total bytes', inspect(info.which), info.size);
var buffer = '', count = 0;
stream.on('data', function(chunk) {
count += chunk.length;
buffer += chunk.toString('utf8');
console.log("BUFFER", buffer)
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] (%d/%d)', inspect(info.which), count, info.size);
});
stream.once('end', function() {
if (info.which !== 'TEXT')
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
else
console.log(prefix + 'Body [%s] Finished', inspect(info.which));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
});
});
});
Try:
msg.once('end', function() {
console.log(buffer);
});
I am creating a login authentication page, where a user would input there active directory username and password and using NodeJS I would check to see if it's valid, but I keep getting
[Error: LDAP Error Bad search filter]
or
[Error: Search returned != 1 results]
When I'm trying to search for the username and password, my code is below:
I'm using: https://github.com/jeremycx/node-LDAP, let's say that the user entered a username of hhill
var ldap = require('LDAP');
var ldapServer = new ldap({ uri: 'ldap://batman.lan', version: 3});
ldapServer.open(function(error) {
if(error) {
throw new Error('Cant not connect');
} else {
console.log('---- connected to ldap ----');
username = '(cn='+username+')';
ldapServer.findandbind({
base: 'ou=users,ou=compton,dc=batman,dc=lan',
filter: username,
password: password
}, function(error, data) {
if(error){
console.log(error);
} else {
console.log('---- verified user ----');
}
});
}
});
Does anyone have any suggestions on what I'm doing wrong?
UPDATE
Here is the solution I came up with if anyone ever needs it, with the help of the answer below
var username = request.param('username');
var password = request.param('password');
var ldap = require('ldapjs');
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var client = ldap.createClient({
url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
timeout: 5000,
connectTimeout: 10000
});
var opts = {
filter: '(&(objectclass=user)(samaccountname='+username+'))',
scope: 'sub',
attributes: ['objectGUID']
};
console.log('--- going to try to connect user ---');
try {
client.bind(username, password, function (error) {
if(error){
console.log(error.message);
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
} else {
console.log('connected');
client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
console.log('Searching.....');
search.on('searchEntry', function(entry) {
if(entry.object){
console.log('entry: %j ' + JSON.stringify(entry.object));
}
});
search.on('error', function(error) {
console.error('error: ' + error.message);
});
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
});
}
});
} catch(error){
console.log(error);
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
}
In this case, you need ldapClient rather than ldapServer, this is the example code from the official doc:
var ldap = require('ldapjs');
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var client = ldap.createClient({
url: 'ldap://127.0.0.1/CN=test,OU=Development,DC=Home'
});
var opts = {
filter: '(objectclass=user)',
scope: 'sub',
attributes: ['objectGUID']
};
client.bind('username', 'password', function (err) {
client.search('CN=test,OU=Development,DC=Home', opts, function (err, search) {
search.on('searchEntry', function (entry) {
var user = entry.object;
console.log(user.objectGUID);
});
});
});
#Sukh Thank you for posting your UPDATE solution; however, there is a problem with the code you posted in your UPDATE. While it works for simple cases, with larger queries, you will find you are unbinding before the results have been output. The solution for me was to move your unbinds into the search.on functions.
Here is an edit of your UPDATE:
var ldap = require('ldapjs');
ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_B;
var client = ldap.createClient({
url: 'ldap://batman.com/cn='+username+', ou=users, ou=compton, dc=batman, dc=com',
timeout: 5000,
connectTimeout: 10000
});
var opts = {
filter: '(&(objectclass=user)(samaccountname='+username+'))',
scope: 'sub',
//attributes: ['objectGUID']
// This attribute list is what broke your solution
attributes: ['objectGUID','sAMAccountName','cn','mail','manager','memberOf']
};
console.log('--- going to try to connect user ---');
try {
client.bind(username, password, function (error) {
if(error){
console.log(error.message);
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
} else {
console.log('connected');
client.search('ou=users, ou=compton, dc=batman, dc=com', opts, function(error, search) {
console.log('Searching.....');
search.on('searchEntry', function(entry) {
if(entry.object){
console.log('entry: %j ' + JSON.stringify(entry.object));
}
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
});
search.on('error', function(error) {
console.error('error: ' + error.message);
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
});
// don't do this here
//client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
});
}
});
} catch(error){
console.log(error);
client.unbind(function(error) {if(error){console.log(error.message);} else{console.log('client disconnected');}});
}
At least this is what I discovered when using your solution with Active Directory searches. memberOf returns A LOT of entries in my use case and the unbinds were being done prematurely, so I was getting the following error:
error: 1__ldap://my.domain.com/,OU=Employees,OU=Accounts,DC=my,DC=domain,DC=com closed
client disconnected
Suggestions
1.Don't use ldapauth-fork (Huge hanging issue, if we hit multiple requests then after some time library gets unresponsive and doesn't return anything.)
2.Don't use passport-ldapauth (Internally calls ldapauth-fork)
We can use ldapjs, which has easy implementation and is based on event driven approach.
Below nodejs code explain complete solution for ldap auth and search.
JS code
const ldap = require('ldapjs');
let client
// unbind after completion of process
function closeConnection() {
console.log('closeConnection')
client.unbind(err => {
console.log('unbind error', err)
});
}
function search() {
const searchOptions = {
filter: '(uid=yourSearchText)', // search text
scope: 'sub'
};
return new Promise((resolve, reject) => {
client.search('ou=consultants,' + 'ou="Your OU",ou=yourOu,dc=yourDc,dc=com', searchOptions, (err, res) => {
res.on('searchEntry', entry => {
console.log('searchEntry', entry.object);
resolve(entry.object)
});
res.on('searchReference', referral => {
console.log('referral: ' + referral.uris.join());
resolve(referral.uris.join())
});
res.on('error', err => {
console.error('search error: ' + err.message);
reject(err)
});
res.on('end', result => {
console.log('If not found', result);
reject({ message:'User not found'})
});
});
})
}
function authenticate() {
const server = 'ldap server ip';
client = ldap.createClient({
url: `ldap://${server}`
});
return new Promise((resolve, reject) => {
client.bind('cn=yourcn,dc=yourdc,dc=com', 'sortedSolutions', err => {
if (err) {
reject(err)
}
resolve('Authenticated successfully')
});
})
}
function start(req, res) {
let searchResponseData
authenticate()
.then(authenticateResponse => {
console.log('authenticateResponse', authenticateResponse)
return search()
})
.then(searchResponse => {
console.log('searchResponsesearchResponse', searchResponse)
searchResponseData = searchResponse
return closeConnection()
})
.then(closeConnectionResponse => {
console.log('ldap connection closed', closeConnectionResponse)
res.status(200).send(searchResponseData)
})
.catch(error => {
console.log('catch error', error)
res.status(400).send(error)
})
}
module.exports.start = start
// We can use same code with no authentication, Just pass '' to bind function client.bind('', '', err => { //same as above })