diff --git a/lib/cli.js b/lib/cli.js index 4fe5b238..ab055b48 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -124,8 +124,8 @@ program }) program - .command('auth') - .description('start auth server') + .command('auth-ldap') + .description('start LDAP auth client') .option('-p, --port ' , 'port (or $PORT)' , Number @@ -163,27 +163,51 @@ program , 'user') .action(function(options) { var env = process.env - require('./roles/auth')({ + require('./roles/auth/ldap')({ port: env.PORT || options.port - , secret: env.SECRET || options.secret - , ssid: env.SSID || options.ssid + , secret: options.secret || env.SECRET + , ssid: options.ssid || env.SSID , ldap: { - url: env.LDAP_URL || options.ldapUrl - , timeout: env.LDAP_TIMEOUT || options.ldapTimeout + url: options.ldapUrl || env.LDAP_URL + , timeout: options.ldapTimeout || env.LDAP_TIMEOUT , bind: { - dn: env.LDAP_BIND_DN || options.ldapBindDn - , credentials: env.LDAP_BIND_CREDENTIALS || options.ldapBindCredentials + dn: options.ldapBindDn || env.LDAP_BIND_DN + , credentials: options.ldapBindCredentials || env.LDAP_BIND_CREDENTIALS } , search: { - dn: env.LDAP_SEARCH_DN || options.ldapSearchDn - , scope: env.LDAP_SEARCH_SCOPE || options.ldapSearchScope - , objectClass: env.LDAP_SEARCH_CLASS || options.ldapSearchClass - , loginField: env.LDAP_SEARCH_LOGINFIELD || options.ldapSearchLoginField + dn: options.ldapSearchDn || env.LDAP_SEARCH_DN + , scope: options.ldapSearchScope || env.LDAP_SEARCH_SCOPE + , objectClass: options.ldapSearchClass || env.LDAP_SEARCH_CLASS + , loginField: options.ldapSearchLoginField || env.LDAP_SEARCH_LOGINFIELD } } }) }) + +program + .command('auth-mock') + .description('start mock auth client') + .option('-p, --port ' + , 'port (or $PORT)' + , Number + , 7100) + .option('-s, --secret ' + , 'secret (or $SECRET)' + , String) + .option('-i, --ssid ' + , 'session SSID (or $SSID)' + , String + , 'ssid') + .action(function(options) { + var env = process.env + require('./roles/auth/mock')({ + port: env.PORT || options.port + , secret: options.secret || env.SECRET + , ssid: options.ssid || env.SSID + }) + }) + program .command('console') .description('start console') diff --git a/lib/roles/auth.js b/lib/roles/auth/ldap.js similarity index 92% rename from lib/roles/auth.js rename to lib/roles/auth/ldap.js index a73095ca..0a3031ad 100644 --- a/lib/roles/auth.js +++ b/lib/roles/auth/ldap.js @@ -3,10 +3,10 @@ var url = require('url') var express = require('express') var validator = require('express-validator') -var logger = require('../util/logger') -var requtil = require('../util/requtil') -var ldaputil = require('../util/ldaputil') -var jwtutil = require('../util/jwtutil') +var logger = require('../../util/logger') +var requtil = require('../../util/requtil') +var ldaputil = require('../../util/ldaputil') +var jwtutil = require('../../util/jwtutil') module.exports = function(options) { var log = logger.createLogger('app') @@ -48,7 +48,7 @@ module.exports = function(options) { ) }) .then(function(user) { - log.info('Authenticated "%s"', user.userPrincipalName) + log.info('Authenticated "%s"', ldaputil.email(user)) var token = jwtutil.encode({ payload: { email: ldaputil.email(user) diff --git a/lib/roles/auth/mock.js b/lib/roles/auth/mock.js new file mode 100644 index 00000000..3836d831 --- /dev/null +++ b/lib/roles/auth/mock.js @@ -0,0 +1,86 @@ +var url = require('url') + +var express = require('express') +var validator = require('express-validator') + +var logger = require('../../util/logger') +var requtil = require('../../util/requtil') +var jwtutil = require('../../util/jwtutil') + +module.exports = function(options) { + var log = logger.createLogger('app') + , app = express() + + app.use(express.cookieParser()) + app.use(express.cookieSession({ + secret: options.secret + , key: options.ssid + })) + app.use(express.json()) + app.use(express.urlencoded()) + app.use(validator()) + + app.get('/auth', function(req, res) { + res.locals.csrf = req.csrfToken() + }) + + app.post('/auth', function(req, res) { + var log = logger.createLogger('auth') + log.setLocalIdentifier(req.ip) + switch (req.accepts(['json'])) { + case 'json': + requtil.validate(req, function() { + req.checkBody('name').notEmpty() + req.checkBody('email').isEmail() + + // This is a security risk. Someone might forward the user + // to the login page with their own redirect set, and they'd + // then be able to steal the token. Some kind of a whitelist + // or a fixed redirect URL is needed. + req.checkBody('redirect').isUrl() + }) + .then(function() { + log.info('Authenticated "%s"', req.body.email) + var token = jwtutil.encode({ + payload: { + email: req.body.email + , name: req.body.name + } + , secret: options.secret + }) + var target = url.parse(req.body.redirect) + target.query = { + jwt: token + } + res.status(200) + .json({ + success: true + , redirect: url.format(target) + }) + }) + .catch(requtil.ValidationError, function(err) { + res.status(400) + .json({ + success: false + , error: 'ValidationError' + , validationErrors: err.errors + }) + }) + .catch(function(err) { + log.error('Unexpected error', err.stack) + res.status(500) + .json({ + success: false + , error: 'ServerError' + }) + }) + break + default: + res.send(406) + break + } + }) + + app.listen(options.port) + log.info('Listening on port %d', options.port) +}