remove oauth proxy backend logic

This commit is contained in:
Girish Ramakrishnan
2016-11-13 07:09:19 +05:30
parent 3457890b24
commit 94037e5266
12 changed files with 21 additions and 271 deletions
+3 -5
View File
@@ -60,7 +60,7 @@ var assert = require('assert'),
var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationState', 'apps.installationProgress', 'apps.runState',
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.httpPort', 'apps.location', 'apps.dnsRecordId',
'apps.accessRestrictionJson', 'apps.lastBackupId', 'apps.oldConfigJson', 'apps.memoryLimit', 'apps.altDomain',
'apps.xFrameOptions', 'apps.oauthProxy', 'apps.sso' ].join(',');
'apps.xFrameOptions', 'apps.sso' ].join(',');
var PORT_BINDINGS_FIELDS = [ 'hostPort', 'environmentVariable', 'appId' ].join(',');
@@ -97,7 +97,6 @@ function postProcess(result) {
// TODO remove later once all apps have this attribute
result.xFrameOptions = result.xFrameOptions || 'SAMEORIGIN';
result.oauthProxy = !!result.oauthProxy; // make it bool
result.sso = !!result.sso; // make it bool
}
@@ -185,12 +184,11 @@ function add(id, appStoreId, manifest, location, portBindings, data, callback) {
var xFrameOptions = data.xFrameOptions || '';
var installationState = data.installationState || exports.ISTATE_PENDING_INSTALL;
var lastBackupId = data.lastBackupId || null; // used when cloning
var oauthProxy = data.oauthProxy || false;
var queries = [ ];
queries.push({
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, accessRestrictionJson, memoryLimit, altDomain, xFrameOptions, lastBackupId, oauthProxy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
args: [ id, appStoreId, manifestJson, installationState, location, accessRestrictionJson, memoryLimit, altDomain, xFrameOptions, lastBackupId, oauthProxy ]
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, accessRestrictionJson, memoryLimit, altDomain, xFrameOptions, lastBackupId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
args: [ id, appStoreId, manifestJson, installationState, location, accessRestrictionJson, memoryLimit, altDomain, xFrameOptions, lastBackupId ]
});
Object.keys(portBindings).forEach(function (env) {
-7
View File
@@ -149,7 +149,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('oauthProxyPort'), /* oauth proxy server (lo) */
config.get('simpleAuthPort'), /* simple auth server (lo) */
3306, /* mysql (lo) */
4190, /* managesieve */
@@ -476,7 +475,6 @@ function install(data, auditSource, callback) {
memoryLimit = data.memoryLimit || 0,
altDomain = data.altDomain || null,
xFrameOptions = data.xFrameOptions || 'SAMEORIGIN',
oauthProxy = data.oauthProxy === true,
sso = 'sso' in data ? data.sso : null;
assert(data.appStoreId || data.manifest); // atleast one of them is required
@@ -532,7 +530,6 @@ function install(data, auditSource, callback) {
memoryLimit: memoryLimit,
altDomain: altDomain,
xFrameOptions: xFrameOptions,
oauthProxy: oauthProxy,
sso: sso
};
@@ -612,10 +609,6 @@ function configure(appId, data, auditSource, callback) {
if (error) return callback(error);
}
if ('oauthProxy' in data) {
values.oauthProxy = data.oauthProxy;
}
// save cert to data/box/certs. TODO: move this to apptask when we have a real task queue
if ('cert' in data && 'key' in data) {
if (data.cert && data.key) {
-45
View File
@@ -12,8 +12,6 @@ exports = module.exports = {
_unconfigureNginx: unconfigureNginx,
_createVolume: createVolume,
_deleteVolume: deleteVolume,
_allocateOAuthProxyCredentials: allocateOAuthProxyCredentials,
_removeOAuthProxyCredentials: removeOAuthProxyCredentials,
_verifyManifest: verifyManifest,
_registerSubdomain: registerSubdomain,
_unregisterSubdomain: unregisterSubdomain,
@@ -155,34 +153,6 @@ function deleteVolume(app, callback) {
shell.sudo('deleteVolume', [ RMAPPDIR_CMD, app.id ], callback);
}
function allocateOAuthProxyCredentials(app, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof callback, 'function');
if (!app.oauthProxy) return callback(null);
debugApp(app, 'Creating oauth proxy credentials');
var redirectURI = 'https://' + config.appFqdn(app.location);
var scope = 'profile';
clients.add(app.id, clients.TYPE_PROXY, redirectURI, scope, callback);
}
function removeOAuthProxyCredentials(app, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof callback, 'function');
clients.delByAppIdAndType(app.id, clients.TYPE_PROXY, function (error) {
if (error && error.reason !== ClientsError.NOT_FOUND) {
debugApp(app, 'Error removing OAuth client id', error);
return callback(error);
}
callback(null);
});
}
function addCollectdProfile(app, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof callback, 'function');
@@ -393,7 +363,6 @@ function install(app, callback) {
addons.teardownAddons.bind(null, app, app.manifest.addons),
deleteVolume.bind(null, app),
unregisterSubdomain.bind(null, app, app.location),
removeOAuthProxyCredentials.bind(null, app),
// removeIcon.bind(null, app), // do not remove icon for non-appstore installs
reserveHttpPort.bind(null, app),
@@ -401,9 +370,6 @@ function install(app, callback) {
updateApp.bind(null, app, { installationProgress: '20, Downloading icon' }),
downloadIcon.bind(null, app),
updateApp.bind(null, app, { installationProgress: '25, Creating OAuth proxy credentials' }),
allocateOAuthProxyCredentials.bind(null, app),
updateApp.bind(null, app, { installationProgress: '30, Registering subdomain' }),
registerSubdomain.bind(null, app),
@@ -497,7 +463,6 @@ function restore(app, callback) {
docker.deleteImage(app.oldConfig.manifest, done);
},
removeOAuthProxyCredentials.bind(null, app),
removeIcon.bind(null, app),
reserveHttpPort.bind(null, app),
@@ -505,9 +470,6 @@ function restore(app, callback) {
updateApp.bind(null, app, { installationProgress: '40, Downloading icon' }),
downloadIcon.bind(null, app),
updateApp.bind(null, app, { installationProgress: '50, Create OAuth proxy credentials' }),
allocateOAuthProxyCredentials.bind(null, app),
updateApp.bind(null, app, { installationProgress: '55, Registering subdomain' }), // ip might change during upgrades
registerSubdomain.bind(null, app),
@@ -568,13 +530,9 @@ function configure(app, callback) {
if (!app.oldConfig || app.oldConfig.location === app.location) return next();
unregisterSubdomain(app, app.oldConfig.location, next);
},
removeOAuthProxyCredentials.bind(null, app),
reserveHttpPort.bind(null, app),
updateApp.bind(null, app, { installationProgress: '30, Create OAuth proxy credentials' }),
allocateOAuthProxyCredentials.bind(null, app),
updateApp.bind(null, app, { installationProgress: '35, Registering subdomain' }),
registerSubdomain.bind(null, app),
@@ -714,9 +672,6 @@ function uninstall(app, callback) {
updateApp.bind(null, app, { installationProgress: '60, Unregistering subdomain' }),
unregisterSubdomain.bind(null, app, app.location),
updateApp.bind(null, app, { installationProgress: '70, Remove OAuth credentials' }),
removeOAuthProxyCredentials.bind(null, app),
updateApp.bind(null, app, { installationProgress: '80, Cleanup icon' }),
removeIcon.bind(null, app),
-1
View File
@@ -81,7 +81,6 @@ function initConfig() {
data.smtpPort = 2525; // // this value comes from mail container
data.sysadminPort = 3001;
data.ldapPort = 3002;
data.oauthProxyPort = 3003;
data.simpleAuthPort = 3004;
data.provider = 'caas';
data.appBundle = [ ];
+1 -2
View File
@@ -49,8 +49,7 @@ function configureApp(app, certFilePath, keyFilePath, callback) {
assert.strictEqual(typeof callback, 'function');
var sourceDir = path.resolve(__dirname, '..');
var oauthProxy = app.oauthProxy;
var endpoint = oauthProxy ? 'oauthproxy' : 'app';
var endpoint = 'app';
var vhost = app.altDomain || config.appFqdn(app.location);
var data = {
-196
View File
@@ -1,196 +0,0 @@
'use strict';
exports = module.exports = {
start: start,
stop: stop
};
var appdb = require('./appdb.js'),
assert = require('assert'),
clients = require('./clients.js'),
config = require('./config.js'),
DatabaseError = require('./databaseerror.js'),
debug = require('debug')('box:oauthproxy'),
express = require('express'),
http = require('http'),
proxy = require('proxy-middleware'),
session = require('cookie-session'),
superagent = require('superagent'),
tokendb = require('./tokendb.js'),
url = require('url'),
uuid = require('node-uuid');
var gSessions = {};
var gProxyMiddlewareCache = {};
var gHttpServer = null;
var CALLBACK_URI = '/callback';
function clearSession(req) {
delete gSessions[req.session.id];
req.session.id = uuid.v4();
gSessions[req.session.id] = {};
req.sessionData = gSessions[req.session.id];
}
function attachSessionData(req, res, next) {
assert.strictEqual(typeof req.session, 'object');
if (!req.session.id || !gSessions[req.session.id]) clearSession(req);
// attach the session data to the requeset
req.sessionData = gSessions[req.session.id];
next();
}
function verifySession(req, res, next) {
assert.strictEqual(typeof req.sessionData, 'object');
if (!req.sessionData.accessToken) {
req.authenticated = false;
return next();
}
tokendb.get(req.sessionData.accessToken, function (error, token) {
if (error) {
if (error.reason !== DatabaseError.NOT_FOUND) console.error(error);
clearSession(req);
req.authenticated = false;
} else {
req.authenticated = true;
}
next();
});
}
function authenticate(req, res, next) {
// proceed if we are authenticated
if (req.authenticated) return next();
if (req.path === CALLBACK_URI && req.sessionData.returnTo) {
// exchange auth code for an access token
var query = {
response_type: 'token',
client_id: req.sessionData.clientId
};
var data = {
grant_type: 'authorization_code',
code: req.query.code,
redirect_uri: req.sessionData.returnTo,
client_id: req.sessionData.clientId,
client_secret: req.sessionData.clientSecret
};
// use http admin origin so that it works with self-signed certs
superagent
.post(config.internalAdminOrigin() + '/api/v1/oauth/token')
.query(query).send(data)
.timeout(30 * 1000)
.end(function (error, result) {
if (error && !error.response) {
console.error(error);
return res.send(500, 'Unable to contact the oauth server.');
}
if (result.statusCode !== 200) {
console.error('Failed to exchange auth code for a token.', result.statusCode, result.body);
return res.send(500, 'Failed to exchange auth code for a token.');
}
req.sessionData.accessToken = result.body.access_token;
debug('user verified.');
// now redirect to the actual initially requested URL
res.redirect(req.sessionData.returnTo);
});
} else {
var port = parseInt(req.headers['x-cloudron-proxy-port'], 10);
if (!Number.isFinite(port)) {
console.error('Failed to parse nginx proxy header to get app port.');
return res.send(500, 'Routing error. No forwarded port.');
}
debug('begin verifying user for app on port %s.', port);
appdb.getByHttpPort(port, function (error, result) {
if (error) {
console.error('Unknown app.', error);
return res.send(500, 'Unknown app.');
}
clients.getByAppIdAndType(result.id, clients.TYPE_PROXY, function (error, result) {
if (error) {
console.error('Unknown OAuth client.', error);
return res.send(500, 'Unknown OAuth client.');
}
req.sessionData.port = port;
req.sessionData.returnTo = result.redirectURI + req.path;
req.sessionData.clientId = result.id;
req.sessionData.clientSecret = result.clientSecret;
var callbackUrl = result.redirectURI + CALLBACK_URI;
var scope = 'profile';
var oauthLogin = config.adminOrigin() + '/api/v1/oauth/dialog/authorize?response_type=code&client_id=' + result.id + '&redirect_uri=' + callbackUrl + '&scope=' + scope;
debug('begin OAuth flow for client %s.', result.id);
// begin the OAuth flow
res.redirect(oauthLogin);
});
});
}
}
function forwardRequestToApp(req, res, next) {
var port = req.sessionData.port;
debug('proxy request for port %s with path %s.', port, req.path);
var proxyMiddleware = gProxyMiddlewareCache[port];
if (!proxyMiddleware) {
console.log('Adding proxy middleware for port %d', port);
proxyMiddleware = proxy(url.parse('http://127.0.0.1:' + port));
gProxyMiddlewareCache[port] = proxyMiddleware;
}
proxyMiddleware(req, res, next);
}
function initializeServer() {
var app = express();
var httpServer = http.createServer(app);
httpServer.on('error', console.error);
app
.use(session({ keys: ['blue', 'cheese', 'is', 'something'] }))
.use(attachSessionData)
.use(verifySession)
.use(authenticate)
.use(forwardRequestToApp);
return httpServer;
}
function start(callback) {
assert.strictEqual(typeof callback, 'function');
gHttpServer = initializeServer();
gHttpServer.listen(config.get('oauthProxyPort'), callback);
}
function stop(callback) {
assert.strictEqual(typeof callback, 'function');
if (gHttpServer) gHttpServer.close(callback);
}
+1 -5
View File
@@ -54,8 +54,7 @@ function removeInternalAppFields(app) {
fqdn: app.fqdn,
memoryLimit: app.memoryLimit,
altDomain: app.altDomain,
xFrameOptions: app.xFrameOptions,
oauthProxy: app.oauthProxy
xFrameOptions: app.xFrameOptions
};
}
@@ -124,7 +123,6 @@ function installApp(req, res, next) {
if (data.xFrameOptions && typeof data.xFrameOptions !== 'string') return next(new HttpError(400, 'xFrameOptions must be a string'));
if ('oauthProxy' in data && typeof data.oauthProxy !== 'boolean') return next(new HttpError(400, 'oauthProxy must be a boolean'));
if ('sso' in data && typeof data.sso !== 'boolean') return next(new HttpError(400, 'sso must be a boolean'));
debug('Installing app :%j', data);
@@ -163,8 +161,6 @@ function configureApp(req, res, next) {
if (data.altDomain && typeof data.altDomain !== 'string') return next(new HttpError(400, 'altDomain must be a string'));
if (data.xFrameOptions && typeof data.xFrameOptions !== 'string') return next(new HttpError(400, 'xFrameOptions must be a string'));
if ('oauthProxy' in data && typeof data.oauthProxy !== 'boolean') return next(new HttpError(400, 'oauthProxy must be a boolean'));
debug('Configuring app id:%s data:%j', req.params.id, data);
apps.configure(req.params.id, data, auditSource(req), function (error) {
-2
View File
@@ -544,7 +544,6 @@ describe('database', function () {
memoryLimit: 4294967296,
altDomain: null,
xFrameOptions: 'DENY',
oauthProxy: false,
sso: true
};
var APP_1 = {
@@ -566,7 +565,6 @@ describe('database', function () {
memoryLimit: 0,
altDomain: null,
xFrameOptions: 'SAMEORIGIN',
oauthProxy: false,
sso: true
};