diff --git a/db/patch-add-other-auth.sql b/db/patch-add-other-auth.sql new file mode 100644 index 000000000..b83f1ee76 --- /dev/null +++ b/db/patch-add-other-auth.sql @@ -0,0 +1,18 @@ +BEGIN TRANSACTION; + + ALTER TABLE monitor + ADD auth_method VARCHAR(250); + + ALTER TABLE monitor + ADD auth_domain TEXT; + ALTER TABLE monitor + + ADD auth_workstation TEXT; + +COMMIT; + +BEGIN TRANSACTION; + UPDATE monitor + SET auth_method = 'basic' + WHERE basic_auth_user is not null; +COMMIT; diff --git a/package-lock.json b/package-lock.json index 481636db3..24f4cca4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "args-parser": "~1.3.0", "axios": "~0.26.1", "axios-cached-dns-resolve": "^3.0.6", + "axios-ntlm": "^1.3.0", "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", @@ -4647,6 +4648,23 @@ "node": ">=14.0.0" } }, + "node_modules/axios-ntlm": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.3.0.tgz", + "integrity": "sha512-NPNsIMO1SGX5scs3ZWJqsV7iRLvET+DlRl94aZ7Sx14zA8RTQh9EDxsJmxB9cKjardKfp2Vge444uYYLfvWC0Q==", + "dependencies": { + "axios": "^0.21.3", + "dev-null": "^0.1.1" + } + }, + "node_modules/axios-ntlm/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -6635,6 +6653,11 @@ "node": ">=8" } }, + "node_modules/dev-null": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", + "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==" + }, "node_modules/devtools-protocol": { "version": "0.0.948846", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.948846.tgz", @@ -22317,6 +22340,25 @@ "pino-pretty": "^7.6.1" } }, + "axios-ntlm": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.3.0.tgz", + "integrity": "sha512-NPNsIMO1SGX5scs3ZWJqsV7iRLvET+DlRl94aZ7Sx14zA8RTQh9EDxsJmxB9cKjardKfp2Vge444uYYLfvWC0Q==", + "requires": { + "axios": "^0.21.3", + "dev-null": "^0.1.1" + }, + "dependencies": { + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + } + } + }, "babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -23843,6 +23885,11 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "dev-null": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", + "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==" + }, "devtools-protocol": { "version": "0.0.948846", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.948846.tgz", diff --git a/package.json b/package.json index 0d555ce8f..ee07c4678 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "args-parser": "~1.3.0", "axios": "~0.26.1", "axios-cached-dns-resolve": "^3.0.6", + "axios-ntlm": "^1.3.0", "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", diff --git a/server/database.js b/server/database.js index 831e99062..c5650808a 100644 --- a/server/database.js +++ b/server/database.js @@ -59,6 +59,7 @@ class Database { "patch-status-page-footer-css.sql": true, "patch-added-mqtt-monitor.sql": true, "patch-add-sqlserver-monitor.sql": true, + "patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] }, }; /** diff --git a/server/model/monitor.js b/server/model/monitor.js index 36df44181..eb8f69009 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -7,7 +7,7 @@ dayjs.extend(timezone); const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); -const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mqttAsync, setSetting } = require("../util-server"); +const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification"); @@ -96,6 +96,9 @@ class Monitor extends BeanModel { mqttSuccessMessage: this.mqttSuccessMessage, databaseConnectionString: this.databaseConnectionString, databaseQuery: this.databaseQuery, + authMethod: this.authMethod, + authWorkstation: this.authWorkstation, + authDomain: this.authDomain, }; if (includeSensitiveData) { @@ -221,7 +224,7 @@ class Monitor extends BeanModel { // HTTP basic auth let basicAuthHeader = {}; - if (this.basic_auth_user) { + if (this.auth_method === "basic") { basicAuthHeader = { "Authorization": "Basic " + this.encodeBase64(this.basic_auth_user, this.basic_auth_pass), }; @@ -272,7 +275,21 @@ class Monitor extends BeanModel { log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`); log.debug("monitor", `[${this.name}] Axios Request`); - let res = await axiosClient.request(options); + let res; + if (this.auth_method === "ntlm") { + options.httpsAgent.keepAlive = true; + + res = await httpNtlm(options, { + username: this.basic_auth_user, + password: this.basic_auth_pass, + domain: this.authDomain, + workstation: this.authWorkstation, + }); + + } else { + res = await axiosClient.request(options); + } + bean.msg = `${res.status} - ${res.statusText}`; bean.ping = dayjs().valueOf() - startTime; diff --git a/server/server.js b/server/server.js index 41ba75336..2a4a5a4db 100644 --- a/server/server.js +++ b/server/server.js @@ -671,6 +671,9 @@ let needSetup = false; bean.mqttSuccessMessage = monitor.mqttSuccessMessage; bean.databaseConnectionString = monitor.databaseConnectionString; bean.databaseQuery = monitor.databaseQuery; + bean.authMethod = monitor.authMethod; + bean.authWorkstation = monitor.authWorkstation; + bean.authDomain = monitor.authDomain; await R.store(bean); @@ -1244,8 +1247,11 @@ let needSetup = false; method: monitorListData[i].method || "GET", body: monitorListData[i].body, headers: monitorListData[i].headers, + authMethod: monitorListData[i].authMethod, basic_auth_user: monitorListData[i].basic_auth_user, basic_auth_pass: monitorListData[i].basic_auth_pass, + authWorkstation: monitorListData[i].authWorkstation, + authDomain: monitorListData[i].authDomain, interval: monitorListData[i].interval, retryInterval: retryInterval, hostname: monitorListData[i].hostname, diff --git a/server/util-server.js b/server/util-server.js index 6c7e49804..87f9151d3 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -11,6 +11,7 @@ const mqtt = require("mqtt"); const chroma = require("chroma-js"); const { badgeConstants } = require("./config"); const mssql = require("mssql"); +const { NtlmClient } = require("axios-ntlm"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -173,6 +174,26 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) { }); }; +/** + * Use NTLM Auth for a http request. + * @param {Object} options The http request options + * @param {Object} ntlmOptions The auth options + * @returns {Promise<(string[]|Object[]|Object)>} + */ +exports.httpNtlm = function (options, ntlmOptions) { + return new Promise((resolve, reject) => { + let client = NtlmClient(ntlmOptions); + + client(options) + .then((resp) => { + resolve(resp); + }) + .catch((err) => { + reject(err); + }); + }); +}; + /** * Resolves a given record using the specified DNS server * @param {string} hostname The hostname of the record to lookup diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index c7a285832..bf0b5655c 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -368,18 +368,46 @@ - -

{{ $t("HTTP Basic Auth") }}

+ +

{{ $t("HTTP Authentication") }}

+
- - + +
+ @@ -569,6 +597,7 @@ export default { mqttPassword: "", mqttTopic: "", mqttSuccessMessage: "", + authMethod: null, }; if (this.$root.proxyList && !this.monitor.proxyId) {