From 6444de0554ef19bd2f82a8668c78e1a63ca3aa7c Mon Sep 17 00:00:00 2001 From: Kasra Bigdeli Date: Thu, 28 Dec 2017 14:58:56 -0800 Subject: [PATCH] Force SSL implementation in Backend App --- app-backend/src/datastore/DataStoreImpl.js | 23 +++++++++- app-backend/src/routes/AppDefinitionRouter.js | 3 +- app-backend/src/template/root-nginx-conf.ejs | 1 - .../src/template/server-block-conf.ejs | 43 ++++++++++++++++++- app-backend/src/user/ServiceManager.js | 4 +- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/app-backend/src/datastore/DataStoreImpl.js b/app-backend/src/datastore/DataStoreImpl.js index a113751..a5d2093 100644 --- a/app-backend/src/datastore/DataStoreImpl.js +++ b/app-backend/src/datastore/DataStoreImpl.js @@ -338,11 +338,13 @@ class DataStore { } let localDomain = self.getServiceName(appName); + let forceSsl = !!webApp.forceSsl; let serverWithSubDomain = {}; serverWithSubDomain.hasSsl = hasRootSsl && webApp.hasDefaultSubDomainSsl; serverWithSubDomain.publicDomain = appName + '.' + rootDomain; serverWithSubDomain.localDomain = localDomain; + serverWithSubDomain.forceSsl = forceSsl; servers.push(serverWithSubDomain); @@ -353,6 +355,7 @@ class DataStore { let d = customDomainArray[idx]; servers.push({ hasSsl: d.hasSsl, + forceSsl: forceSsl, publicDomain: d.publicDomain, localDomain: localDomain }); @@ -398,7 +401,7 @@ class DataStore { }); } - updateAppDefinitionInDb(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, ports, appPushWebhook, authenticator) { + updateAppDefinitionInDb(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports, appPushWebhook, authenticator) { const self = this; let app; @@ -440,8 +443,26 @@ class DataStore { app.notExposeAsWebApp = !!notExposeAsWebApp; + app.forceSsl = !!forceSsl; app.nodeId = nodeId; + if (app.forceSsl) { + let hasAtLeastOneSslDomain = app.hasDefaultSubDomainSsl; + let customDomainArray = app.customDomain; + if (customDomainArray && customDomainArray.length > 0) { + for (let idx = 0; idx < customDomainArray.length; idx++) { + if (customDomainArray[idx].hasSsl) { + hasAtLeastOneSslDomain = true; + } + } + } + + if (!hasAtLeastOneSslDomain) { + throw new ApiStatusCodes.createError(ApiStatusCodes.ILLEGAL_OPERATION, "Cannot force SSL without any SSL-enabled domain!"); + } + + } + if (appPushWebhookRepoInfo) { app.appPushWebhook = app.appPushWebhook || {}; diff --git a/app-backend/src/routes/AppDefinitionRouter.js b/app-backend/src/routes/AppDefinitionRouter.js index ac6b62d..ab25a0f 100644 --- a/app-backend/src/routes/AppDefinitionRouter.js +++ b/app-backend/src/routes/AppDefinitionRouter.js @@ -320,6 +320,7 @@ router.post('/update/', function (req, res, next) { let appName = req.body.appName; let nodeId = req.body.nodeId; let notExposeAsWebApp = req.body.notExposeAsWebApp; + let forceSsl = !!req.body.forceSsl; let appPushWebhook = req.body.appPushWebhook || {}; let envVars = req.body.envVars || []; let volumes = req.body.volumes || []; @@ -340,7 +341,7 @@ router.post('/update/', function (req, res, next) { Logger.d('Updating app started: ' + appName); - serviceManager.updateAppDefinition(appName, Number(instanceCount), envVars, volumes, nodeId, notExposeAsWebApp, ports, appPushWebhook) + serviceManager.updateAppDefinition(appName, Number(instanceCount), envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports, appPushWebhook) .then(function () { Logger.d('AppName is updated: ' + appName); diff --git a/app-backend/src/template/root-nginx-conf.ejs b/app-backend/src/template/root-nginx-conf.ejs index 10a4467..01984dd 100644 --- a/app-backend/src/template/root-nginx-conf.ejs +++ b/app-backend/src/template/root-nginx-conf.ejs @@ -61,7 +61,6 @@ proxy_read_timeout 120s; } - # change to this to allow the applications to serve well-known files as well https://stackoverflow.com/questions/869001/how-to-serve-all-existing-static-files-directly-with-nginx-but-proxy-the-rest-t location /.well-known/ { root <%-captain.staticWebRoot%>; } diff --git a/app-backend/src/template/server-block-conf.ejs b/app-backend/src/template/server-block-conf.ejs index 68524e9..ad70753 100644 --- a/app-backend/src/template/server-block-conf.ejs +++ b/app-backend/src/template/server-block-conf.ejs @@ -3,9 +3,47 @@ var s = servers[idx]; %> +<% +if (s.forceSsl) { +%> + server { listen 80; + + server_name <%-s.publicDomain%>; + + location /.well-known/ { + root <%-s.staticWebRoot%>; + } + + location / { + return 302 https://$http_host$request_uri$is_args$query_string; + } + + } + +<% +} +%> + + +<% +if (!s.forceSsl || s.hasSsl) { +%> + + server { + + <% + if (!s.forceSsl) { + %> + + listen 80; + + <% + } + %> + <% if (s.hasSsl) { %> @@ -31,13 +69,16 @@ proxy_set_header X-Forwarded-Proto $scheme; } - # change to this to allow the applications to serve well-known files as well https://stackoverflow.com/questions/869001/how-to-serve-all-existing-static-files-directly-with-nginx-but-proxy-the-rest-t location /.well-known/ { root <%-s.staticWebRoot%>; } } +<% +} +%> + <% } %> \ No newline at end of file diff --git a/app-backend/src/user/ServiceManager.js b/app-backend/src/user/ServiceManager.js index a0d6591..4c044ca 100644 --- a/app-backend/src/user/ServiceManager.js +++ b/app-backend/src/user/ServiceManager.js @@ -663,7 +663,7 @@ class ServiceManager { }); } - updateAppDefinition(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, ports, appPushWebhook) { + updateAppDefinition(appName, instanceCount, envVars, volumes, nodeId, notExposeAsWebApp, forceSsl, ports, appPushWebhook) { const self = this; const dataStore = this.dataStore; @@ -755,7 +755,7 @@ class ServiceManager { .then(function () { return dataStore.updateAppDefinitionInDb(appName, instanceCount, envVars, volumes, nodeId, - notExposeAsWebApp, ports, appPushWebhook, Authenticator.get(dataStore.getNameSpace())); + notExposeAsWebApp, forceSsl, ports, appPushWebhook, Authenticator.get(dataStore.getNameSpace())); }) .then(function () {