mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-06-18 18:16:26 +00:00
Compare commits
40 Commits
2bb99e68d8
...
openidc
Author | SHA1 | Date | |
---|---|---|---|
fdb22e467b | |||
694d8a0f21 | |||
63d06da8a8 | |||
b5a0d74654 | |||
99cce7e2b0 | |||
120d50e5c0 | |||
5454fd61b3 | |||
b33012705b | |||
e948b60194 | |||
7913c9a07d | |||
d1c23b6286 | |||
c7e2946dbf | |||
8936402229 | |||
001c77e686 | |||
5578e825b1 | |||
c93656a7a1 | |||
50aeae234f | |||
a5c06c1a34 | |||
51414ced3a | |||
5e35e538af | |||
13fec42d1f | |||
b4560d7dde | |||
6f9eed8a61 | |||
d66e4e03e6 | |||
1d19c29bb0 | |||
e20a11de4a | |||
ef23e796ec | |||
3ce477d350 | |||
12d77e3ab6 | |||
a91dcb144d | |||
e7f7be2a2b | |||
076d89b5b5 | |||
8539930f89 | |||
87d9babbd3 | |||
9f2d3a1737 | |||
daf399163c | |||
cdf702e545 | |||
5811345050 | |||
53792a5cf7 | |||
8e10b7da37 |
@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://nginxproxymanager.com/github.png">
|
<img src="https://nginxproxymanager.com/github.png">
|
||||||
<br><br>
|
<br><br>
|
||||||
<img src="https://img.shields.io/badge/version-2.11.2-green.svg?style=for-the-badge">
|
<img src="https://img.shields.io/badge/version-2.11.3-green.svg?style=for-the-badge">
|
||||||
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
||||||
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
@ -56,7 +56,6 @@ I won't go in to too much detail here but here are the basics for someone new to
|
|||||||
2. Create a docker-compose.yml file similar to this:
|
2. Create a docker-compose.yml file similar to this:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
version: '3.8'
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
image: 'docker.io/jc21/nginx-proxy-manager:latest'
|
image: 'docker.io/jc21/nginx-proxy-manager:latest'
|
||||||
|
@ -861,9 +861,8 @@ const internalCertificate = {
|
|||||||
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
|
||||||
|
|
||||||
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
|
||||||
// Escape single quotes and backslashes
|
fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
|
||||||
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
|
fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
|
||||||
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
|
|
||||||
|
|
||||||
// Whether the plugin has a --<name>-credentials argument
|
// Whether the plugin has a --<name>-credentials argument
|
||||||
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
|
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
|
||||||
@ -898,17 +897,15 @@ const internalCertificate = {
|
|||||||
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
|
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Command:', `${credentialsCmd} && && ${mainCmd}`);
|
logger.info('Command:', mainCmd);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await utils.exec(credentialsCmd);
|
|
||||||
const result = await utils.exec(mainCmd);
|
const result = await utils.exec(mainCmd);
|
||||||
logger.info(result);
|
logger.info(result);
|
||||||
return result;
|
return result;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Don't fail if file does not exist
|
// Don't fail if file does not exist, so no need for action in the callback
|
||||||
const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`;
|
fs.unlink(credentialsLocation, () => {});
|
||||||
await utils.exec(delete_credentialsCmd);
|
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -93,7 +93,7 @@ const generateKeys = () => {
|
|||||||
try {
|
try {
|
||||||
fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
|
fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message);
|
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' + err.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
logger.info('Wrote JWT key pair to config file: ' + keysFile);
|
logger.info('Wrote JWT key pair to config file: ' + keysFile);
|
||||||
|
48
backend/migrations/20200522113248_openid_connect.js
Normal file
48
backend/migrations/20200522113248_openid_connect.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const migrate_name = 'openid_connect';
|
||||||
|
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_enabled').notNull().unsigned().defaultTo(0);
|
||||||
|
proxy_host.text('openidc_redirect_uri').notNull().defaultTo('');
|
||||||
|
proxy_host.text('openidc_discovery').notNull().defaultTo('');
|
||||||
|
proxy_host.text('openidc_auth_method').notNull().defaultTo('');
|
||||||
|
proxy_host.text('openidc_client_id').notNull().defaultTo('');
|
||||||
|
proxy_host.text('openidc_client_secret').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_enabled');
|
||||||
|
proxy_host.dropColumn('openidc_redirect_uri');
|
||||||
|
proxy_host.dropColumn('openidc_discovery');
|
||||||
|
proxy_host.dropColumn('openidc_auth_method');
|
||||||
|
proxy_host.dropColumn('openidc_client_id');
|
||||||
|
proxy_host.dropColumn('openidc_client_secret');
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
logger.info('[' + migrate_name + '] proxy_host Table altered');
|
||||||
|
});
|
||||||
|
};
|
40
backend/migrations/20200522144240_openid_allowed_users.js
Normal file
40
backend/migrations/20200522144240_openid_allowed_users.js
Normal 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');
|
||||||
|
});
|
||||||
|
};
|
@ -20,12 +20,23 @@ class ProxyHost extends Model {
|
|||||||
this.domain_names = [];
|
this.domain_names = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default for openidc_allowed_users
|
||||||
|
if (typeof this.openidc_allowed_users === 'undefined') {
|
||||||
|
this.openidc_allowed_users = [];
|
||||||
|
}
|
||||||
|
|
||||||
// Default for meta
|
// Default for meta
|
||||||
if (typeof this.meta === 'undefined') {
|
if (typeof this.meta === 'undefined') {
|
||||||
this.meta = {};
|
this.meta = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Openidc defaults
|
||||||
|
if (typeof this.openidc_auth_method === 'undefined') {
|
||||||
|
this.openidc_auth_method = 'client_secret_post';
|
||||||
|
}
|
||||||
|
|
||||||
this.domain_names.sort();
|
this.domain_names.sort();
|
||||||
|
this.openidc_allowed_users.sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
$beforeUpdate () {
|
$beforeUpdate () {
|
||||||
@ -35,6 +46,11 @@ class ProxyHost extends Model {
|
|||||||
if (typeof this.domain_names !== 'undefined') {
|
if (typeof this.domain_names !== 'undefined') {
|
||||||
this.domain_names.sort();
|
this.domain_names.sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort openidc_allowed_users
|
||||||
|
if (typeof this.openidc_allowed_users !== 'undefined') {
|
||||||
|
this.openidc_allowed_users.sort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name () {
|
static get name () {
|
||||||
@ -46,7 +62,7 @@ class ProxyHost extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get jsonAttributes () {
|
static get jsonAttributes () {
|
||||||
return ['domain_names', 'meta', 'locations'];
|
return ['domain_names', 'meta', 'locations', 'openidc_allowed_users'];
|
||||||
}
|
}
|
||||||
|
|
||||||
static get relationMappings () {
|
static get relationMappings () {
|
||||||
|
@ -235,6 +235,43 @@
|
|||||||
"description": "Should we cache assets",
|
"description": "Should we cache assets",
|
||||||
"example": true,
|
"example": true,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"openidc_enabled": {
|
||||||
|
"description": "Is OpenID Connect authentication enabled",
|
||||||
|
"example": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"openidc_redirect_uri": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"openidc_discovery": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"openidc_auth_method": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^(client_secret_basic|client_secret_post)$"
|
||||||
|
},
|
||||||
|
"openidc_client_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,30 @@
|
|||||||
"advanced_config": {
|
"advanced_config": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"openidc_enabled": {
|
||||||
|
"$ref": "../definitions.json#/definitions/openidc_enabled"
|
||||||
|
},
|
||||||
|
"openidc_redirect_uri": {
|
||||||
|
"$ref": "../definitions.json#/definitions/openidc_redirect_uri"
|
||||||
|
},
|
||||||
|
"openidc_discovery": {
|
||||||
|
"$ref": "../definitions.json#/definitions/openidc_discovery"
|
||||||
|
},
|
||||||
|
"openidc_auth_method": {
|
||||||
|
"$ref": "../definitions.json#/definitions/openidc_auth_method"
|
||||||
|
},
|
||||||
|
"openidc_client_id": {
|
||||||
|
"$ref": "../definitions.json#/definitions/openidc_client_id"
|
||||||
|
},
|
||||||
|
"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": {
|
"enabled": {
|
||||||
"$ref": "../definitions.json#/definitions/enabled"
|
"$ref": "../definitions.json#/definitions/enabled"
|
||||||
},
|
},
|
||||||
@ -161,6 +185,30 @@
|
|||||||
"advanced_config": {
|
"advanced_config": {
|
||||||
"$ref": "#/definitions/advanced_config"
|
"$ref": "#/definitions/advanced_config"
|
||||||
},
|
},
|
||||||
|
"openidc_enabled": {
|
||||||
|
"$ref": "#/definitions/openidc_enabled"
|
||||||
|
},
|
||||||
|
"openidc_redirect_uri": {
|
||||||
|
"$ref": "#/definitions/openidc_redirect_uri"
|
||||||
|
},
|
||||||
|
"openidc_discovery": {
|
||||||
|
"$ref": "#/definitions/openidc_discovery"
|
||||||
|
},
|
||||||
|
"openidc_auth_method": {
|
||||||
|
"$ref": "#/definitions/openidc_auth_method"
|
||||||
|
},
|
||||||
|
"openidc_client_id": {
|
||||||
|
"$ref": "#/definitions/openidc_client_id"
|
||||||
|
},
|
||||||
|
"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": {
|
"enabled": {
|
||||||
"$ref": "#/definitions/enabled"
|
"$ref": "#/definitions/enabled"
|
||||||
},
|
},
|
||||||
@ -251,6 +299,30 @@
|
|||||||
"advanced_config": {
|
"advanced_config": {
|
||||||
"$ref": "#/definitions/advanced_config"
|
"$ref": "#/definitions/advanced_config"
|
||||||
},
|
},
|
||||||
|
"openidc_enabled": {
|
||||||
|
"$ref": "#/definitions/openidc_enabled"
|
||||||
|
},
|
||||||
|
"openidc_redirect_uri": {
|
||||||
|
"$ref": "#/definitions/openidc_redirect_uri"
|
||||||
|
},
|
||||||
|
"openidc_discovery": {
|
||||||
|
"$ref": "#/definitions/openidc_discovery"
|
||||||
|
},
|
||||||
|
"openidc_auth_method": {
|
||||||
|
"$ref": "#/definitions/openidc_auth_method"
|
||||||
|
},
|
||||||
|
"openidc_client_id": {
|
||||||
|
"$ref": "#/definitions/openidc_client_id"
|
||||||
|
},
|
||||||
|
"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": {
|
"enabled": {
|
||||||
"$ref": "#/definitions/enabled"
|
"$ref": "#/definitions/enabled"
|
||||||
},
|
},
|
||||||
@ -324,6 +396,30 @@
|
|||||||
"advanced_config": {
|
"advanced_config": {
|
||||||
"$ref": "#/definitions/advanced_config"
|
"$ref": "#/definitions/advanced_config"
|
||||||
},
|
},
|
||||||
|
"openidc_enabled": {
|
||||||
|
"$ref": "#/definitions/openidc_enabled"
|
||||||
|
},
|
||||||
|
"openidc_redirect_uri": {
|
||||||
|
"$ref": "#/definitions/openidc_redirect_uri"
|
||||||
|
},
|
||||||
|
"openidc_discovery": {
|
||||||
|
"$ref": "#/definitions/openidc_discovery"
|
||||||
|
},
|
||||||
|
"openidc_auth_method": {
|
||||||
|
"$ref": "#/definitions/openidc_auth_method"
|
||||||
|
},
|
||||||
|
"openidc_client_id": {
|
||||||
|
"$ref": "#/definitions/openidc_client_id"
|
||||||
|
},
|
||||||
|
"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": {
|
"enabled": {
|
||||||
"$ref": "#/definitions/enabled"
|
"$ref": "#/definitions/enabled"
|
||||||
},
|
},
|
||||||
|
@ -21,11 +21,14 @@ const setupDefaultUser = () => {
|
|||||||
.then((row) => {
|
.then((row) => {
|
||||||
if (!row.count) {
|
if (!row.count) {
|
||||||
// Create a new user and set password
|
// Create a new user and set password
|
||||||
logger.info('Creating a new user: admin@example.com with password: changeme');
|
let email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
|
||||||
|
let password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
|
||||||
|
|
||||||
|
logger.info('Creating a new user: ' + email + ' with password: ' + password);
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
is_deleted: 0,
|
is_deleted: 0,
|
||||||
email: 'admin@example.com',
|
email: email,
|
||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
nickname: 'Admin',
|
nickname: 'Admin',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
@ -41,7 +44,7 @@ const setupDefaultUser = () => {
|
|||||||
.insert({
|
.insert({
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
type: 'password',
|
type: 'password',
|
||||||
secret: 'changeme',
|
secret: password,
|
||||||
meta: {},
|
meta: {},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
47
backend/templates/_openid_connect.conf
Normal file
47
backend/templates/_openid_connect.conf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{% if openidc_enabled == 1 or openidc_enabled == true -%}
|
||||||
|
access_by_lua_block {
|
||||||
|
local openidc = require("resty.openidc")
|
||||||
|
local opts = {
|
||||||
|
redirect_uri = "{{- openidc_redirect_uri -}}",
|
||||||
|
discovery = "{{- openidc_discovery -}}",
|
||||||
|
token_endpoint_auth_method = "{{- openidc_auth_method -}}",
|
||||||
|
client_id = "{{- openidc_client_id -}}",
|
||||||
|
client_secret = "{{- openidc_client_secret -}}",
|
||||||
|
scope = "openid email profile"
|
||||||
|
}
|
||||||
|
|
||||||
|
local res, err = openidc.authenticate(opts)
|
||||||
|
|
||||||
|
if err then
|
||||||
|
ngx.status = 500
|
||||||
|
ngx.say(err)
|
||||||
|
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||||
|
end
|
||||||
|
|
||||||
|
{% if openidc_restrict_users_enabled == 1 or openidc_restrict_users_enabled == true -%}
|
||||||
|
local function contains(table, val)
|
||||||
|
for i=1,#table do
|
||||||
|
if table[i] == val then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local allowed_users = {
|
||||||
|
{% for user in openidc_allowed_users %}
|
||||||
|
"{{ user }}",
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
|
||||||
|
if not contains(allowed_users, res.id_token.email) then
|
||||||
|
ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||||
|
end
|
||||||
|
{% endif -%}
|
||||||
|
|
||||||
|
|
||||||
|
ngx.req.set_header("X-OIDC-SUB", res.id_token.sub)
|
||||||
|
ngx.req.set_header("X-OIDC-EMAIL", res.id_token.email)
|
||||||
|
ngx.req.set_header("X-OIDC-NAME", res.id_token.name)
|
||||||
|
}
|
||||||
|
{% endif %}
|
@ -33,8 +33,30 @@ proxy_http_version 1.1;
|
|||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
|
||||||
{% include "_access.conf" %}
|
{% if access_list_id > 0 %}
|
||||||
{% include "_hsts.conf" %}
|
{% if access_list.items.length > 0 %}
|
||||||
|
# Authorization
|
||||||
|
auth_basic "Authorization required";
|
||||||
|
auth_basic_user_file /data/access/{{ access_list_id }};
|
||||||
|
|
||||||
|
{{ access_list.passauth }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Access Rules
|
||||||
|
{% for client in access_list.clients %}
|
||||||
|
{{- client.rule -}};
|
||||||
|
{% endfor %}deny all;
|
||||||
|
|
||||||
|
# Access checks must...
|
||||||
|
{% if access_list.satisfy %}
|
||||||
|
{{ access_list.satisfy }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% include "_openid_connect.conf" %}
|
||||||
|
{% include "_access.conf" %}
|
||||||
|
{% include "_hsts.conf" %}
|
||||||
|
|
||||||
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
@ -448,11 +448,11 @@ brace-expansion@^1.1.7:
|
|||||||
concat-map "0.0.1"
|
concat-map "0.0.1"
|
||||||
|
|
||||||
braces@~3.0.2:
|
braces@~3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
|
||||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.1.1"
|
||||||
|
|
||||||
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
|
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
|
||||||
version "0.2.13"
|
version "0.2.13"
|
||||||
@ -1206,10 +1206,10 @@ file-entry-cache@^6.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache "^3.0.4"
|
flat-cache "^3.0.4"
|
||||||
|
|
||||||
fill-range@^7.0.1:
|
fill-range@^7.1.1:
|
||||||
version "7.0.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
|
||||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range "^5.0.1"
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
@ -1402,9 +1402,9 @@ glob-parent@^6.0.2:
|
|||||||
is-glob "^4.0.3"
|
is-glob "^4.0.3"
|
||||||
|
|
||||||
glob-parent@~5.1.0:
|
glob-parent@~5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
|
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||||
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
|
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||||
dependencies:
|
dependencies:
|
||||||
is-glob "^4.0.1"
|
is-glob "^4.0.1"
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ set $test "";
|
|||||||
if ($scheme = "http") {
|
if ($scheme = "http") {
|
||||||
set $test "H";
|
set $test "H";
|
||||||
}
|
}
|
||||||
if ($request_uri ~ "^\/\.well-known\/acme-challenge\/(.*)") {
|
if ($request_uri = /.well-known/acme-challenge/test-challenge) {
|
||||||
set $test "${test}T";
|
set $test "${test}T";
|
||||||
}
|
}
|
||||||
if ($test = H) {
|
if ($test = H) {
|
||||||
|
4
docker/rootfs/etc/nginx/conf.d/include/log.conf
Normal file
4
docker/rootfs/etc/nginx/conf.d/include/log.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
|
||||||
|
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
|
||||||
|
|
||||||
|
access_log /data/logs/fallback_access.log proxy;
|
@ -14,6 +14,9 @@ error_log /data/logs/fallback_error.log warn;
|
|||||||
# Includes files with directives to load dynamic modules.
|
# Includes files with directives to load dynamic modules.
|
||||||
include /etc/nginx/modules/*.conf;
|
include /etc/nginx/modules/*.conf;
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
include /data/nginx/custom/root_top[.]conf;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
include /data/nginx/custom/events[.]conf;
|
include /data/nginx/custom/events[.]conf;
|
||||||
}
|
}
|
||||||
@ -43,11 +46,23 @@ http {
|
|||||||
proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m;
|
proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m;
|
||||||
proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m;
|
proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m;
|
||||||
|
|
||||||
|
lua_package_path '~/lua/?.lua;;';
|
||||||
|
|
||||||
|
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
|
lua_ssl_verify_depth 5;
|
||||||
|
|
||||||
|
# cache for discovery metadata documents
|
||||||
|
lua_shared_dict discovery 1m;
|
||||||
|
# cache for JWKs
|
||||||
|
lua_shared_dict jwks 1m;
|
||||||
|
|
||||||
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
|
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
|
||||||
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
|
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
|
||||||
|
|
||||||
access_log /data/logs/fallback_access.log proxy;
|
access_log /data/logs/fallback_access.log proxy;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/include/log.conf;
|
||||||
|
|
||||||
# Dynamically generated resolvers file
|
# Dynamically generated resolvers file
|
||||||
include /etc/nginx/conf.d/include/resolvers.conf;
|
include /etc/nginx/conf.d/include/resolvers.conf;
|
||||||
|
|
||||||
|
@ -173,6 +173,7 @@ NPM has the ability to include different custom configuration snippets in differ
|
|||||||
|
|
||||||
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
|
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
|
||||||
|
|
||||||
|
- `/data/nginx/custom/root_top.conf`: Included at the top of nginx.conf
|
||||||
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
|
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
|
||||||
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
|
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
|
||||||
- `/data/nginx/custom/http.conf`: Included at the end of the main http block
|
- `/data/nginx/custom/http.conf`: Included at the end of the main http block
|
||||||
@ -199,6 +200,28 @@ value by specifying it as a Docker environment variable. The default if not spec
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## OpenID Connect SSO
|
||||||
|
|
||||||
|
You can secure any of your proxy hosts with OpenID Connect authentication, providing SSO support from an identity provider like Azure AD or KeyCloak. OpenID Connect support is provided through the [`lua-resty-openidc`](https://github.com/zmartzone/lua-resty-openidc) library of [`OpenResty`](https://github.com/openresty/openresty).
|
||||||
|
|
||||||
|
You will need a few things to get started with OpenID Connect:
|
||||||
|
|
||||||
|
- A registered application with your identity provider, they will provide you with a `Client ID` and a `Client Secret`. Public OpenID Connect applications (without a client secret) are not yet supported.
|
||||||
|
|
||||||
|
- A redirect URL to send the users to after they login with the identity provider, this can be any unused URL under the proxy host, like `https://<proxy host url>/private/callback`, the server will take care of capturing that URL and redirecting you to the proxy host root. You will need to add this URL to the list of allowed redirect URLs for the application you registered with your identity provider.
|
||||||
|
|
||||||
|
- The well-known discovery endpoint of the identity provider you want to use, this is an URL usually with the form `https://<provider URL>/.well-known/openid-configuration`.
|
||||||
|
|
||||||
|
After you have all this you can proceed to configure the proxy host with OpenID Connect authentication.
|
||||||
|
|
||||||
|
You can also add some rudimentary access control through a list of allowed emails in case your identity provider doesn't let you do that, if this option is enabled, any email not on that list will be denied access to the proxied host.
|
||||||
|
|
||||||
|
The proxy adds some headers based on the authentication result from the identity provider:
|
||||||
|
|
||||||
|
- `X-OIDC-SUB`: The subject identifier, according to the OpenID Coonect spec: `A locally unique and never reassigned identifier within the Issuer for the End-User`.
|
||||||
|
- `X-OIDC-EMAIL`: The email of the user that logged in, as specified in the `id_token` returned from the identity provider. The same value that will be checked for the email whitelist.
|
||||||
|
- `X-OIDC-NAME`: The user's name claim from the `id_token`, please note that not all id tokens necessarily contain this claim.
|
||||||
|
|
||||||
## Customising logrotate settings
|
## Customising logrotate settings
|
||||||
|
|
||||||
By default, NPM rotates the access- and error logs weekly and keeps 4 and 10 log files respectively.
|
By default, NPM rotates the access- and error logs weekly and keeps 4 and 10 log files respectively.
|
||||||
@ -212,3 +235,12 @@ You can customise the logrotate configuration through a mount (if your custom co
|
|||||||
```
|
```
|
||||||
|
|
||||||
For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager).
|
For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager).
|
||||||
|
|
||||||
|
## Enabling the geoip2 module
|
||||||
|
|
||||||
|
To enable the geoip2 module, you can create the custom configuration file `/data/nginx/custom/root_top.conf` and include the following snippet:
|
||||||
|
|
||||||
|
```
|
||||||
|
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
|
||||||
|
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
|
||||||
|
```
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<li role="presentation" class="nav-item"><a href="#locations" aria-controls="tab4" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-layers"></i> <%- i18n('all-hosts', 'locations') %></a></li>
|
<li role="presentation" class="nav-item"><a href="#locations" aria-controls="tab4" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-layers"></i> <%- i18n('all-hosts', 'locations') %></a></li>
|
||||||
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
|
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
|
||||||
<li role="presentation" class="nav-item"><a href="#advanced" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('all-hosts', 'advanced') %></a></li>
|
<li role="presentation" class="nav-item"><a href="#advanced" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('all-hosts', 'advanced') %></a></li>
|
||||||
|
<li role="presentation" class="nav-item"><a href="#openidc" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i><%- i18n('proxy-hosts', 'oidc') %></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
|
||||||
@ -271,6 +272,71 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- OpenID Connect -->
|
||||||
|
<div role="tabpanel" class="tab-pane" id="openidc">
|
||||||
|
<div class="row">
|
||||||
|
<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_enabled" value="1"<%- openidc_enabled ? ' checked' : '' %>>
|
||||||
|
<span class="custom-switch-indicator"></span>
|
||||||
|
<span class="custom-switch-description"><%- i18n('proxy-hosts', 'oidc-enabled') %></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-redirect-uri') %><span class="form-required">*</span></label>
|
||||||
|
<input type="text" name="openidc_redirect_uri" class="form-control text-monospace" placeholder="" value="<%- openidc_redirect_uri %>" autocomplete="off" maxlength="255" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-discovery-endpoint') %><span class="form-required">*</span></label>
|
||||||
|
<input type="text" name="openidc_discovery" class="form-control text-monospace" placeholder="" value="<%- openidc_discovery %>" autocomplete="off" maxlength="255" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-token-auth-method') %><span class="form-required">*</span></label>
|
||||||
|
<select name="openidc_auth_method" class="form-control custom-select" placeholder="client_secret_post">
|
||||||
|
<option value="client_secret_post" <%- openidc_auth_method === 'client_secret_post' ? 'selected' : '' %>>client_secret_post</option>
|
||||||
|
<option value="client_secret_basic" <%- openidc_auth_method === 'client_secret_basic' ? 'selected' : '' %>>client_secret_basic</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-client-id') %><span class="form-required">*</span></label>
|
||||||
|
<input type="text" name="openidc_client_id" class="form-control text-monospace" placeholder="" value="<%- openidc_client_id %>" autocomplete="off" maxlength="255" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-client-secret') %><span class="form-required">*</span></label>
|
||||||
|
<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"><%- i18n('proxy-hosts', 'oidc-allow-only-emails') %></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-12 openidc_users">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%- i18n('proxy-hosts', 'oidc-allowed-emails') %><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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,29 +21,34 @@ module.exports = Mn.View.extend({
|
|||||||
locationsCollection: new ProxyLocationModel.Collection(),
|
locationsCollection: new ProxyLocationModel.Collection(),
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
form: 'form',
|
form: 'form',
|
||||||
domain_names: 'input[name="domain_names"]',
|
domain_names: 'input[name="domain_names"]',
|
||||||
forward_host: 'input[name="forward_host"]',
|
forward_host: 'input[name="forward_host"]',
|
||||||
buttons: '.modal-footer button',
|
buttons: '.modal-footer button',
|
||||||
cancel: 'button.cancel',
|
cancel: 'button.cancel',
|
||||||
save: 'button.save',
|
save: 'button.save',
|
||||||
add_location_btn: 'button.add_location',
|
add_location_btn: 'button.add_location',
|
||||||
locations_container: '.locations_container',
|
locations_container: '.locations_container',
|
||||||
le_error_info: '#le-error-info',
|
le_error_info: '#le-error-info',
|
||||||
certificate_select: 'select[name="certificate_id"]',
|
certificate_select: 'select[name="certificate_id"]',
|
||||||
access_list_select: 'select[name="access_list_id"]',
|
access_list_select: 'select[name="access_list_id"]',
|
||||||
ssl_forced: 'input[name="ssl_forced"]',
|
ssl_forced: 'input[name="ssl_forced"]',
|
||||||
hsts_enabled: 'input[name="hsts_enabled"]',
|
hsts_enabled: 'input[name="hsts_enabled"]',
|
||||||
hsts_subdomains: 'input[name="hsts_subdomains"]',
|
hsts_subdomains: 'input[name="hsts_subdomains"]',
|
||||||
http2_support: 'input[name="http2_support"]',
|
http2_support: 'input[name="http2_support"]',
|
||||||
dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
|
dns_challenge_switch: 'input[name="meta[dns_challenge]"]',
|
||||||
dns_challenge_content: '.dns-challenge',
|
dns_challenge_content: '.dns-challenge',
|
||||||
dns_provider: 'select[name="meta[dns_provider]"]',
|
dns_provider: 'select[name="meta[dns_provider]"]',
|
||||||
credentials_file_content: '.credentials-file-content',
|
credentials_file_content: '.credentials-file-content',
|
||||||
dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
|
dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]',
|
||||||
propagation_seconds: 'input[name="meta[propagation_seconds]"]',
|
propagation_seconds: 'input[name="meta[propagation_seconds]"]',
|
||||||
forward_scheme: 'select[name="forward_scheme"]',
|
forward_scheme: 'select[name="forward_scheme"]',
|
||||||
letsencrypt: '.letsencrypt'
|
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: {
|
regions: {
|
||||||
@ -113,7 +118,7 @@ module.exports = Mn.View.extend({
|
|||||||
} else {
|
} else {
|
||||||
this.ui.dns_provider.prop('required', false);
|
this.ui.dns_provider.prop('required', false);
|
||||||
this.ui.dns_provider_credentials.prop('required', false);
|
this.ui.dns_provider_credentials.prop('required', false);
|
||||||
this.ui.dns_challenge_content.hide();
|
this.ui.dns_challenge_content.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -125,13 +130,34 @@ module.exports = Mn.View.extend({
|
|||||||
this.ui.credentials_file_content.show();
|
this.ui.credentials_file_content.show();
|
||||||
} else {
|
} else {
|
||||||
this.ui.dns_provider_credentials.prop('required', false);
|
this.ui.dns_provider_credentials.prop('required', false);
|
||||||
this.ui.credentials_file_content.hide();
|
this.ui.credentials_file_content.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'change @ui.openidc_enabled': function () {
|
||||||
|
let checked = this.ui.openidc_enabled.prop('checked');
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
this.ui.openidc.show().find('input').prop('disabled', false);
|
||||||
|
} else {
|
||||||
|
this.ui.openidc.hide().find('input').prop('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.openidc_restrict_users_enabled.trigger('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
'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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'click @ui.add_location_btn': function (e) {
|
'click @ui.add_location_btn': function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const model = new ProxyLocationModel.Model();
|
const model = new ProxyLocationModel.Model();
|
||||||
this.locationsCollection.add(model);
|
this.locationsCollection.add(model);
|
||||||
},
|
},
|
||||||
@ -167,17 +193,25 @@ module.exports = Mn.View.extend({
|
|||||||
data.hsts_enabled = !!data.hsts_enabled;
|
data.hsts_enabled = !!data.hsts_enabled;
|
||||||
data.hsts_subdomains = !!data.hsts_subdomains;
|
data.hsts_subdomains = !!data.hsts_subdomains;
|
||||||
data.ssl_forced = !!data.ssl_forced;
|
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 = {};
|
if (typeof data.meta === 'undefined') data.meta = {};
|
||||||
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
|
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
|
||||||
data.meta.dns_challenge = data.meta.dns_challenge == 1;
|
data.meta.dns_challenge = data.meta.dns_challenge == 1;
|
||||||
|
|
||||||
if(!data.meta.dns_challenge){
|
if(!data.meta.dns_challenge){
|
||||||
data.meta.dns_provider = undefined;
|
data.meta.dns_provider = undefined;
|
||||||
data.meta.dns_provider_credentials = undefined;
|
data.meta.dns_provider_credentials = undefined;
|
||||||
data.meta.propagation_seconds = undefined;
|
data.meta.propagation_seconds = undefined;
|
||||||
} else {
|
} else {
|
||||||
if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
|
if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof data.domain_names === 'string' && data.domain_names) {
|
if (typeof data.domain_names === 'string' && data.domain_names) {
|
||||||
@ -185,7 +219,7 @@ module.exports = Mn.View.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for any domain names containing wildcards, which are not allowed with letsencrypt
|
// Check for any domain names containing wildcards, which are not allowed with letsencrypt
|
||||||
if (data.certificate_id === 'new') {
|
if (data.certificate_id === 'new') {
|
||||||
let domain_err = false;
|
let domain_err = false;
|
||||||
if (!data.meta.dns_challenge) {
|
if (!data.meta.dns_challenge) {
|
||||||
data.domain_names.map(function (name) {
|
data.domain_names.map(function (name) {
|
||||||
@ -203,6 +237,12 @@ module.exports = Mn.View.extend({
|
|||||||
data.certificate_id = parseInt(data.certificate_id, 10);
|
data.certificate_id = parseInt(data.certificate_id, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenID Connect won't work with multiple domain names because the redirect URL has to point to a specific one
|
||||||
|
if (data.openidc_enabled && data.domain_names.length > 1) {
|
||||||
|
alert('Cannot use mutliple domain names when OpenID Connect is enabled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let method = App.Api.Nginx.ProxyHosts.create;
|
let method = App.Api.Nginx.ProxyHosts.create;
|
||||||
let is_new = true;
|
let is_new = true;
|
||||||
|
|
||||||
@ -344,6 +384,23 @@ module.exports = Mn.View.extend({
|
|||||||
view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
|
view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// OpenID Connect
|
||||||
|
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) {
|
initialize: function (options) {
|
||||||
|
@ -132,6 +132,16 @@
|
|||||||
"access-list": "Access List",
|
"access-list": "Access List",
|
||||||
"allow-websocket-upgrade": "Websockets Support",
|
"allow-websocket-upgrade": "Websockets Support",
|
||||||
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL",
|
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL",
|
||||||
|
"custom-forward-host-help": "Use 1.1.1.1/path for sub-folder forwarding",
|
||||||
|
"oidc": "OpenID Connect",
|
||||||
|
"oidc-enabled": "Use OpenID Connect authentication",
|
||||||
|
"oidc-redirect-uri": "Redirect URI",
|
||||||
|
"oidc-discovery-endpoint": "Well-known discovery endpoint",
|
||||||
|
"oidc-token-auth-method": "Token endpoint auth method",
|
||||||
|
"oidc-client-id": "Client ID",
|
||||||
|
"oidc-client-secret": "Client secret",
|
||||||
|
"oidc-allow-only-emails": "Allow only these user emails",
|
||||||
|
"oidc-allowed-emails": "Allowed email addresses",
|
||||||
"custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/",
|
"custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/",
|
||||||
"search": "Search Host…"
|
"search": "Search Host…"
|
||||||
},
|
},
|
||||||
|
@ -22,6 +22,14 @@ const model = Backbone.Model.extend({
|
|||||||
block_exploits: false,
|
block_exploits: false,
|
||||||
http2_support: false,
|
http2_support: false,
|
||||||
advanced_config: '',
|
advanced_config: '',
|
||||||
|
openidc_enabled: false,
|
||||||
|
openidc_redirect_uri: '',
|
||||||
|
openidc_discovery: '',
|
||||||
|
openidc_auth_method: 'client_secret_post',
|
||||||
|
openidc_client_id: '',
|
||||||
|
openidc_client_secret: '',
|
||||||
|
openidc_restrict_users_enabled: false,
|
||||||
|
openidc_allowed_users: [],
|
||||||
enabled: true,
|
enabled: true,
|
||||||
meta: {},
|
meta: {},
|
||||||
// The following are expansions:
|
// The following are expansions:
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"package_name": "certbot-dns-cloudflare",
|
"package_name": "certbot-dns-cloudflare",
|
||||||
"version": "=={{certbot-version}}",
|
"version": "=={{certbot-version}}",
|
||||||
"dependencies": "cloudflare==2.19.* acme=={{certbot-version}}",
|
"dependencies": "cloudflare==2.19.* acme=={{certbot-version}}",
|
||||||
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567",
|
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567",
|
||||||
"full_plugin_name": "dns-cloudflare"
|
"full_plugin_name": "dns-cloudflare"
|
||||||
},
|
},
|
||||||
"cloudns": {
|
"cloudns": {
|
||||||
@ -239,6 +239,14 @@
|
|||||||
"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
|
"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
|
||||||
"full_plugin_name": "dns-hetzner"
|
"full_plugin_name": "dns-hetzner"
|
||||||
},
|
},
|
||||||
|
"hover": {
|
||||||
|
"name": "Hover",
|
||||||
|
"package_name": "certbot-dns-hover",
|
||||||
|
"version": "~=1.2.1",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_hover_hoverurl = https://www.hover.com\ndns_hover_username = hover-admin-username\ndns_hover_password = hover-admin-password\ndns_hover_totpsecret = 2fa-totp-secret",
|
||||||
|
"full_plugin_name": "dns-hover"
|
||||||
|
},
|
||||||
"infomaniak": {
|
"infomaniak": {
|
||||||
"name": "Infomaniak",
|
"name": "Infomaniak",
|
||||||
"package_name": "certbot-dns-infomaniak",
|
"package_name": "certbot-dns-infomaniak",
|
||||||
@ -454,5 +462,13 @@
|
|||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "dns_websupport_identifier = <api_key>\ndns_websupport_secret_key = <secret>",
|
"credentials": "dns_websupport_identifier = <api_key>\ndns_websupport_secret_key = <secret>",
|
||||||
"full_plugin_name": "dns-websupport"
|
"full_plugin_name": "dns-websupport"
|
||||||
|
},
|
||||||
|
"wedos":{
|
||||||
|
"name": "Wedos",
|
||||||
|
"package_name": "certbot-dns-wedos",
|
||||||
|
"version": "~=2.2",
|
||||||
|
"dependencies": "",
|
||||||
|
"credentials": "dns_wedos_user = <wedos_registration>\ndns_wedos_auth = <wapi_sha256_password>",
|
||||||
|
"full_plugin_name": "dns-wedos"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user