diff --git a/CHANGES b/CHANGES index 5725b6681..12ca63ce0 100644 --- a/CHANGES +++ b/CHANGES @@ -803,4 +803,5 @@ [0.106.0] * (mail) Fix email forwarding to external domains * (mail) Set maximum email size to 25MB +* Remove SimpleAuth addon diff --git a/box.js b/box.js index 7d81066ff..26e952258 100755 --- a/box.js +++ b/box.js @@ -13,8 +13,7 @@ var appHealthMonitor = require('./src/apphealthmonitor.js'), async = require('async'), config = require('./src/config.js'), ldap = require('./src/ldap.js'), - server = require('./src/server.js'), - simpleauth = require('./src/simpleauth.js'); + server = require('./src/server.js'); console.log(); console.log('=========================================='); @@ -33,7 +32,6 @@ console.log(); async.series([ server.start, ldap.start, - simpleauth.start, appHealthMonitor.start, ], function (error) { if (error) { @@ -48,13 +46,11 @@ var NOOP_CALLBACK = function () { }; process.on('SIGINT', function () { server.stop(NOOP_CALLBACK); ldap.stop(NOOP_CALLBACK); - simpleauth.stop(NOOP_CALLBACK); setTimeout(process.exit.bind(process), 3000); }); process.on('SIGTERM', function () { server.stop(NOOP_CALLBACK); ldap.stop(NOOP_CALLBACK); - simpleauth.stop(NOOP_CALLBACK); setTimeout(process.exit.bind(process), 3000); }); diff --git a/docs/references/addons.md b/docs/references/addons.md index fdb93afe7..f38dd42b1 100644 --- a/docs/references/addons.md +++ b/docs/references/addons.md @@ -318,67 +318,3 @@ cloudron exec > swaks --server "${MAIL_SMTP_SERVER}" -p "${MAIL_SMTP_PORT}" --from "${MAIL_SMTP_USERNAME}@${MAIL_DOMAIN}" --body "Test mail from cloudron app at $(hostname -f)" --auth-user "${MAIL_SMTP_USERNAME}" --auth-password "${MAIL_SMTP_PASSWORD}" ``` -## simpleauth - -Simple Auth can be used for authenticating users with a HTTP request. This method of authentication is targeted -at applications, which for whatever reason can't use the ldap addon. -The response contains an `accessToken` which can then be used to access the [Cloudron API](/references/api.html). - -Exported environment variables: -``` -SIMPLE_AUTH_SERVER= # the simple auth HTTP server -SIMPLE_AUTH_PORT= # the simple auth server port -SIMPLE_AUTH_URL= # the simple auth server URL. same as "http://SIMPLE_AUTH_SERVER:SIMPLE_AUTH_PORT -SIMPLE_AUTH_CLIENT_ID # a client id for identifying the request originator with the auth server -``` - -This addons provides two REST APIs: - -**POST /api/v1/login** - -Request JSON body: -``` -{ - "username": " or ", - "password": "" -} -``` - -Response 200 with JSON body: -``` -{ - "accessToken": "", - "user": { - "id": "", - "username": "", - "email": "", - "admin": , - "displayName": "" - } -} -``` - -**GET /api/v1/logout** - -Request params: -``` -?access_token= -``` - -Response 200 with JSON body: -``` -{} -``` - -For debugging, [cloudron exec](https://www.npmjs.com/package/cloudron) can be used to run the `curl` tool within the context of the app: -``` -cloudron exec - -> USERNAME= - -> PASSWORD= - -> PAYLOAD="{\"clientId\":\"${SIMPLE_AUTH_CLIENT_ID}\", \"username\":\"${USERNAME}\", \"password\":\"${PASSWORD}\"}" - -> curl -H "Content-Type: application/json" -X POST -d "${PAYLOAD}" "${SIMPLE_AUTH_ORIGIN}/api/v1/login" -``` diff --git a/docs/references/api.md b/docs/references/api.md index b76ef2582..6e7ebc374 100644 --- a/docs/references/api.md +++ b/docs/references/api.md @@ -62,7 +62,7 @@ curl -H "Content-Type: application/json" -H "Authorization: Bearer " http ## OAuth OAuth authentication is meant to be used by apps. An app can get an OAuth token using the -[oauth](addons.html#oauth) or [simpleauth](addons.html#simpleauth) addon. +[oauth](addons.html#oauth) addon. Tokens obtained via OAuth have a restricted scope wherein they can only access the user's profile. This restriction is so that apps cannot make undesired changes to the user's Cloudron. @@ -844,7 +844,7 @@ Response (200): * user.remove * user.update -`source` contains information on the originator of the action. For example, for user.login, this contains the IP address, the appId and the authType (ldap or simpleauth or oauth). +`source` contains information on the originator of the action. For example, for user.login, this contains the IP address, the appId and the authType (ldap or oauth). `data` contains information on the event itself. For example, for user.login, this contains the userId that logged in. For app.install, it contains the manifest and location of the app that was installed. diff --git a/docs/references/authentication.md b/docs/references/authentication.md index b4c301da6..1ee474993 100644 --- a/docs/references/authentication.md +++ b/docs/references/authentication.md @@ -29,7 +29,6 @@ Cloudron provides multiple authentication strategies. * OAuth 2.0 provided by the [OAuth addon](/references/addons.html#oauth) * LDAP provided by the [LDAP addon](/references/addons.html#ldap) -* Simple Auth provided by [Simple Auth addon](/references/addons.html#simpleauth) # Choosing a strategy diff --git a/src/addons.js b/src/addons.js index 4c1550df5..0ebb31857 100644 --- a/src/addons.js +++ b/src/addons.js @@ -106,12 +106,6 @@ var KNOWN_ADDONS = { teardown: NOOP, backup: NOOP, restore: NOOP - }, - simpleauth: { - setup: setupSimpleAuth, - teardown: teardownSimpleAuth, - backup: NOOP, - restore: setupSimpleAuth } }; @@ -286,51 +280,6 @@ function teardownOauth(app, options, callback) { }); } -function setupSimpleAuth(app, options, callback) { - assert.strictEqual(typeof app, 'object'); - assert.strictEqual(typeof options, 'object'); - assert.strictEqual(typeof callback, 'function'); - - if (!app.sso) return callback(null); - - var appId = app.id; - var scope = 'profile'; - - clients.delByAppIdAndType(app.id, clients.TYPE_SIMPLE_AUTH, function (error) { // remove existing creds - if (error && error.reason !== ClientsError.NOT_FOUND) return callback(error); - - clients.add(appId, clients.TYPE_SIMPLE_AUTH, '', scope, function (error, result) { - if (error) return callback(error); - - var env = [ - 'SIMPLE_AUTH_SERVER=172.18.0.1', - 'SIMPLE_AUTH_PORT=' + config.get('simpleAuthPort'), - 'SIMPLE_AUTH_URL=http://172.18.0.1:' + config.get('simpleAuthPort'), // obsolete, remove - 'SIMPLE_AUTH_ORIGIN=http://172.18.0.1:' + config.get('simpleAuthPort'), - 'SIMPLE_AUTH_CLIENT_ID=' + result.id - ]; - - debugApp(app, 'Setting simple auth addon config to %j', env); - - appdb.setAddonConfig(appId, 'simpleauth', env, callback); - }); - }); -} - -function teardownSimpleAuth(app, options, callback) { - assert.strictEqual(typeof app, 'object'); - assert.strictEqual(typeof options, 'object'); - assert.strictEqual(typeof callback, 'function'); - - debugApp(app, 'teardownSimpleAuth'); - - clients.delByAppIdAndType(app.id, clients.TYPE_SIMPLE_AUTH, function (error) { - if (error && error.reason !== ClientsError.NOT_FOUND) debug(error); - - appdb.unsetAddonConfig(app.id, 'simpleauth', callback); - }); -} - function setupEmail(app, options, callback) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof options, 'object'); diff --git a/src/apps.js b/src/apps.js index 71ed98b97..bffbcb529 100644 --- a/src/apps.js +++ b/src/apps.js @@ -152,7 +152,6 @@ function validatePortBindings(portBindings, tcpPorts) { config.get('sysadminPort'), /* sysadmin app server (lo) */ config.get('smtpPort'), /* internal smtp port (lo) */ config.get('ldapPort'), /* ldap server (lo) */ - config.get('simpleAuthPort'), /* simple auth server (lo) */ 3306, /* mysql (lo) */ 4190, /* managesieve */ 8000 /* graphite (lo) */ @@ -528,7 +527,7 @@ function install(data, auditSource, callback) { if ('sso' in data && !('optionalSso' in manifest)) return callback(new AppsError(AppsError.BAD_FIELD, 'sso can only be specified for apps with optionalSso')); // if sso was unspecified, enable it by default if possible - if (sso === null) sso = !!manifest.addons['simpleauth'] || !!manifest.addons['ldap'] || !!manifest.addons['oauth']; + if (sso === null) sso = !!manifest.addons['ldap'] || !!manifest.addons['oauth']; if (altDomain !== null && !validator.isFQDN(altDomain)) return callback(new AppsError(AppsError.BAD_FIELD, 'Invalid alt domain')); diff --git a/src/clients.js b/src/clients.js index da064c1bc..3ac87aa66 100644 --- a/src/clients.js +++ b/src/clients.js @@ -32,7 +32,6 @@ exports = module.exports = { TYPE_EXTERNAL: 'external', TYPE_BUILT_IN: 'built-in', TYPE_OAUTH: 'addon-oauth', - TYPE_SIMPLE_AUTH: 'addon-simpleauth', TYPE_PROXY: 'addon-proxy' }; @@ -192,7 +191,6 @@ function getAll(callback) { if (record.type === exports.TYPE_PROXY) record.name = result.manifest.title + ' Website Proxy'; if (record.type === exports.TYPE_OAUTH) record.name = result.manifest.title + ' OAuth'; - if (record.type === exports.TYPE_SIMPLE_AUTH) record.name = result.manifest.title + ' Simple Auth'; record.location = result.location; diff --git a/src/config.js b/src/config.js index cd3d32ca1..5cdf991a9 100644 --- a/src/config.js +++ b/src/config.js @@ -84,7 +84,6 @@ function initConfig() { data.smtpPort = 2525; // // this value comes from mail container data.sysadminPort = 3001; data.ldapPort = 3002; - data.simpleAuthPort = 3004; data.provider = 'caas'; data.appBundle = [ ]; diff --git a/src/routes/oauth2.js b/src/routes/oauth2.js index 5287c2c63..882f14f89 100644 --- a/src/routes/oauth2.js +++ b/src/routes/oauth2.js @@ -233,7 +233,6 @@ function loginForm(req, res) { switch (result.type) { case clients.TYPE_BUILT_IN: return renderBuiltIn(); case clients.TYPE_EXTERNAL: return render(result.appId, '/api/v1/cloudron/avatar'); - case clients.TYPE_SIMPLE_AUTH: return sendError(req, res, 'Unknown OAuth client'); default: break; } @@ -450,8 +449,6 @@ var authorization = [ 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 }); return next(); - } else if (type === clients.TYPE_SIMPLE_AUTH) { - return sendError(req, res, 'Unknown OAuth client.'); } appdb.get(req.oauth2.client.appId, function (error, appObject) { diff --git a/src/routes/test/apps-test.js b/src/routes/test/apps-test.js index 0ce0b3572..e30c47a08 100644 --- a/src/routes/test/apps-test.js +++ b/src/routes/test/apps-test.js @@ -30,7 +30,6 @@ var appdb = require('../../appdb.js'), safe = require('safetydance'), server = require('../../server.js'), settings = require('../../settings.js'), - simpleauth = require('../../simpleauth.js'), superagent = require('superagent'), taskmanager = require('../../taskmanager.js'), tokendb = require('../../tokendb.js'), @@ -42,7 +41,7 @@ var SERVER_URL = 'http://localhost:' + config.get('port'); // Test image information var TEST_IMAGE_REPO = 'cloudron/test'; -var TEST_IMAGE_TAG = '19.0.1'; +var TEST_IMAGE_TAG = '20.0.0'; var TEST_IMAGE = TEST_IMAGE_REPO + ':' + TEST_IMAGE_TAG; // var TEST_IMAGE_ID = child_process.execSync('docker inspect --format={{.Id}} ' + TEST_IMAGE).toString('utf8').trim(); @@ -174,7 +173,6 @@ function startBox(done) { server.start.bind(server), ldap.start, - simpleauth.start, function (callback) { var scope1 = nock(config.apiServerOrigin()).get('/api/v1/boxes/' + config.fqdn() + '/setup/verify?setupToken=somesetuptoken').reply(200, {}); @@ -257,7 +255,6 @@ function stopBox(done) { appdb._clear, server.stop, ldap.stop, - simpleauth.stop, config._reset ], done); } diff --git a/src/routes/test/oauth2-test.js b/src/routes/test/oauth2-test.js index c9bd8d831..ae908d00a 100644 --- a/src/routes/test/oauth2-test.js +++ b/src/routes/test/oauth2-test.js @@ -273,16 +273,6 @@ describe('OAuth2', function () { scope: 'profile' }; - // simple auth client - var CLIENT_8 = { - id: 'cid-client8', - appId: APP_2.id, - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'secret8', - redirectURI: 'http://redirect8', - scope: 'profile' - }; - // app with accessRestriction allowing group var CLIENT_9 = { id: 'cid-client9', @@ -311,7 +301,6 @@ describe('OAuth2', function () { 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_8.id, CLIENT_8.appId, CLIENT_8.type, CLIENT_8.clientSecret, CLIENT_8.redirectURI, CLIENT_8.scope), clientdb.add.bind(null, CLIENT_9.id, CLIENT_9.appId, CLIENT_9.type, CLIENT_9.clientSecret, CLIENT_9.redirectURI, CLIENT_9.scope), appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.portBindings, APP_0), appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.portBindings, APP_1), @@ -557,24 +546,6 @@ describe('OAuth2', function () { }); }); }); - - it('fails when using simple auth credentials', function (done) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_8.redirectURI + '&client_id=' + CLIENT_8.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_8.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); - expect(body.indexOf('Unknown OAuth client')).to.not.equal(-1); - - done(); - }); - }); - }); }); describe('loginForm submit', function () { @@ -796,21 +767,6 @@ describe('OAuth2', function () { }); }); - it('fails for grant type code due to simple auth credentials', function (done) { - startAuthorizationFlow(CLIENT_7, 'code', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_8.redirectURI + '&client_id=' + CLIENT_8.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('Unknown OAuth client.')).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'; @@ -858,21 +814,6 @@ describe('OAuth2', function () { }); }); - it('fails for grant type token due to simple auth credentials', function (done) { - startAuthorizationFlow(CLIENT_7, 'token', function (jar) { - var url = SERVER_URL + '/api/v1/oauth/dialog/authorize?redirect_uri=' + CLIENT_8.redirectURI + '&client_id=' + CLIENT_8.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('Unknown OAuth client.')).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'; diff --git a/src/routes/test/simpleauth-test.js b/src/routes/test/simpleauth-test.js deleted file mode 100644 index 059b50557..000000000 --- a/src/routes/test/simpleauth-test.js +++ /dev/null @@ -1,512 +0,0 @@ -/* global it:false */ -/* global describe:false */ -/* global before:false */ -/* global after:false */ - -'use strict'; - -var appdb = require('../../appdb.js'), - async = require('async'), - clientdb = require('../../clientdb.js'), - clients = require('../../clients.js'), - config = require('../../config.js'), - database = require('../../database.js'), - expect = require('expect.js'), - superagent = require('superagent'), - server = require('../../server.js'), - simpleauth = require('../../simpleauth.js'), - nock = require('nock'), - settings = require('../../settings.js'); - -describe('SimpleAuth API', function () { - var SERVER_URL = 'http://localhost:' + config.get('port'); - var SIMPLE_AUTH_ORIGIN = 'http://localhost:' + config.get('simpleAuthPort'); - - var USERNAME = 'superaDMin', PASSWORD = 'Foobar?1337', EMAIL ='silly@ME.com'; - - var APP_0 = { - id: 'app0', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test0', - portBindings: {}, - accessRestriction: { users: [ 'foobar', 'someone'] }, - memoryLimit: 0, - altDomain: null - }; - - var APP_1 = { - id: 'app1', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test1', - portBindings: {}, - accessRestriction: { users: [ 'foobar', 'someone' ] }, - memoryLimit: 0, - altDomain: null - }; - - var APP_2 = { - id: 'app2', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test2', - portBindings: {}, - accessRestriction: null, - memoryLimit: 0, - altDomain: null - }; - - var APP_3 = { - id: 'app3', - appStoreId: '', - manifest: { version: '0.1.0', addons: { } }, - location: 'test3', - portBindings: {}, - accessRestriction: { groups: [ 'someothergroup', 'admin', 'anothergroup' ] }, - memoryLimit: 0, - altDomain: null - }; - - var CLIENT_0 = { - id: 'someclientid', - appId: 'someappid', - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'someclientsecret', - redirectURI: '', - scope: 'user,profile' - }; - - var CLIENT_1 = { - id: 'someclientid1', - appId: APP_0.id, - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'someclientsecret1', - redirectURI: '', - scope: 'user,profile' - }; - - var CLIENT_2 = { - id: 'someclientid2', - appId: APP_1.id, - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'someclientsecret2', - redirectURI: '', - scope: 'user,profile' - }; - - var CLIENT_3 = { - id: 'someclientid3', - appId: APP_2.id, - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'someclientsecret3', - redirectURI: '', - scope: 'user,profile' - }; - - var CLIENT_4 = { - id: 'someclientid4', - appId: APP_2.id, - type: clients.TYPE_OAUTH, - clientSecret: 'someclientsecret4', - redirectURI: '', - scope: 'user,profile' - }; - - var CLIENT_5 = { - id: 'someclientid5', - appId: APP_3.id, - type: clients.TYPE_SIMPLE_AUTH, - clientSecret: 'someclientsecret5', - redirectURI: '', - scope: 'user,profile' - }; - - before(function (done) { - async.series([ - server.start.bind(server), - simpleauth.start.bind(simpleauth), - - database._clear, - - function createAdmin(callback) { - var scope1 = nock(config.apiServerOrigin()).get('/api/v1/boxes/' + config.fqdn() + '/setup/verify?setupToken=somesetuptoken').reply(200, {}); - var scope2 = nock(config.apiServerOrigin()).post('/api/v1/boxes/' + config.fqdn() + '/setup/done?setupToken=somesetuptoken').reply(201, {}); - - superagent.post(SERVER_URL + '/api/v1/cloudron/activate') - .query({ setupToken: 'somesetuptoken' }) - .send({ username: USERNAME, password: PASSWORD, email: EMAIL }) - .end(function (error, result) { - expect(error).to.not.be.ok(); - expect(result).to.be.ok(); - expect(result.statusCode).to.eql(201); - expect(scope1.isDone()).to.be.ok(); - expect(scope2.isDone()).to.be.ok(); - - superagent.get(SERVER_URL + '/api/v1/profile').query({ access_token: result.body.token}).end(function (error, result) { - expect(error).to.not.be.ok(); - expect(result.statusCode).to.eql(200); - - APP_1.accessRestriction.users.push(result.body.id); - - callback(); - }); - }); - }, - - 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), - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.portBindings, APP_0), - appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.portBindings, APP_1), - appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.portBindings, APP_2), - appdb.add.bind(null, APP_3.id, APP_3.appStoreId, APP_3.manifest, APP_3.location, APP_3.portBindings, APP_3), - settings.setBackupConfig.bind(null, { provider: 'caas', token: 'BACKUP_TOKEN', bucket: 'Bucket', prefix: 'Prefix' }) - ], done); - }); - - after(function (done) { - async.series([ - database._clear, - simpleauth.stop.bind(simpleauth), - server.stop.bind(server) - ], done); - }); - - describe('login', function () { - it('cannot login without clientId', function (done) { - var body = {}; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('cannot login without username', function (done) { - var body = { - clientId: 'someclientid' - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('cannot login without password', function (done) { - var body = { - clientId: 'someclientid', - username: USERNAME - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('cannot login with unkown clientId', function (done) { - var body = { - clientId: CLIENT_0.id+CLIENT_0.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot login with unkown user', function (done) { - var body = { - clientId: CLIENT_0.id, - username: USERNAME+USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot login with empty password', function (done) { - var body = { - clientId: CLIENT_0.id, - username: USERNAME, - password: '' - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('cannot login with wrong password', function (done) { - var body = { - clientId: CLIENT_0.id, - username: USERNAME, - password: PASSWORD+PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('fails for unkown app', function (done) { - var body = { - clientId: CLIENT_0.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('fails for disallowed app', function (done) { - var body = { - clientId: CLIENT_1.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('succeeds for allowed app', function (done) { - var body = { - clientId: CLIENT_2.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - expect(result.body.accessToken).to.be.a('string'); - expect(result.body.user).to.be.an('object'); - expect(result.body.user.id).to.be.a('string'); - expect(result.body.user.username).to.be.a('string'); - expect(result.body.user.email).to.be.a('string'); - expect(result.body.user.displayName).to.be.a('string'); - expect(result.body.user.admin).to.be.a('boolean'); - - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: result.body.accessToken }) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.body).to.be.an('object'); - expect(result.body.username).to.eql(USERNAME.toLowerCase()); - expect(result.body.email).to.eql(EMAIL.toLowerCase()); - - done(); - }); - }); - }); - - it('succeeds for allowed app with email', function (done) { - var body = { - clientId: CLIENT_2.id, - username: EMAIL, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - expect(result.body.accessToken).to.be.a('string'); - expect(result.body.user).to.be.an('object'); - expect(result.body.user.id).to.be.a('string'); - expect(result.body.user.username).to.be.a('string'); - expect(result.body.user.email).to.be.a('string'); - expect(result.body.user.displayName).to.be.a('string'); - expect(result.body.user.admin).to.be.a('boolean'); - - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: result.body.accessToken }) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.body).to.be.an('object'); - expect(result.body.username).to.eql(USERNAME.toLowerCase()); - expect(result.body.email).to.eql(EMAIL.toLowerCase()); - - done(); - }); - }); - }); - - it('succeeds for app without accessRestriction', function (done) { - var body = { - clientId: CLIENT_3.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - expect(result.body.accessToken).to.be.a('string'); - expect(result.body.user).to.be.an('object'); - expect(result.body.user.id).to.be.a('string'); - expect(result.body.user.username).to.be.a('string'); - expect(result.body.user.email).to.be.a('string'); - expect(result.body.user.displayName).to.be.a('string'); - expect(result.body.user.admin).to.be.a('boolean'); - - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: result.body.accessToken }) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.body).to.be.an('object'); - expect(result.body.username).to.eql(USERNAME.toLowerCase()); - expect(result.body.email).to.eql(EMAIL.toLowerCase()); - - done(); - }); - }); - }); - - it('succeeds for app with group accessRestriction', function (done) { - var body = { - clientId: CLIENT_5.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - expect(result.body.accessToken).to.be.a('string'); - expect(result.body.user).to.be.an('object'); - expect(result.body.user.id).to.be.a('string'); - expect(result.body.user.username).to.be.a('string'); - expect(result.body.user.email).to.be.a('string'); - expect(result.body.user.displayName).to.be.a('string'); - expect(result.body.user.admin).to.be.a('boolean'); - - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: result.body.accessToken }) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.body).to.be.an('object'); - expect(result.body.username).to.eql(USERNAME.toLowerCase()); - expect(result.body.email).to.eql(EMAIL.toLowerCase()); - - done(); - }); - }); - }); - - it('fails for wrong client credentials', function (done) { - var body = { - clientId: CLIENT_4.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - }); - - describe('logout', function () { - var accessToken; - - before(function (done) { - var body = { - clientId: CLIENT_3.id, - username: USERNAME, - password: PASSWORD - }; - - superagent.post(SIMPLE_AUTH_ORIGIN + '/api/v1/login') - .send(body) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - - accessToken = result.body.accessToken; - - done(); - }); - }); - - it('fails without access_token', function (done) { - superagent.get(SIMPLE_AUTH_ORIGIN + '/api/v1/logout') - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails with unkonwn access_token', function (done) { - superagent.get(SIMPLE_AUTH_ORIGIN + '/api/v1/logout') - .query({ access_token: accessToken+accessToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('succeeds', function (done) { - superagent.get(SIMPLE_AUTH_ORIGIN + '/api/v1/logout') - .query({ access_token: accessToken }) - .end(function (error, result) { - expect(error).to.be(null); - expect(result.statusCode).to.equal(200); - - superagent.get(SERVER_URL + '/api/v1/profile') - .query({ access_token: accessToken }) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - - done(); - }); - }); - }); - }); -}); diff --git a/src/simpleauth.js b/src/simpleauth.js deleted file mode 100644 index 0b0115364..000000000 --- a/src/simpleauth.js +++ /dev/null @@ -1,163 +0,0 @@ -'use strict'; - -exports = module.exports = { - start: start, - stop: stop -}; - -var apps = require('./apps.js'), - AppsError = apps.AppsError, - assert = require('assert'), - clients = require('./clients.js'), - ClientsError = clients.ClientsError, - config = require('./config.js'), - constants = require('./constants.js'), - DatabaseError = require('./databaseerror.js'), - debug = require('debug')('box:src/simpleauth'), - eventlog = require('./eventlog.js'), - express = require('express'), - http = require('http'), - HttpError = require('connect-lastmile').HttpError, - HttpSuccess = require('connect-lastmile').HttpSuccess, - middleware = require('./middleware'), - tokendb = require('./tokendb.js'), - user = require('./user.js'), - UserError = require('./user.js').UserError; - -var gHttpServer = null; - -function loginLogic(clientId, username, password, callback) { - assert.strictEqual(typeof clientId, 'string'); - assert.strictEqual(typeof username, 'string'); - assert.strictEqual(typeof password, 'string'); - assert.strictEqual(typeof callback, 'function'); - - debug('login: client %s and user %s', clientId, username); - - clients.get(clientId, function (error, clientObject) { - if (error) return callback(error); - - // only allow simple auth clients - if (clientObject.type !== clients.TYPE_SIMPLE_AUTH) return callback(new ClientsError(ClientsError.INVALID_CLIENT)); - - var authFunction = (username.indexOf('@') === -1) ? user.verifyWithUsername : user.verifyWithEmail; - authFunction(username, password, function (error, userObject) { - if (error) return callback(error); - - apps.get(clientObject.appId, function (error, appObject) { - if (error) return callback(error); - - apps.hasAccessTo(appObject, userObject, function (error, access) { - if (error) return callback(error); - if (!access) return callback(new AppsError(AppsError.ACCESS_DENIED)); - - var accessToken = tokendb.generateToken(); - var expires = Date.now() + constants.DEFAULT_TOKEN_EXPIRATION; - - tokendb.add(accessToken, userObject.id, clientId, expires, clientObject.scope, function (error) { - if (error) return callback(error); - - debug('login: new access token for client %s and user %s: %s', clientId, username, accessToken); - - callback(null, { accessToken: accessToken, user: userObject }); - }); - }); - }); - }); - }); -} - -function logoutLogic(accessToken, callback) { - assert.strictEqual(typeof accessToken, 'string'); - assert.strictEqual(typeof callback, 'function'); - - debug('logout: %s', accessToken); - - tokendb.del(accessToken, function (error) { - if (error) return callback(error); - callback(null); - }); -} - -function login(req, res, next) { - assert.strictEqual(typeof req.body, 'object'); - - if (typeof req.body.clientId !== 'string') return next(new HttpError(400, 'clientId is required')); - if (typeof req.body.username !== 'string') return next(new HttpError(400, 'username is required')); - if (typeof req.body.password !== 'string') return next(new HttpError(400, 'password is required')); - - loginLogic(req.body.clientId, req.body.username, req.body.password, function (error, result) { - if (error && error.reason === ClientsError.NOT_FOUND) return next(new HttpError(401, 'Unknown client')); - if (error && error.reason === ClientsError.INVALID_CLIENT) return next(new HttpError(401, 'Unknown client')); - if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(401, 'Forbidden')); - if (error && error.reason === AppsError.NOT_FOUND) return next(new HttpError(401, 'Unknown app')); - if (error && error.reason === UserError.WRONG_PASSWORD) return next(new HttpError(401, 'Forbidden')); - if (error && error.reason === AppsError.ACCESS_DENIED) return next(new HttpError(401, 'Forbidden')); - if (error) return next(new HttpError(500, error)); - - eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'simpleauth', clientId: req.body.clientId }, { userId: result.user.id }); - - var tmp = { - accessToken: result.accessToken, - user: { - id: result.user.id, - username: result.user.username, - email: result.user.email, - admin: !!result.user.admin, - displayName: result.user.displayName - } - }; - - next(new HttpSuccess(200, tmp)); - }); -} - -function logout(req, res, next) { - assert.strictEqual(typeof req.query, 'object'); - - if (typeof req.query.access_token !== 'string') return next(new HttpError(400, 'access_token in query required')); - - logoutLogic(req.query.access_token, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return next(new HttpError(401, 'Forbidden')); - if (error) return next(new HttpError(500, error)); - - next(new HttpSuccess(200, {})); - }); -} - -function initializeExpressSync() { - var app = express(); - var httpServer = http.createServer(app); - - httpServer.on('error', console.error); - - var json = middleware.json({ strict: true, limit: '100kb' }); - var router = new express.Router(); - - // basic auth - router.post('/api/v1/login', login); - router.get ('/api/v1/logout', logout); - - if (process.env.BOX_ENV !== 'test') app.use(middleware.morgan('SimpleAuth :method :url :status :response-time ms - :res[content-length]', { immediate: false })); - - app - .use(middleware.timeout(10000)) - .use(json) - .use(router) - .use(middleware.lastMile()); - - return httpServer; -} - -function start(callback) { - assert.strictEqual(typeof callback, 'function'); - - gHttpServer = initializeExpressSync(); - gHttpServer.listen(config.get('simpleAuthPort'), '0.0.0.0', callback); -} - -function stop(callback) { - assert.strictEqual(typeof callback, 'function'); - - if (gHttpServer) gHttpServer.close(callback); -} diff --git a/webadmin/src/views/apps.js b/webadmin/src/views/apps.js index bbf10003f..6117d9350 100644 --- a/webadmin/src/views/apps.js +++ b/webadmin/src/views/apps.js @@ -188,7 +188,7 @@ angular.module('Application').controller('AppsController', ['$scope', '$location $scope.appConfigure.accessRestriction = app.accessRestriction || { users: [], groups: [] }; $scope.appConfigure.memoryLimit = app.memoryLimit || app.manifest.memoryLimit || (256 * 1024 * 1024); $scope.appConfigure.xFrameOptions = app.xFrameOptions.indexOf('ALLOW-FROM') === 0 ? app.xFrameOptions.split(' ')[1] : ''; - $scope.appConfigure.customAuth = !(app.manifest.addons['simpleauth'] || app.manifest.addons['ldap'] || app.manifest.addons['oauth']); + $scope.appConfigure.customAuth = !(app.manifest.addons['ldap'] || app.manifest.addons['oauth']); // create ticks starting from manifest memory limit $scope.appConfigure.memoryTicks = [ diff --git a/webadmin/src/views/appstore.js b/webadmin/src/views/appstore.js index 3a4060766..44be9ef7c 100644 --- a/webadmin/src/views/appstore.js +++ b/webadmin/src/views/appstore.js @@ -118,7 +118,7 @@ angular.module('Application').controller('AppStoreController', ['$scope', '$loca var manifest = app.manifest; $scope.appInstall.optionalSso = !!manifest.optionalSso; - $scope.appInstall.customAuth = !(manifest.addons['simpleauth'] || manifest.addons['ldap'] || manifest.addons['oauth']); + $scope.appInstall.customAuth = !(manifest.addons['ldap'] || manifest.addons['oauth']); $scope.appInstall.accessRestrictionOption = 'any'; // set default ports