Active directory proxy in node.js - node.js

I'm trying to write an activty directory proxy, that will receive search requests, run some code, and then recreate the request with the real server.
I'm not able to get it to work, here's the code so far:
var ldap = require('ldapjs');
var ActiveDirectory = require('activedirectory');
var server = ldap.createServer();
server.bind('cn=root', function(req, res, next) {
console.log('BIND REACHED');
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'somepassword')
return next(new ldap.InvalidCredentialsError());
res.end();
return next();
});
server.listen(389, '127.0.0.1', function() {
console.log('LDAP server listening at %s', server.url);
});
var ad = new ActiveDirectory({
url: 'ldap://127.0.0.1',
baseDN: 'dc=lab,dc=ldapproxy,dc=local',
username: 'root',
password: 'somepassword'
});
ad.findUser('root', function (err, results) {
if (err) {
console.log('AD Login Failed: '+err);
}
else
console.log('AD Login Succeeded.');
});
The error that im getting is:
ProtocolError: InvalidDistinguishedNameError: root
It seems no matter how or what i put in the ActiveDirectory credentials i keep getting the same error.
But when i run that same code with different credentials on a real active directory server it works without any errors.
What am i missing here?
The site i'm reading is explaining how to do this on linux and with the passwords file, i'm not using linux or any files and i don't see any samples describing how to configure the server on the binding and searching based on what i wrote.
EDIT I forgot to mention that this code snappit is for debugging, i know that i'm trying to connect to the same server i just created, that's for testing purposes and learning how to ldap.

The error says it all: root is not a valid distinguished name you can use for binding.
In generic LDAP (OpenLDAP, for instance), you can only perform a bind operation with a "username" that is a fully qualified distinguished name (FQDN) of the object (the user, in the ldap database) with which you want to bind. That would be something like this:
CN=root,OU=Users,DC=example,DC=local
This, of course, depends on where the user account is located in the database.
Note: In Active Directory, the bind operation is not limited to a FQDN of the user - there are several other options what can be used as a username during binding. I have covered this in a previous SO question. However, I am unsure if ldapjs supports these username formats, considering the error message you are seeing.

Related

Mongodb database.collection confusion

