nodejs with ldapjs authentication possible without password - node.js

I gonna write a API which get a Username and password from the Front-End. This username and password get passed into my LDAP bind and should get checked if these informations are correct. Now I got the problem when the use types a wrong password I get the correct error code 49 for invalid credentials. But when the user just enter his username and nothing into password, then LDAP is automatically accepting it and passes through the authentication.
Can maybe someone help me or give me an advice whats wrong?
const ldap = require('ldapjs');
var client = ldap.createClient({
url: `ldap://${process.env.LDAP_HOST}:${process.env.LDAP_PORT}`
});
function ldapauth(dn, password, callback) {
var serverStatus;
//dn = entry.object.dn from another ldap query
client.bind(dn, password, function(err, res) {
if(err) {
console.log(['Error:',err.code, err.dn, err.message]);
serverStatus = err.code;
client.unbind();
return callback (serverStatus);
} else {
console.log('Auth Status: ' + res.status);
if(res.status == 0) {
serverStatus = res.status;
} else {
serverStatus = 500;
}
client.unbind();
return callback(serverStatus);
};
});
}
This is my output which I get when the password is empty

The activedirectory package solves this by returning an error if no password is supplied:
if ((! username) || (! password)) {
var err = {
'code': 0x31,
'errno': 'LDAP_INVALID_CREDENTIALS',
'description': 'The supplied credential is invalid'
};
return(callback(err, false));
}
Here is the code: https://github.com/gheeres/node-activedirectory/blob/master/lib/activedirectory.js#L1803
More info about the bind command: https://ldap.com/the-ldap-bind-operation/
This sounds like is the cause of your issue:
An anonymous simple bind can be performed by providing empty strings as the bind DN and password (technically, the LDAPv3 specification states that only the password must be empty, but this has been responsible for many security problems with LDAP clients in the past, and many servers require that if an empty password is provided then an empty DN must also be given).

Related

why do i need to check if the password has not been changed after the JWT is issued

I don't get it why do i need to check if the password has not been changed after the JWT is issued.
I have a piece of code right here and i have to carry out authorization of user and i don't know why i have to check this issue. Could you explain me why do i need to do this ?
I tried to figure out of this but still i don't get it.
exports.protect = catchAsync(async (req,res,next)=>{
let token;
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
token = req.headers.authorization.split(' ')[1];
}
if(!token){
return next(new AppError('You are not log in , please log in to get the access!',401));
}
const decoded = await promisify(jwt.verify)(token, process.env.TOKEN_PASSWORD);
const freshUser = await User.findById(decoded.id);
if(!freshUser){
return next(new AppError('The user belonging to this token does no longer exist',401));
}
if(freshUser.changedPasswordAfter(decoded.iat)){
return next(new AppError('User recently changed the password, Please log in again',401));
} // <--- this piece is not understandable
console.log(decoded);
req.user = freshUser;
next();
});
Schema.methods.changedPasswordAfter = function(JWTTimestamp)
{
if(this.passwordDateAt)
{
const changeTimeStamp = parseInt(this.passwordDateAt / 1000 , 10);
return JWTTimestamp < changeTimeStamp;
}
return false;
}
If the password has been changed, you generally don't want to allow any previously issued JWTs to be used because it's possible that the reason the password was changed is that the old password was compromised and thus the user is changing their password to prevent any access using the old password.
But, if you allow an existing JWT (from the old password) to still be used, then you won't be blocking use of that compromised password.

Can I insert a function inside of a prompt?

