app.portBindings and newManifest.tcpPorts may be null
This commit is contained in:
185
oauthproxy.js
Executable file
185
oauthproxy.js
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
require('supererror')({ splatchError: true });
|
||||
|
||||
var express = require('express'),
|
||||
url = require('url'),
|
||||
uuid = require('node-uuid'),
|
||||
async = require('async'),
|
||||
superagent = require('superagent'),
|
||||
assert = require('assert'),
|
||||
debug = require('debug')('box:proxy'),
|
||||
proxy = require('proxy-middleware'),
|
||||
session = require('cookie-session'),
|
||||
database = require('./src/database.js'),
|
||||
appdb = require('./src/appdb.js'),
|
||||
clientdb = require('./src/clientdb.js'),
|
||||
config = require('./src/config.js'),
|
||||
http = require('http');
|
||||
|
||||
// Allow self signed certs!
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
|
||||
var gSessions = {};
|
||||
var gProxyMiddlewareCache = {};
|
||||
var gApp = express();
|
||||
var gHttpServer = http.createServer(gApp);
|
||||
|
||||
var CALLBACK_URI = '/callback';
|
||||
var PORT = 4000;
|
||||
|
||||
function startServer(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
gHttpServer.on('error', console.error);
|
||||
|
||||
gApp.use(session({
|
||||
keys: ['blue', 'cheese', 'is', 'something']
|
||||
}));
|
||||
|
||||
// ensure we have a in memory store for the session to cache client information
|
||||
gApp.use(function (req, res, next) {
|
||||
assert.strictEqual(typeof req.session, 'object');
|
||||
|
||||
if (!req.session.id || !gSessions[req.session.id]) {
|
||||
req.session.id = uuid.v4();
|
||||
gSessions[req.session.id] = {};
|
||||
}
|
||||
|
||||
// attach the session data to the requeset
|
||||
req.sessionData = gSessions[req.session.id];
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
gApp.use(function verifySession(req, res, next) {
|
||||
assert.strictEqual(typeof req.sessionData, 'object');
|
||||
|
||||
if (!req.sessionData.accessToken) {
|
||||
req.authenticated = false;
|
||||
return next();
|
||||
}
|
||||
|
||||
superagent.get(config.adminOrigin() + '/api/v1/profile').query({ access_token: req.sessionData.accessToken}).end(function (error, result) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
req.authenticated = false;
|
||||
} else if (result.statusCode !== 200) {
|
||||
req.sessionData.accessToken = null;
|
||||
req.authenticated = false;
|
||||
} else {
|
||||
req.authenticated = true;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
gApp.use(function (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
|
||||
};
|
||||
|
||||
superagent.post(config.adminOrigin() + '/api/v1/oauth/token').query(query).send(data).end(function (error, result) {
|
||||
if (error) {
|
||||
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.');
|
||||
}
|
||||
|
||||
clientdb.getByAppId('proxy-' + result.id, function (error, result) {
|
||||
if (error) {
|
||||
console.error('Unkonwn 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,roleUser';
|
||||
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.name);
|
||||
|
||||
// begin the OAuth flow
|
||||
res.redirect(oauthLogin);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
gApp.use(function (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);
|
||||
});
|
||||
|
||||
gHttpServer.listen(PORT, callback);
|
||||
}
|
||||
|
||||
async.series([
|
||||
database.initialize,
|
||||
startServer
|
||||
], function (error) {
|
||||
if (error) {
|
||||
console.error('Failed to start proxy server.', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Proxy server listening...');
|
||||
});
|
||||
Reference in New Issue
Block a user