I created a MEAN project in heroku.
In MongoDB I have a DB / Collection like this:
db == content / collection == android_main
I have verified that the collection is in the proper database (and not in admin) via the following MongoSH exchange:
Atlas atlas-xxxxxx-shard-0 [primary] content> use admin
switched to db admin
Atlas atlas-xxxxxx-shard-0 [primary] admin> show collections
Atlas atlas-xxxxxx-shard-0 [primary] admin> use content
switched to db content
Atlas atlas-xxxxxx-shard-0 [primary] content> show collections
android_main
In MongoDB I also have a user w/ specific privs to read this db/collection.
In the code (Node.js) I use the following connection string:
mongodb+srv://<USER>:<PASS>#<MONGO URL>/content?retryWrites=true&w=majority
The connection completes successfully. I pass in the user I mentioned above, e.g. the user with just the specific read privs on the database (content) and collection (android_main).
In the code, the mechanism I use to get the database variable via the connection and connection string specifically is:
mongodb.MongoClient.connect(process.env.MONGODB_URI, function (err, database) {
Now, in the code, in response to an `HTTP GET` I issue the following:
db.collection("android_main").find({}).toArray(function(err, docs) {
...
}
I get back this error:
ERROR: user is not allowed to do action [find] on [admin.android_main]
Question: how can I modify my code a/o setup to ensure the db.collection.find() call references the proper database? I would have thought this was taken care of in the connection, where the database is explicitly called out.
I'm going to post the following answer which solves the issue above.
I found it by just playing around with random ideas.
I'd like to thank Heroku and their pathetic documentation for turning a 30 minute task into a 3 day ordeal.
client.connect(
process.env.MONGODB_URI,
function (err, database) {
console.log("CONNECT...");
if (err) {
console.log(err);
process.exit(1);
}
db = database.db(DATABASE);
var server = app.listen(process.env.PORT || 8080,
function () {
var port = server.address().port;
console.log("CONNECT App now running on port", port);
}
);
console.log("CONNECT Done.");
}
);
Apparently, to properly set the variable db (the one which you will use in the queries later) you should note that the database you receive in the connection callback is the admin database (that which was used for auth), and from that you make the db() request passing in the database you intend to use. All of this is utterly redundant b/c we pass the database we intend to use in the connection string. What a complete CF; but it's certainly not the 1st one. Enjoy.

Best NodeJS Workflow for team development

I'm trying to implement NodeJS and Socket.io for real time communication between two devices (PC & Smartphones) in my company product.
Basically what I want to achieve is sending a notification to all online users when somebody change something on a file.
All the basic functionality for saving the updates are already there and so, when everything is stored and calculated, I send a POST request to my Node server saying that something changed and he need to notify the users.
The problem now is that when I want to change some code in the NodeJS scripts, as long as I work alone, I can just upload the new files via FTP and just restart the pm2 service, but when my colleagues will start working with me on this story we will have problems merging our changes without overlapping each other.
Launching a local server is also not possible because we need the connection between our current server and the node machine and since our server is online it cannot access our localhosts.
It's there a way for a team to work together in the same Node server but without overlapping each other ?
Implement changes using some other option rather than FTP. For example:
You can use webdav-fs in authenticated or non-authenticated mode:
// Using authentication:
var wfs = require("webdav-fs")(
"http://example.com/webdav/",
"username",
"password"
);
wfs.readdir("/Work", function(err, contents) {
if (!err) {
console.log("Dir contents:", contents);
} else {
console.log("Error:", err.message);
}
});
putFileContents(remotePath, format, data [, options])
Put some data in a remote file at remotePath from a Buffer or String. data is a Buffer or a String. options has a property called format which can be "binary" (default) or "text".
var fs = require("fs");
var imageData = fs.readFileSync("someImage.jpg");
client
.putFileContents("/folder/myImage.jpg", imageData, { format: "binary" })
.catch(function(err) {
console.error(err);
});
And use callbacks to notify your team, or lock the files via the callback.
References
webdav-fs
webdav
lockfile
Choosing Secure Passwords

Unknown error during authentication

I'm using PouchDB 4.0. To test the credentials to a remote CouchDB server, I use the following code:
testCredentials: function(credentials, callback){
var remoteDb = new PouchDB('http://X.X.X.X/dbName', {
auth: {
username: credentials.username,
password: credentials.password
}
});
remoteDb.info(function(err, info) {
if (err) {
if(err.status == 401)
callback("unauthorized");
else {
console.log(err);
callback("error");
}
} else {
callback("success");
}
});
}
When I pass invalid credentials (e.g. existing user but invalid password), I see a 401 error returned inside the CouchDB log file. However, PouchDb always returns the following 500 error:
{"status":500,
"name":"unknown_error",
"message":"Database encountered an unknown error",
"error":true}
The same problem occurs when using the pouchdb-authentication plugin.
This code worked perfectly in previous versions of PouchDB.
Can you file a bug with steps to reproduce at the Github issues page? Seems to be a new bug in PouchDB. Also if you could print out the logs from the error (might be an HTTP error, check the "Network" tab), then that would be helpful too.
"Database encountered an unknown error" is a generic error message that PouchDB throws up when it hits an error it doesn't know how to handle, so posting or screenshotting that other error would be very helpful. :)
Also, if you are using pouchdb-authentication, then you typically don't need to add the auth option when creating a new PouchDB; that option is for plain http-based authentication, whereas pouchdb-authentication uses cookie authentication.

Debug Node.js & Express App - Intermittently using 100% CPU

I'm developing an app using NGinx + Node.js + Express + Firebase that simply takes input from a mobile app and stores it to Firebase, optionally uploading files to S3.
In its simplest terms, the "create" function does this
Validates input
Formats the input Checks if there is a file uploaded
(via the multer plugin) and stores it
If there was a file, upload
to Amazon S3 and delete the source file (it's important to note I was
encountering this issue before the inclusion of S3).
Create the item
by pushing into the items reference on Firebase
Create the item for
the user by pushing into the user_items reference on Firebase.
There are a few other functions that I have implemented as an API.
My trouble is coming from an intermittent spike in CPU usage, which is causing the nginx server to report a gateway timeout from the Node.js application.
Sometimes the server will fall over when performing authentication against a MongoDB instance, other times it will fall over when I'm recieving the input from the Mobile app. There doesn't seem to be any consistency between when it falls over. Sometimes it works fine for 15+ various requests (upload/login/list, etc), but sometimes it will fall over after just one request.
I have added error checking in the form of:
process.on('uncaughtException', function(err) {
console.error(err.stack);
});
Which will throw errors if I mistype a variable for example, but when the server crashes there are no exceptions thrown. Similarly checking my logs shows me nothing. I've tried profiling the application but the output doesn't make any sense at all to me. It doesn't point to a function or plugin in particular.
I appreciate this is a long winded problem but I'd really appreciate it if you could point me in a direction for debugging this issue, it's causing me such a headache!
This may be a bug in the Firebase library. What version are you using?
I've been having a very similar issue that has had me frustrated for days. Node.js + Express + Firebase on Heroku. Process will run for a seemingly random time then I start getting timeout errors from Heroku without the process ever actually crashing or showing an error. Higher load doesn't seem to make it happen sooner.
I just updated from Firebase 1.0.14 to latest 1.0.19 and I think it may have fixed the problem for me. Process has been up for 2 hours now where it would only last for 5-30 min previously. More testing to do, but thought I'd share my in-progress results in case they were helpful.
It seems the answer was to do with the fact that my Express app was reusing one Firebase connection for every request, and for some reason this was causing the server to lock up.
My solution was to create some basic middleware that provides a new reference to the Firebase on each API request, see below:
var Middleware = {
/*
* Initialise Firebase Refs per connection
*/
initFireBase: function(req, res, next) {
console.log('Intialising Firebase for user');
// We need a authToken
var authToken = req.param('authToken');
// Validate the auth token
if(!authToken || authToken.length === 0) {
return res.send(500, {code: 'INVALID_TOKEN', message: 'You must supply an authToken to this method.'});
}
else {
// Attempt to parse the auth token
try {
var decodedToken = JWTSimple.decode(authToken, serverToken);
}
catch(e) {
return res.send(500, {code: 'INVALID_TOKEN', message: 'Supplied token was not recognised.'});
}
// Bail out if the token is invalid
if(!decodedToken) {
return res.send(500, {code: 'INVALID_TOKEN', message: 'Supplied token was not recognised.'});
}
// Otherwise send the decoded token with the request
else {
req.auth = decodedToken.d;
}
}
// Create a root reference
var rootRef = new Firebase('my firebase url');
// Apply the references to each request
req.refs = {
root: rootRef,
user: rootRef.child('users'),
inbox: rootRef.child('inbox')
};
// Carry on to the calling function
next();
}
};
I then simply call this middleware on my routes:
/*
* Create a post
*/
router.all('/createPost', Middleware.initFireBase, function(req, res) {
var refs = req.refs;
refs.inbox.push({}) // etc
....
This middleware will soon be extended to provide Firebase.auth() on the connection to ensure that any API call made with a valid authToken would be signed to the user on Firebase's side. However for development this is acceptable.
Hopefully this helps someone.

Meteor - Check if user is logged in as administrator (Client - Side)

I'm currently developing an app which needs users and administrators. What I do right now is, I create an admin account on the client with username 'admin' and a default password that should be changed over the accounts-ui.
I do this because creating a user like this:
Accounts.createUser({
username : 'admin',
email : 'test#test.com',
password : 'changethispasswordovertheuserinterface',
profile : { type : 'admin' }
});
doesn't work for me on server side. That means I just create the admin in my client.js and just use this code to check if the admin is logged in.
Template.admin.isAdmin = function () {
var currentUser = Meteor.user();
// Is this hackable?
if (null !== currentUser) {
if ('admin' === currentUser.username) {
return true;
}
}
};
Is this the best way to approach this? And most importantly, is my site hackable like this (Could somebody fake it)?
Yes this is hackable, one could pull up the chrome inspector and modify this quite easily. Or even faster, by typing something like Template.admin.isAdmin = function () { return true; } into Chrome's web console
The best approach would be to only provide the information to the client from the servers end if the user is an admin. So this would mean using Meteor.allow to ensure the database can only be changed by an administrative user, if peforming ops from the client end.
It also depends a bit on what you want to use 'isAdmin' for too. If its content, you could generate the html on the server's end and send it down to the client in a Meteor.methods. At the moment the templating system doesn't provide for locking down the UI on the clients end depending on what the user's document contains.
For any administrative commands, you could use a Meteor.call at which point the user is vetted on the server's and and the transaction is performed there.
The answer on this thread works too AND the top-voted answer has code for a server side, Meteor method call.

Resources