From 35fdf2e49dd08ad7a56cc9270de19f3cdfd3027f Mon Sep 17 00:00:00 2001 From: HdroguettA Date: Mon, 16 Oct 2023 15:00:49 +1100 Subject: [PATCH 1/2] reattempt request on oauth2 authentication failure --- server/model/monitor.js | 48 ++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 3e595f92ed..c962b53e90 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -401,9 +401,7 @@ class Monitor extends BeanModel { if (this.auth_method === "oauth2-cc") { try { if (this.oauthAccessToken === undefined || new Date(this.oauthAccessToken.expires_at * 1000) <= new Date()) { - log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new one`); - this.oauthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_auth_method); - log.debug("monitor", `[${this.name}] Obtained oauth access-token. Expires at ${new Date(this.oauthAccessToken.expires_at * 1000)}`); + this.oauthAccessToken = await this.makeOidcTokenClientCredentialsRequest(); } oauth2AuthHeader = { "Authorization": this.oauthAccessToken.token_type + " " + this.oauthAccessToken.access_token, @@ -1016,18 +1014,35 @@ class Monitor extends BeanModel { } return res; - } catch (e) { + } catch (error) { + + /** + * Make a single attempt to obtain an new access token in the event that + * the recent api request failed for authentication purposes + */ + if (this.auth_method === "oauth2-cc" && error.response.status === 401 && !options.isReattempt) { + this.oauthAccessToken = await this.makeOidcTokenClientCredentialsRequest(); + let oauth2AuthHeader = { + "Authorization": this.oauthAccessToken.token_type + " " + this.oauthAccessToken.access_token, + }; + options.headers = { ...(options.headers), + ...(oauth2AuthHeader) + }; + options.isReattempt = true; + return this.makeAxiosRequest(options, true); + } + // Fix #2253 // Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining - if (!finalCall && typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) { + if (!finalCall && typeof error.message === "string" && error.message.includes("maxContentLength size of -1 exceeded")) { log.debug("monitor", "makeAxiosRequest with gzip"); options.headers["Accept-Encoding"] = "gzip, deflate"; return this.makeAxiosRequest(options, true); } else { - if (typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) { - e.message = "response timeout: incomplete response within a interval"; + if (typeof error.message === "string" && error.message.includes("maxContentLength size of -1 exceeded")) { + error.message = "response timeout: incomplete response within a interval"; } - throw e; + throw error; } } } @@ -1530,6 +1545,23 @@ class Monitor extends BeanModel { const parentActive = await Monitor.isParentActive(parent.id); return parent.active && parentActive; } + + /** + * Obtains a new Oidc Token + * @returns {Promise} OAuthProvider client + */ + async makeOidcTokenClientCredentialsRequest() { + log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new one`); + const oAuthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_auth_method); + if (this.oauthAccessToken?.expires_at) { + log.debug("monitor", `[${this.name}] Obtained oauth access-token. Expires at ${new Date(this.oauthAccessToken?.expires_at * 1000)}`); + } else { + log.debug("monitor", `[${this.name}] Obtained oauth access-token. Time until expiry was not provided`); + } + + return oAuthAccessToken; + } + } module.exports = Monitor; From 42260f6f121a550d3fe248b1ffb8fe8a0d5e90a2 Mon Sep 17 00:00:00 2001 From: HdroguettA Date: Mon, 11 Dec 2023 09:58:19 +1100 Subject: [PATCH 2/2] utilise existing finalCall logic for reattempt loop prevention --- server/model/monitor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index f6150ad2b1..3979594ea9 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -1022,7 +1022,7 @@ class Monitor extends BeanModel { * Make a single attempt to obtain an new access token in the event that * the recent api request failed for authentication purposes */ - if (this.auth_method === "oauth2-cc" && error.response.status === 401 && !options.isReattempt) { + if (this.auth_method === "oauth2-cc" && error.response.status === 401 && !finalCall) { this.oauthAccessToken = await this.makeOidcTokenClientCredentialsRequest(); let oauth2AuthHeader = { "Authorization": this.oauthAccessToken.token_type + " " + this.oauthAccessToken.access_token, @@ -1030,7 +1030,7 @@ class Monitor extends BeanModel { options.headers = { ...(options.headers), ...(oauth2AuthHeader) }; - options.isReattempt = true; + return this.makeAxiosRequest(options, true); } @@ -1553,7 +1553,7 @@ class Monitor extends BeanModel { * @returns {Promise} OAuthProvider client */ async makeOidcTokenClientCredentialsRequest() { - log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new one`); + log.debug("monitor", `[${this.name}] The oauth access-token undefined or expired. Requesting a new token`); const oAuthAccessToken = await getOidcTokenClientCredentials(this.oauth_token_url, this.oauth_client_id, this.oauth_client_secret, this.oauth_scopes, this.oauth_auth_method); if (this.oauthAccessToken?.expires_at) { log.debug("monitor", `[${this.name}] Obtained oauth access-token. Expires at ${new Date(this.oauthAccessToken?.expires_at * 1000)}`);