Add a field to specify a list of allowed emails when using OpenID Connect auth.

This commit is contained in:
Subv 2020-05-22 15:51:34 -05:00 committed by Jamie Curnow
parent 5811345050
commit cdf702e545
7 changed files with 172 additions and 30 deletions

View File

@ -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');
});
};

View File

@ -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 () {

View File

@ -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
}
}
}
}

View File

@ -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"
},

View File

@ -280,7 +280,7 @@
<label class="custom-switch">
<input type="checkbox" class="custom-switch-input" name="openidc_enabled" value="1"<%- openidc_enabled ? ' checked' : '' %>>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description">Use OpenID Connect authentication <span class="form-required">*</span></span>
<span class="custom-switch-description">Use OpenID Connect authentication</span>
</label>
</div>
</div>
@ -317,6 +317,23 @@
<input type="text" name="openidc_client_secret" class="form-control text-monospace" placeholder="" value="<%- openidc_client_secret %>" autocomplete="off" maxlength="255" required>
</div>
</div>
<div class="openidc">
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="custom-switch">
<input type="checkbox" class="custom-switch-input" name="openidc_restrict_users_enabled" value="1"<%- openidc_restrict_users_enabled ? ' checked' : '' %>>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description">Allow only these user emails</span>
</label>
</div>
</div>
<div class="col-sm-12 col-md-12 openidc_users">
<div class="form-group">
<label class="form-label">Allowed email addresses<span class="form-required">*</span></label>
<input type="text" name="openidc_allowed_users" class="form-control" id="openidc_allowed_users" value="<%- openidc_allowed_users.join(',') %>" required>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -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) {

View File

@ -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: