LDAP Bind Error using node.js and ldapjs - javascript

I am trying to implement a basic ldap bind with the following node.js file. Unfortunately, I keep getting a bind error with code 128. I looked online and found no references of code 128. The LDAP server I am trying to search is an eDirectory. Does anyone have any experience with this or have you had similar problems? My node version is v0.10.22 and my ldapjs version is v0.7.1
var ldap = require('ldapjs');
var creds = {
url: "ldaps://ldap.url.com:636",
bindDN: "cn=ldap,o=com"
};
var opts = {
filter: "(cn=username)",
scope: "sub"
};
function authDN(client, dn, password, cb) {
client.bind(dn, password, function (err) {
client.unbind();
cb(err === null, err);
});
}
function output(res, err) {
if (res) {
console.log('success');
} else {
console.log(['Error',err.code, err.dn, err.message ]);
}
}
var client = ldap.createClient(creds);
authDN(client, '(cn=username)', 'password', output);

This authenticates when i added the following to the top of my file:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
I haven't researched enough to know why this works but I found this answer here: https://github.com/mikeal/request/issues/418

In general when debugging an eDirectory issue, ask for access to iMonitor, so you can look at DStrace with the +LDAP option. That would show you what the LDAP server is sending back, making troubleshooting easier.

To augment Kaiser's answer, an explanation on why adding process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; to the code may work is found at the top of this link: https://github.com/visionmedia/superagent/issues/205.
Potential fixes:
Add process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0; to the top of your script for node v0.10.x (and above)
Setup a trusted CA certificate on the server instead of a self-signed certificate (must have server admin rights and pay for a valid cert)
Use the LDAP server IP or load balancer IP instead of dns for the url parameter.
Because you are using the secure protocol (ldaps:// instead of ldap://), and I'm assuming you are trying to connect to a server with a self-signed certificate, you will get a failure if using node v0.10.x (and probably all later versions as well) and the code/module you are using doesn't specifically set the process.env.NODE_TLS_REJECT_UNAUTHORIZED to false.
NODE_TLS_REJECT_UNAUTHORIZED was changed to true by default for a reason. If you choose to set NODE_TLS_REJECT_UNAUTHORIZED to false, you are opening up more security risks, and I would advise only doing this on private networks at best, and never in production environments. Without going down a security discussion rabbit hole, it's always best to use a cert signed by a CA. More info on the differences on certs can be found here. This can also cause problems if your application is robust enough to make multiple connections to various secured servers where only some use self signed certs, again mentioned in this link.
If the cert wasn't self-signed, you most likely shouldn't be getting this error, so another potential fix is to setup and use a trusted CA Certificate on the LDAP server instead.
On the other hand, if you are using a normal, non-secure ldap connection (not through TLS), and/or you get this error only occasionally while other times it goes through, you should try setting the ldap url to the LDAP server IP or load balancer IP (and use port 3268 to allow searching in all domains). In larger network setups this will avoid potential round robin dns queries that sometimes point you to a slow server or one you can't route to.

Related

Try to connect to a server with Google Assistance App

I need to send data out from my google assistance app to a database. In order to do this, I've created a server that takes the data, packages it, and then sends it out. I have the hostname and port and it works in a normal javascript/node.js program but when I use it in my google assistant app nothing happens. I tried figuring out the problem and it looks like the code just isn't connecting. The code I'm using to send data to the server is as follows:
function sendData(app){
var net = require('net');
var message = {"test": 200};
var thisMessage = JSON.stringify(message);
var client = new net.Socket();
client.connect(<port>, '<hostname>', function() {
app.tell(JSON.stringify(client.address()));
console.log('Connected');
client.write(thisMessage);
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy();
});
client.on('close', function() {
console.log('Connection closed');
});
return 0;
}
(NOTE: Port and hostname left out for privacy purposes)
This completely skips over the app.tell, leading me to believe the connection is never made. I know it works asynchronously with the server, however, I don't understand why it isn't connecting whatsoever.
I have tried it both in simulation and on my smartphone with sandbox on and off. Is there a better way to connect? Note that the server I'm connecting to is python-based.
The problem is likely that you're running it on Cloud Functions for Firebase which has a limit on outbound connections under their free "Spark" plan. With this plan, you can only connect to other Google services. This is usually a good way to start understanding how to handle Action requests, but has limitations. To access endpoints outside of Google, you need to upgrade to either their "Flame" fixed price plan or "Blaze" pay-as-you-go plan.
You do not, however, need to run on Google's servers or need to use node.js. All you need is a public HTTPS server with a valid SSL cert. If you are familiar with JSON, you can use any programming language to handle the request and response. If you are familiar with node.js, you just need a node.js server that can create Express request and response objects.

Websockets Address on Internal Network need's static ip?

I'm running a Go webserver using Gorilla/websocket for a real-time chess/chat application. As far as I know, I define the address and port in two locations, the Go http.ListenAndServer() method and the Javascript new Websocket(); function. This works great accross browsers on the same host machine, but it gets tricky when trying to extend the functionality over my internal network. So I use, for instance:
Go:
PORT := "0.0.0.0:8080"
// ...
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
h.serveWs(hub, w, r) // h is a chessboard Handler wrapper
})
//...
http.ListenAndServe(PORT, nil)
Javascript:
conn = new WebSocket("ws://0.0.0.0:8080/ws");
In my effort to get this working on different devices over the network I've tried using, instead of the 0.0.0.0 address, localhost or my hostname and my host's internal ip (e.g.) 10.232.44.20; With the latter, the internal ip hardcoded in, it works, but the other attempts don't. I thought that using 0.0.0.0 would accept all connections from within the network, which I gathered from this answer:
What is the difference between 0.0.0.0, 127.0.0.1 and localhost?
How should I program ListenAndServe as well as new Websocket so that I can access the server within the internal network, without having to hardcode my internal ip address? Should I access that number programmatically from Js and Go? In the end, I want to be able to run this server on a variety of networks, without configuration, and have it just work. What am I missing?
If the web page and websocket endpoints are served by the same host, then create the websocket using the host used to fetch the web page:
conn = new WebSocket("ws://" + window.location.host + "/ws");
This will just work in all network configurations.
As far as the Go code is concerned, the easiest approach is to listen on all networks:
if err := http.ListenAndServe(":8080", nil); err != nil {
// handle error
}

