Skip to content

Commit

Permalink
Merge branch 'sandrinodimattia-auth-when-pwd-change-required'
Browse files Browse the repository at this point in the history
  • Loading branch information
twistedstream committed Oct 14, 2015
2 parents 67462db + cf0e682 commit ad7e7f2
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 37 deletions.
13 changes: 13 additions & 0 deletions lib/errors/AccountDisabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var util = require('util');

function AccountDisabled(profile) {
this.message = "Account disabled";
this.profile = profile;
this.name = 'AccountDisabled';
Error.call(this, this.message);
Error.captureStackTrace(this, this.constructor);
}

util.inherits(AccountDisabled, Error);

module.exports = AccountDisabled;
6 changes: 3 additions & 3 deletions lib/errors/AccountExpired.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var util = require('util');

function AccountExpired(username) {
function AccountExpired(profile) {
this.message = "Account expired";
this.username = username;
this.profile = profile;
this.name = 'AccountExpired';
Error.call(this, this.message);
Error.captureStackTrace(this, this.constructor);
}

util.inherits(AccountExpired, Error);

module.exports = AccountExpired;
module.exports = AccountExpired;
6 changes: 3 additions & 3 deletions lib/errors/AccountLocked.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var util = require('util');

function AccountLocked(username) {
function AccountLocked(profile) {
this.message = "Account locked";
this.username = username;
this.profile = profile;
this.name = 'AccountLocked';
Error.call(this, this.message);
Error.captureStackTrace(this, this.constructor);
}

util.inherits(AccountLocked, Error);

module.exports = AccountLocked;
module.exports = AccountLocked;
4 changes: 2 additions & 2 deletions lib/errors/PasswordChangeRequired.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
var util = require('util');

function PasswordChangeRequired(username) {
function PasswordChangeRequired(profile) {
this.message = "Password change required";
this.username = username;
this.profile = profile;
this.name = 'PasswordChangeRequired';
Error.call(this, this.message);
Error.captureStackTrace(this, this.constructor);
Expand Down
6 changes: 3 additions & 3 deletions lib/errors/PasswordExpired.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var util = require('util');

function PasswordExpired(username) {
function PasswordExpired(profile) {
this.message = "Password expired";
this.username = username;
this.profile = profile;
this.name = 'PasswordExpired';
Error.call(this, this.message);
Error.captureStackTrace(this, this.constructor);
}

util.inherits(PasswordExpired, Error);

module.exports = PasswordExpired;
module.exports = PasswordExpired;
30 changes: 16 additions & 14 deletions lib/initConf.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ nconf.env('||')
})
.env()
.defaults({
PORT: 4000,
SESSION_SECRET: 'a1b2c3d4567',
AUTHENTICATION: 'FORM',
LDAP_SEARCH_QUERY: '(&(objectCategory=person)(anr={0}))',
LDAP_SEARCH_ALL_QUERY: '(objectCategory=person)',
LDAP_SEARCH_GROUPS: '(member:1.2.840.113556.1.4.1941:={0})',
LDAP_USER_BY_NAME: '(sAMAccountName={0})',
WSFED_ISSUER: 'urn:auth0',
AGENT_MODE: true,
GROUPS: true,
LDAP_HEARTBEAT_SECONDS: 60,
GROUPS_TIMEOUT_SECONDS: 20,
GROUP_PROPERTY: 'cn',
GROUPS_CACHE_SECONDS: 600
PORT: 4000,
SESSION_SECRET: 'a1b2c3d4567',
AUTHENTICATION: 'FORM',
LDAP_SEARCH_QUERY: '(&(objectCategory=person)(anr={0}))',
LDAP_SEARCH_ALL_QUERY: '(objectCategory=person)',
LDAP_SEARCH_GROUPS: '(member:1.2.840.113556.1.4.1941:={0})',
LDAP_USER_BY_NAME: '(sAMAccountName={0})',
WSFED_ISSUER: 'urn:auth0',
AGENT_MODE: true,
GROUPS: true,
LDAP_HEARTBEAT_SECONDS: 60,
GROUPS_TIMEOUT_SECONDS: 20,
GROUP_PROPERTY: 'cn',
GROUPS_CACHE_SECONDS: 600,
ALLOW_PASSWORD_EXPIRED: false,
ALLOW_PASSWORD_CHANGE_REQUIRED: false
});
21 changes: 14 additions & 7 deletions lib/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var ldap_clients = require('./ldap');
var cb = require('cb');
var graph = require('./graph');

var AccountDisabled = require('./errors/AccountDisabled');
var AccountExpired = require('./errors/AccountExpired');
var AccountLocked = require('./errors/AccountLocked');
var PasswordChangeRequired = require('./errors/PasswordChangeRequired');
Expand Down Expand Up @@ -74,8 +75,10 @@ Users.prototype.validate = function (userName, password, callback) {
binder.bind(profile.dn, password, function(err) {
if (err) {
if (err instanceof ldap.InvalidCredentialsError) {
var detailedError = getDetailedError(err);
profile.ldapStatus = detailedError.code;
return self.enrichProfile(profile, function (e, profile) {
callback(getDetailedError(profile, err));
callback(new detailedError.err_type(profile));
});
} else {
return callback(UnexpectedError.wrap(err));
Expand All @@ -85,6 +88,7 @@ Users.prototype.validate = function (userName, password, callback) {
log('Bind OK.');

log('Enrich profile.');
profile.ldapStatus = 'active';
self.enrichProfile(profile, function (err, profile) {
log('Enrich profile OK.');
return callback(null, profile);
Expand All @@ -93,20 +97,23 @@ Users.prototype.validate = function (userName, password, callback) {
});
};

function getDetailedError(profile, invalidCredentialsError) {
// Get detailed error for AD: http://www-01.ibm.com/support/docview.wss?uid=swg21290631
function getDetailedError(invalidCredentialsError) {
if (invalidCredentialsError && invalidCredentialsError.message) {
if (invalidCredentialsError.message.indexOf('data 532') > -1) {
return new PasswordExpired(profile);
return { code: 'password_expired', err_type: PasswordExpired };
} else if (invalidCredentialsError.message.indexOf('data 533') > -1 || invalidCredentialsError.message.indexOf('data 534') > -1) {
return { code: 'account_disabled', err_type: AccountDisabled };
} else if (invalidCredentialsError.message.indexOf('data 701') > -1) {
return new AccountExpired(profile);
return { code: 'account_expired', err_type: AccountExpired };
} else if (invalidCredentialsError.message.indexOf('data 773') > -1) {
return new PasswordChangeRequired(profile);
return { code: 'password_change_required', err_type: PasswordChangeRequired };
} else if (invalidCredentialsError.message.indexOf('data 775') > -1) {
return new AccountLocked(profile);
return { code: 'account_locked', err_type: AccountLocked };
}
}

return new WrongPassword(profile);
return { code: 'wrong_password', err_type: WrongPassword };
}

function getProperObject(entry) {
Expand Down
34 changes: 29 additions & 5 deletions ws_validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ var cert = {
cert: fs.readFileSync(__dirname + '/certs/cert.pem')
};

var authenticate_when_password_expired = nconf.get('ALLOW_PASSWORD_EXPIRED');
var authenticate_when_password_change_required = nconf.get('ALLOW_PASSWORD_CHANGE_REQUIRED');

var socket_server_address = nconf.get('AD_HUB').replace(/^http/i, 'ws');
var ws = module.exports = new WebSocket(socket_server_address);

var AccountDisabled = require('./lib/errors/AccountDisabled');
var AccountExpired = require('./lib/errors/AccountExpired');
var AccountLocked = require('./lib/errors/AccountLocked');
var PasswordChangeRequired = require('./lib/errors/PasswordChangeRequired');
Expand Down Expand Up @@ -129,6 +133,10 @@ ws.on('open', function () {

users.validate(payload.username, payload.password, function (err, user) {
if (err) {
if (err instanceof AccountDisabled) {
log("Authentication attempt failed. Reason: " + "account disabled".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
}
if (err instanceof AccountExpired) {
log("Authentication attempt failed. Reason: " + "account expired".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
Expand All @@ -138,12 +146,24 @@ ws.on('open', function () {
return ws.reply(payload.pid, { err: err, profile: err.profile });
}
if (err instanceof PasswordChangeRequired) {
log("Authentication attempt failed. Reason: " + "password change is required".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
if (authenticate_when_password_change_required) {
log("Authentication succeeded, but " + "password change is required".red);
return ws.sendEvent(payload.pid + '_result', { profile: err.profile });
}
else {
log("Authentication attempt failed. Reason: " + "password change is required".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
}
}
if (err instanceof PasswordExpired) {
log("Authentication attempt failed. Reason: " + "password expired".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
if (authenticate_when_password_expired) {
log("Authentication succeeded but " + "password expired".red);
return ws.sendEvent(payload.pid + '_result', { profile: err.profile });
}
else {
log("Authentication attempt failed. Reason: " + "password expired".red);
return ws.reply(payload.pid, { err: err, profile: err.profile });
}
}
if (err instanceof WrongPassword) {
log("Authentication attempt failed. Reason: " + "wrong password".red);
Expand All @@ -155,7 +175,11 @@ ws.on('open', function () {
}
log("Authentication attempt failed. Reason: " + "unexpected error".red);

console.error('Inner error:', err.inner.stack);
if (err.inner && err.inner.stack) {
console.error('Inner error:', err.inner.stack);
} else {
console.log(err);
}

ws.reply(payload.pid, { err: err });
return exit(1);
Expand Down

0 comments on commit ad7e7f2

Please sign in to comment.