mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-07-17 15:04:34 +00:00
Add support for adding Client Certificates to access-lists
Client certificate support is added as a new separate type of option for access-lists. This commit is the support code to enable access-lists to contain Client Certificate references.
This commit is contained in:
@ -1,15 +1,16 @@
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const batchflow = require('batchflow');
|
||||
const logger = require('../logger').access;
|
||||
const error = require('../lib/error');
|
||||
const utils = require('../lib/utils');
|
||||
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 _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const batchflow = require('batchflow');
|
||||
const logger = require('../logger').access;
|
||||
const error = require('../lib/error');
|
||||
const utils = require('../lib/utils');
|
||||
const accessListModel = require('../models/access_list');
|
||||
const accessListAuthModel = require('../models/access_list_auth');
|
||||
const accessListClientModel = require('../models/access_list_client');
|
||||
const accessListClientCAsModel = require('../models/access_list_clientcas');
|
||||
const proxyHostModel = require('../models/proxy_host');
|
||||
const internalAuditLog = require('./audit-log');
|
||||
const internalNginx = require('./nginx');
|
||||
|
||||
function omissions () {
|
||||
return ['is_deleted'];
|
||||
@ -66,13 +67,26 @@ const internalAccessList = {
|
||||
});
|
||||
}
|
||||
|
||||
// Now add the client certificate references
|
||||
if (typeof data.clientcas !== 'undefined' && data.clientcas) {
|
||||
data.clientcas.map((certificate_id) => {
|
||||
promises.push(accessListClientCAsModel
|
||||
.query()
|
||||
.insert({
|
||||
access_list_id: row.id,
|
||||
certificate_id: certificate_id
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(() => {
|
||||
// re-fetch with expansions
|
||||
return internalAccessList.get(access, {
|
||||
id: data.id,
|
||||
expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
|
||||
expand: ['owner', 'items', 'clients', 'clientcas', 'proxy_hosts.access_list.[clientcas.certificate,clients,items]']
|
||||
}, true /* <- skip masking */);
|
||||
})
|
||||
.then((row) => {
|
||||
@ -204,6 +218,35 @@ const internalAccessList = {
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// Check for client certificates and add/update/remove them
|
||||
if (typeof data.clientcas !== 'undefined' && data.clientcas) {
|
||||
let promises = [];
|
||||
|
||||
data.clientcas.map(function (certificate_id) {
|
||||
promises.push(accessListClientCAsModel
|
||||
.query()
|
||||
.insert({
|
||||
access_list_id: data.id,
|
||||
certificate_id: certificate_id
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
let query = accessListClientCAsModel
|
||||
.query()
|
||||
.delete()
|
||||
.where('access_list_id', data.id);
|
||||
|
||||
return query
|
||||
.then(() => {
|
||||
// Add new items
|
||||
if (promises.length) {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(internalNginx.reload)
|
||||
.then(() => {
|
||||
// Add to audit log
|
||||
@ -218,7 +261,7 @@ const internalAccessList = {
|
||||
// re-fetch with expansions
|
||||
return internalAccessList.get(access, {
|
||||
id: data.id,
|
||||
expand: ['owner', 'items', 'clients', 'proxy_hosts.[certificate,access_list.[clients,items]]']
|
||||
expand: ['owner', 'items', 'clients', 'clientcas', 'proxy_hosts.[certificate,access_list.[clientcas.certificate,clients,items]]']
|
||||
}, true /* <- skip masking */);
|
||||
})
|
||||
.then((row) => {
|
||||
@ -256,7 +299,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)
|
||||
.allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
|
||||
.withGraphFetched('[owner,items,clients,clientcas,proxy_hosts.[certificate,access_list.[clientcas.certificate,clients,items]]]')
|
||||
.first();
|
||||
|
||||
if (access_data.permission_visibility !== 'all') {
|
||||
@ -294,7 +337,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', 'clients']});
|
||||
return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients', 'clientcas']});
|
||||
})
|
||||
.then((row) => {
|
||||
if (!row) {
|
||||
@ -377,7 +420,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)
|
||||
.groupBy('access_list.id')
|
||||
.allowGraph('[owner,items,clients]')
|
||||
.withGraphFetched('[owner,items,clients,clientcas.certificate]')
|
||||
.orderBy('access_list.name', 'ASC');
|
||||
|
||||
if (access_data.permission_visibility !== 'all') {
|
||||
|
@ -0,0 +1,50 @@
|
||||
const migrate_name = 'client_certificates';
|
||||
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_clientcas', (table) => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('access_list_id').notNull().unsigned();
|
||||
table.integer('certificate_id').notNull().unsigned();
|
||||
table.json('meta').notNull();
|
||||
})
|
||||
.then(function () {
|
||||
logger.info('[' + migrate_name + '] access_list_clientcas Table created');
|
||||
})
|
||||
.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.dropTable('access_list_clientcas')
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] access_list_clientcas Table dropped');
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] Migrating Down Complete');
|
||||
});
|
||||
};
|
@ -1,12 +1,13 @@
|
||||
// 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 AccessListClient = require('./access_list_client');
|
||||
const now = require('./now_helper');
|
||||
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');
|
||||
const AccessListClientCAs = require('./access_list_clientcas');
|
||||
const now = require('./now_helper');
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
@ -68,6 +69,14 @@ class AccessList extends Model {
|
||||
to: 'access_list_client.access_list_id'
|
||||
}
|
||||
},
|
||||
clientcas: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: AccessListClientCAs,
|
||||
join: {
|
||||
from: 'access_list.id',
|
||||
to: 'access_list_clientcas.access_list_id'
|
||||
}
|
||||
},
|
||||
proxy_hosts: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: ProxyHost,
|
||||
|
62
backend/models/access_list_clientcas.js
Normal file
62
backend/models/access_list_clientcas.js
Normal file
@ -0,0 +1,62 @@
|
||||
// Objection Docs:
|
||||
// http://vincit.github.io/objection.js/
|
||||
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
const now = require('./now_helper');
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
class AccessListClientCAs extends Model {
|
||||
$beforeInsert () {
|
||||
this.created_on = now();
|
||||
this.modified_on = now();
|
||||
|
||||
// Default for meta
|
||||
if (typeof this.meta === 'undefined') {
|
||||
this.meta = {};
|
||||
}
|
||||
}
|
||||
|
||||
$beforeUpdate () {
|
||||
this.modified_on = now();
|
||||
}
|
||||
|
||||
static get name () {
|
||||
return 'AccessListClientCAs';
|
||||
}
|
||||
|
||||
static get tableName () {
|
||||
return 'access_list_clientcas';
|
||||
}
|
||||
|
||||
static get jsonAttributes () {
|
||||
return ['meta'];
|
||||
}
|
||||
|
||||
static get relationMappings () {
|
||||
return {
|
||||
access_list: {
|
||||
relation: Model.HasOneRelation,
|
||||
modelClass: require('./access_list'),
|
||||
join: {
|
||||
from: 'access_list_clientcas.access_list_id',
|
||||
to: 'access_list.id'
|
||||
},
|
||||
modify: function (qb) {
|
||||
qb.where('access_list.is_deleted', 0);
|
||||
}
|
||||
},
|
||||
certificate: {
|
||||
relation: Model.HasOneRelation,
|
||||
modelClass: require('./certificate'),
|
||||
join: {
|
||||
from: 'access_list_clientcas.certificate_id',
|
||||
to: 'certificate.id'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AccessListClientCAs;
|
@ -142,6 +142,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clientcas": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"$ref": "#/definitions/meta"
|
||||
}
|
||||
@ -209,6 +216,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clientcas": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Reference in New Issue
Block a user