diff --git a/backend/migrations/20200522144240_openid_allowed_users.js b/backend/migrations/20200522144240_openid_allowed_users.js
new file mode 100644
index 0000000..9b4e0aa
--- /dev/null
+++ b/backend/migrations/20200522144240_openid_allowed_users.js
@@ -0,0 +1,40 @@
+const migrate_name = 'openid_allowed_users';
+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('openidc_restrict_users_enabled').notNull().unsigned().defaultTo(0);
+ proxy_host.json('openidc_allowed_users').notNull().defaultTo([]);
+ })
+ .then(() => {
+ logger.info('[' + migrate_name + '] proxy_host Table altered');
+ });
+};
+
+/**
+ * Undo Migrate
+ *
+ * @param {Object} knex
+ * @param {Promise} Promise
+ * @returns {Promise}
+ */
+exports.down = function (knex/*, Promise*/) {
+ return knex.schema.table('proxy_host', function (proxy_host) {
+ proxy_host.dropColumn('openidc_restrict_users_enabled');
+ proxy_host.dropColumn('openidc_allowed_users');
+ })
+ .then(() => {
+ logger.info('[' + migrate_name + '] proxy_host Table altered');
+ });
+};
diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js
index a758308..e86b802 100644
--- a/backend/models/proxy_host.js
+++ b/backend/models/proxy_host.js
@@ -20,12 +20,18 @@ class ProxyHost extends Model {
this.domain_names = [];
}
+ // Default for openidc_allowed_users
+ if (typeof this.openidc_allowed_users === 'undefined') {
+ this.openidc_allowed_users = [];
+ }
+
// Default for meta
if (typeof this.meta === 'undefined') {
this.meta = {};
}
this.domain_names.sort();
+ this.openidc_allowed_users.sort();
}
$beforeUpdate () {
@@ -35,6 +41,11 @@ class ProxyHost extends Model {
if (typeof this.domain_names !== 'undefined') {
this.domain_names.sort();
}
+
+ // Sort openidc_allowed_users
+ if (typeof this.openidc_allowed_users !== 'undefined') {
+ this.openidc_allowed_users.sort();
+ }
}
static get name () {
@@ -46,7 +57,7 @@ class ProxyHost extends Model {
}
static get jsonAttributes () {
- return ['domain_names', 'meta', 'locations'];
+ return ['domain_names', 'meta', 'locations', 'openidc_allowed_users'];
}
static get relationMappings () {
diff --git a/backend/schema/definitions.json b/backend/schema/definitions.json
index 87db39a..eda3605 100644
--- a/backend/schema/definitions.json
+++ b/backend/schema/definitions.json
@@ -256,6 +256,22 @@
},
"openidc_client_secret": {
"type": "string"
+ },
+ "openidc_restrict_users_enabled": {
+ "description": "Only allow a specific set of OpenID Connect emails to access the resource",
+ "example": true,
+ "type": "boolean"
+ },
+ "openidc_allowed_users": {
+ "type": "array",
+ "minItems": 0,
+ "items": {
+ "type": "string",
+ "description": "Email Address",
+ "example": "john@example.com",
+ "format": "email",
+ "minLength": 1
+ }
}
}
}
diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json
index 849a0f7..1186225 100644
--- a/backend/schema/endpoints/proxy-hosts.json
+++ b/backend/schema/endpoints/proxy-hosts.json
@@ -82,6 +82,12 @@
"openidc_client_secret": {
"$ref": "../definitions.json#/definitions/openidc_client_secret"
},
+ "openidc_restrict_users_enabled": {
+ "$ref": "../definitions.json#/definitions/openidc_restrict_users_enabled"
+ },
+ "openidc_allowed_users": {
+ "$ref": "../definitions.json#/definitions/openidc_allowed_users"
+ },
"enabled": {
"$ref": "../definitions.json#/definitions/enabled"
},
@@ -197,6 +203,12 @@
"openidc_client_secret": {
"$ref": "#/definitions/openidc_client_secret"
},
+ "openidc_restrict_users_enabled": {
+ "$ref": "#/definitions/openidc_restrict_users_enabled"
+ },
+ "openidc_allowed_users": {
+ "$ref": "#/definitions/openidc_allowed_users"
+ },
"enabled": {
"$ref": "#/definitions/enabled"
},
@@ -305,6 +317,12 @@
"openidc_client_secret": {
"$ref": "#/definitions/openidc_client_secret"
},
+ "openidc_restrict_users_enabled": {
+ "$ref": "#/definitions/openidc_restrict_users_enabled"
+ },
+ "openidc_allowed_users": {
+ "$ref": "#/definitions/openidc_allowed_users"
+ },
"enabled": {
"$ref": "#/definitions/enabled"
},
@@ -396,6 +414,12 @@
"openidc_client_secret": {
"$ref": "#/definitions/openidc_client_secret"
},
+ "openidc_restrict_users_enabled": {
+ "$ref": "#/definitions/openidc_restrict_users_enabled"
+ },
+ "openidc_allowed_users": {
+ "$ref": "#/definitions/openidc_allowed_users"
+ },
"enabled": {
"$ref": "#/definitions/enabled"
},
diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs
index 36b62bb..41acf6c 100644
--- a/frontend/js/app/nginx/proxy/form.ejs
+++ b/frontend/js/app/nginx/proxy/form.ejs
@@ -280,7 +280,7 @@
@@ -317,6 +317,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js
index b72457a..16278eb 100644
--- a/frontend/js/app/nginx/proxy/form.js
+++ b/frontend/js/app/nginx/proxy/form.js
@@ -21,31 +21,34 @@ module.exports = Mn.View.extend({
locationsCollection: new ProxyLocationModel.Collection(),
ui: {
- form: 'form',
- domain_names: 'input[name="domain_names"]',
- forward_host: 'input[name="forward_host"]',
- buttons: '.modal-footer button',
- cancel: 'button.cancel',
- save: 'button.save',
- add_location_btn: 'button.add_location',
- locations_container: '.locations_container',
- le_error_info: '#le-error-info',
- certificate_select: 'select[name="certificate_id"]',
- access_list_select: 'select[name="access_list_id"]',
- ssl_forced: 'input[name="ssl_forced"]',
- hsts_enabled: 'input[name="hsts_enabled"]',
- hsts_subdomains: 'input[name="hsts_subdomains"]',
- http2_support: 'input[name="http2_support"]',
- dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
- dns_challenge_content: '.dns-challenge',
- dns_provider: 'select[name="meta[dns_provider]"]',
- credentials_file_content: '.credentials-file-content',
- dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
- propagation_seconds: 'input[name="meta[propagation_seconds]"]',
- forward_scheme: 'select[name="forward_scheme"]',
- letsencrypt: '.letsencrypt',
- openidc_enabled: 'input[name="openidc_enabled"]',
- openidc: '.openidc'
+ form: 'form',
+ domain_names: 'input[name="domain_names"]',
+ forward_host: 'input[name="forward_host"]',
+ buttons: '.modal-footer button',
+ cancel: 'button.cancel',
+ save: 'button.save',
+ add_location_btn: 'button.add_location',
+ locations_container: '.locations_container',
+ le_error_info: '#le-error-info',
+ certificate_select: 'select[name="certificate_id"]',
+ access_list_select: 'select[name="access_list_id"]',
+ ssl_forced: 'input[name="ssl_forced"]',
+ hsts_enabled: 'input[name="hsts_enabled"]',
+ hsts_subdomains: 'input[name="hsts_subdomains"]',
+ http2_support: 'input[name="http2_support"]',
+ dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
+ dns_challenge_content: '.dns-challenge',
+ dns_provider: 'select[name="meta[dns_provider]"]',
+ credentials_file_content: '.credentials-file-content',
+ dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
+ propagation_seconds: 'input[name="meta[propagation_seconds]"]',
+ forward_scheme: 'select[name="forward_scheme"]',
+ letsencrypt: '.letsencrypt',
+ openidc_enabled: 'input[name="openidc_enabled"]',
+ openidc_restrict_users_enabled: 'input[name="openidc_restrict_users_enabled"]',
+ openidc_allowed_users: 'input[name="openidc_allowed_users"]',
+ openidc: '.openidc',
+ openidc_users: '.openidc_users',
},
regions: {
@@ -135,9 +138,18 @@ module.exports = Mn.View.extend({
let checked = this.ui.openidc_enabled.prop('checked');
if (checked) {
- this.ui.openidc.show().find('input').prop('required', true);
+ this.ui.openidc.show().find('input').prop('disabled', false);
} else {
- this.ui.openidc.hide().find('input').prop('required', false);
+ this.ui.openidc.hide().find('input').prop('disabled', true);
+ }
+ },
+
+ 'change @ui.openidc_restrict_users_enabled': function () {
+ let checked = this.ui.openidc_restrict_users_enabled.prop('checked');
+ if (checked) {
+ this.ui.openidc_users.show().find('input').prop('disabled', false);
+ } else {
+ this.ui.openidc_users.hide().find('input').prop('disabled', true);
}
},
@@ -180,6 +192,13 @@ module.exports = Mn.View.extend({
data.hsts_subdomains = !!data.hsts_subdomains;
data.ssl_forced = !!data.ssl_forced;
data.openidc_enabled = data.openidc_enabled === '1';
+ data.openidc_restrict_users_enabled = data.openidc_restrict_users_enabled === '1';
+
+ if (data.openidc_restrict_users_enabled) {
+ if (typeof data.openidc_allowed_users === 'string' && data.openidc_allowed_users) {
+ data.openidc_allowed_users = data.openidc_allowed_users.split(',');
+ }
+ }
if (typeof data.meta === 'undefined') data.meta = {};
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
@@ -365,8 +384,21 @@ module.exports = Mn.View.extend({
});
// OpenID Connect
- this.ui.openidc.hide().find('input').prop('required', false);
+ this.ui.openidc_allowed_users.selectize({
+ delimiter: ',',
+ persist: false,
+ maxOptions: 15,
+ create: function (input) {
+ return {
+ value: input,
+ text: input
+ };
+ }
+ });
+ this.ui.openidc.hide().find('input').prop('disabled', true);
+ this.ui.openidc_users.hide().find('input').prop('disabled', true);
this.ui.openidc_enabled.trigger('change');
+ this.ui.openidc_restrict_users_enabled.trigger('change');
},
initialize: function (options) {
diff --git a/frontend/js/models/proxy-host.js b/frontend/js/models/proxy-host.js
index ef1f1f4..85429d1 100644
--- a/frontend/js/models/proxy-host.js
+++ b/frontend/js/models/proxy-host.js
@@ -28,6 +28,8 @@ const model = Backbone.Model.extend({
openidc_auth_method: 'client_secret_post',
openidc_client_id: '',
openidc_client_secret: '',
+ openidc_restrict_users_enabled: false,
+ openidc_allowed_users: [],
enabled: true,
meta: {},
// The following are expansions: