Skip to content

Commit 3a5f3fc

Browse files
committed
Add pre-fix files from www-authenticate to folder www-authenticate-patched
1 parent b1befbc commit 3a5f3fc

File tree

6 files changed

+372
-5
lines changed

6 files changed

+372
-5
lines changed

lib/requester.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
33
*/
44
'use strict';
5-
var createAuthInitializer = require('./www-authenticate/www-authenticate');
5+
var createAuthInitializer = require('./www-authenticate-patched/www-authenticate');
66
var Kerberos = require('./optional.js')
77
.libraryProperty('kerberos', 'Kerberos');
88
var Multipart = require('multipart-stream');
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var crypto= require('crypto')
2+
, md5sum = crypto.createHash('md5')
3+
;
4+
5+
function md5(s) {
6+
return crypto.createHash('md5').update(s).digest('hex');
7+
}
8+
9+
module.exports= md5;
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
var ParseAuth= /(\w+)\s+(.*)/ // -> scheme, params
2+
, Separators= /([",=])/
3+
;
4+
5+
function parse_params(header) {
6+
// This parser will definitely fail if there is more than one challenge
7+
var tok, last_tok, _i, _len, key, value;
8+
var state= 0; //0: token,
9+
var m= header.split(Separators)
10+
for (_i = 0, _len = m.length; _i < _len; _i++) {
11+
last_tok= tok;
12+
tok = m[_i];
13+
if (!tok.length) continue;
14+
switch (state) {
15+
case 0: // token
16+
key= tok.trim();
17+
state= 1; // expect equals
18+
continue;
19+
case 1: // expect equals
20+
if ('=' != tok) return 'Equal sign was expected after '+key;
21+
state= 2;
22+
continue;
23+
case 2: // expect value
24+
if ('"' == tok) {
25+
value= '';
26+
state= 3; // expect quoted
27+
continue;
28+
}
29+
else {
30+
this.parms[key]= value= tok.trim();
31+
state= 9; // expect comma or end
32+
continue;
33+
}
34+
case 3: // handling quoted string
35+
if ('"' == tok) {
36+
state= 8; // end quoted
37+
continue;
38+
}
39+
else {
40+
value+= tok;
41+
state= 3; // continue accumulating quoted string
42+
continue;
43+
}
44+
case 8: // end quote encountered
45+
if ('"' == tok) {
46+
// double quoted
47+
value+= '"';
48+
state= 3; // back to quoted string
49+
continue;
50+
}
51+
if (',' == tok) {
52+
this.parms[key]= value;
53+
state= 0;
54+
continue;
55+
}
56+
else {
57+
return 'Unexpected token ('+tok+') after '+value+'"';
58+
}
59+
continue;
60+
case 9: // expect commma
61+
if (',' != tok) return 'Comma expected after '+value;
62+
state= 0;
63+
continue;
64+
}
65+
}
66+
switch (state) { // terminal state
67+
case 0: // Empty or ignoring terminal comma
68+
case 9: // Expecting comma or end of header
69+
return;
70+
case 8: // Last token was end quote
71+
this.parms[key]= value;
72+
return;
73+
default:
74+
return 'Unexpected end of www-authenticate value.';
75+
}
76+
}
77+
78+
function Parse_WWW_Authenticate(to_parse)
79+
{
80+
var m= to_parse.match(ParseAuth);
81+
this.scheme= m[1];
82+
this.parms= {};
83+
var err= this.parse_params(m[2]);
84+
if (err) {
85+
this.scheme= '';
86+
this.parms= {};
87+
this.err= err;
88+
}
89+
}
90+
91+
Parse_Authentication_Info.prototype.parse_params= parse_params;
92+
93+
function Parse_Authentication_Info(to_parse)
94+
{
95+
this.scheme= 'Digest';
96+
this.parms= {};
97+
var err= this.parse_params(to_parse);
98+
if (err) {
99+
this.scheme= '';
100+
this.parms= {};
101+
this.err= err;
102+
}
103+
}
104+
105+
Parse_WWW_Authenticate.prototype.parse_params= parse_params;
106+
107+
module.exports = {
108+
WWW_Authenticate: Parse_WWW_Authenticate,
109+
Authentication_Info: Parse_Authentication_Info
110+
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
var md5= require('./md5');
2+
3+
/*
4+
* Hide the password. Uses the password to form authorization strings,
5+
* but provides no interface for exporting it.
6+
*/
7+
function user_credentials(username,password,options) {
8+
if (username.is_user_credentials &&
9+
typeof username.basic === 'function' &&
10+
typeof username.digest === 'function'
11+
) {
12+
return username;
13+
}
14+
15+
var basic_string= options && options.hide_basic ?
16+
''
17+
:
18+
(!password && password !== '' ?
19+
new Buffer(username, "ascii").toString("base64")
20+
:
21+
new Buffer(username+':'+password, "ascii").toString("base64")
22+
)
23+
function Credentials()
24+
{
25+
this.username= username;
26+
}
27+
Credentials.prototype.basic= function()
28+
{
29+
return basic_string;
30+
}
31+
Credentials.prototype.digest= function(realm)
32+
{
33+
return !password && password !== '' ?
34+
md5(username+':'+realm)
35+
:
36+
md5(username+':'+realm+':'+password)
37+
}
38+
Credentials.prototype.is_user_credentials= function()
39+
{
40+
return true;
41+
}
42+
43+
return new Credentials;
44+
}
45+
46+
module.exports= user_credentials;
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
2+
/*
3+
* www-authenticate
4+
* https://github.com/randymized/www-authenticate
5+
*
6+
* Copyright (c) 2013 Randy McLaughlin
7+
* Licensed under the MIT license.
8+
*/
9+
10+
'use strict';
11+
12+
var crypto= require('crypto')
13+
, md5sum = crypto.createHash('md5')
14+
, parsers= require('./parsers')
15+
, md5= require('./md5')
16+
, user_credentials= require('./user-credentials')
17+
, basic_challenge= {
18+
statusCode: 401,
19+
headers: {
20+
'www-authenticate': 'Basic realm="sample"'
21+
}
22+
}
23+
;
24+
25+
function hex8(num)
26+
{
27+
return ("00000000" + num.toString(16)).slice(-8);
28+
}
29+
30+
var www_authenticator = function(username,password,options)
31+
{
32+
if (2 == arguments.length && toString.call(password) != '[object String]') {
33+
options= password;
34+
password= null;
35+
}
36+
var credentials= user_credentials(username,password)
37+
var cnonce;
38+
if (options) {
39+
if (toString.call(options.cnonce) == '[object String]')
40+
cnonce= options.cnonce;
41+
}
42+
if (cnonce === void 0) cnonce= crypto.pseudoRandomBytes(8).toString('hex');
43+
var parse_header= function(www_authenticate)
44+
{
45+
function Authenticator()
46+
{
47+
function note_error(err)
48+
{
49+
this.err= err
50+
}
51+
var nc= 0;
52+
53+
var parsed= new parsers.WWW_Authenticate(www_authenticate);
54+
if (parsed.err) return note_error(parsed.err);
55+
var auth_parms= this.parms= parsed.parms;
56+
this.cnonce= cnonce;
57+
58+
switch(parsed.scheme) {
59+
case 'Basic':
60+
var auth_string= 'Basic '+credentials.basic();
61+
this.authorize= function() {
62+
return auth_string;
63+
};
64+
return;
65+
case 'Digest':
66+
var realm= auth_parms.realm;
67+
if (!realm) {
68+
return note_error("Realm not found in www-authenticate header.");
69+
}
70+
71+
var ha1=
72+
credentials.digest(realm);
73+
var nonce= auth_parms.nonce;
74+
if (!nonce) {
75+
return note_error("Nonce not found in www-authenticate header.");
76+
}
77+
78+
var fixed= 'Digest username="'+credentials.username+'",'+
79+
' realm="'+realm+'",'+
80+
' nonce="'+nonce+'",';
81+
var qop= auth_parms.qop;
82+
if (!qop) {
83+
this.authorize= function(method,digestURI) {
84+
var ha2= md5(method+':'+digestURI);
85+
return fixed+
86+
' uri="'+digestURI+'",'+
87+
' response="'+md5(ha1+':'+nonce+':'+ha2)+'",';
88+
};
89+
return;
90+
}
91+
else {
92+
var qopa= qop.split(',');
93+
var q, x, _i, _len;
94+
for (_i = 0, _len = qopa.length; _i < _len; _i++) {
95+
if ('auth' === qopa[_i]) {
96+
var opaque= auth_parms.opaque;
97+
var algorithm= auth_parms.algorithm;
98+
if (algorithm) {
99+
fixed+= ' algorithm="'+algorithm+'",';
100+
}
101+
else {
102+
algorithm= 'MD5';
103+
}
104+
var a1= 'MD5-sess' == algorithm ?
105+
md5(ha1+':'+nonce+':'+cnonce)
106+
:
107+
ha1;
108+
this.authorize= function(method,digestURI) {
109+
var ha2= md5(method+':'+digestURI);
110+
nc= nc+1;
111+
var hexed_nc= hex8(nc);
112+
var s= fixed+
113+
' uri="'+digestURI+'",'+
114+
' qop=auth,'+
115+
' nc='+hexed_nc+','+
116+
' cnonce="'+cnonce+'",'+
117+
' response="'+md5(a1+':'+nonce+':'+hexed_nc+':'+cnonce+':auth:'+ha2)+'"';
118+
if (opaque) {
119+
s+= ', opaque="'+opaque+'"';
120+
}
121+
return s;
122+
};
123+
return;
124+
}
125+
return note_error('Server does not accept any supported quality of protection techniques.');
126+
}
127+
}
128+
break;
129+
default:
130+
return note_error("Unknown scheme");
131+
}
132+
}
133+
134+
return new Authenticator();
135+
};
136+
137+
parse_header.authenticator= new HigherLevel(credentials,options); // deprecated
138+
return parse_header;
139+
};
140+
141+
142+
function HigherLevel(credentials,options)
143+
{
144+
this.credentials= credentials
145+
this.options= options
146+
if (options && options.sendImmediately) {
147+
this.sendImmediately= true;
148+
}
149+
}
150+
HigherLevel.prototype.get_challenge= function(request) {
151+
if (401 == request.statusCode && 'www-authenticate' in request.headers) {
152+
if (!this.parse_header) {
153+
this.parse_header= www_authenticator(this.credentials,this.options)
154+
}
155+
this.challenge= this.parse_header(request.headers['www-authenticate'])
156+
return this.challenge.err;
157+
}
158+
}
159+
HigherLevel.prototype._challenge= function() {
160+
if (!this.challenge) {
161+
if (this.sendImmediately) {
162+
// simulate receipt of a basic challenge
163+
this.get_challenge(basic_challenge)
164+
return this.challenge
165+
}
166+
else return; // simply won't produce an 'Authorization' header
167+
}
168+
return this.challenge;
169+
}
170+
HigherLevel.prototype.authentication_string= function(method,digestURI) {
171+
var challenge= this._challenge();
172+
if (!challenge) return; // simply won't produce an 'Authorization' header
173+
if (challenge.err) return challenge.err;
174+
return challenge.authorize(method,digestURI);
175+
}
176+
HigherLevel.prototype.authenticate_headers= function(headers,method,digestURI) {
177+
var challenge= this._challenge();
178+
if (!challenge) return; // simply won't produce an 'Authorization' header
179+
if (challenge.err) return challenge.err;
180+
headers.authorization= challenge.authorize(method,digestURI);
181+
}
182+
HigherLevel.prototype.authenticate_request_options= function(request_options) {
183+
var challenge= this._challenge();
184+
if (!challenge) return; // simply won't produce an 'Authorization' header
185+
if (challenge.err) return challenge.err;
186+
if (!request_options.headers) request_options.headers= {};
187+
request_options.headers.authorization= challenge.authorize(request_options.method,request_options.path);
188+
}
189+
190+
module.exports = www_authenticator;
191+
module.exports.parsers= parsers;
192+
module.exports.user_credentials= user_credentials;
193+
module.exports.basic_challenge= basic_challenge;
194+
module.exports.authenticator= function(username,password,options)
195+
{
196+
if (2 == arguments.length && toString.call(password) != '[object String]') {
197+
options= password;
198+
password= null;
199+
}
200+
var credentials= user_credentials(username,password)
201+
return new HigherLevel(credentials,options);
202+
}

0 commit comments

Comments
 (0)