I'm trying to launch a really basic chat app for myself and a few friends and wanted to include a password check upon loading the site by using a prompt + socket.emit:
var username = prompt('password:');
socket.emit('password', password);
I wanted to insert a function that checks their input against whatever I define as the answer. Something like this:
var codeword = prompt('password:', function checkPrompt(password) {
if (prompt.password.length === 0) {
return false;
}
if (password.value !== answer.value) {
return false;
}
return true;
});
But I get ERR_INVALID_ARG_TYPE(name, 'Function', value); once I run the app. How can I implement this?
Sidenote: I know this is super insecure. I'll implement a real password check once I have a DB set up but until then I just wanted a simple placeholder.
prompt is a "blocking" method, so there is no need for a callback. Callbacks are needed when you are uncertain when code within the callback will be executed. This is not the case here. You can work with the returned result in a do...while loop for example.
Dummy example with static password check:
// We will keep the user in the loop until the password is correct...
do {
var password = prompt('Password:');
} while (password !== 'abcd');
// At this point we know the password was correct.
alert('Password was correct!');
Dummy example with dedicated auth method:
function authenticate(username, password) {
if (username == 'john' && password == 'abcd') {
return true;
}
return false;
}
// We will keep the user in the loop until the password is correct...
do {
var username = prompt('Username:');
var password = prompt('Password:');
var loginSuccessful = authenticate(username, password);
} while (!loginSuccessful);
// At this point we know the password was correct.
alert('Password was correct!');
From the security point of view, it only makes sense to have the authentication logic on server-side, so you'll most probably will want to make an AJAX call from within the above authenticate function (using the Fetch API for example or jQuery.post - if you're using jQuery). Then the method would return true or false based on the response of the server-side call.

Authentication with Active Directory using sAMAccountName and password / NodeJs

I m trying to authenticate to a server with Active Directory using Nodejs. I read a lot a of answers of that but no body use the sAMAccountName as attribute to do that.
My code is :
let ActiveDirectory = require('activedirectory');
let config = {
url: 'ldap://XX.XX.XX.XXX:389',
baseDN: 'DC=domain,DC=com',
username: 'serverUserName',
password: 'serverPsw'
};
let ad = new ActiveDirectory(config);
let username = 'sAMAccountName=11111111111, OU=Usuarios, DC=domain,DC=com',
password = 'myPassword';
ad.authenticate(username, password, function (err, auth) {
if (err) {
console.log('ERROR: ' + JSON.stringify(err));
return;
}
if (auth) {
console.log('\nAuthenticated!', auth);
}
else {
console.log('\nAuthentication failed!');
}
});
This code only works if a change the username
'CN=myIdentifier,OU=Usuarios,DC=domain,DC=com'
and use the CN as attribute.
I really don't have idea what to do but it must work using the sAMAccountName.
Can anybody give me a help of how to make it work?
Thanks
You can authenticate against Active directory LDAP using sAMAccountName if you include the domain too - like company\logonid instead of just login ID. You can also use the full userPrincipalName like logonid#company.ccTLD
With either of those formats, you do not use any of the LDAP syntax components (something= or the ,ou=xyz,dc=abc). You use just the login ID and domain name (in the example above, the legacy style domain name is company and the AD style domain name is company.ccTLD)

How to renew a session of salesforce using jsforce?