Node.js http-proxy drops websocket requests

Okay, I've spent over a week trying to figure this out to no avail, so if anyone has a clue, you are a hero. This isn't going to be an easy question to answer, unless I am being a dunce.
I am using node-http-proxy to proxy sticky sessions to 16 node.js workers running on different ports.
I use Socket.IO's Web Sockets to handle a bunch of different types of requests, and use traditional requests as well.
When I switched my server over to proxying via node-http-proxy, a new problem crept up in that sometimes, my Socket.IO session cannot establish a connection.
I literally can't stably reproduce it for the life of me, with the only way to turn it on being to throw a lot of traffic from multiple clients to the server.
If I reload the user's browser, it can then sometimes re-connect, and sometimes not.
Sticky Sessions
I have to proxy sticky sessions as my app authenticates on a per-worker basis, and so it routes a request based on its Connect.SID cookie (I am using connect/express).
Okay, some code
This is my proxy.js file that runs in node and routes to each of the workers:
var http = require('http');
var httpProxy = require('http-proxy');
// What ports the proxy is routing to.
var data = {
proxyPort: 8888,
currentPort: 8850,
portStart: 8850,
portEnd: 8865,
};
// Just gives the next port number.
nextPort = function() {
var next = data.currentPort++;
next = (next > data.portEnd) ? data.portStart : next;
data.currentPort = next;
return data.currentPort;
};
// A hash of Connect.SIDs for sticky sessions.
data.routes = {}
var svr = httpProxy.createServer(function (req, res, proxy) {
var port = false;
// parseCookies is just a little function
// that... parses cookies.
var cookies = parseCookies(req);
// If there is an SID passed from the browser.
if (cookies['connect.sid'] !== undefined) {
var ip = req.connection.remoteAddress;
if (data.routes[cookies['connect.sid']] !== undefined) {
// If there is already a route assigned to this SID,
// make that route's port the assigned port.
port = data.routes[cookies['connect.sid']].port;
} else {
// If there isn't a route for this SID,
// create the route object and log its
// assigned port.
port = data.currentPort;
data.routes[cookies['connect.sid']] = {
port: port,
}
nextPort();
}
} else {
// Otherwise assign a random port, it will/
// pick up a connect SID on the next go.
// This doesn't really happen.
port = nextPort();
}
// Now that we have the chosen port,
// proxy the request.
proxy.proxyRequest(req, res, {
host: '127.0.0.1',
port: port
});
}).listen(data.proxyPort);
// Now we handle WebSocket requests.
// Basically, I feed off of the above route
// logic and try to route my WebSocket to the
// same server regular requests are going to.
svr.on('upgrade', function (req, socket, head) {
var cookies = parseCookies(req);
var port = false;
// Make sure there is a Connect.SID,
if (cookies['connect.sid'] != undefined) {
// Make sure there is a route...
if (data.routes[cookies['connect.sid']] !== undefined) {
// Assign the appropriate port.
port = data.routes[cookies['connect.sid']].port;
} else {
// this has never, ever happened, i've been logging it.
}
} else {
// this has never, ever happened, i've been logging it.
};
if (port === false) {
// this has never happened...
};
// So now route the WebSocket to the same port
// as the regular requests are getting.
svr.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: port
});
});
Client Side / The Phenomena
Socket connects like so:
var socket = io.connect('http://whatever:8888');
After about 10 seconds on logging on, I get this error back on this listener, which doesn't help much.
socket.on('error', function (data) {
// this is what gets triggered. ->
// Firefox can't establish a connection to the server at ws://whatever:8888/socket.io/1/websocket/Nnx08nYaZkLY2N479KX0.
});
The Socket.IO GET request that the browser sends never comes back - it just hangs in pending, even after the error comes back, so it looks like a timeout error. The server never responds.
Server Side - A Worker
This is how a worker receives a socket request. Pretty simple. All workers have the same code, so you think one of them would get the request and acknowledge it...
app.sio.socketio.sockets.on('connection', function (socket) {
// works... some of the time! all of my workers run this
// exact same process.
});
Summary
That's a lot of data, and I doubt anyone is willing to confront it, but i'm totally stumped, don't know where to check next, log next, whatever, to solve it. I've tried everything I know to see what the problem is, to no avail.
UPDATE
Okay, I am fairly certain that the problem is in this statement on the node-http-proxy github homepage:
node-http-proxy is <= 0.8.x compatible, if you're looking for a >=
0.10 compatible version please check caronte
I am running Node.js v0.10.13, and the phenomena is exactly as some have commented in github issues on this subject: it just drops websocket connections randomly.
I've tried to implement caronte, the 'newer' fork, but it is not at all documented and I have tried my hardest to piece together their docs in a workable solution, but I can't get it forwarding websockets, my Socket.IO downgrades to polling.
Are there any other ideas on how to get this implemented and working? node-http-proxy has 8200 downloads yesterday! Sure someone is using a Node build from this year and proxying websockets....
What I am look for exactly
I want to accomplish a proxy server (preferrably Node) that proxies to multiple node.js workers, and which routes the requests via sticky sessions based on a browser cookie. This proxy would need to stably support traditional requests as well as web sockets.
Or...
I don't mind accomplishing the above via clustered node workers, if that works. My only real requirement is maintaining sticky sessions based on a cookie in the request header.
If there is a better way to accomplish the above than what I am trying, I am all for it.
In general I don't think node is not the most used option as a proxy server, I, for one use nginx as a frontend server for node and it's a really great combination. Here are some instructions to install and use the nginx sticky sessions module.
It's a lightweight frontend server with json like configuration, solid and very well tested.
nginx is also a lot faster if you want to serve static pages, css. It's ideal to configure your caching headers, redirect traffic to multiple servers depending on domain, sticky sessions, compress css and javascript, etc.
You could also consider a pure load balancing open source solution like HAProxy. In any case I don't believe node is the best tool for this, it's better to use it to implement your backend only and put something like nginx in front of it to handle the usual frontend server tasks.
I agree with hexacyanide. To me it would make the most sense to queue workers through a service like redis or some kind of Message Query system. Workers would be queued through Redis Pub/Sub functionality by web nodes(which are proxied). Workers would callback upon error, finish, or stream data in realtime with a 'data' event. Maybe check out the library kue. You could also roll your own similar library. RabbitMQ is another system for similar purpose.
I get using socket.io if you're already using that technology, but you need to use tools for their intended purpose. Redis or a MQ system would make the most sense, and pair great with websockets(socket.io) to create realtime, insightful applications.
Session Affinity(sticky sessions) is supported through Elastic LoadBalancer for aws, this supports webSockets. A PaaS provider(Modulus) does this exactly. Theres also satalite which provides sticky sessions for node-http-proxy, however I have no idea if it supports webSockets.
I've been looking into something very similar to this myself, with the intent of generating (and destroying) Node.js cluster nodes on the fly.
Disclaimer: I'd still not recommend doing this with Node; nginx is more stable for the sort of design architecture that you're looking for, or even more so, HAProxy (very mature, and easily supports sticky-session proxying). As #tsturzl indicates, there is satellite, but given the low volume of downloads, I'd tread carefully (at least in a production environment).
That said, since you appear to have everything already set up with Node, rebuilding and re-architecting may be more work than it's worth. Therefore, to install the caronte branch with NPM:
Remove your previous http-node-proxy Master installation with npm uninstall node-proxy and/or sudo npm -d uninstall node-proxy
Download the caronte branch .zip and extract it.
Run npm -g install /path/to/node-http-proxy-caronte
In my case, the install linkage was broken, so I had to run sudo npm link http-proxy
I've got it up and running using their basic proxy example -- whether or not this resolves your dropped sessions issue or not, only you will know.

