From b1befbc2eb04a7a1eeabb5b1c24cc8e80112531a Mon Sep 17 00:00:00 2001 From: Steve Biondi Date: Mon, 22 Sep 2025 08:47:04 -0700 Subject: [PATCH 1/3] Remove fixed files, will re-create with commits to show changes. --- lib/www-authenticate/md5.js | 7 - lib/www-authenticate/parsers.js | 109 ------------ lib/www-authenticate/user-credentials.js | 46 ----- lib/www-authenticate/www-authenticate.js | 218 ----------------------- 4 files changed, 380 deletions(-) delete mode 100644 lib/www-authenticate/md5.js delete mode 100644 lib/www-authenticate/parsers.js delete mode 100644 lib/www-authenticate/user-credentials.js delete mode 100644 lib/www-authenticate/www-authenticate.js diff --git a/lib/www-authenticate/md5.js b/lib/www-authenticate/md5.js deleted file mode 100644 index 3e6de8bf..00000000 --- a/lib/www-authenticate/md5.js +++ /dev/null @@ -1,7 +0,0 @@ -var crypto= require('crypto'); - -function md5(s) { - return crypto.createHash('md5').update(s).digest('hex'); -} - -module.exports= md5; \ No newline at end of file diff --git a/lib/www-authenticate/parsers.js b/lib/www-authenticate/parsers.js deleted file mode 100644 index 65e2be1d..00000000 --- a/lib/www-authenticate/parsers.js +++ /dev/null @@ -1,109 +0,0 @@ -var ParseAuth= /(\w+)\s+(.*)/ // -> scheme, params - , Separators= /([",=])/ - ; - -function parse_params(header) { - // This parser will definitely fail if there is more than one challenge - var tok, last_tok, _i, _len, key, value; - var state= 0; //0: token, - var m= header.split(Separators) - for (_i = 0, _len = m.length; _i < _len; _i++) { - last_tok= tok; - tok = m[_i]; - if (!tok.length) continue; - switch (state) { - case 0: // token - key= tok.trim(); - state= 1; // expect equals - continue; - case 1: // expect equals - if ('=' != tok) return 'Equal sign was expected after '+key; - state= 2; - continue; - case 2: // expect value - if ('"' == tok) { - value= ''; - state= 3; // expect quoted - continue; - } - else { - this.parms[key]= value= tok.trim(); - state= 9; // expect comma or end - continue; - } - case 3: // handling quoted string - if ('"' == tok) { - state= 8; // end quoted - continue; - } - else { - value+= tok; - state= 3; // continue accumulating quoted string - continue; - } - case 8: // end quote encountered - if ('"' == tok) { - // double quoted - value+= '"'; - state= 3; // back to quoted string - continue; - } - if (',' == tok) { - this.parms[key]= value; - state= 0; - continue; - } - else { - return 'Unexpected token ('+tok+') after '+value+'"'; - } - continue; - case 9: // expect commma - if (',' != tok) return 'Comma expected after '+value; - state= 0; - continue; - } - } - switch (state) { // terminal state - case 0: // Empty or ignoring terminal comma - case 9: // Expecting comma or end of header - return; - case 8: // Last token was end quote - this.parms[key]= value; - return; - default: - return 'Unexpected end of www-authenticate value.'; - } -} - -function Parse_WWW_Authenticate(to_parse) -{ - var m= to_parse.match(ParseAuth); - this.scheme= m[1]; - this.parms= {}; - var err= this.parse_params(m[2]); - if (err) { - this.scheme= ''; - this.parms= {}; - this.err= err; - } -} - -function Parse_Authentication_Info(to_parse) -{ - this.scheme= 'Digest'; - this.parms= {}; - var err= this.parse_params(to_parse); - if (err) { - this.scheme= ''; - this.parms= {}; - this.err= err; - } -} - -Parse_Authentication_Info.prototype.parse_params= parse_params; -Parse_WWW_Authenticate.prototype.parse_params= parse_params; - -module.exports = { - WWW_Authenticate: Parse_WWW_Authenticate, - Authentication_Info: Parse_Authentication_Info -}; diff --git a/lib/www-authenticate/user-credentials.js b/lib/www-authenticate/user-credentials.js deleted file mode 100644 index 25bc405d..00000000 --- a/lib/www-authenticate/user-credentials.js +++ /dev/null @@ -1,46 +0,0 @@ -var md5= require('./md5'); - -/* - * Hide the password. Uses the password to form authorization strings, - * but provides no interface for exporting it. - */ -function user_credentials(username,password,options) { - if (username.is_user_credentials && - typeof username.basic === 'function' && - typeof username.digest === 'function' - ) { - return username; - } - - var basic_string= options && options.hide_basic ? - '' - : - (!password && password !== '' ? - Buffer.from(username, "ascii").toString("base64") - : - Buffer.from(username+':'+password, "ascii").toString("base64") - ) - function Credentials() - { - this.username= username; - } - Credentials.prototype.basic= function() - { - return basic_string; - } - Credentials.prototype.digest= function(realm) - { - return !password && password !== '' ? - md5(username+':'+realm) - : - md5(username+':'+realm+':'+password) - } - Credentials.prototype.is_user_credentials= function() - { - return true; - } - - return new Credentials; -} - -module.exports= user_credentials; diff --git a/lib/www-authenticate/www-authenticate.js b/lib/www-authenticate/www-authenticate.js deleted file mode 100644 index f09c16ba..00000000 --- a/lib/www-authenticate/www-authenticate.js +++ /dev/null @@ -1,218 +0,0 @@ -/* - * www-authenticate - * https://github.com/randymized/www-authenticate - * - * Copyright (c) 2013 Randy McLaughlin - * Licensed under the MIT license. - */ - -/* -* Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. -*/ - -'use strict'; - -var crypto= require('crypto') - , parsers= require('./parsers') - , md5= require('./md5') - , user_credentials= require('./user-credentials') - , basic_challenge= { - statusCode: 401, - headers: { - 'www-authenticate': 'Basic realm="sample"' - } - } - ; - -function hex8(num) -{ - return ("00000000" + num.toString(16)).slice(-8); -} - -var www_authenticator = function(username,password,options) -{ - if (2 == arguments.length && toString.call(password) != '[object String]') { - options= password; - password= null; - } - var credentials= user_credentials(username,password) - var cnonce; - if (options) { - if (toString.call(options.cnonce) == '[object String]') - cnonce= options.cnonce; - } - if (cnonce === void 0) cnonce= crypto.pseudoRandomBytes(8).toString('hex'); - - /** - * @typedef {Object} Authenticator - * @property {any} [err] - * @property {function(string=, string=): string} [authorize] - * @property {any} [parms] - * @property {string} [cnonce] - */ - - /** - * Parses the WWW-Authenticate header. - * @param {string} www_authenticate - * @returns {Authenticator} - */ - var parse_header= function(www_authenticate) - { - function Authenticator() - { - function note_error(err) - { - this.err= err - } - var nc= 0; - - var parsed= new parsers.WWW_Authenticate(www_authenticate); - if (parsed.err) return note_error(parsed.err); - var auth_parms= this.parms= parsed.parms; - this.cnonce= cnonce; - - switch(parsed.scheme) { - case 'Basic': - var auth_string= 'Basic '+credentials.basic(); - this.authorize= function() { - return auth_string; - }; - return; - case 'Digest': - var realm= auth_parms.realm; - if (!realm) { - return note_error("Realm not found in www-authenticate header."); - } - - var ha1= - credentials.digest(realm); - var nonce= auth_parms.nonce; - if (!nonce) { - return note_error("Nonce not found in www-authenticate header."); - } - - var fixed= 'Digest username="'+credentials.username+'",'+ - ' realm="'+realm+'",'+ - ' nonce="'+nonce+'",'; - var qop= auth_parms.qop; - if (!qop) { - this.authorize= function(method,digestURI) { - var ha2= md5(method+':'+digestURI); - return fixed+ - ' uri="'+digestURI+'",'+ - ' response="'+md5(ha1+':'+nonce+':'+ha2)+'",'; - }; - return; - } - else { - var qopa= qop.split(','); - var q, x, _i, _len; - for (_i = 0, _len = qopa.length; _i < _len; _i++) { - if ('auth' === qopa[_i]) { - var opaque= auth_parms.opaque; - var algorithm= auth_parms.algorithm; - if (algorithm) { - fixed+= ' algorithm="'+algorithm+'",'; - } - else { - algorithm= 'MD5'; - } - var a1= 'MD5-sess' == algorithm ? - md5(ha1+':'+nonce+':'+cnonce) - : - ha1; - this.authorize= function(method,digestURI) { - var ha2= md5(method+':'+digestURI); - nc= nc+1; - var hexed_nc= hex8(nc); - var s= fixed+ - ' uri="'+digestURI+'",'+ - ' qop=auth,'+ - ' nc='+hexed_nc+','+ - ' cnonce="'+cnonce+'",'+ - ' response="'+md5(a1+':'+nonce+':'+hexed_nc+':'+cnonce+':auth:'+ha2)+'"'; - if (opaque) { - s+= ', opaque="'+opaque+'"'; - } - return s; - }; - return; - } - return note_error('Server does not accept any supported quality of protection techniques.'); - } - } - break; - default: - return note_error("Unknown scheme"); - } - } - - return new Authenticator(); - }; - - parse_header.authenticator= new HigherLevel(credentials,options); // deprecated - return parse_header; -}; - - -function HigherLevel(credentials,options) -{ - this.credentials= credentials - this.options= options - if (options && options.sendImmediately) { - this.sendImmediately= true; - } -} -HigherLevel.prototype.get_challenge= function(request) { - if (401 == request.statusCode && 'www-authenticate' in request.headers) { - if (!this.parse_header) { - this.parse_header= www_authenticator(this.credentials,this.options) - } - this.challenge= this.parse_header(request.headers['www-authenticate']) - return this.challenge.err; - } -} -HigherLevel.prototype._challenge= function() { - if (!this.challenge) { - if (this.sendImmediately) { - // simulate receipt of a basic challenge - this.get_challenge(basic_challenge) - return this.challenge - } - else return; // simply won't produce an 'Authorization' header - } - return this.challenge; -} -HigherLevel.prototype.authentication_string= function(method,digestURI) { - var challenge= this._challenge(); - if (!challenge) return; // simply won't produce an 'Authorization' header - if (challenge.err) return challenge.err; - return challenge.authorize(method,digestURI); -} -HigherLevel.prototype.authenticate_headers= function(headers,method,digestURI) { - var challenge= this._challenge(); - if (!challenge) return; // simply won't produce an 'Authorization' header - if (challenge.err) return challenge.err; - headers.authorization= challenge.authorize(method,digestURI); -} -HigherLevel.prototype.authenticate_request_options= function(request_options) { - var challenge= this._challenge(); - if (!challenge) return; // simply won't produce an 'Authorization' header - if (challenge.err) return challenge.err; - if (!request_options.headers) request_options.headers= {}; - request_options.headers.authorization= challenge.authorize(request_options.method,request_options.path); -} - -module.exports = www_authenticator; -module.exports.parsers= parsers; -module.exports.user_credentials= user_credentials; -module.exports.basic_challenge= basic_challenge; -module.exports.authenticator= function(username,password,options) -{ - if (2 == arguments.length && toString.call(password) != '[object String]') { - options= password; - password= null; - } - var credentials= user_credentials(username,password) - return new HigherLevel(credentials,options); -} \ No newline at end of file From 3a5f3fc20647b20817cd8178fb434009df606f5f Mon Sep 17 00:00:00 2001 From: Steve Biondi Date: Mon, 22 Sep 2025 08:48:30 -0700 Subject: [PATCH 2/3] Add pre-fix files from www-authenticate to folder www-authenticate-patched --- lib/requester.js | 2 +- lib/www-authenticate-patched/md5.js | 9 + lib/www-authenticate-patched/parsers.js | 110 ++++++++++ .../user-credentials.js | 46 ++++ .../www-authenticate.js | 202 ++++++++++++++++++ test-basic/digestauth-fips-nomd5load.js | 8 +- 6 files changed, 372 insertions(+), 5 deletions(-) create mode 100644 lib/www-authenticate-patched/md5.js create mode 100644 lib/www-authenticate-patched/parsers.js create mode 100644 lib/www-authenticate-patched/user-credentials.js create mode 100644 lib/www-authenticate-patched/www-authenticate.js diff --git a/lib/requester.js b/lib/requester.js index bb063426..8f922a2c 100644 --- a/lib/requester.js +++ b/lib/requester.js @@ -2,7 +2,7 @@ * Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ 'use strict'; -var createAuthInitializer = require('./www-authenticate/www-authenticate'); +var createAuthInitializer = require('./www-authenticate-patched/www-authenticate'); var Kerberos = require('./optional.js') .libraryProperty('kerberos', 'Kerberos'); var Multipart = require('multipart-stream'); diff --git a/lib/www-authenticate-patched/md5.js b/lib/www-authenticate-patched/md5.js new file mode 100644 index 00000000..5af85469 --- /dev/null +++ b/lib/www-authenticate-patched/md5.js @@ -0,0 +1,9 @@ +var crypto= require('crypto') + , md5sum = crypto.createHash('md5') + ; + +function md5(s) { + return crypto.createHash('md5').update(s).digest('hex'); +} + +module.exports= md5; \ No newline at end of file diff --git a/lib/www-authenticate-patched/parsers.js b/lib/www-authenticate-patched/parsers.js new file mode 100644 index 00000000..8659d62d --- /dev/null +++ b/lib/www-authenticate-patched/parsers.js @@ -0,0 +1,110 @@ +var ParseAuth= /(\w+)\s+(.*)/ // -> scheme, params + , Separators= /([",=])/ + ; + +function parse_params(header) { + // This parser will definitely fail if there is more than one challenge + var tok, last_tok, _i, _len, key, value; + var state= 0; //0: token, + var m= header.split(Separators) + for (_i = 0, _len = m.length; _i < _len; _i++) { + last_tok= tok; + tok = m[_i]; + if (!tok.length) continue; + switch (state) { + case 0: // token + key= tok.trim(); + state= 1; // expect equals + continue; + case 1: // expect equals + if ('=' != tok) return 'Equal sign was expected after '+key; + state= 2; + continue; + case 2: // expect value + if ('"' == tok) { + value= ''; + state= 3; // expect quoted + continue; + } + else { + this.parms[key]= value= tok.trim(); + state= 9; // expect comma or end + continue; + } + case 3: // handling quoted string + if ('"' == tok) { + state= 8; // end quoted + continue; + } + else { + value+= tok; + state= 3; // continue accumulating quoted string + continue; + } + case 8: // end quote encountered + if ('"' == tok) { + // double quoted + value+= '"'; + state= 3; // back to quoted string + continue; + } + if (',' == tok) { + this.parms[key]= value; + state= 0; + continue; + } + else { + return 'Unexpected token ('+tok+') after '+value+'"'; + } + continue; + case 9: // expect commma + if (',' != tok) return 'Comma expected after '+value; + state= 0; + continue; + } + } + switch (state) { // terminal state + case 0: // Empty or ignoring terminal comma + case 9: // Expecting comma or end of header + return; + case 8: // Last token was end quote + this.parms[key]= value; + return; + default: + return 'Unexpected end of www-authenticate value.'; + } +} + +function Parse_WWW_Authenticate(to_parse) +{ + var m= to_parse.match(ParseAuth); + this.scheme= m[1]; + this.parms= {}; + var err= this.parse_params(m[2]); + if (err) { + this.scheme= ''; + this.parms= {}; + this.err= err; + } +} + +Parse_Authentication_Info.prototype.parse_params= parse_params; + +function Parse_Authentication_Info(to_parse) +{ + this.scheme= 'Digest'; + this.parms= {}; + var err= this.parse_params(to_parse); + if (err) { + this.scheme= ''; + this.parms= {}; + this.err= err; + } +} + +Parse_WWW_Authenticate.prototype.parse_params= parse_params; + +module.exports = { + WWW_Authenticate: Parse_WWW_Authenticate, + Authentication_Info: Parse_Authentication_Info +}; diff --git a/lib/www-authenticate-patched/user-credentials.js b/lib/www-authenticate-patched/user-credentials.js new file mode 100644 index 00000000..60ce4f0a --- /dev/null +++ b/lib/www-authenticate-patched/user-credentials.js @@ -0,0 +1,46 @@ +var md5= require('./md5'); + +/* + * Hide the password. Uses the password to form authorization strings, + * but provides no interface for exporting it. + */ +function user_credentials(username,password,options) { + if (username.is_user_credentials && + typeof username.basic === 'function' && + typeof username.digest === 'function' + ) { + return username; + } + + var basic_string= options && options.hide_basic ? + '' + : + (!password && password !== '' ? + new Buffer(username, "ascii").toString("base64") + : + new Buffer(username+':'+password, "ascii").toString("base64") + ) + function Credentials() + { + this.username= username; + } + Credentials.prototype.basic= function() + { + return basic_string; + } + Credentials.prototype.digest= function(realm) + { + return !password && password !== '' ? + md5(username+':'+realm) + : + md5(username+':'+realm+':'+password) + } + Credentials.prototype.is_user_credentials= function() + { + return true; + } + + return new Credentials; +} + +module.exports= user_credentials; diff --git a/lib/www-authenticate-patched/www-authenticate.js b/lib/www-authenticate-patched/www-authenticate.js new file mode 100644 index 00000000..6bcb129f --- /dev/null +++ b/lib/www-authenticate-patched/www-authenticate.js @@ -0,0 +1,202 @@ + +/* + * www-authenticate + * https://github.com/randymized/www-authenticate + * + * Copyright (c) 2013 Randy McLaughlin + * Licensed under the MIT license. + */ + +'use strict'; + +var crypto= require('crypto') + , md5sum = crypto.createHash('md5') + , parsers= require('./parsers') + , md5= require('./md5') + , user_credentials= require('./user-credentials') + , basic_challenge= { + statusCode: 401, + headers: { + 'www-authenticate': 'Basic realm="sample"' + } + } + ; + +function hex8(num) +{ + return ("00000000" + num.toString(16)).slice(-8); +} + +var www_authenticator = function(username,password,options) +{ + if (2 == arguments.length && toString.call(password) != '[object String]') { + options= password; + password= null; + } + var credentials= user_credentials(username,password) + var cnonce; + if (options) { + if (toString.call(options.cnonce) == '[object String]') + cnonce= options.cnonce; + } + if (cnonce === void 0) cnonce= crypto.pseudoRandomBytes(8).toString('hex'); + var parse_header= function(www_authenticate) + { + function Authenticator() + { + function note_error(err) + { + this.err= err + } + var nc= 0; + + var parsed= new parsers.WWW_Authenticate(www_authenticate); + if (parsed.err) return note_error(parsed.err); + var auth_parms= this.parms= parsed.parms; + this.cnonce= cnonce; + + switch(parsed.scheme) { + case 'Basic': + var auth_string= 'Basic '+credentials.basic(); + this.authorize= function() { + return auth_string; + }; + return; + case 'Digest': + var realm= auth_parms.realm; + if (!realm) { + return note_error("Realm not found in www-authenticate header."); + } + + var ha1= + credentials.digest(realm); + var nonce= auth_parms.nonce; + if (!nonce) { + return note_error("Nonce not found in www-authenticate header."); + } + + var fixed= 'Digest username="'+credentials.username+'",'+ + ' realm="'+realm+'",'+ + ' nonce="'+nonce+'",'; + var qop= auth_parms.qop; + if (!qop) { + this.authorize= function(method,digestURI) { + var ha2= md5(method+':'+digestURI); + return fixed+ + ' uri="'+digestURI+'",'+ + ' response="'+md5(ha1+':'+nonce+':'+ha2)+'",'; + }; + return; + } + else { + var qopa= qop.split(','); + var q, x, _i, _len; + for (_i = 0, _len = qopa.length; _i < _len; _i++) { + if ('auth' === qopa[_i]) { + var opaque= auth_parms.opaque; + var algorithm= auth_parms.algorithm; + if (algorithm) { + fixed+= ' algorithm="'+algorithm+'",'; + } + else { + algorithm= 'MD5'; + } + var a1= 'MD5-sess' == algorithm ? + md5(ha1+':'+nonce+':'+cnonce) + : + ha1; + this.authorize= function(method,digestURI) { + var ha2= md5(method+':'+digestURI); + nc= nc+1; + var hexed_nc= hex8(nc); + var s= fixed+ + ' uri="'+digestURI+'",'+ + ' qop=auth,'+ + ' nc='+hexed_nc+','+ + ' cnonce="'+cnonce+'",'+ + ' response="'+md5(a1+':'+nonce+':'+hexed_nc+':'+cnonce+':auth:'+ha2)+'"'; + if (opaque) { + s+= ', opaque="'+opaque+'"'; + } + return s; + }; + return; + } + return note_error('Server does not accept any supported quality of protection techniques.'); + } + } + break; + default: + return note_error("Unknown scheme"); + } + } + + return new Authenticator(); + }; + + parse_header.authenticator= new HigherLevel(credentials,options); // deprecated + return parse_header; +}; + + +function HigherLevel(credentials,options) +{ + this.credentials= credentials + this.options= options + if (options && options.sendImmediately) { + this.sendImmediately= true; + } +} +HigherLevel.prototype.get_challenge= function(request) { + if (401 == request.statusCode && 'www-authenticate' in request.headers) { + if (!this.parse_header) { + this.parse_header= www_authenticator(this.credentials,this.options) + } + this.challenge= this.parse_header(request.headers['www-authenticate']) + return this.challenge.err; + } +} +HigherLevel.prototype._challenge= function() { + if (!this.challenge) { + if (this.sendImmediately) { + // simulate receipt of a basic challenge + this.get_challenge(basic_challenge) + return this.challenge + } + else return; // simply won't produce an 'Authorization' header + } + return this.challenge; +} +HigherLevel.prototype.authentication_string= function(method,digestURI) { + var challenge= this._challenge(); + if (!challenge) return; // simply won't produce an 'Authorization' header + if (challenge.err) return challenge.err; + return challenge.authorize(method,digestURI); +} +HigherLevel.prototype.authenticate_headers= function(headers,method,digestURI) { + var challenge= this._challenge(); + if (!challenge) return; // simply won't produce an 'Authorization' header + if (challenge.err) return challenge.err; + headers.authorization= challenge.authorize(method,digestURI); +} +HigherLevel.prototype.authenticate_request_options= function(request_options) { + var challenge= this._challenge(); + if (!challenge) return; // simply won't produce an 'Authorization' header + if (challenge.err) return challenge.err; + if (!request_options.headers) request_options.headers= {}; + request_options.headers.authorization= challenge.authorize(request_options.method,request_options.path); +} + +module.exports = www_authenticator; +module.exports.parsers= parsers; +module.exports.user_credentials= user_credentials; +module.exports.basic_challenge= basic_challenge; +module.exports.authenticator= function(username,password,options) +{ + if (2 == arguments.length && toString.call(password) != '[object String]') { + options= password; + password= null; + } + var credentials= user_credentials(username,password) + return new HigherLevel(credentials,options); +} \ No newline at end of file diff --git a/test-basic/digestauth-fips-nomd5load.js b/test-basic/digestauth-fips-nomd5load.js index c90ca73d..fd244643 100644 --- a/test-basic/digestauth-fips-nomd5load.js +++ b/test-basic/digestauth-fips-nomd5load.js @@ -22,8 +22,8 @@ describe('FIPS test - ensure MD5 hash digester object is not loaded by default o * To simulate the require/load, we first delete the module from Node's require cache * and then require it again, which forces a reload of the module. */ - delete require.cache[require.resolve('../lib/www-authenticate/www-authenticate')]; - delete require.cache[require.resolve('../lib/www-authenticate/md5')]; + delete require.cache[require.resolve('../lib/www-authenticate-patched/www-authenticate')]; + delete require.cache[require.resolve('../lib/www-authenticate-patched/md5')]; const crypto = require('crypto'); const originalCreateHash = crypto.createHash; @@ -40,8 +40,8 @@ describe('FIPS test - ensure MD5 hash digester object is not loaded by default o (() => crypto.createHash('md5')).should.throw('FIPS emulation: MD5 digest algorithm is not allowed on this system!'); // Require the module - should not call to get MD5 digester so should not throw - (() => require('../lib/www-authenticate/md5')).should.not.throw(); - (() => require('../lib/www-authenticate/www-authenticate')).should.not.throw(); + (() => require('../lib/www-authenticate-patched/md5')).should.not.throw(); + (() => require('../lib/www-authenticate-patched/www-authenticate')).should.not.throw(); } finally { // Restore the original createHash function to avoid side effects From cc32ad69119fc3688e9f8816f07599c32952e53f Mon Sep 17 00:00:00 2001 From: Steve Biondi Date: Mon, 22 Sep 2025 09:35:32 -0700 Subject: [PATCH 3/3] MLE-24397 - fix reported issue on Linux FIPS around exception caused by default load of FIPS-forbidden MD5 digest algorithm. Incorporate the source from the abandoned www-authenticate project to lib/www-authenticate-patched, and fix in place. Changes to www-authenticate-patched include: removal of unnecessary pre-load of MD5 digester function from www-authenticate and md5 js files, use of Buffer.from rather than new Buffer (deprecated), and moving a prototype decl to after function has been defined. Add Progress copyright and typedef comment to Authenticator. --- lib/www-authenticate-patched/md5.js | 4 +--- lib/www-authenticate-patched/parsers.js | 3 +-- .../user-credentials.js | 4 ++-- .../www-authenticate.js | 19 ++++++++++++++++++- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/www-authenticate-patched/md5.js b/lib/www-authenticate-patched/md5.js index 5af85469..3e6de8bf 100644 --- a/lib/www-authenticate-patched/md5.js +++ b/lib/www-authenticate-patched/md5.js @@ -1,6 +1,4 @@ -var crypto= require('crypto') - , md5sum = crypto.createHash('md5') - ; +var crypto= require('crypto'); function md5(s) { return crypto.createHash('md5').update(s).digest('hex'); diff --git a/lib/www-authenticate-patched/parsers.js b/lib/www-authenticate-patched/parsers.js index 8659d62d..65e2be1d 100644 --- a/lib/www-authenticate-patched/parsers.js +++ b/lib/www-authenticate-patched/parsers.js @@ -88,8 +88,6 @@ function Parse_WWW_Authenticate(to_parse) } } -Parse_Authentication_Info.prototype.parse_params= parse_params; - function Parse_Authentication_Info(to_parse) { this.scheme= 'Digest'; @@ -102,6 +100,7 @@ function Parse_Authentication_Info(to_parse) } } +Parse_Authentication_Info.prototype.parse_params= parse_params; Parse_WWW_Authenticate.prototype.parse_params= parse_params; module.exports = { diff --git a/lib/www-authenticate-patched/user-credentials.js b/lib/www-authenticate-patched/user-credentials.js index 60ce4f0a..25bc405d 100644 --- a/lib/www-authenticate-patched/user-credentials.js +++ b/lib/www-authenticate-patched/user-credentials.js @@ -16,9 +16,9 @@ function user_credentials(username,password,options) { '' : (!password && password !== '' ? - new Buffer(username, "ascii").toString("base64") + Buffer.from(username, "ascii").toString("base64") : - new Buffer(username+':'+password, "ascii").toString("base64") + Buffer.from(username+':'+password, "ascii").toString("base64") ) function Credentials() { diff --git a/lib/www-authenticate-patched/www-authenticate.js b/lib/www-authenticate-patched/www-authenticate.js index 6bcb129f..15aa8f6f 100644 --- a/lib/www-authenticate-patched/www-authenticate.js +++ b/lib/www-authenticate-patched/www-authenticate.js @@ -7,10 +7,13 @@ * Licensed under the MIT license. */ +/* + * Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + */ + 'use strict'; var crypto= require('crypto') - , md5sum = crypto.createHash('md5') , parsers= require('./parsers') , md5= require('./md5') , user_credentials= require('./user-credentials') @@ -40,6 +43,20 @@ var www_authenticator = function(username,password,options) cnonce= options.cnonce; } if (cnonce === void 0) cnonce= crypto.pseudoRandomBytes(8).toString('hex'); + + /** + * @typedef {Object} Authenticator + * @property {any} [err] + * @property {function(string=, string=): string} [authorize] + * @property {any} [parms] + * @property {string} [cnonce] + */ + + /** + * Parses the WWW-Authenticate header. + * @param {string} www_authenticate + * @returns {Authenticator} + */ var parse_header= function(www_authenticate) { function Authenticator()