diff --git a/backend/doc/api.swagger.json b/backend/doc/api.swagger.json index 3fa19fc4..e389b1c9 100644 --- a/backend/doc/api.swagger.json +++ b/backend/doc/api.swagger.json @@ -82,6 +82,7 @@ "ssl_forced": 0, "caching_enabled": 0, "block_exploits": 0, + "drop_unauthorized": 0, "advanced_config": "sdfsdfsdf", "meta": { "letsencrypt_agree": false, @@ -124,6 +125,7 @@ "ssl_forced": 0, "caching_enabled": 0, "block_exploits": 0, + "drop_unauthorized": 0, "advanced_config": "", "meta": { "letsencrypt_agree": false, @@ -204,6 +206,7 @@ "ssl_forced": 0, "caching_enabled": 0, "block_exploits": 0, + "drop_unauthorized": 0, "advanced_config": "", "meta": { "letsencrypt_agree": false, @@ -1117,6 +1120,7 @@ "ssl_forced", "caching_enabled", "block_exploits", + "drop_unauthorized", "advanced_config", "meta", "allow_websocket_upgrade", @@ -1184,6 +1188,9 @@ "block_exploits": { "type": "integer" }, + "drop_unauthorized": { + "type": "integer" + }, "advanced_config": { "type": "string" }, diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 77933e73..2df4beab 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -153,7 +153,7 @@ const internalNginx = { const locationRendering = async () => { for (let i = 0; i < host.locations.length; i++) { let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id}, - {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits}, + {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits}, {drop_unauthorized: host.drop_unauthorized}, {allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support}, {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list}, {certificate: host.certificate}, host.locations[i]); @@ -205,6 +205,12 @@ const internalNginx = { let origLocations; // Manipulate the data a bit before sending it to the template + if (typeof host.drop_unauthorized === 'undefined') { + // Only proxy-hosts can have drop_unauthorized, but all hosts share + // the templates. + host.drop_unauthorized = 0; + } + if (nice_host_type !== 'default') { host.use_default_location = true; if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { diff --git a/backend/migrations/20230529030411_add_drop_unauthorized_to_proxyhosts.js b/backend/migrations/20230529030411_add_drop_unauthorized_to_proxyhosts.js new file mode 100644 index 00000000..411e1a6f --- /dev/null +++ b/backend/migrations/20230529030411_add_drop_unauthorized_to_proxyhosts.js @@ -0,0 +1,39 @@ +const migrate_name = 'drop_unauthorized'; +const logger = require('../logger').migrate; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.up = function (knex/*, Promise*/) { + + logger.info('[' + migrate_name + '] Migrating Up...'); + + return knex.schema.table('proxy_host', function(proxy_host) { + proxy_host.integer('drop_unauthorized').notNull().unsigned().defaultTo(0); + }).then(() =>{ + logger.info('[' + migrate_name + '] Migrating Up Complete'); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex/*, Promise*/) { + logger.info('[' + migrate_name + '] Migrating Down...'); + + return knex.schema.table('proxy_host', function(proxy_host) { + proxy_host.dropColumn('drop_unauthorized'); + }).then(() =>{ + logger.info('[' + migrate_name + '] Migrating Up Complete'); + }); +}; diff --git a/backend/schema/definitions.json b/backend/schema/definitions.json index 136b0235..61bbb6dd 100644 --- a/backend/schema/definitions.json +++ b/backend/schema/definitions.json @@ -231,6 +231,11 @@ "example": true, "type": "boolean" }, + "drop_unauthorized": { + "description": "Close TCP connection with no response when authorization fails", + "example": true, + "type": "boolean" + }, "caching_enabled": { "description": "Should we cache assets", "example": true, diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json index 9a3fff2f..ec812f1b 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -50,6 +50,9 @@ "block_exploits": { "$ref": "../definitions.json#/definitions/block_exploits" }, + "drop_unauthorized": { + "$ref": "../definitions.json#/definitions/drop_unauthorized" + }, "caching_enabled": { "$ref": "../definitions.json#/definitions/caching_enabled" }, @@ -149,6 +152,9 @@ "block_exploits": { "$ref": "#/definitions/block_exploits" }, + "drop_unauthorized": { + "$ref": "#/definitions/drop_unauthorized" + }, "caching_enabled": { "$ref": "#/definitions/caching_enabled" }, @@ -239,6 +245,9 @@ "block_exploits": { "$ref": "#/definitions/block_exploits" }, + "drop_unauthorized": { + "$ref": "#/definitions/drop_unauthorized" + }, "caching_enabled": { "$ref": "#/definitions/caching_enabled" }, @@ -312,6 +321,9 @@ "block_exploits": { "$ref": "#/definitions/block_exploits" }, + "drop_unauthorized": { + "$ref": "#/definitions/drop_unauthorized" + }, "caching_enabled": { "$ref": "#/definitions/caching_enabled" }, diff --git a/backend/templates/_access.conf b/backend/templates/_access.conf index cf1950ad..f19a8228 100644 --- a/backend/templates/_access.conf +++ b/backend/templates/_access.conf @@ -2,7 +2,7 @@ {% if access_list.clientcas.size > 0 %} # TLS Client Certificate Authorization if ($ssl_client_verify != "SUCCESS") { - return 403; + return {% if drop_unauthorized == 1 %}444{% else %}403{% endif %}; } {% endif %} {% if access_list.items.length > 0 %} diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 56868f55..a95e4d5f 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -72,7 +72,7 @@ -