Skip to content

Instantly share code, notes, and snippets.

@Scarbous
Created November 8, 2021 07:28
Show Gist options
  • Save Scarbous/5766ff455e2e6ffe947ea9c0f49cd13c to your computer and use it in GitHub Desktop.
Save Scarbous/5766ff455e2e6ffe947ea9c0f49cd13c to your computer and use it in GitHub Desktop.
Handle nginx njs Digest Auth
http {
resolver 8.8.8.8;
js_path "/etc/nginx/js/";
js_import server.js;
js_var $digest_header;
js_var $digest_path;
location ~ ^/api/getFoo/(\d*) {
limit_except GET { deny all; }
js_content server.getFoo;
}
location ~* ^/service {
internal;
proxy_pass https://target.server.foo$digest_path$is_args$args;
proxy_set_header Host "target.server.foo";
proxy_set_header authorization $digest_header;
}
}
const auth = {
username: 'foo',
password: 'bar'
}
function getFoo(r: NginxHTTPRequest) {
const id = r.uri.split('/')[3];
digestSubrequest(r, '/api/getFoo', {
method: 'GET',
args: `id=${id}`,
},
(res: NginxHTTPRequest) => r.return(res.status, res.responseText)
);
}
function digestSubrequest(r: NginxHTTPRequest, uri: string, options: NginxSubrequestOptions, cb: (reply: NginxHTTPRequest) => void): void {
r.variables.digest_path = uri + (options.args ? '?' + options.args : '');
r.subrequest('/service', options, reply => {
if (reply.status != 401) {
cb(reply);
return;
}
const
header = reply.headersOut['WWW-Authenticate'],
realm = header.match(/realm="([^"]*)/i)[1],
nonce = header.match(/nonce="([^"]*)/i)[1],
qop = header.match(/qop="([^"]*)/i)[1],
opaque = header.match(/opaque="([^"]*)/i)[1];
r.variables.digest_header = digest(r.variables.digest_path, options.method ?? r.method, nonce, realm, qop, opaque);
r.subrequest('/service', options, cb);
});
}
function digest(uri: string, method: string, nonce: string, realm: string, qop: string, opaque: string): string {
const crypto = require('crypto'),
nc = "00000001",
cnonce = (() => {
const characters = 'abcdef0123456789';
var token = '';
for (var i = 0; i < 32; i++) {
token += characters.substr(Math.round(Math.random() * characters.length), 1);
}
return token;
})(),
A1 = crypto.createHash("md5").update(`${auth.username}:${realm}:${auth.password}`).digest('hex'),
A2 = crypto.createHash("md5").update(`${method}:${uri}`).digest('hex'),
response = crypto.createHash("md5").update(`${A1}:${nonce}:${nc}:${cnonce}:${qop}:${A2}`).digest('hex');
return `Digest username="${username}",realm="${realm}",nonce="${nonce}",uri="${uri}",cnonce="${cnonce}",nc=${nc},response="${response}",qop="${qop}",opaque="${opaque}"`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment