diff --git a/package-lock.json b/package-lock.json index fdd2f26e9..3a2b0e572 100644 --- a/package-lock.json +++ b/package-lock.json @@ -489,11 +489,6 @@ "precond": "0.2" } }, - "bagpipe": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/bagpipe/-/bagpipe-0.3.5.tgz", - "integrity": "sha1-40HRZPyyTN8E6n4Ft2XsEMiupqE=" - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -877,11 +872,6 @@ } } }, - "connect-ensure-login": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz", - "integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI=" - }, "connect-lastmile": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/connect-lastmile/-/connect-lastmile-1.2.2.tgz", @@ -949,20 +939,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-parser": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", - "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", - "requires": { - "cookie": "0.3.1", - "cookie-signature": "1.0.6" - } - }, "cookie-session": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-1.4.0.tgz", @@ -1565,51 +1541,6 @@ } } }, - "express-session": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", - "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.0", - "uid-safe": "~2.1.5" - }, - "dependencies": { - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1743,16 +1674,6 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2544,14 +2465,6 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -2602,11 +2515,6 @@ "tsscmp": "1.0.6" } }, - "kruptein": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-2.0.5.tgz", - "integrity": "sha512-1WRXAil8d5jZ6jNXC0/pOC2lJsu2GhL3zhzL7DDvtCsef+NC1JvZUXnyNnM6Kuv0aan54moM/hsPvUAkx3y7/w==" - }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -3411,35 +3319,11 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, - "oauth2orize": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/oauth2orize/-/oauth2orize-1.11.0.tgz", - "integrity": "sha1-eTzvJR1F696sMq5AqLaBT6qx1IM=", - "requires": { - "debug": "2.x.x", - "uid2": "0.0.x", - "utils-merge": "1.x.x" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-inspect": { "version": "1.7.0", @@ -3612,14 +3496,6 @@ "pause": "0.0.1" } }, - "passport-http": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/passport-http/-/passport-http-0.3.0.tgz", - "integrity": "sha1-juU9Q4C+nGDfIVGSUCmCb3cRVgM=", - "requires": { - "passport-strategy": "1.x.x" - } - }, "passport-http-bearer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz", @@ -3636,14 +3512,6 @@ "passport-strategy": "1.x.x" } }, - "passport-oauth2-client-password": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/passport-oauth2-client-password/-/passport-oauth2-client-password-0.1.2.tgz", - "integrity": "sha1-TzeLZ4uS0W270jOmxwZSAJPlYbo=", - "requires": { - "passport-strategy": "1.x.x" - } - }, "passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", @@ -4103,11 +3971,6 @@ "path-parse": "^1.0.6" } }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, "retry-request": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", @@ -4364,31 +4227,6 @@ "send": "0.17.1" } }, - "session-file-store": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/session-file-store/-/session-file-store-1.4.0.tgz", - "integrity": "sha512-jBeQwoHoHMOBoELxf+f/IDtMI94PqkFrwCP6O3DlvJlsCU6gY6pgWJGxUOtLWxauIdvAqmgoAbpJi7vJih9bvA==", - "requires": { - "bagpipe": "^0.3.5", - "fs-extra": "^8.0.1", - "kruptein": "^2.0.4", - "object-assign": "^4.1.1", - "retry": "^0.12.0", - "write-file-atomic": "1.3.1" - }, - "dependencies": { - "write-file-atomic": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz", - "integrity": "sha1-fUW6MjFjKN0ex9kPYOvA2EW7dZo=", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - } - } - }, "set-blocking": { "version": "2.0.0", "resolved": false, @@ -4454,11 +4292,6 @@ "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, "smtp-connection": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", @@ -5025,11 +4858,6 @@ "random-bytes": "~1.0.0" } }, - "uid2": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", - "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" - }, "underscore": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", @@ -5043,11 +4871,6 @@ "crypto-random-string": "^1.0.0" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index 11803ebdb..bd7c035d0 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,8 @@ "body-parser": "^1.19.0", "cloudron-manifestformat": "^4.0.0", "connect": "^3.7.0", - "connect-ensure-login": "^0.1.1", "connect-lastmile": "^1.2.2", "connect-timeout": "^1.9.0", - "cookie-parser": "^1.4.4", "cookie-session": "^1.4.0", "cron": "^1.8.2", "db-migrate": "^0.11.6", @@ -35,7 +33,6 @@ "ejs": "^2.6.1", "ejs-cli": "^2.1.1", "express": "^4.17.1", - "express-session": "^1.17.0", "js-yaml": "^3.13.1", "json": "^9.0.6", "ldapjs": "^1.0.2", @@ -48,14 +45,11 @@ "mysql": "^2.18.1", "nodemailer": "^6.4.2", "nodemailer-smtp-transport": "^2.7.4", - "oauth2orize": "^1.11.0", "once": "^1.4.0", "parse-links": "^0.1.0", "passport": "^0.4.1", - "passport-http": "^0.3.0", "passport-http-bearer": "^1.0.1", "passport-local": "^1.0.0", - "passport-oauth2-client-password": "^0.1.2", "pretty-bytes": "^5.3.0", "progress-stream": "^2.0.0", "proxy-middleware": "^0.15.0", @@ -66,7 +60,6 @@ "s3-block-read-stream": "^0.5.0", "safetydance": "^1.0.0", "semver": "^6.1.1", - "session-file-store": "^1.4.0", "showdown": "^1.9.1", "speakeasy": "^2.0.0", "split": "^1.0.1", diff --git a/src/authcodedb.js b/src/authcodedb.js deleted file mode 100644 index f431b76b4..000000000 --- a/src/authcodedb.js +++ /dev/null @@ -1,78 +0,0 @@ -/* jslint node:true */ - -'use strict'; - -exports = module.exports = { - get: get, - add: add, - del: del, - delExpired: delExpired, - - _clear: clear -}; - -var assert = require('assert'), - BoxError = require('./boxerror.js'), - database = require('./database.js'); - -var AUTHCODES_FIELDS = [ 'authCode', 'userId', 'clientId', 'expiresAt' ].join(','); - -function get(authCode, callback) { - assert.strictEqual(typeof authCode, 'string'); - assert.strictEqual(typeof callback, 'function'); - - database.query('SELECT ' + AUTHCODES_FIELDS + ' FROM authcodes WHERE authCode = ? AND expiresAt > ?', [ authCode, Date.now() ], function (error, result) { - if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); - if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Authcode not found')); - - callback(null, result[0]); - }); -} - -function add(authCode, clientId, userId, expiresAt, callback) { - assert.strictEqual(typeof authCode, 'string'); - assert.strictEqual(typeof clientId, 'string'); - assert.strictEqual(typeof userId, 'string'); - assert.strictEqual(typeof expiresAt, 'number'); - assert.strictEqual(typeof callback, 'function'); - - database.query('INSERT INTO authcodes (authCode, clientId, userId, expiresAt) VALUES (?, ?, ?, ?)', - [ authCode, clientId, userId, expiresAt ], function (error, result) { - if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS)); - if (error || result.affectedRows !== 1) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); - - callback(null); - }); -} - -function del(authCode, callback) { - assert.strictEqual(typeof authCode, 'string'); - assert.strictEqual(typeof callback, 'function'); - - database.query('DELETE FROM authcodes WHERE authCode = ?', [ authCode ], function (error, result) { - if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); - if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Authcode not found')); - - callback(null); - }); -} - -function delExpired(callback) { - assert.strictEqual(typeof callback, 'function'); - - database.query('DELETE FROM authcodes WHERE expiresAt <= ?', [ Date.now() ], function (error, result) { - if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); - return callback(null, result.affectedRows); - }); -} - -function clear(callback) { - assert.strictEqual(typeof callback, 'function'); - - database.query('DELETE FROM authcodes', function (error) { - if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); - - callback(null); - }); -} - diff --git a/src/janitor.js b/src/janitor.js index 2c98d780c..ee2880b39 100644 --- a/src/janitor.js +++ b/src/janitor.js @@ -2,7 +2,6 @@ var assert = require('assert'), async = require('async'), - authcodedb = require('./authcodedb.js'), BoxError = require('./boxerror.js'), debug = require('debug')('box:janitor'), Docker = require('dockerode'), @@ -39,26 +38,13 @@ function cleanupExpiredTokens(callback) { }); } -function cleanupExpiredAuthCodes(callback) { - assert.strictEqual(typeof callback, 'function'); - - authcodedb.delExpired(function (error, result) { - if (error) return callback(error); - - debug('Cleaned up %s expired authcodes.', result); - - callback(null); - }); -} - function cleanupTokens(callback) { assert(!callback || typeof callback === 'function'); // callback is null when called from cronjob debug('Cleaning up expired tokens'); async.series([ - ignoreError(cleanupExpiredTokens), - ignoreError(cleanupExpiredAuthCodes) + ignoreError(cleanupExpiredTokens) ], callback); } diff --git a/src/middleware/index.js b/src/middleware/index.js index 6a6a9da6f..4aa7a86df 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -1,14 +1,12 @@ 'use strict'; exports = module.exports = { - cookieParser: require('cookie-parser'), cors: require('./cors'), json: require('body-parser').json, morgan: require('morgan'), proxy: require('proxy-middleware'), lastMile: require('connect-lastmile'), multipart: require('./multipart.js'), - session: require('express-session'), timeout: require('connect-timeout'), urlencoded: require('body-parser').urlencoded }; diff --git a/src/oauth2views/callback.ejs b/src/oauth2views/callback.ejs deleted file mode 100644 index 8198cdcac..000000000 --- a/src/oauth2views/callback.ejs +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/src/oauth2views/error.ejs b/src/oauth2views/error.ejs deleted file mode 100644 index c65ef66e9..000000000 --- a/src/oauth2views/error.ejs +++ /dev/null @@ -1,27 +0,0 @@ -<% include header %> - - - -
- -
-
-
-
-
- <%- message %> -
-
-
-
-
-
-
- Back -
-
-
-
-
- -<% include footer %> diff --git a/src/oauth2views/footer.ejs b/src/oauth2views/footer.ejs deleted file mode 100644 index e52032461..000000000 --- a/src/oauth2views/footer.ejs +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/src/oauth2views/header.ejs b/src/oauth2views/header.ejs deleted file mode 100644 index 50f60d95a..000000000 --- a/src/oauth2views/header.ejs +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - <%= title %> - - - - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/src/oauth2views/login.ejs b/src/oauth2views/login.ejs deleted file mode 100644 index 15d25c179..000000000 --- a/src/oauth2views/login.ejs +++ /dev/null @@ -1,57 +0,0 @@ -<% include header %> - - - -
-
-
-
- -

Login to <%= applicationName %>

-
-
-
-
-<% if (error) { -%> -
-
-

<%= error %>

-
-
-<% } -%> -
-
-
-
- - -
-
- - -
-
- - -
- -
- Reset password -
-
-
-
- - - -<% include footer %> diff --git a/src/paths.js b/src/paths.js index 43d52b132..449899c2e 100644 --- a/src/paths.js +++ b/src/paths.js @@ -36,9 +36,6 @@ exports = module.exports = { DYNDNS_INFO_FILE: path.join(baseDir(), 'platformdata/dyndns-info.json'), VERSION_FILE: path.join(baseDir(), 'platformdata/VERSION'), - SESSION_SECRET_FILE: path.join(baseDir(), 'boxdata/session.secret'), - SESSION_DIR: path.join(baseDir(), 'platformdata/sessions'), - // this is not part of appdata because an icon may be set before install APP_ICONS_DIR: path.join(baseDir(), 'boxdata/appicons'), PROFILE_ICONS_DIR: path.join(baseDir(), 'boxdata/profileicons'), diff --git a/src/routes/accesscontrol.js b/src/routes/accesscontrol.js index db69d6522..0a2133293 100644 --- a/src/routes/accesscontrol.js +++ b/src/routes/accesscontrol.js @@ -10,11 +10,8 @@ exports = module.exports = { var accesscontrol = require('../accesscontrol.js'), assert = require('assert'), - BasicStrategy = require('passport-http').BasicStrategy, BearerStrategy = require('passport-http-bearer').Strategy, BoxError = require('../boxerror.js'), - clients = require('../clients.js'), - ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy, externalLdap = require('../externalldap.js'), HttpError = require('connect-lastmile').HttpError, LocalStrategy = require('passport-local').Strategy, @@ -38,7 +35,6 @@ function initialize(callback) { }); }); - // used when username/password is sent in request body. used in CLI login & oauth2 login route passport.use(new LocalStrategy(function (username, password, callback) { @@ -79,26 +75,6 @@ function initialize(callback) { } })); - // Used to authenticate a OAuth2 client which uses clientId and clientSecret in the Authorization header - passport.use(new BasicStrategy(function (clientId, clientSecret, callback) { - clients.get(clientId, function (error, client) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); - if (error) return callback(error); - if (client.clientSecret !== clientSecret) return callback(null, false); - callback(null, client); - }); - })); - - // Used to authenticate a OAuth2 client which uses clientId and clientSecret in the request body (client_id, client_secret) - passport.use(new ClientPasswordStrategy(function (clientId, clientSecret, callback) { - clients.get(clientId, function(error, client) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); - if (error) { return callback(error); } - if (client.clientSecret !== clientSecret) { return callback(null, false); } - callback(null, client); - }); - })); - // used for "Authorization: Bearer token" or access_token query param authentication passport.use(new BearerStrategy(function (token, callback) { accesscontrol.validateToken(token, callback); diff --git a/src/routes/index.js b/src/routes/index.js index 71811e81c..55aa077ec 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -13,7 +13,6 @@ exports = module.exports = { eventlog: require('./eventlog.js'), graphs: require('./graphs.js'), groups: require('./groups.js'), - oauth2: require('./oauth2.js'), mail: require('./mail.js'), notifications: require('./notifications.js'), profile: require('./profile.js'), diff --git a/src/routes/oauth2.js b/src/routes/oauth2.js deleted file mode 100644 index 63ff8501c..000000000 --- a/src/routes/oauth2.js +++ /dev/null @@ -1,395 +0,0 @@ -'use strict'; - -exports = module.exports = { - initialize: initialize, - uninitialize: uninitialize, - loginForm: loginForm, - login: login, - logout: logout, - sessionCallback: sessionCallback, - authorization: authorization, - token: token -}; - -var apps = require('../apps.js'), - assert = require('assert'), - async = require('async'), - authcodedb = require('../authcodedb.js'), - BoxError = require('../boxerror.js'), - clients = require('../clients'), - constants = require('../constants.js'), - debug = require('debug')('box:routes/oauth2'), - eventlog = require('../eventlog.js'), - hat = require('../hat.js'), - HttpError = require('connect-lastmile').HttpError, - oauth2orize = require('oauth2orize'), - passport = require('passport'), - querystring = require('querystring'), - session = require('connect-ensure-login'), - settings = require('../settings.js'), - speakeasy = require('speakeasy'), - url = require('url'), - users = require('../users.js'), - util = require('util'), - _ = require('underscore'); - -// appId is optional here -function auditSource(req, appId) { - var tmp = { - authType: 'oauth', - ip: req.headers['x-forwarded-for'] || req.connection.remoteAddress || null - }; - - if (appId) tmp.appId = appId; - - return tmp; -} - -var gServer = null; - -function initialize() { - assert.strictEqual(gServer, null); - - gServer = oauth2orize.createServer(); - - gServer.serializeClient(function (client, callback) { - return callback(null, client.id); - }); - - gServer.deserializeClient(function (id, callback) { - clients.get(id, callback); - }); - - // grant authorization code that can be exchanged for access tokens. this is used by external oauth clients - gServer.grant(oauth2orize.grant.code({ scopeSeparator: ',' }, function (client, redirectURI, user, ares, callback) { - debug('grant code:', client.id, redirectURI, user.id, ares); - - var code = hat(256); - var expiresAt = Date.now() + 60 * 60000; // 1 hour - - authcodedb.add(code, client.id, user.id, expiresAt, function (error) { - if (error) return callback(error); - - debug('grant code: new auth code for client %s code %s', client.id, code); - - callback(null, code); - }); - })); - - // exchange authorization codes for access tokens. this is used by external oauth clients - gServer.exchange(oauth2orize.exchange.code(function (client, code, redirectURI, callback) { - authcodedb.get(code, function (error, authCode) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); - if (error) return callback(error); - if (client.id !== authCode.clientId) return callback(null, false); - - authcodedb.del(code, function (error) { - if(error) return callback(error); - - clients.addTokenByUserId(client.id, authCode.userId, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) { - if (error) return callback(error); - - debug('exchange: new access token for client %s user %s token %s', client.id, authCode.userId, result.accessToken.slice(0, 6)); // partial token for security - - callback(null, result.accessToken); - }); - }); - }); - })); - - // implicit token grant that skips issuing auth codes. this is used by our webadmin - gServer.grant(oauth2orize.grant.token({ scopeSeparator: ',' }, function (client, user, ares, callback) { - clients.addTokenByUserId(client.id, user.id, Date.now() + constants.DEFAULT_TOKEN_EXPIRATION, {}, function (error, result) { - if (error) return callback(error); - - debug('grant token: new access token for client %s user %s token %s', client.id, user.id, result.accessToken.slice(0, 6)); // partial token for security - - callback(null, result.accessToken); - }); - })); - - // overwrite the session.ensureLoggedIn to not use res.redirect() due to a chrome bug not sending cookies on redirects - session.ensureLoggedIn = function (redirectTo) { - assert.strictEqual(typeof redirectTo, 'string'); - - return function (req, res, next) { - if (!req.isAuthenticated || !req.isAuthenticated()) { - if (req.session) { - req.session.returnTo = req.originalUrl || req.url; - } - - res.status(200).send(util.format('', redirectTo)); - } else { - next(); - } - }; - }; -} - -function uninitialize() { - gServer = null; -} - -function renderTemplate(res, template, data) { - assert.strictEqual(typeof res, 'object'); - assert.strictEqual(typeof template, 'string'); - assert.strictEqual(typeof data, 'object'); - - settings.getCloudronName(function (error, cloudronName) { - if (error) { - console.error(error); - cloudronName = 'Cloudron'; - } - - // amend template properties, for example used in the header - data.title = data.title || 'Cloudron'; - data.adminOrigin = settings.adminOrigin(); - data.cloudronName = cloudronName; - - res.render(template, data); - }); -} - -function sendErrorPageOrRedirect(req, res, message) { - assert.strictEqual(typeof req, 'object'); - assert.strictEqual(typeof res, 'object'); - assert.strictEqual(typeof message, 'string'); - - debug('sendErrorPageOrRedirect: returnTo %s.', req.query.returnTo, message); - - if (typeof req.query.returnTo !== 'string') { - renderTemplate(res, 'error', { - message: message, - title: 'Cloudron Error' - }); - } else { - var u = url.parse(req.query.returnTo); - if (!u.protocol || !u.host) { - return renderTemplate(res, 'error', { - message: 'Invalid request. returnTo query is not a valid URI. ' + message, - title: 'Cloudron Error' - }); - } - - res.redirect(util.format('%s//%s', u.protocol, u.host)); - } -} - -// use this instead of sendErrorPageOrRedirect(), in case we have a returnTo provided in the query, to avoid login loops -// This usually happens when the OAuth client ID is wrong -function sendError(req, res, message) { - assert.strictEqual(typeof req, 'object'); - assert.strictEqual(typeof res, 'object'); - assert.strictEqual(typeof message, 'string'); - - renderTemplate(res, 'error', { - message: message, - title: 'Cloudron Error' - }); -} - -// -> GET /api/v1/session/login -function loginForm(req, res) { - if (typeof req.session.returnTo !== 'string') return sendErrorPageOrRedirect(req, res, 'Invalid login request. No returnTo provided.'); - - var u = url.parse(req.session.returnTo, true); - if (!u.query.client_id) return sendErrorPageOrRedirect(req, res, 'Invalid login request. No client_id provided.'); - - function render(applicationName, applicationLogo) { - var error = req.query.error || null; - - renderTemplate(res, 'login', { - applicationName: applicationName, - applicationLogo: applicationLogo, - error: error, - username: settings.isDemo() ? constants.DEMO_USERNAME : '', - password: settings.isDemo() ? 'cloudron' : '', - title: applicationName + ' Login' - }); - } - - function renderBuiltIn() { - settings.getCloudronName(function (error, cloudronName) { - if (error) { - console.error(error); - cloudronName = 'Cloudron'; - } - - render(cloudronName, '/api/v1/cloudron/avatar'); - }); - } - - clients.get(u.query.client_id, function (error, result) { - if (error) return sendError(req, res, 'Unknown OAuth client'); - - switch (result.type) { - case clients.TYPE_BUILT_IN: return renderBuiltIn(); - case clients.TYPE_EXTERNAL: return render(result.appId, '/api/v1/cloudron/avatar'); - default: break; - } - - apps.get(result.appId, function (error, result) { - if (error) return sendErrorPageOrRedirect(req, res, 'Unknown Application for those OAuth credentials'); - - var applicationName = result.fqdn; - render(applicationName, '/api/v1/apps/' + result.id + '/icon'); - }); - }); -} - -// -> POST /api/v1/session/login -function login(req, res) { - var returnTo = req.session.returnTo || req.query.returnTo; - - var failureQuery = querystring.stringify({ error: 'Invalid username or password', returnTo: returnTo }); - passport.authenticate('local', { - failureRedirect: '/api/v1/session/login?' + failureQuery - })(req, res, function (error) { - if (error) return res.redirect('/api/v1/session/login?' + failureQuery); // on some exception in the handlers - - if (!req.user.ghost && !req.user.appPassword && req.user.twoFactorAuthenticationEnabled) { - if (!req.body.totpToken) { - let failureQuery = querystring.stringify({ error: 'A 2FA token is required', returnTo: returnTo }); - return res.redirect('/api/v1/session/login?' + failureQuery); - } - - let verified = speakeasy.totp.verify({ secret: req.user.twoFactorAuthenticationSecret, encoding: 'base32', token: req.body.totpToken, window: 2 }); - if (!verified) { - let failureQuery = querystring.stringify({ error: 'The 2FA token is invalid', returnTo: returnTo }); - return res.redirect('/api/v1/session/login?' + failureQuery); - } - } - - res.redirect(returnTo); - }); -} - -// -> GET /api/v1/session/logout -function logout(req, res) { - function done() { - req.logout(); - - if (req.query && req.query.redirect) res.redirect(req.query.redirect); - else res.redirect('/'); - } - - if (!req.query.all) return done(); - - // find and destroy all login sessions by this user - this got rather complex quickly - req.sessionStore.list(function (error, result) { - if (error) { - console.error('Error listing sessions', error); - return done(); - } - - // WARNING fix this if we change the storage backend - Great stuff! - var sessionIds = result.map(function(s) { return s.replace('.json', ''); }); - - async.each(sessionIds, function (id, callback) { - req.sessionStore.get(id, function (error, result) { - if (error) { - console.error(`Error getting session ${id}`, error); - return callback(); - } - - // ignore empty or non passport sessions - if (!result || !result.passport || !result.passport.user) return callback(); - - // not this user - if (result.passport.user !== req.user.id) return callback(); - - req.sessionStore.destroy(id, function (error) { - if (error) console.error(`Unable to destroy session ${id}`, error); - callback(); - }); - }); - }, done); - }); -} - -// The callback page takes the redirectURI and the authCode and redirects the browser accordingly -// -// -> GET /api/v1/session/callback -function sessionCallback() { - return [ - session.ensureLoggedIn('/api/v1/session/login'), - function (req, res) { - renderTemplate(res, 'callback', { callbackServer: req.query.redirectURI }); - } - ]; -} - -// The authorization endpoint is the entry point for an OAuth login. -// -// Each app would start OAuth by redirecting the user to: -// -// /api/v1/oauth/dialog/authorize?response_type=code&client_id=&redirect_uri=&scope= -// -// - First, this will ensure the user is logged in. -// - Then it will redirect the browser to the given containing the authcode in the query -// -// -> GET /api/v1/oauth/dialog/authorize -function authorization() { - return [ - function (req, res, next) { - if (!req.query.redirect_uri) return sendErrorPageOrRedirect(req, res, 'Invalid request. redirect_uri query param is not set.'); - if (!req.query.client_id) return sendErrorPageOrRedirect(req, res, 'Invalid request. client_id query param is not set.'); - if (!req.query.response_type) return sendErrorPageOrRedirect(req, res, 'Invalid request. response_type query param is not set.'); - if (req.query.response_type !== 'code' && req.query.response_type !== 'token') return sendErrorPageOrRedirect(req, res, 'Invalid request. Only token and code response types are supported.'); - - session.ensureLoggedIn('/api/v1/session/login?returnTo=' + req.query.redirect_uri)(req, res, next); - }, - gServer.authorization({}, function (clientId, redirectURI, callback) { - debug('authorization: client %s with callback to %s.', clientId, redirectURI); - - clients.get(clientId, function (error, client) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); - if (error) return callback(error); - - // ignore the origin passed into form the client, but use the one from the clientdb - var redirectPath = url.parse(redirectURI).path; - var redirectOrigin = client.redirectURI; - - callback(null, client, '/api/v1/session/callback?redirectURI=' + encodeURIComponent(url.resolve(redirectOrigin, redirectPath))); - }); - }), - function (req, res, next) { - // Handle our different types of oauth clients - var type = req.oauth2.client.type; - - if (type === clients.TYPE_EXTERNAL || type === clients.TYPE_BUILT_IN) { - eventlog.add(eventlog.ACTION_USER_LOGIN, auditSource(req, req.oauth2.client.appId), { userId: req.oauth2.user.id, user: users.removePrivateFields(req.oauth2.user) }); - return next(); - } - - apps.get(req.oauth2.client.appId, function (error, appObject) { - if (error) return sendErrorPageOrRedirect(req, res, 'Invalid request. Unknown app for this client_id.'); - - apps.hasAccessTo(appObject, req.oauth2.user, function (error, access) { - if (error) return sendError(req, res, 'Internal error'); - if (!access) return sendErrorPageOrRedirect(req, res, 'No access to this app.'); - - eventlog.add(eventlog.ACTION_USER_LOGIN, auditSource(req, appObject.id), { userId: req.oauth2.user.id, user: users.removePrivateFields(req.oauth2.user) }); - - next(); - }); - }); - }, - gServer.decision({ loadTransaction: false }) - ]; -} - -// The token endpoint allows an OAuth client to exchange an authcode with an accesstoken. -// -// Authcodes are obtained using the authorization endpoint. The route is authenticated by -// providing a Basic auth with clientID as username and clientSecret as password. -// An authcode is only good for one such exchange to an accesstoken. -// -// -> POST /api/v1/oauth/token -function token() { - return [ - passport.authenticate(['basic', 'oauth2-client-password'], { session: false }), - gServer.token(), // will call the token grant callback registered in initialize() - gServer.errorHandler() - ]; -} diff --git a/src/routes/test/oauth2-test.js b/src/routes/test/oauth2-test.js deleted file mode 100644 index 4823a7056..000000000 --- a/src/routes/test/oauth2-test.js +++ /dev/null @@ -1,1491 +0,0 @@ -/* jslint node:true */ -/* global it:false */ -/* global describe:false */ -/* global before:false */ -/* global after:false */ - -'use strict'; - -var accesscontrol = require('../../accesscontrol.js'), - appdb = require('../../appdb.js'), - async = require('async'), - clientdb = require('../../clientdb.js'), - clients = require('../../clients.js'), - constants = require('../../constants.js'), - database = require('../../database.js'), - domains = require('../../domains.js'), - expect = require('expect.js'), - hat = require('../../hat.js'), - nock = require('nock'), - oauth2 = require('../oauth2.js'), - querystring = require('querystring'), - request = require('request'), - server = require('../../server.js'), - settings = require('../../settings.js'), - speakeasy = require('speakeasy'), - superagent = require('superagent'), - urlParse = require('url').parse, - userdb = require('../../userdb.js'), - users = require('../../users.js'), - uuid = require('uuid'); - -var SERVER_URL = 'http://localhost:' + constants.PORT; - -let AUDIT_SOURCE = { ip: '1.2.3.4', userId: 'someuserid' }; - -describe('OAuth2', function () { - - describe('flow', function () { - const DOMAIN_0 = { - domain: 'example.com', - zoneName: 'example.com', - config: {}, - provider: 'manual', - fallbackCertificate: null, - tlsConfig: { provider: 'fallback' } - }; - - var USER_0 = { - id: uuid.v4(), - username: 'someUSERname', - password: '@#45Strongpassword', - email: 'some@EMAIL.com', - salt: 'somesalt', - createdAt: (new Date()).toUTCString(), - modifiedAt: (new Date()).toUTCString(), - resetToken: hat(256), - displayName: '', - source: '' - }; - - var APP_0 = { - id: 'app0', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test', - domain: DOMAIN_0.domain, - portBindings: {}, - accessRestriction: null, - memoryLimit: 0, - installationState: 'pending_install', - runState: 'running', - mailboxDomain: DOMAIN_0.domain - }; - - var APP_1 = { - id: 'app1', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test1', - domain: DOMAIN_0.domain, - portBindings: {}, - accessRestriction: { users: [ 'foobar' ] }, - memoryLimit: 0, - installationState: 'pending_install', - runState: 'running', - mailboxDomain: DOMAIN_0.domain - }; - - var APP_2 = { - id: 'app2', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test2', - domain: DOMAIN_0.domain, - portBindings: {}, - accessRestriction: { users: [ USER_0.id ] }, - memoryLimit: 0, - installationState: 'pending_install', - runState: 'running', - mailboxDomain: DOMAIN_0.domain - }; - - var APP_3 = { - id: 'app3', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test3', - domain: DOMAIN_0.domain, - portBindings: {}, - accessRestriction: { groups: [ 'someothergroup', 'admin', 'anothergroup' ] }, - memoryLimit: 0, - installationState: 'pending_install', - runState: 'running', - mailboxDomain: DOMAIN_0.domain - }; - - // unknown app - var CLIENT_0 = { - id: 'cid-client0', - appId: 'appid-app0', - type: clients.TYPE_OAUTH, - clientSecret: 'secret0', - redirectURI: 'http://redirect0', - scope: accesscontrol.SCOPE_PROFILE - }; - - // unknown app through addon - var CLIENT_1 = { - id: 'cid-client1', - appId: 'appid-app1', - type: clients.TYPE_OAUTH, - clientSecret: 'secret1', - redirectURI: 'http://redirect1', - scope: accesscontrol.SCOPE_PROFILE - }; - - // known app - var CLIENT_2 = { - id: 'cid-client2', - appId: APP_0.id, - type: clients.TYPE_OAUTH, - clientSecret: 'secret2', - redirectURI: 'http://redirect2', - scope: accesscontrol.SCOPE_PROFILE - }; - - // known app through addon - var CLIENT_3 = { - id: 'cid-client3', - appId: APP_0.id, - type: clients.TYPE_OAUTH, - clientSecret: 'secret3', - redirectURI: 'http://redirect1', - scope: accesscontrol.SCOPE_PROFILE - }; - - // unknown app through proxy - var CLIENT_4 = { - id: 'cid-client4', - appId: 'appid-app4', - type: clients.TYPE_PROXY, - clientSecret: 'secret4', - redirectURI: 'http://redirect4', - scope: accesscontrol.SCOPE_PROFILE - }; - - // known app through proxy - var CLIENT_5 = { - id: 'cid-client5', - appId: APP_0.id, - type: clients.TYPE_PROXY, - clientSecret: 'secret5', - redirectURI: 'http://redirect5', - scope: accesscontrol.SCOPE_PROFILE - }; - - // app with accessRestriction not allowing user - var CLIENT_6 = { - id: 'cid-client6', - appId: APP_1.id, - type: clients.TYPE_OAUTH, - clientSecret: 'secret6', - redirectURI: 'http://redirect6', - scope: accesscontrol.SCOPE_PROFILE - }; - - // app with accessRestriction allowing user - var CLIENT_7 = { - id: 'cid-client7', - appId: APP_2.id, - type: clients.TYPE_OAUTH, - clientSecret: 'secret7', - redirectURI: 'http://redirect7', - scope: accesscontrol.SCOPE_PROFILE - }; - - // app with accessRestriction allowing group - var CLIENT_9 = { - id: 'cid-client9', - appId: APP_3.id, - type: clients.TYPE_OAUTH, - clientSecret: 'secret9', - redirectURI: 'http://redirect9', - scope: accesscontrol.SCOPE_PROFILE - }; - - function setup(done) { - async.series([ - server.start, - database._clear, - domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0, AUDIT_SOURCE), - settings.setAdmin.bind(null, DOMAIN_0.domain, 'my.' + DOMAIN_0.domain), - clientdb.add.bind(null, CLIENT_0.id, CLIENT_0.appId, CLIENT_0.type, CLIENT_0.clientSecret, CLIENT_0.redirectURI, CLIENT_0.scope), - clientdb.add.bind(null, CLIENT_1.id, CLIENT_1.appId, CLIENT_1.type, CLIENT_1.clientSecret, CLIENT_1.redirectURI, CLIENT_1.scope), - clientdb.add.bind(null, CLIENT_2.id, CLIENT_2.appId, CLIENT_2.type, CLIENT_2.clientSecret, CLIENT_2.redirectURI, CLIENT_2.scope), - clientdb.add.bind(null, CLIENT_3.id, CLIENT_3.appId, CLIENT_3.type, CLIENT_3.clientSecret, CLIENT_3.redirectURI, CLIENT_3.scope), - clientdb.add.bind(null, CLIENT_4.id, CLIENT_4.appId, CLIENT_4.type, CLIENT_4.clientSecret, CLIENT_4.redirectURI, CLIENT_4.scope), - clientdb.add.bind(null, CLIENT_5.id, CLIENT_5.appId, CLIENT_5.type, CLIENT_5.clientSecret, CLIENT_5.redirectURI, CLIENT_5.scope), - clientdb.add.bind(null, CLIENT_6.id, CLIENT_6.appId, CLIENT_6.type, CLIENT_6.clientSecret, CLIENT_6.redirectURI, CLIENT_6.scope), - clientdb.add.bind(null, CLIENT_7.id, CLIENT_7.appId, CLIENT_7.type, CLIENT_7.clientSecret, CLIENT_7.redirectURI, CLIENT_7.scope), - clientdb.add.bind(null, CLIENT_9.id, CLIENT_9.appId, CLIENT_9.type, CLIENT_9.clientSecret, CLIENT_9.redirectURI, CLIENT_9.scope), - function (callback) { - users.create(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, { }, AUDIT_SOURCE, function (error, userObject) { - expect(error).to.not.be.ok(); - - // update the global objects to reflect the new user id - APP_2.accessRestriction = { users: [ 'foobar', userObject.id ] }; - - async.series([ - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_1.portBindings, APP_1), - appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, APP_2.portBindings, APP_2), - appdb.add.bind(null, APP_3.id, APP_3.appStoreId, APP_3.manifest, APP_3.location, APP_3.domain, APP_3.portBindings, APP_3), - - appdb.update.bind(null, APP_2.id, APP_2) - ], callback); - }); - }, - ], done); - } - - function cleanup(done) { - database._clear(function (error) { - expect(error).to.not.be.ok(); - - server.stop(done); - }); - } - - describe('authorization', function () { - before(setup); - after(cleanup); - - it('fails due to missing redirect_uri param', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid request. redirect_uri query param is not set.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('fails due to missing client_id param', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid request. client_id query param is not set.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('fails due to missing response_type param', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&client_id=someclientid') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid request. response_type query param is not set.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('fails for unkown grant type', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&client_id=someclientid&response_type=foobar') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid request. Only token and code response types are supported.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('succeeds for grant type code', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&client_id=someclientid&response_type=code') - .end(function (error, result) { - expect(result.text).to.eql(''); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('succeeds for grant type token', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&client_id=someclientid&response_type=token') - .end(function (error, result) { - expect(result.text).to.eql(''); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - }); - - describe('loginForm', function () { - before(setup); - after(cleanup); - - it('fails without prior authentication call and not returnTo query', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/login') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid login request. No returnTo provided.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - - done(); - }); - }); - - it('redirects without prior authentication call', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/login?returnTo=http://someredirect') - .redirects(0) - .end(function (error, result) { - expect(result.statusCode).to.equal(302); - expect(result.headers.location).to.eql('http://someredirect'); - - done(); - }); - }); - - it('fails due to unknown missing client_id', function (done) { - superagent.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&response_type=code') - .redirects(0) - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.text.indexOf('Invalid request. client_id query param is not set.')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - - done(); - }); - }); - - it('fails due to unknown oauth client', function (done) { - request.get(SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=http://someredirect&client_id=someclientid&response_type=code', { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=http://someredirect', { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - expect(body.indexOf('Unknown OAuth client')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('fails due to unknown app', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_0.redirectURI + '&client_id=' + CLIENT_0.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_0.redirectURI, { jar: true, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - expect(response.headers.location).to.eql(CLIENT_0.redirectURI); - - done(); - }); - }); - }); - - it('fails due to unknown app for addon', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_1.redirectURI + '&client_id=' + CLIENT_1.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_1.redirectURI, { jar: true, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - expect(response.headers.location).to.eql(CLIENT_1.redirectURI); - - done(); - }); - }); - }); - - it('succeeds for known app', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI, { jar: true, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('succeeds for known app for addon', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_3.redirectURI + '&client_id=' + CLIENT_3.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_3.redirectURI, { jar: true, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('fails due to unknown app for proxy', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_4.redirectURI + '&client_id=' + CLIENT_4.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_4.redirectURI, { jar: true, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - expect(response.headers.location).to.eql(CLIENT_4.redirectURI); - - done(); - }); - }); - }); - - it('succeeds for known app for proxy', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_5.redirectURI + '&client_id=' + CLIENT_5.id + '&response_type=code'; - request.get(url, { jar: true }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_5.redirectURI, { jar: true, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - done(); - }); - }); - }); - }); - - describe('loginForm submit', function () { - before(setup); - after(cleanup); - - function startAuthorizationFlow(client, callback) { - var jar = request.jar(); - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + client.redirectURI + '&client_id=' + client.id + '&response_type=code'; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + client.redirectURI, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - callback(jar); - }); - }); - } - - it('fails due to missing credentials', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = {}; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.error).to.eql('Invalid username or password'); - expect(tmp.query.returnTo).to.eql('/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'); - - done(); - }); - }); - }); - - it('fails due to wrong username', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: 'foobar', - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.error).to.eql('Invalid username or password'); - expect(tmp.query.returnTo).to.eql('/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'); - - done(); - }); - }); - }); - - it('fails due to wrong password', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: 'password' - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.error).to.eql('Invalid username or password'); - expect(tmp.query.returnTo).to.eql('/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'); - - done(); - }); - }); - }); - - it('succeeds with username', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(CLIENT_2.redirectURI); - expect(tmp.query.client_id).to.eql(CLIENT_2.id); - expect(tmp.query.response_type).to.eql('code'); - - done(); - }); - }); - }); - - it('succeeds with email', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.email, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(CLIENT_2.redirectURI); - expect(tmp.query.client_id).to.eql(CLIENT_2.id); - expect(tmp.query.response_type).to.eql('code'); - - done(); - }); - }); - }); - }); - - describe('loginForm 2FA submit', function () { - var secret, accessToken; - - before(function (done) { - async.series([ - setup, - function (callback) { - superagent.post(`${SERVER_URL}/api/v1/developer/login`).send({ username: USER_0.username, password: USER_0.password }).end(function (error, result) { - accessToken = result.body.accessToken; - callback(error); - }); - }, - function (callback) { - superagent.post(`${SERVER_URL}/api/v1/profile/twofactorauthentication`).query({ access_token: accessToken }).end(function (error, result) { - secret = result.body.secret; - callback(error); - }); - }, - function (callback) { - var totpToken = speakeasy.totp({ - secret: secret, - encoding: 'base32' - }); - - superagent.post(`${SERVER_URL}/api/v1/profile/twofactorauthentication/enable`).query({ access_token: accessToken }).send({ totpToken: totpToken }).end(function (error) { - callback(error); - }); - } - ], done); - }); - - after(cleanup); - - function startAuthorizationFlow(client, callback) { - var jar = request.jar(); - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + client.redirectURI + '&client_id=' + client.id + '&response_type=code'; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + client.redirectURI, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - callback(jar); - }); - }); - } - - it('fails due to missing token', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.error).to.eql('A 2FA token is required'); - expect(tmp.query.returnTo).to.eql('/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'); - - done(); - }); - }); - }); - - it('fails due to wrong token', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password, - totpToken: 'wrongtoken' - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.error).to.eql('The 2FA token is invalid'); - expect(tmp.query.returnTo).to.eql('/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'); - - done(); - }); - }); - }); - - it('succeeds', function (done) { - startAuthorizationFlow(CLIENT_2, function (jar) { - var totpToken = speakeasy.totp({ - secret: secret, - encoding: 'base32' - }); - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password, - totpToken: totpToken - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(CLIENT_2.redirectURI); - expect(tmp.query.client_id).to.eql(CLIENT_2.id); - expect(tmp.query.response_type).to.eql('code'); - - done(); - }); - }); - }); - }); - - describe('authorization with valid session', function () { - before(setup); - after(cleanup); - - function startAuthorizationFlow(client, grant, callback) { - var jar = request.jar(); - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + client.redirectURI + '&client_id=' + client.id + '&response_type=' + grant; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + client.redirectURI, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + client.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(client.redirectURI); - expect(tmp.query.client_id).to.eql(client.id); - expect(tmp.query.response_type).to.eql(grant); - - callback(jar); - }); - }); - }); - } - - it('succeeds for grant type code', function (done) { - startAuthorizationFlow(CLIENT_2, 'code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - done(); - }); - }); - }); - - it('succeeds for grant type token', function (done) { - startAuthorizationFlow(CLIENT_2, 'token', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=token'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - - var foo = querystring.parse(tmp.hash.slice(1)); // remove # - expect(foo.access_token).to.be.a('string'); - expect(foo.token_type).to.eql('Bearer'); - - done(); - }); - }); - }); - - it('fails for grant type code due to accessRestriction', function (done) { - startAuthorizationFlow(CLIENT_6, 'code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_6.redirectURI + '&client_id=' + CLIENT_6.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - expect(body.indexOf('No access to this app.')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('succeeds for grant type code with accessRestriction', function (done) { - startAuthorizationFlow(CLIENT_7, 'code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_7.redirectURI + '&client_id=' + CLIENT_7.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirectURI).to.eql(CLIENT_7.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - done(); - }); - }); - }); - - it('fails for grant type code with accessRestriction (group)', function (done) { // USER_0 is not an admin - startAuthorizationFlow(CLIENT_9, 'code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_9.redirectURI + '&client_id=' + CLIENT_9.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - expect(body.indexOf('No access to this app.')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('fails for grant type token due to accessRestriction', function (done) { - startAuthorizationFlow(CLIENT_6, 'token', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_6.redirectURI + '&client_id=' + CLIENT_6.id + '&response_type=token'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - expect(body.indexOf('No access to this app.')).to.not.equal(-1); - - done(); - }); - }); - }); - - it('succeeds for grant type token', function (done) { - startAuthorizationFlow(CLIENT_7, 'token', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_7.redirectURI + '&client_id=' + CLIENT_7.id + '&response_type=token'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirectURI).to.eql(CLIENT_7.redirectURI + '/'); - - var foo = querystring.parse(tmp.hash.slice(1)); // remove # - expect(foo.access_token).to.be.a('string'); - expect(foo.token_type).to.eql('Bearer'); - - // Ensure the token is also usable - superagent.get(SERVER_URL + '/api/v1/profile?access_token=' + foo.access_token, function (error, result) { - expect(error).to.not.be.ok(); - expect(result.status).to.eql(200); - expect(result.body.username).to.equal(USER_0.username.toLowerCase()); - - done(); - }); - }); - }); - }); - - it('fails after logout', function (done) { - startAuthorizationFlow(CLIENT_2, 'token', function (jar) { - - request.get(SERVER_URL + '/api/v1/session/logout', { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - expect(response.headers.location).to.eql('/'); - - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=token'; - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - done(); - }); - }); - }); - }); - - it('fails after logout width redirect', function (done) { - startAuthorizationFlow(CLIENT_2, 'token', function (jar) { - - request.get(SERVER_URL + '/api/v1/session/logout', { jar: jar, followRedirect: false, qs: { redirect: 'http://foobar' } }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - expect(response.headers.location).to.eql('http://foobar'); - - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=token'; - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - done(); - }); - }); - }); - }); - }); - - describe('callback', function () { - before(setup); - after(cleanup); - - function startAuthorizationFlow(grant, callback) { - var jar = request.jar(); - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=' + grant; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(CLIENT_2.redirectURI); - expect(tmp.query.client_id).to.eql(CLIENT_2.id); - expect(tmp.query.response_type).to.eql(grant); - - callback(jar); - }); - }); - }); - } - - it('sends correct redirect', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - done(); - }); - }); - }); - - it('is rendered correctly', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - done(); - }); - }); - }); - }); - - describe('token exchange', function () { - before(setup); - after(cleanup); - - function startAuthorizationFlow(grant, callback) { - var jar = request.jar(); - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=' + grant; - - request.get(url, { jar: jar }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body).to.eql(''); - - request.get(SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI, { jar: jar, followRedirect: false }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.indexOf('')).to.not.equal(-1); - - var url = SERVER_URL + '/api/v1/session/login?returnTo=' + CLIENT_2.redirectURI; - var data = { - username: USER_0.username, - password: USER_0.password - }; - - request.post({ url: url, jar: jar, form: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.query.redirect_uri).to.eql(CLIENT_2.redirectURI); - expect(tmp.query.client_id).to.eql(CLIENT_2.id); - expect(tmp.query.response_type).to.eql(grant); - - callback(jar); - }); - }); - }); - } - - it('fails due to missing credentials', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(401); - - done(); - }); - }); - }); - }); - - it('fails due to missing client_id', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - code: tmp.query.code, - // client_id: CLIENT_2.id, - client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(401); - done(); - }); - }); - }); - }); - - it('fails due to missing grant_type', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - // grant_type: 'authorization_code', - code: tmp.query.code, - client_id: CLIENT_2.id, - client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(501); - done(); - }); - }); - }); - }); - - it('fails due to missing code', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - // code: tmp.query.code, - client_id: CLIENT_2.id, - client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(400); - done(); - }); - }); - }); - }); - - it('fails due to missing client_secret', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - code: tmp.query.code, - client_id: CLIENT_2.id, - // client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(401); - done(); - }); - }); - }); - }); - - it('fails due to wrong client_secret', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - code: tmp.query.code, - client_id: CLIENT_2.id, - client_secret: CLIENT_2.clientSecret+CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(401); - done(); - }); - }); - }); - }); - - it('fails due to wrong client_id', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - code: tmp.query.code, - client_id: CLIENT_2.id+CLIENT_2.id, - client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(401); - done(); - }); - }); - }); - }); - - it('succeeds', function (done) { - startAuthorizationFlow('code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_2.redirectURI + '&client_id=' + CLIENT_2.id + '&response_type=code'; - - request.get(url, { jar: jar, followRedirect: false }, function (error, response) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(302); - - var tmp = urlParse(response.headers.location, true); - expect(tmp.pathname).to.eql('/api/v1/session/callback'); - expect(tmp.query.redirectURI).to.eql(CLIENT_2.redirectURI + '/'); - expect(tmp.query.code).to.be.a('string'); - - var data = { - grant_type: 'authorization_code', - code: tmp.query.code, - client_id: CLIENT_2.id, - client_secret: CLIENT_2.clientSecret - }; - - request.post(SERVER_URL + '/api/v1/oauth/token', { jar: jar, json: data }, function (error, response, body) { - expect(error).to.not.be.ok(); - expect(response.statusCode).to.eql(200); - expect(body.access_token).to.be.a('string'); - expect(body.token_type).to.eql('Bearer'); - - // Ensure the token is also usable - superagent.get(SERVER_URL + '/api/v1/profile?access_token=' + body.access_token, function (error, result) { - expect(error).to.not.be.ok(); - expect(result.status).to.eql(200); - expect(result.body.username).to.equal(USER_0.username.toLowerCase()); - - done(); - }); - }); - }); - }); - }); - }); - }); -}); - -describe('Password', function () { - var USER_0 = { - userId: uuid.v4(), - username: 'someusername', - password: 'passWord%1234', - email: 'some@email.com', - fallbackEmail: 'somefallback@email.com', - admin: true, - salt: 'somesalt', - createdAt: (new Date()).toUTCString(), - modifiedAt: (new Date()).toUTCString(), - resetToken: hat(256), - displayName: '', - source: '' - }; - - function setup(done) { - async.series([ - server.start, - database._clear, - settings.setAdmin.bind(null, 'example.com', 'my.example.com'), - userdb.add.bind(null, USER_0.userId, USER_0) - ], done); - } - - function cleanup(done) { - database._clear(function (error) { - expect(error).to.not.be.ok(); - - server.stop(done); - }); - } - - describe('pages', function () { - before(setup); - after(cleanup); - - it('reset request succeeds', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/resetRequest.html') - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.text.indexOf('')).to.not.equal(-1); - done(); - }); - }); - - it('setup fails due to missing reset_token', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/account/setup.html') - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.text.indexOf('')).to.not.equal(-1); - done(); - }); - }); - - it('setup fails due to invalid reset_token', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/account/setup.html') - .query({ reset_token: hat(256) }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.text.indexOf('')).to.not.equal(-1); - done(); - }); - }); - - it('setup fails without email', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/account/setup.html') - .query({ reset_token: USER_0.resetToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.text.indexOf('')).to.not.equal(-1); - done(); - }); - }); - - it('setup succeeds', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/account/setup.html') - .query({ email: USER_0.email, reset_token: USER_0.resetToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - expect(result.text.indexOf('')).to.not.equal(-1); - done(); - }); - }); - - it('reset fails due to missing reset_token', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/reset.html') - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('reset fails due to invalid reset_token', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/reset.html') - .query({ email: USER_0.email, reset_token: hat(256) }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('reset fails due to invalid email', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/reset.html') - .query({ email: USER_0.email + 'x', reset_token: hat(256) }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('reset succeeds', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/reset.html') - .query({ email: USER_0.email, reset_token: USER_0.resetToken }) - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - - it('sent succeeds', function (done) { - superagent.get(SERVER_URL + '/api/v1/session/password/sent.html') - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - }); - - describe('reset request handler', function () { - before(setup); - after(cleanup); - - it('succeeds', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/resetRequest') - .send({ identifier: USER_0.email }) - .end(function (error, result) { - expect(result.text.indexOf('')).to.not.equal(-1); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - }); - - describe('reset handler', function () { - before(setup); - after(cleanup); - - it('fails due to missing resetToken', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ password: 'somepassword' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails due to missing password', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ resetToken: hat(256) }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails due to empty password', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ password: '', email: USER_0.email, resetToken: hat(256) }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('fails due to empty resetToken', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ password: '', email: USER_0.email, resetToken: '' }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('fails due to weak password', function (done) { - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ password: 'foobar', email: USER_0.email, resetToken: USER_0.resetToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(406); - done(); - }); - }); - - it('succeeds', function (done) { - var scope = nock(settings.adminOrigin()) - .filteringPath(function (path) { - path = path.replace(/accessToken=[^&]*/, 'accessToken=token'); - path = path.replace(/expiresAt=[^&]*/, 'expiresAt=1234'); - return path; - }) - .get('/?accessToken=token&expiresAt=1234').reply(200, {}); - - superagent.post(SERVER_URL + '/api/v1/session/password/reset') - .send({ password: '12345678', email: USER_0.email, resetToken: USER_0.resetToken }) - .end(function (error, result) { - expect(scope.isDone()).to.be.ok(); - expect(result.statusCode).to.equal(200); - done(); - }); - }); - }); -}); - diff --git a/src/server.js b/src/server.js index c53e49c33..ca633d7ee 100644 --- a/src/server.js +++ b/src/server.js @@ -13,14 +13,10 @@ var accesscontrol = require('./accesscontrol.js'), database = require('./database.js'), eventlog = require('./eventlog.js'), express = require('express'), - hat = require('./hat.js'), http = require('http'), middleware = require('./middleware'), passport = require('passport'), - path = require('path'), - paths = require('./paths.js'), routes = require('./routes/index.js'), - safe = require('safetydance'), settings = require('./settings.js'), ws = require('ws'); @@ -40,9 +36,6 @@ function initializeExpressSync() { var json = middleware.json({ strict: true, limit: QUERY_LIMIT }), // application/json urlencoded = middleware.urlencoded({ extended: false, limit: QUERY_LIMIT }); // application/x-www-form-urlencoded - app.set('views', path.join(__dirname, 'oauth2views')); - app.set('view options', { layout: true, debug: false }); - app.set('view engine', 'ejs'); app.set('json spaces', 2); // pretty json // for rate limiting @@ -68,39 +61,14 @@ function initializeExpressSync() { var router = new express.Router(); router.del = router.delete; // amend router.del for readability further on - // load or generate the session secret - var sessionSecret = safe.fs.readFileSync(paths.SESSION_SECRET_FILE, 'utf8'); - if (!sessionSecret) { - sessionSecret = hat(128); - safe.fs.writeFileSync(paths.SESSION_SECRET_FILE, sessionSecret); - } - - var SessionFileStore = require('session-file-store')(middleware.session); - app // the timeout middleware will respond with a 503. the request itself cannot be 'aborted' and will continue // search for req.clearTimeout in route handlers to see places where this timeout is reset .use(middleware.timeout(REQUEST_TIMEOUT, { respond: true })) .use(json) .use(urlencoded) - .use(middleware.cookieParser()) .use(middleware.cors({ origins: [ '*' ], allowCredentials: false })) - .use(middleware.session({ - secret: sessionSecret, - saveUninitialized: false, - resave: false, - store: new SessionFileStore({ - path: paths.SESSION_DIR - }), - cookie: { - path: '/', - httpOnly: true, - secure: process.env.BOX_ENV !== 'test', - maxAge: 600000 - } - })) .use(passport.initialize()) - .use(passport.session()) .use(router) .use(middleware.lastMile()); @@ -220,18 +188,6 @@ function initializeExpressSync() { router.post('/api/v1/groups/:groupId', usersManageScope, routes.groups.update); router.del ('/api/v1/groups/:groupId', usersManageScope, routes.groups.remove); - // form based login routes used by oauth2 frame - router.get ('/api/v1/session/login', routes.oauth2.loginForm); - router.post('/api/v1/session/login', routes.oauth2.login); - router.get ('/api/v1/session/logout', routes.oauth2.logout); - router.get ('/api/v1/session/callback', routes.oauth2.sessionCallback()); - router.get ('/api/v1/session/account/setup.html', routes.oauth2.accountSetupSite); - router.post('/api/v1/session/account/setup', routes.oauth2.accountSetup); - - // oauth2 routes - router.get ('/api/v1/oauth/dialog/authorize', routes.oauth2.authorization()); - router.post('/api/v1/oauth/token', routes.oauth2.token()); - // client/token routes router.get ('/api/v1/clients', clientsScope, routes.clients.getAll); router.post('/api/v1/clients', clientsScope, routes.clients.add); @@ -380,8 +336,6 @@ function start(callback) { assert.strictEqual(typeof callback, 'function'); assert.strictEqual(gHttpServer, null, 'Server is already up and running.'); - routes.oauth2.initialize(); // init's the oauth server - gHttpServer = initializeExpressSync(); async.series([ @@ -407,8 +361,6 @@ function stop(callback) { ], function (error) { if (error) return callback(error); - routes.oauth2.uninitialize(); - gHttpServer = null; callback(null); diff --git a/src/test/database-test.js b/src/test/database-test.js index f2e6306cb..002d19952 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -8,7 +8,6 @@ var appdb = require('../appdb.js'), apps = require('../apps.js'), async = require('async'), - authcodedb = require('../authcodedb.js'), backupdb = require('../backupdb.js'), BoxError = require('../boxerror.js'), clientdb = require('../clientdb.js'), @@ -716,108 +715,6 @@ describe('database', function () { }); }); - describe('authcode', function () { - var AUTHCODE_0 = { - authCode: 'authcode-0', - clientId: 'clientid-0', - userId: 'userid-0', - expiresAt: Date.now() + 500000 - }; - var AUTHCODE_1 = { - authCode: 'authcode-1', - clientId: 'clientid-1', - userId: 'userid-1', - expiresAt: Date.now() + 500000 - }; - var AUTHCODE_2 = { - authCode: 'authcode-2', - clientId: 'clientid-2', - userId: 'userid-2', - expiresAt: Date.now() - }; - - it('add fails due to missing arguments', function () { - expect(function () { authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId); }).to.throwError(); - expect(function () { authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, function () {}); }).to.throwError(); - expect(function () { authcodedb.add(AUTHCODE_0.authCode, function () {}); }).to.throwError(); - }); - - it('add succeeds', function (done) { - authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId, AUTHCODE_0.expiresAt, function (error) { - expect(error).to.be(null); - done(); - }); - }); - - it('add of same authcode fails', function (done) { - authcodedb.add(AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId, AUTHCODE_0.expiresAt, function (error) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.ALREADY_EXISTS); - done(); - }); - }); - - it('get succeeds', function (done) { - authcodedb.get(AUTHCODE_0.authCode, function (error, result) { - expect(error).to.be(null); - expect(result).to.be.an('object'); - expect(result).to.be.eql(AUTHCODE_0); - done(); - }); - }); - - it('get of nonexisting code fails', function (done) { - authcodedb.get(AUTHCODE_1.authCode, function (error, result) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.NOT_FOUND); - expect(result).to.not.be.ok(); - done(); - }); - }); - - it('get of expired code fails', function (done) { - authcodedb.add(AUTHCODE_2.authCode, AUTHCODE_2.clientId, AUTHCODE_2.userId, AUTHCODE_2.expiresAt, function (error) { - expect(error).to.be(null); - - authcodedb.get(AUTHCODE_2.authCode, function (error, result) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.NOT_FOUND); - expect(result).to.not.be.ok(); - done(); - }); - }); - }); - - it('delExpired succeeds', function (done) { - authcodedb.delExpired(function (error, result) { - expect(error).to.not.be.ok(); - expect(result).to.eql(1); - - authcodedb.get(AUTHCODE_2.authCode, function (error, result) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.NOT_FOUND); - expect(result).to.not.be.ok(); - done(); - }); - }); - }); - - it('delete succeeds', function (done) { - authcodedb.del(AUTHCODE_0.authCode, function (error) { - expect(error).to.be(null); - done(); - }); - }); - - it('cannot delete previously delete record', function (done) { - authcodedb.del(AUTHCODE_0.authCode, function (error) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.NOT_FOUND); - done(); - }); - }); - }); - describe('token', function () { var TOKEN_0 = { id: 'tid-0', diff --git a/src/test/janitor-test.js b/src/test/janitor-test.js index f9970af6f..3caf46996 100644 --- a/src/test/janitor-test.js +++ b/src/test/janitor-test.js @@ -7,7 +7,6 @@ 'use strict'; var async = require('async'), - authcodedb = require('../authcodedb.js'), BoxError = require('../boxerror.js'), database = require('../database'), expect = require('expect.js'), @@ -16,19 +15,6 @@ var async = require('async'), tokendb = require('../tokendb.js'); describe('janitor', function () { - var AUTHCODE_0 = { - authCode: 'authcode-0', - clientId: 'clientid-0', - userId: 'userid-0', - expiresAt: Date.now() + 60 * 60 * 1000 - }; - var AUTHCODE_1 = { - authCode: 'authcode-1', - clientId: 'clientid-1', - userId: 'userid-1', - expiresAt: Date.now() - 5000 - }; - var TOKEN_0 = { id: 'tid-0', accessToken: hat(8 * 32), @@ -52,8 +38,6 @@ describe('janitor', function () { async.series([ database.initialize, database._clear, - authcodedb.add.bind(null, AUTHCODE_0.authCode, AUTHCODE_0.clientId, AUTHCODE_0.userId, AUTHCODE_0.expiresAt), - authcodedb.add.bind(null, AUTHCODE_1.authCode, AUTHCODE_1.clientId, AUTHCODE_1.userId, AUTHCODE_1.expiresAt), tokendb.add.bind(null, TOKEN_0), tokendb.add.bind(null, TOKEN_1) ], done); @@ -70,23 +54,6 @@ describe('janitor', function () { janitor.cleanupTokens(done); }); - it('did not remove the non-expired authcode', function (done) { - authcodedb.get(AUTHCODE_0.authCode, function (error, result) { - expect(error).to.be(null); - expect(result).to.be.eql(AUTHCODE_0); - done(); - }); - }); - - it('did remove expired authcode', function (done) { - authcodedb.get(AUTHCODE_1.authCode, function (error, result) { - expect(error).to.be.a(BoxError); - expect(error.reason).to.be(BoxError.NOT_FOUND); - expect(result).to.not.be.ok(); - done(); - }); - }); - it('did not remove the non-expired token', function (done) { tokendb.getByAccessToken(TOKEN_0.accessToken, function (error, result) { expect(error).to.be(null);