How do I do an LDAP query with JavaScript?

I'm trying to make a sidebar gadget that has an LDAP query function but haven't been able to find very good, or any, useful documentation on the matter. I'm not hugely experienced with Javascript and know little to nothing about how LDAP queries function, so any information at all would be useful.
info:
host: a.b.c.d.e
port: 389
ou: people
o: x_y_z
c: us
first snippet:
var sSearchURL = "ldap://a.b.c.d.e:389/o=x_y_z,c=us";
var URLsuffix = "dc=" + form.SearchData.value;
document.location = sSearchURL URLsuffix;
other snippet:
var ldap = GetObject('LDAP:');
var ad = ldap.OpenDSObject(
'LDAP://a.b.c.d.e:389/o=x_y_z',
'cn=Administrator,ou=People,o=rootname',
'password',
0
);
As long as you want to run your JavaScript in a web browser, you are limited to the HTTP protocol and to the domain from which your script was loaded in the first place.
So, talking to an LDAP server will not be possible from a web browsers JavaScript engine.
There are JavaScript runtime environments that have less limitations where you can implement socket servers and clients. For LDAP conenctivity you'd have to write your own library or find some existing one.
You could write a proxy web service that translates your HTTP requests into LDAP queries, forwards them to an LDAP server and returns the results back to you. Of course that'd have both security and scalability implications and is far from trivial.
As Selfawaresoup already mentioned there are limitations to perfoming this on client side alone, however, if you're able to host your application/page on nodejs you can utilise an LDAP plugin with it.
Links to nodejs are as follows:
https://nodejs.org/en/
https://nodejs.org/en/download/
Nodejs LDAP plugin:
http://ldapjs.org/
Instruction on setting up nodejs to serve http:
https://www.sitepoint.com/build-a-simple-web-server-with-node-js/
https://blog.risingstack.com/your-first-node-js-http-server/
Although it's for a specific application here's a manual demonstrating the integration of LDAP query via nodejs:
https://www.ibm.com/developerworks/library/se-use-ldap-authentication-authorization-node.js-bluemix-application/index.html
Here's a working demo of it (note this is for querying public facing LDAP servers):
https://login-using-ldap.mybluemix.net/
Best of luck to you however you resolve this.
I am not sure answer 1 is correct. Domain would be limited to client's domain for an active directory ldap query. However, LDAP://server is not limited to just local domain. Its limited to 'reachable' domains. If you can ping it you should be able to query it, given proper credentials.