I am using jsforce node module for doing CRUD operation in salesforce.
For making a connection to salesforce, I have following input
username, password, securityToken and loginUrl.
Here's how I make a connection first time.
var conn = new jsforce.Connection({
loginUrl: connectionDetails.salesforce.loginUrl
});
conn.login(connectionDetails.salesforce.username,
connectionDetails.salesforce.password + connectionDetails.salesforce.securityToken,
function(err, userInfo) {
if (!err) {
console.log('User with user id ' + userInfo.id + ' successfully logged into Salesforce');
successCb(conn.accessToken, conn.instanceUrl);
} else {
console.log('Login failed to https://test.salesforce.com/');
errorCb('Login failed to https://test.salesforce.com/');
}
});
I store the accessToken and Instanceurl in the req object provided by Express.
After that any CRUD operation I perform like below
var salesConn = new jsforce.Connection({
accessToken: salesforceAccessToken,
instanceUrl: salesforceInstanceUrl
});
salesConn.sobject('Lead').retrieve(someLeadID, function(err, data) {
...
});
Now suppose I keep my server idle for few hours or may be even a day, then if I do a CRUD operation then the call fails. This I am pretty sure that the session has expired.
Now I have two queries
Is the above correct way of making connection to salesforce using the input connection details I have?
How can I know that the session has expired and make a new session?
PS
I tried to look into the Access Token with Refresh Token, but that is only available with OAuth2 authorization code flow.
A little late, but I had the same issue today and I fixed it by calling conn.login(username, password+token) whenever I get an invalid session error.
I am doing something different though, I'm not creating a second variable to use with my SF calls, but instead use the original conn variable, conn.sobject(...).
It would refresh token automatically.
my jsforce version is "jsforce": "^1.4.1"
jsforce has a _refreshDelegate
Connection.prototype.login = function(username, password, callback) {
// register refreshDelegate for session expiration
this._refreshDelegate = new HttpApi.SessionRefreshDelegate(this, createUsernamePasswordRefreshFn(username, password));
if (this.oauth2 && this.oauth2.clientId && this.oauth2.clientSecret) {
return this.loginByOAuth2(username, password, callback);
} else {
return this.loginBySoap(username, password, callback);
}
};

Allowing both email and username for authentication

I'm creating two projects (MVC 5 and Web API) using ASP.Net Identity 2.1 and I couldn't find how to use both email and username for authentication (an area called Admin must use a username and the common area must use email addresses for authentication).
The problem is that there is only one method for authentication and it does not allow you to specify if you will compare with the email address or the username.
SignInHelper.PasswordSignIn
What should I do to achieve this?
SignInManager will not you help with it, you'll need to use UserManager and a bit more jiggery-pokery (that's technical term!):
This is what I have for this scenario:
var unauthUserByUsername = await userManager.FindByNameAsync(command.UserName);
var unauthUserByEmail = await userManager.FindByEmailAsync(command.UserName);
var unauthenticatedUser = unauthUserByUsername ?? unauthUserByEmail;
if (unauthenticatedUser == null)
{
logger.Warn("User {0} is trying to login but username is not correct", command.UserName);
return View(); // stop processing
}
var loggedInUser = await userManager.FindAsync(unauthenticatedUser.UserName, command.Password);
if (loggedInUser == null)
{
// username is correct, but password is not correct
logger.Warn("User {0} is trying to login with incorrect password", command.UserName);
await userManager.AccessFailedAsync(unauthenticatedUser.Id);
return View(); // stop processing
}
// Ok, from now on we have user who provided correct username and password.
// and because correct username/password was given, we reset count for incorrect logins.
await userManager.ResetAccessFailedCountAsync(loggedInUser.Id);
if (!loggedInUser.EmailConfirmed)
{
logger.Warn("User {0} is trying to login, entering correct login details, but email is not confirmed yet.", command.UserName);
return View("Please confirm your email"); // stop processing
}
if (await userManager.IsLockedOutAsync(loggedInUser.Id))
{
// when user is locked, but provide correct credentials, show them the lockout message
logger.Warn("User {0} is locked out and trying to login", command.UserName);
return View("Your account is locked");
}
logger.Info("User {0} is logged in", loggedInUser.UserName);
// actually sign-in.
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
await userManager.SignInAsync(authenticationManager, loggedInUser, false);
This checks if user has confirmed email, if user is locked out and does lock user out after a certain number of attempts (given all other settings for locking-out are enabled).
This way both are allowed
var userEmail = await UserManager.FindByEmailAsync(model.Login);
if (userEmail == null)
{
var user = await UserManager.FindByNameAsync(model.Login);
if (user == null)
{
model.Login = "";
}
}
else
{
model.Login = userEmail.UserName;
}
var result = await SignInManager.PasswordSignInAsync(model.Login, model.Password, model.RememberMe, shouldLockout: false);

Resources