Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# @sensu/superlogin [![Build Status](https://travis-ci.org/sen-su/superlogin.png?branch=master)](https://travis-ci.org/sen-su/superlogin)
# @jaredthirsk/superlogin

## An up-to-date version of superlogin that is actually published.
A fork of @sensu/superlogin, which seems to be a strong contender as a current / maintained version of the original @colinskow/superlogin, (which seems to be broken and out of date.)

Features I add to @sensu's version:
- options to disable
- authenticating to superlogin via API token (`authStrategies.userPassToken = false`)
- authenticating to superlogin via username and password (`authStrategies.userPass = false`)

# Superlogin

SuperLogin is a full-featured NodeJS/Express user authentication solution for APIs and Single Page Apps (SPA) using CouchDB or Cloudant.

Expand Down
8 changes: 6 additions & 2 deletions config/default.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var path = require('path');
var path = require('path')

// These are the default settings that will be used if you don't override them in your config
module.exports = {
Expand All @@ -11,6 +11,10 @@ module.exports = {
loginOnRegistration: false,
loginOnPasswordReset: false
},
authStrategies: {
userPass: true,
apiToken: true
},
local: {
usernameField: 'username',
passwordField: 'password'
Expand Down Expand Up @@ -41,4 +45,4 @@ module.exports = {
format: 'text'
}
}
};
}
100 changes: 51 additions & 49 deletions lib/local.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
'use strict';
var util = require('./util');
var LocalStrategy = require('passport-local');
var BearerStrategy = require('passport-http-bearer-sl').Strategy;

'use strict'
var util = require('./util')
var LocalStrategy = require('passport-local')
var BearerStrategy = require('passport-http-bearer-sl').Strategy

module.exports = function (config, passport, user) {

// API token strategy
passport.use(new BearerStrategy(
function (tokenPass, done) {
var parse = tokenPass.split(':');
if(parse.length < 2) {
done(null, false, {message: 'invalid token'});
if (config.authStrategies.apiToken) {
passport.use(new BearerStrategy(
function (tokenPass, done) {
var parse = tokenPass.split(':')
if (parse.length < 2) {
done(null, false, { message: 'invalid token' })
} else {
var token = parse[0]
var password = parse[1]
user.confirmSession(token, password)
.then(function (theuser) {
done(null, theuser)
}, function (err) {
if (err instanceof Error) {
done(err, false)
} else {
done(null, false, { message: err })
}
})
}
}
var token = parse[0];
var password = parse[1];
user.confirmSession(token, password)
.then(function (theuser) {
done(null, theuser);
}, function (err) {
if (err instanceof Error) {
done(err, false);
} else {
done(null, false, {message: err});
}
});
}
));
))
}

// Use local strategy
passport.use(new LocalStrategy({
if (config.authStrategies.userPass) {
passport.use(new LocalStrategy({
usernameField: config.getItem('local.usernameField') || 'username',
passwordField: config.getItem('local.passwordField') || 'password',
session: false,
Expand All @@ -40,65 +42,65 @@ module.exports = function (config, passport, user) {
.then(function (theuser) {
if (theuser) {
// Check if the account is locked
if(theuser.local && theuser.local.lockedUntil && theuser.local.lockedUntil > Date.now()) {
if (theuser.local && theuser.local.lockedUntil && theuser.local.lockedUntil > Date.now()) {
return done(null, false, {
error: 'Unauthorized',
message: 'Your account is currently locked. Please wait a few minutes and try again.'
});
})
}
if(!theuser.local || !theuser.local.derived_key) {
if (!theuser.local || !theuser.local.derived_key) {
return done(null, false, {
error: 'Unauthorized',
message: 'Invalid username or password'
});
})
}
util.verifyPassword(theuser.local, password)
.then(function () {
// Check if the email has been confirmed if it is required
if(config.getItem('local.requireEmailConfirm') && !theuser.email) {
if (config.getItem('local.requireEmailConfirm') && !theuser.email) {
return done(null, false, {
error: 'Unauthorized',
message: 'You must confirm your email address.'
});
})
}
// Success!!!
return done(null, theuser);
return done(null, theuser)
}, function (err) {
if (!err) {
// Password didn't authenticate
return handleFailedLogin(theuser, req, done);
return handleFailedLogin(theuser, req, done)
} else {
// Hashing function threw an error
return done(err);
return done(err)
}
});
})
} else {
// user not found
return done(null, false, {
error: 'Unauthorized',
message: 'Invalid username or password'
});
})
}
}, function (err) {
// Database threw an error
return done(err);
});
return done(err)
})
}
));
))
}

function handleFailedLogin(userDoc, req, done) {
function handleFailedLogin (userDoc, req, done) {
var invalid = {
error: 'Unauthorized',
message: 'Invalid username or password'
};
}
return user.handleFailedLogin(userDoc, req)
.then(function(locked) {
if(locked) {
.then(function (locked) {
if (locked) {
invalid.message = 'Maximum failed login attempts exceeded. Your account has been locked for ' +
Math.round(config.getItem('security.lockoutTime') / 60) + ' minutes.';
Math.round(config.getItem('security.lockoutTime') / 60) + ' minutes.'
}
return done(null, false, invalid);
});
return done(null, false, invalid)
})
}

};
}
Loading