Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 70 additions & 70 deletions internal/configs/oidc/openid_connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -55,21 +55,21 @@ 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";
if (reply.status == 504) {
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);

Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
}
}
);
}

Expand All @@ -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]);
}
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
Expand All @@ -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');
Expand All @@ -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 {
Expand Down