From f990d3f674a661dddd3735d8d794c8bdde26ba29 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Fri, 10 Apr 2020 16:38:54 -0700 Subject: [PATCH 01/10] add access list clients to back-end --- backend/internal/access-list.js | 81 +++++++++++++++---- .../20200410143839_access_list_client.js | 46 +++++++++++ backend/models/access_list.js | 20 ++++- backend/models/access_list_client.js | 54 +++++++++++++ backend/schema/endpoints/access-lists.json | 40 +++++++++ 5 files changed, 220 insertions(+), 21 deletions(-) create mode 100644 backend/migrations/20200410143839_access_list_client.js create mode 100644 backend/models/access_list_client.js diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index bfecf613..0411b59d 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -1,14 +1,15 @@ -const _ = require('lodash'); -const fs = require('fs'); -const batchflow = require('batchflow'); -const logger = require('../logger').access; -const error = require('../lib/error'); -const accessListModel = require('../models/access_list'); -const accessListAuthModel = require('../models/access_list_auth'); -const proxyHostModel = require('../models/proxy_host'); -const internalAuditLog = require('./audit-log'); -const internalNginx = require('./nginx'); -const utils = require('../lib/utils'); +const _ = require('lodash'); +const fs = require('fs'); +const batchflow = require('batchflow'); +const logger = require('../logger').access; +const error = require('../lib/error'); +const accessListModel = require('../models/access_list'); +const accessListAuthModel = require('../models/access_list_auth'); +const accessListClientModel = require('../models/access_list_client'); +const proxyHostModel = require('../models/proxy_host'); +const internalAuditLog = require('./audit-log'); +const internalNginx = require('./nginx'); +const utils = require('../lib/utils'); function omissions () { return ['is_deleted']; @@ -35,8 +36,9 @@ const internalAccessList = { .then((row) => { data.id = row.id; - // Now add the items let promises = []; + + // Now add the items data.items.map((item) => { promises.push(accessListAuthModel .query() @@ -48,13 +50,27 @@ const internalAccessList = { ); }); + // Now add the clients + if (typeof data.clients !== 'undefined' && data.clients) { + data.clients.map((client) => { + promises.push(accessListClientModel + .query() + .insert({ + access_list_id: row.id, + address: client.address, + directive: client.directive + }) + ); + }); + } + return Promise.all(promises); }) .then(() => { // re-fetch with expansions return internalAccessList.get(access, { id: data.id, - expand: ['owner', 'items'] + expand: ['owner', 'items', 'clients'] }, true /* <- skip masking */); }) .then((row) => { @@ -152,6 +168,37 @@ const internalAccessList = { } }); } + + // Check for clients and add/update/remove them + if (typeof data.clients !== 'undefined' && data.clients) { + let promises = []; + + data.clients.map(function (client) { + if (client.address) { + promises.push(accessListAuthModel + .query() + .insert({ + access_list_id: data.id, + address: client.address, + directive: client.directive + }) + ); + } + }); + + let query = accessListClientModel + .query() + .delete() + .where('access_list_id', data.id); + + return query + .then(() => { + // Add new items + if (promises.length) { + return Promise.all(promises); + } + }); + } }) .then(() => { // Add to audit log @@ -166,7 +213,7 @@ const internalAccessList = { // re-fetch with expansions return internalAccessList.get(access, { id: data.id, - expand: ['owner', 'items'] + expand: ['owner', 'items', 'clients'] }, true /* <- skip masking */); }) .then((row) => { @@ -204,7 +251,7 @@ const internalAccessList = { .joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0') .where('access_list.is_deleted', 0) .andWhere('access_list.id', data.id) - .allowEager('[owner,items,proxy_hosts]') + .allowEager('[owner,items,clients,proxy_hosts]') .omit(['access_list.is_deleted']) .first(); @@ -246,7 +293,7 @@ const internalAccessList = { delete: (access, data) => { return access.can('access_lists:delete', data.id) .then(() => { - return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items']}); + return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']}); }) .then((row) => { if (!row) { @@ -330,7 +377,7 @@ const internalAccessList = { .where('access_list.is_deleted', 0) .groupBy('access_list.id') .omit(['access_list.is_deleted']) - .allowEager('[owner,items]') + .allowEager('[owner,items,clients]') .orderBy('access_list.name', 'ASC'); if (access_data.permission_visibility !== 'all') { diff --git a/backend/migrations/20200410143839_access_list_client.js b/backend/migrations/20200410143839_access_list_client.js new file mode 100644 index 00000000..2432d773 --- /dev/null +++ b/backend/migrations/20200410143839_access_list_client.js @@ -0,0 +1,46 @@ +const migrate_name = 'access_list_client'; +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.createTable('access_list_client', (table) => { + table.increments().primary(); + table.dateTime('created_on').notNull(); + table.dateTime('modified_on').notNull(); + table.integer('access_list_id').notNull().unsigned(); + table.string('address').notNull(); + table.string('directive').notNull(); + table.json('meta').notNull(); + + }) + .then(function () { + logger.info('[' + migrate_name + '] access_list_client Table created'); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex/*, Promise*/) { + logger.info('[' + migrate_name + '] Migrating Down...'); + + return knex.schema.dropTable('access_list_client') + .then(() => { + logger.info('[' + migrate_name + '] access_list_client Table dropped'); + }); +}; diff --git a/backend/models/access_list.js b/backend/models/access_list.js index 7704893f..43a2f128 100644 --- a/backend/models/access_list.js +++ b/backend/models/access_list.js @@ -1,10 +1,11 @@ // Objection Docs: // http://vincit.github.io/objection.js/ -const db = require('../db'); -const Model = require('objection').Model; -const User = require('./user'); -const AccessListAuth = require('./access_list_auth'); +const db = require('../db'); +const Model = require('objection').Model; +const User = require('./user'); +const AccessListAuth = require('./access_list_auth'); +const AccessListClient = require('./access_list_client'); Model.knex(db); @@ -62,6 +63,17 @@ class AccessList extends Model { qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']); } }, + clients: { + relation: Model.HasManyRelation, + modelClass: AccessListClient, + join: { + from: 'access_list.id', + to: 'access_list_client.access_list_id' + }, + modify: function (qb) { + qb.omit(['id', 'created_on', 'modified_on', 'access_list_id', 'meta']); + } + }, proxy_hosts: { relation: Model.HasManyRelation, modelClass: ProxyHost, diff --git a/backend/models/access_list_client.js b/backend/models/access_list_client.js new file mode 100644 index 00000000..1bee2426 --- /dev/null +++ b/backend/models/access_list_client.js @@ -0,0 +1,54 @@ +// Objection Docs: +// http://vincit.github.io/objection.js/ + +const db = require('../db'); +const Model = require('objection').Model; + +Model.knex(db); + +class AccessListClient extends Model { + $beforeInsert () { + this.created_on = Model.raw('NOW()'); + this.modified_on = Model.raw('NOW()'); + + // Default for meta + if (typeof this.meta === 'undefined') { + this.meta = {}; + } + } + + $beforeUpdate () { + this.modified_on = Model.raw('NOW()'); + } + + static get name () { + return 'AccessListClient'; + } + + static get tableName () { + return 'access_list_client'; + } + + static get jsonAttributes () { + return ['meta']; + } + + static get relationMappings () { + return { + access_list: { + relation: Model.HasOneRelation, + modelClass: require('./access_list'), + join: { + from: 'access_list_client.access_list_id', + to: 'access_list.id' + }, + modify: function (qb) { + qb.where('access_list.is_deleted', 0); + qb.omit(['created_on', 'modified_on', 'is_deleted', 'access_list_id']); + } + } + }; + } +} + +module.exports = AccessListClient; diff --git a/backend/schema/endpoints/access-lists.json b/backend/schema/endpoints/access-lists.json index da90a050..f2ff254d 100644 --- a/backend/schema/endpoints/access-lists.json +++ b/backend/schema/endpoints/access-lists.json @@ -19,6 +19,14 @@ "type": "string", "description": "Name of the Access List" }, + "directive": { + "type": "string", + "enum": ["allow", "deny"] + }, + "address": { + "type": "string", + "format": "ipv4" + }, "meta": { "type": "object" } @@ -96,6 +104,22 @@ } } }, + "clients": { + "type": "array", + "minItems": 0, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "address": { + "$ref": "#/definitions/address" + }, + "directive": { + "$ref": "#/definitions/directive" + } + } + } + }, "meta": { "$ref": "#/definitions/meta" } @@ -141,6 +165,22 @@ } } } + }, + "clients": { + "type": "array", + "minItems": 0, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "address": { + "$ref": "#/definitions/address" + }, + "directive": { + "$ref": "#/definitions/directive" + } + } + } } } }, From 46a9f5cb965a597c83c648743c6f3e9063d63d96 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Fri, 10 Apr 2020 17:33:14 -0700 Subject: [PATCH 02/10] add basic functionality to front end --- frontend/js/app/nginx/access/form.ejs | 64 ++++++++++++++------ frontend/js/app/nginx/access/form.js | 52 ++++++++++++---- frontend/js/app/nginx/access/form/client.ejs | 13 ++++ frontend/js/app/nginx/access/form/client.js | 7 +++ frontend/js/app/nginx/access/main.js | 2 +- frontend/js/i18n/messages.json | 5 +- frontend/js/models/access-list.js | 1 + 7 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 frontend/js/app/nginx/access/form/client.ejs create mode 100644 frontend/js/app/nginx/access/form/client.js diff --git a/frontend/js/app/nginx/access/form.ejs b/frontend/js/app/nginx/access/form.ejs index a85e3968..4866171f 100644 --- a/frontend/js/app/nginx/access/form.ejs +++ b/frontend/js/app/nginx/access/form.ejs @@ -3,28 +3,52 @@ - diff --git a/frontend/js/app/nginx/access/form.js b/frontend/js/app/nginx/access/form.js index c932e86b..fdfbb65d 100644 --- a/frontend/js/app/nginx/access/form.js +++ b/frontend/js/app/nginx/access/form.js @@ -65,17 +65,20 @@ module.exports = Mn.View.extend({ } }); - if (!items_data.length) { - alert('You must specify at least 1 Username and Password combination'); + if (!items_data.length && !clients_data.length) { + alert('You must specify at least 1 Authorization or Access rule'); return; } let data = { - name: form_data.name, - items: items_data, - clients: clients_data + name: form_data.name, + satify_any: !!form_data.satify_any, + items: items_data, + clients: clients_data }; + console.log(data); + let method = App.Api.Nginx.AccessLists.create; let is_new = true; diff --git a/frontend/js/app/nginx/access/list/item.ejs b/frontend/js/app/nginx/access/list/item.ejs index d713259d..2979f508 100644 --- a/frontend/js/app/nginx/access/list/item.ejs +++ b/frontend/js/app/nginx/access/list/item.ejs @@ -17,6 +17,13 @@ <%- i18n('access-lists', 'client-count', {count: clients.length || 0}) %> + + <% if (satify_any) { %> + <%- i18n('str', 'any') %> + <%} else { %> + <%- i18n('str', 'all') %> + <% } %> + <%- i18n('access-lists', 'proxy-host-count', {count: proxy_host_count}) %> diff --git a/frontend/js/app/nginx/access/list/main.ejs b/frontend/js/app/nginx/access/list/main.ejs index 1c3b10d4..7988e0c2 100644 --- a/frontend/js/app/nginx/access/list/main.ejs +++ b/frontend/js/app/nginx/access/list/main.ejs @@ -3,6 +3,7 @@ <%- i18n('str', 'name') %> <%- i18n('access-lists', 'authorization') %> <%- i18n('access-lists', 'access') %> + <%- i18n('access-lists', 'satisfy') %> <%- i18n('proxy-hosts', 'title') %> <% if (canManage) { %>   diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index ffab7e8b..162357d7 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -33,7 +33,9 @@ "unknown": "Unknown", "expires": "Expires", "value": "Value", - "please-wait": "Please wait..." + "please-wait": "Please wait...", + "all": "All", + "any": "Any" }, "login": { "title": "Login to your account" @@ -191,7 +193,9 @@ "delete-has-hosts": "This Access List is associated with {count} Proxy Hosts. They will become publicly available upon deletion.", "details": "Details", "authorization": "Authorization", - "access": "Access" + "access": "Access", + "satisfy": "Satisfy", + "satisfy-any": "Satify Any" }, "users": { "title": "Users", From 907e9e182d528039fc8ba448660ae97d85c7b11f Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Sat, 11 Apr 2020 00:42:58 -0700 Subject: [PATCH 06/10] remove testing cruft --- backend/internal/access-list.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index 20c8617a..a640c1e2 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -480,12 +480,10 @@ const internalAccessList = { return new Promise((resolve, reject) => { let htpasswd_file = internalAccessList.getFilename(list); - let nginx_file = internalAccessList.getFilename(list) + '.conf'; // 1. remove any existing access file try { fs.unlinkSync(htpasswd_file); - fs.unlinkSync(nginx_file); } catch (err) { // do nothing } From e9e5d293cc533b1985058acdd7c81c9214acaa29 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Mon, 13 Apr 2020 19:16:18 -0700 Subject: [PATCH 07/10] expand address format now accepts CIDR notation, IPv6 or the string 'any' --- backend/schema/endpoints/access-lists.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/backend/schema/endpoints/access-lists.json b/backend/schema/endpoints/access-lists.json index 18bbf2ae..51a07ba6 100644 --- a/backend/schema/endpoints/access-lists.json +++ b/backend/schema/endpoints/access-lists.json @@ -24,8 +24,20 @@ "enum": ["allow", "deny"] }, "address": { - "type": "string", - "format": "ipv4" + "oneOf": [ + { + "type": "string", + "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$" + }, + { + "type": "string", + "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" + }, + { + "type": "string", + "pattern": "^any$" + } + ] }, "satify_any": { "type": "boolean" From 005e64eb9fcbc7e603dae88a52cd89726794d452 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Mon, 13 Apr 2020 19:23:55 -0700 Subject: [PATCH 08/10] valite auth/access rules in backend --- backend/internal/access-list.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index a640c1e2..69e13f4e 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -25,6 +25,10 @@ const internalAccessList = { create: (access, data) => { return access.can('access_lists:create', data) .then((/*access_data*/) => { + if ((typeof data.items === 'undefined' || !data.items.length) && (typeof data.clients === 'undefined' || !data.clients.length)) { + throw new error.InternalValidationError('At leaste one user/pass or address must be defined'); + } + return accessListModel .query() .omit(omissions()) @@ -110,6 +114,10 @@ const internalAccessList = { update: (access, data) => { return access.can('access_lists:update', data.id) .then((/*access_data*/) => { + if ((typeof data.items === 'undefined' || !data.items.length) && (typeof data.clients === 'undefined' || !data.clients.length)) { + throw new error.InternalValidationError('At leaste one user/pass or address must be defined'); + } + return internalAccessList.get(access, {id: data.id}); }) .then((row) => { From e2ee2cbf2db518260a93ac06332b04890b58ad03 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Mon, 13 Apr 2020 19:52:44 -0700 Subject: [PATCH 09/10] enforce a 'deny all' default rule this ensures that an access list is 'secure by default' and requires the user to create exceptions or holes in the proection instead of building the wall entirely. This also means that we no longer require the user to input any username/passwords or client addressses and can avoid internal errors which generate unhelpful user errors. --- backend/internal/access-list.js | 8 -------- frontend/js/app/nginx/access/form.ejs | 12 ++++++++++++ frontend/js/app/nginx/access/form.js | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index 69e13f4e..a640c1e2 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -25,10 +25,6 @@ const internalAccessList = { create: (access, data) => { return access.can('access_lists:create', data) .then((/*access_data*/) => { - if ((typeof data.items === 'undefined' || !data.items.length) && (typeof data.clients === 'undefined' || !data.clients.length)) { - throw new error.InternalValidationError('At leaste one user/pass or address must be defined'); - } - return accessListModel .query() .omit(omissions()) @@ -114,10 +110,6 @@ const internalAccessList = { update: (access, data) => { return access.can('access_lists:update', data.id) .then((/*access_data*/) => { - if ((typeof data.items === 'undefined' || !data.items.length) && (typeof data.clients === 'undefined' || !data.clients.length)) { - throw new error.InternalValidationError('At leaste one user/pass or address must be defined'); - } - return internalAccessList.get(access, {id: data.id}); }) .then((row) => { diff --git a/frontend/js/app/nginx/access/form.ejs b/frontend/js/app/nginx/access/form.ejs index 40fe8542..3f127cc0 100644 --- a/frontend/js/app/nginx/access/form.ejs +++ b/frontend/js/app/nginx/access/form.ejs @@ -55,6 +55,18 @@
+
+
+
+ +
+
+
+
+ +
+
+
Note that the allow and deny directives will be applied in the order they are defined.
diff --git a/frontend/js/app/nginx/access/form.js b/frontend/js/app/nginx/access/form.js index fdfbb65d..8efdb72a 100644 --- a/frontend/js/app/nginx/access/form.js +++ b/frontend/js/app/nginx/access/form.js @@ -119,7 +119,7 @@ module.exports = Mn.View.extend({ } } - let clients_to_add = 5 - clients.length; + let clients_to_add = 4 - clients.length; if (clients_to_add) { for (let i = 0; i < clients_to_add; i++) { clients.push({}); From f5ee91aeb3756b824aea32db8bfe72f8d4bb8604 Mon Sep 17 00:00:00 2001 From: Kyle Klaus Date: Mon, 13 Apr 2020 23:31:44 -0700 Subject: [PATCH 10/10] write access list to proxy host config --- backend/internal/access-list.js | 10 +++++----- backend/internal/proxy-host.js | 6 +++--- backend/models/access_list.js | 4 ++++ backend/models/access_list_client.js | 4 ++++ backend/templates/proxy_host.conf | 16 +++++++++++++--- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js index a640c1e2..6de3310a 100644 --- a/backend/internal/access-list.js +++ b/backend/internal/access-list.js @@ -71,7 +71,7 @@ const internalAccessList = { // re-fetch with expansions return internalAccessList.get(access, { id: data.id, - expand: ['owner', 'items', 'clients'] + expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.clients'] }, true /* <- skip masking */); }) .then((row) => { @@ -81,7 +81,7 @@ const internalAccessList = { return internalAccessList.build(row) .then(() => { if (row.proxy_host_count) { - return internalNginx.reload(); + return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts); } }) .then(() => { @@ -216,14 +216,14 @@ const internalAccessList = { // re-fetch with expansions return internalAccessList.get(access, { id: data.id, - expand: ['owner', 'items', 'clients'] + expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.clients'] }, true /* <- skip masking */); }) .then((row) => { return internalAccessList.build(row) .then(() => { if (row.proxy_host_count) { - return internalNginx.reload(); + return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts); } }) .then(() => { @@ -254,7 +254,7 @@ const internalAccessList = { .joinRaw('LEFT JOIN `proxy_host` ON `proxy_host`.`access_list_id` = `access_list`.`id` AND `proxy_host`.`is_deleted` = 0') .where('access_list.is_deleted', 0) .andWhere('access_list.id', data.id) - .allowEager('[owner,items,clients,proxy_hosts]') + .allowEager('[owner,items,clients,proxy_hosts,proxy_hosts.access_list.clients]') .omit(['access_list.is_deleted']) .first(); diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 0e9ced9a..c27d0ddc 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -73,7 +73,7 @@ const internalProxyHost = { // re-fetch with cert return internalProxyHost.get(access, { id: row.id, - expand: ['certificate', 'owner', 'access_list'] + expand: ['certificate', 'owner', 'access_list.clients'] }); }) .then((row) => { @@ -186,7 +186,7 @@ const internalProxyHost = { .then(() => { return internalProxyHost.get(access, { id: data.id, - expand: ['owner', 'certificate', 'access_list'] + expand: ['owner', 'certificate', 'access_list.clients'] }) .then((row) => { // Configure nginx @@ -219,7 +219,7 @@ const internalProxyHost = { .query() .where('is_deleted', 0) .andWhere('id', data.id) - .allowEager('[owner,access_list,certificate]') + .allowEager('[owner,access_list,access_list.clients,certificate]') .first(); if (access_data.permission_visibility !== 'all') { diff --git a/backend/models/access_list.js b/backend/models/access_list.js index 43a2f128..482cfc47 100644 --- a/backend/models/access_list.js +++ b/backend/models/access_list.js @@ -88,6 +88,10 @@ class AccessList extends Model { } }; } + + get satisfy() { + return this.satify_any ? 'satisfy any' : 'satisfy all'; + } } module.exports = AccessList; diff --git a/backend/models/access_list_client.js b/backend/models/access_list_client.js index 1bee2426..0386395c 100644 --- a/backend/models/access_list_client.js +++ b/backend/models/access_list_client.js @@ -49,6 +49,10 @@ class AccessListClient extends Model { } }; } + + get rule() { + return `${this.directive} ${this.address}`; + } } module.exports = AccessListClient; diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf index 6448dca5..0da4bed9 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -21,11 +21,21 @@ server { {% if use_default_location %} location / { - {%- if access_list_id > 0 -%} - # Access List + + {% if access_list_id > 0 %} + # Authorization auth_basic "Authorization required"; auth_basic_user_file /data/access/{{ access_list_id }}; - {%- endif %} + + # Access Rules + {% for client in access_list.clients %} + {{- client.rule -}}; + {% endfor %}deny all; + + # Access checks must... + {{ access_list.satisfy }}; + + {% endif %} {% include "_forced_ssl.conf" %} {% include "_hsts.conf" %}