Websocket connection - no valid credentials

I'm trying to create a simple nodejs application that connects to the pathofexile.com/trade api.
The problem with this API is that is that you cannot use it unless you're logged in on the main website (my code works in the browser, but I'm trying to make it into a desktop application). There are several other applications that solves this issue by creating a session ID cookie with a users session ID (ID that you can get by logging in to the website). Unfortunately the documentation of the API is very limited and I havn't been able to find any information on how I can create/use the cookie as needed.
If I try to connect to the websocket, without being logged in to the main pathofexile website, I get the following error:
VM58:1 WebSocket connection to 'wss://www.pathofexile.com/api/trade/live/Metamorph/e602K4cL' failed: HTTP Authentication failed; no valid credentials available
I've tried using my sessionID to create a cookie like this by using the built in features in node:
const cookie = { name: 'POESESSID', value: '3acbf42fb842aasdqwe1a0c355f',domain:
'.pathofexile.com' }
session.defaultSession.cookies.set(cookie)
.then(() => {
// success
console.log("Cookie set (?)")
}, (error) => {
console.error(error)
})
Unfortunately, this does not work. I'm very unfamiliar with websockets (only started playing around with any of this a few days ago by accident), and I'm even less familiar with how websockets access and get data from cookies.
I've tried other modules like npm cookie-parser, npm request and npm needle to no avail.
The closest I've gotten to an answer is from a one year old reddit post where the user used C# to get this to work.
This is the code used in that example:
// Setup HTTP connection
HttpClientHandler handler = new HttpClientHandler();
CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(composeUrl, new Cookie("POESESSID", sessionId));
handler.CookieContainer = cookieContainer;
HttpClient client = new HttpClient(handler);
If someone could help shine some light on this I'd be very appreciative. I understand that this question is incredibly niche and perhaps I'm asking it in the wrong forum, but I really don't know where to turn.
Appreciate any help!
//Alex

Categories

Resources