diff --git a/internal/configs/oidc/openid_connect.js b/internal/configs/oidc/openid_connect.js index 1ec212643a..68195a3f0a 100644 --- a/internal/configs/oidc/openid_connect.js +++ b/internal/configs/oidc/openid_connect.js @@ -5,7 +5,7 @@ */ var newSession = false; // Used by oidcAuth() and validateIdToken() -export default { auth, codeExchange, validateIdToken, logout }; +export default {auth, codeExchange, validateIdToken, logout}; function retryOriginalRequest(r) { delete r.headersOut["WWW-Authenticate"]; // Remove evidence of original failed auth_jwt @@ -55,7 +55,7 @@ function auth(r, afterSyncCheck) { // Pass the refresh token to the /_refresh location so that it can be // proxied to the IdP in exchange for a new id_token r.subrequest("/_refresh", "token=" + r.variables.refresh_token, - function (reply) { + function(reply) { if (reply.status != 200) { // Refresh request failed, log the reason var error_log = "OIDC refresh failure"; @@ -63,13 +63,13 @@ function auth(r, afterSyncCheck) { error_log += ", timeout waiting for IdP"; } else if (reply.status == 400) { try { - var errorset = JSON.parse(reply.responseBody); + var errorset = JSON.parse(reply.responseText); error_log += ": " + errorset.error + " " + errorset.error_description; } catch (e) { - error_log += ": " + reply.responseBody; + error_log += ": " + reply.responseText; } } else { - error_log += " " + reply.status; + error_log += " " + reply.status; } r.error(error_log); @@ -81,7 +81,7 @@ function auth(r, afterSyncCheck) { // Refresh request returned 200, check response try { - var tokenset = JSON.parse(reply.responseBody); + var tokenset = JSON.parse(reply.responseText); if (!tokenset.id_token) { r.error("OIDC refresh response did not include id_token"); if (tokenset.error) { @@ -94,7 +94,7 @@ function auth(r, afterSyncCheck) { // Send the new ID Token to auth_jwt location for validation r.subrequest("/_id_token_validation", "token=" + tokenset.id_token, - function (reply) { + function(reply) { if (reply.status != 204) { r.variables.refresh_token = "-"; r.return(302, r.variables.request_uri); @@ -103,7 +103,7 @@ function auth(r, afterSyncCheck) { // ID Token is valid, update keyval r.log("OIDC refresh success, updating id_token for " + r.variables.cookie_auth_token); - r.variables.session_jwt = tokenset.id_token; + r.variables.session_jwt = tokenset.id_token; // Update key-value store if (tokenset.access_token) { r.variables.access_token = tokenset.access_token; } else { @@ -142,70 +142,70 @@ function codeExchange(r) { // Pass the authorization code to the /_token location so that it can be // proxied to the IdP in exchange for a JWT - r.subrequest("/_token", idpClientAuth(r), function (reply) { - if (reply.status == 504) { - r.error("OIDC timeout connecting to IdP when sending authorization code"); - r.return(504); - return; - } - - if (reply.status != 200) { - try { - var errorset = JSON.parse(reply.responseBody); - if (errorset.error) { - r.error("OIDC error from IdP when sending authorization code: " + errorset.error + ", " + errorset.error_description); - } else { - r.error("OIDC unexpected response from IdP when sending authorization code (HTTP " + reply.status + "). " + reply.responseBody); - } - } catch (e) { - r.error("OIDC unexpected response from IdP when sending authorization code (HTTP " + reply.status + "). " + reply.responseBody); - } - r.return(502); - return; - } - - // Code exchange returned 200, check for errors - try { - var tokenset = JSON.parse(reply.responseBody); - if (tokenset.error) { - r.error("OIDC " + tokenset.error + " " + tokenset.error_description); - r.return(500); + r.subrequest("/_token",idpClientAuth(r), function(reply) { + if (reply.status == 504) { + r.error("OIDC timeout connecting to IdP when sending authorization code"); + r.return(504); return; } - // Send the ID Token to auth_jwt location for validation - r.subrequest("/_id_token_validation", "token=" + tokenset.id_token, - function (reply) { - if (reply.status != 204) { - r.return(500); // validateIdToken() will log errors - return; - } - - // If the response includes a refresh token then store it - if (tokenset.refresh_token) { - r.variables.new_refresh = tokenset.refresh_token; // Create key-value store entry - r.log("OIDC refresh token stored"); + if (reply.status != 200) { + try { + var errorset = JSON.parse(reply.responseText); + if (errorset.error) { + r.error("OIDC error from IdP when sending authorization code: " + errorset.error + ", " + errorset.error_description); } else { - r.warn("OIDC no refresh token"); + r.error("OIDC unexpected response from IdP when sending authorization code (HTTP " + reply.status + "). " + reply.responseText); } + } catch (e) { + r.error("OIDC unexpected response from IdP when sending authorization code (HTTP " + reply.status + "). " + reply.responseText); + } + r.return(502); + return; + } - // Add opaque token to keyval session store - r.log("OIDC success, creating session " + r.variables.request_id); - r.variables.new_session = tokenset.id_token; // Create key-value store entry - if (tokenset.access_token) { - r.variables.new_access_token = tokenset.access_token; - } else { - r.variables.new_access_token = ""; - } - r.headersOut["Set-Cookie"] = "auth_token=" + r.variables.request_id + "; " + r.variables.oidc_cookie_flags; - r.return(302, r.variables.redirect_base + r.variables.cookie_auth_redir); + // Code exchange returned 200, check for errors + try { + var tokenset = JSON.parse(reply.responseText); + if (tokenset.error) { + r.error("OIDC " + tokenset.error + " " + tokenset.error_description); + r.return(500); + return; } - ); - } catch (e) { - r.error("OIDC authorization code sent but token response is not JSON. " + reply.responseBody); - r.return(502); + + // Send the ID Token to auth_jwt location for validation + r.subrequest("/_id_token_validation", "token=" + tokenset.id_token, + function(reply) { + if (reply.status != 204) { + r.return(500); // validateIdToken() will log errors + return; + } + + // If the response includes a refresh token then store it + if (tokenset.refresh_token) { + r.variables.new_refresh = tokenset.refresh_token; // Create key-value store entry + r.log("OIDC refresh token stored"); + } else { + r.warn("OIDC no refresh token"); + } + + // Add opaque token to keyval session store + r.log("OIDC success, creating session " + r.variables.request_id); + r.variables.new_session = tokenset.id_token; // Create key-value store entry + if (tokenset.access_token) { + r.variables.new_access_token = tokenset.access_token; + } else { + r.variables.new_access_token = ""; + } + r.headersOut["Set-Cookie"] = "auth_token=" + r.variables.request_id + "; " + r.variables.oidc_cookie_flags; + r.return(302, r.variables.redirect_base + r.variables.cookie_auth_redir); + } + ); + } catch (e) { + r.error("OIDC authorization code sent but token response is not JSON. " + reply.responseText); + r.return(502); + } } - } ); } @@ -214,7 +214,7 @@ function validateIdToken(r) { var required_claims = ["iat", "iss", "sub"]; // aud is checked separately var missing_claims = []; for (var i in required_claims) { - if (r.variables["jwt_claim_" + required_claims[i]].length == 0) { + if (r.variables["jwt_claim_" + required_claims[i]].length == 0 ) { missing_claims.push(required_claims[i]); } } @@ -265,8 +265,8 @@ function validateIdToken(r) { function logout(r) { r.log("OIDC logout for " + r.variables.cookie_auth_token); - r.variables.session_jwt = "-"; - r.variables.access_token = "-"; + r.variables.session_jwt = "-"; + r.variables.access_token = "-"; r.variables.refresh_token = "-"; r.return(302, r.variables.oidc_logout_redirect); } @@ -277,7 +277,7 @@ function getAuthZArgs(r) { var c = require('crypto'); var h = c.createHmac('sha256', r.variables.oidc_hmac_key).update(noncePlain); var nonceHash = h.digest('base64url'); - var authZArgs = "?response_type=code&scope=" + r.variables.oidc_scopes + "&client_id=" + r.variables.oidc_client + "&redirect_uri=" + r.variables.redirect_base + r.variables.redir_location + "&nonce=" + nonceHash; + var authZArgs = "?response_type=code&scope=" + r.variables.oidc_scopes + "&client_id=" + r.variables.oidc_client + "&redirect_uri="+ r.variables.redirect_base + r.variables.redir_location + "&nonce=" + nonceHash; if (r.variables.oidc_authz_extra_args) { authZArgs += "&" + r.variables.oidc_authz_extra_args; @@ -288,7 +288,7 @@ function getAuthZArgs(r) { "auth_nonce=" + noncePlain + "; " + r.variables.oidc_cookie_flags ]; - if (r.variables.oidc_pkce_enable == 1) { + if ( r.variables.oidc_pkce_enable == 1 ) { var pkce_code_verifier = c.createHmac('sha256', r.variables.oidc_hmac_key).update(String(Math.random())).digest('hex'); r.variables.pkce_id = c.createHash('sha256').update(String(Math.random())).digest('base64url'); var pkce_code_challenge = c.createHash('sha256').update(pkce_code_verifier).digest('base64url'); @@ -303,7 +303,7 @@ function getAuthZArgs(r) { function idpClientAuth(r) { // If PKCE is enabled we have to use the code_verifier - if (r.variables.oidc_pkce_enable == 1) { + if ( r.variables.oidc_pkce_enable == 1 ) { r.variables.pkce_id = r.variables.arg_state; return "code=" + r.variables.arg_code + "&code_verifier=" + r.variables.pkce_code_verifier; } else {