jrottman
Programmer
- Jun 17, 2005
- 47
Has anyone ever successfully performed a remote http server digest authentication? I am currently building a script that authenticates against a server using a supplied username and password. All of my attempts thus far have come up empty and I am not quite sure where I am going wrong with this.
I have modeled my headers exactly after the heads I get with a successful Firefox login.
Here are the headers I get from the Live Headers firefox addon.
Initial Response:
GET /rets/login HTTP/1.1
Host: rets.armls.mlsrets.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
HTTP/1.x 401 Unauthorized
Content-Length: 1944
Content-Type: text/html
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Digest qop="auth",realm="rets@marketlinx.com",nonce="2aaa0db6ed2bb21e8b913e1844b0abf1",opaque="20050024497281"
Date: Sun, 20 May 2007 00:24:49 GMT
Connection: close
Authenticated Response:
GET /rets/login HTTP/1.1
Host: rets.armls.mlsrets.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Authorization: Digest username="cril01", realm="rets@marketlinx.com", nonce="2aaa0db6ed2bb21e8b913e1844b0abf1", uri="/rets/login", response="db214dcb999219968d829b5513e476dd", opaque="20050024497281", qop="auth", nc=00000001, cnonce="1d545807784766d0"
HTTP/1.x 200 OK
Connection: close
Date: Sun, 20 May 2007 00:24:54 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Expires: 0
Cache-Control: private
RETS-Version: RETS/1.5
Set-Cookie: RETS-Session-ID=2aaa0db6ed2bb21e8b913e1844b0abf1; path=/
Content-Type: text/xml
Now even with me exactly copying these headers. I still get 401 (Unauthorized) errors. Does anyone see where I went wrong with this?
Here is a link to my current test:
And here is my code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " dtd">
<html xmlns="<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>RETS 1.5 Auth Test</title>
</head>
<body>
<cfscript>
// set global vars
userAgent = 'FDR/1.8';
retsVersion = 'RETS/1.5';
hostname = 'rets.armls.mlsrets.com';
port = '';
username = 'cril01';
password = 'Jn!23@';
loginArea = 'GET /rets/login/login.aspx%3d HTTP/1.1';
loginUri = '/rets/login/login.aspx';
realm = 'rets@marketlink.com';
A1 = Lcase(Hash(username & ':' & realm & ':' & password,"MD5"));
A2 = Lcase(Hash(loginArea,"MD5"));
nc = '00000001';
// create initial auth header
function initial_Auth(){
qop = 'auth';
nonce = '';
opaque = '';
response = '';
rawDigest = 'Digest username=' & chr(34) & username & chr(34) & ',' &
'realm=' & chr(34) & realm & chr(34) & ',' &
'nonce=' & nonce & ',' &
'uri=' & chr(34) & '/rets/login' & chr(34) & ',' &
'response=' & Lcase(Hash(A1,"MD5")) & ':' & nonce & ':' & Lcase(Hash(A2,"MD5"));
return rawDigest;
}
function create_Auth(){
tempList = Replace(cfhttp.responseHeader["WWW-Authenticate"],"Digest ",'','All');
headerArr = ListToArray(Trim(tempList));
auth_Temp = ListToArray(Trim(cfhttp.responseHeader["WWW-Authenticate"]),' ');
auth_Type = auth_Temp[1];
// create basic auth header
if (auth_Type eq 'Basic'){
auth = username & ':' & password;
encodedAuth = 'Authorization: Basic ' & toBase64(auth);
return encodedAuth;
}
if(auth_Type eq 'Digest'){
authStc = structNew();
for(i=1;i lte ArrayLen(headerArr);i=i+1){
key = Replace(Left(headerArr,Find('=',headerArr)),'=','','ALL');
value = Replace(RemoveChars(headerArr,1,Find('=',headerArr,"1")),'"','','ALL');
authStc[key] = value;
}
auth_Nonce = authStc['nonce'];
auth_Opaque = authStc['opaque'];
is2069 = false;
if(structKeyExists(authStc,'qop') and NOT structKeyExists(authStc,'auth_qop')){
is2069 = true;
}
if(is2069){
rawDigest = Lcase(Hash(A1,"MD5")) & ':' & auth_Nonce & ':' & Lcase(Hash(A2,"MD5"));
encodedAuth = 'Digest username=' & chr(34) & username & chr(34) & ',' &
'qop=' & chr(34) & qop & chr(34) & ',' &
'realm=' & chr(34) & realm & chr(34) & ',' &
'nonce=' & chr(34) & auth_Nonce & chr(34) & ',' &
'uri=' & chr(34) & loginUri & chr(34) & ',' &
'response=' & chr(34) & Lcase(Hash(rawDigest,"MD5")) & chr(34) & ',' &
'opaque=' & chr(34) & auth_Opaque & chr(34) & ',' &
'nc=' & nc;
}else{
return 'Does not meet 2029 standards';
}
return encodedAuth;
}
}
</cfscript>
<cfoutput>
<h3>Generated Header</h3>
<p>Authorization: #initial_Auth()#</p>
</cfoutput>
<!--- First request to get Authenticate Information --->
<cfhttp url=" method="get" >
<cfhttpparam name="User-Agent" type="header" value="#userAgent#">
<cfhttpparam name="Accept" type="header" value="text/xml,application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam name="Accept-Language" type="header" value="en-us,en;q=0.5">
<cfhttpparam name="Accept-Encoding" type="header" value="gzip,deflate">
<cfhttpparam name="Accept-Charset" type="header" value="ISO-8859-1,utf-8;q=0.7,*;q=0. 7">
<cfhttpparam name="Keep-Alive" type="header" value="300">
<cfhttpparam name="Connection" type="header" value="keep-alive">
<cfhttpparam name="RETS-Version" type="header" value="#retsVersion#">
</cfhttp>
<h3>Initial Response</h3>
<cfdump var="#cfhttp#" /><br><br>
<cfoutput>
<h3>Generated Header</h3>
<p>Authorization: #create_Auth()#</p>
</cfoutput>
<!--- Second request to get Authenticated --->
<cfhttp url=" method="POST">
<cfhttpparam name="User-Agent" type="header" value="#userAgent#">
<cfhttpparam name="Accept" type="header" value="text/xml,application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam name="Accept-Language" type="header" value="en-us,en;q=0.5">
<cfhttpparam name="Accept-Encoding" type="header" value="gzip,deflate">
<cfhttpparam name="Accept-Charset" type="header" value="ISO-8859-1,utf-8;q=0.7,*;q=0. 7">
<cfhttpparam name="Keep-Alive" type="header" value="300">
<cfhttpparam name="Connection" type="header" value="keep-alive">
<cfhttpparam name="RETS-Version" type="header" value="#retsVersion#">
<cfhttpparam name="Authorization" type="header" value="#create_Auth()#">
</cfhttp>
<h3>Response</h3> <cfdump var="#cfhttp#" /> </body> </html>
I have modeled my headers exactly after the heads I get with a successful Firefox login.
Here are the headers I get from the Live Headers firefox addon.
Initial Response:
GET /rets/login HTTP/1.1
Host: rets.armls.mlsrets.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
HTTP/1.x 401 Unauthorized
Content-Length: 1944
Content-Type: text/html
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Digest qop="auth",realm="rets@marketlinx.com",nonce="2aaa0db6ed2bb21e8b913e1844b0abf1",opaque="20050024497281"
Date: Sun, 20 May 2007 00:24:49 GMT
Connection: close
Authenticated Response:
GET /rets/login HTTP/1.1
Host: rets.armls.mlsrets.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Authorization: Digest username="cril01", realm="rets@marketlinx.com", nonce="2aaa0db6ed2bb21e8b913e1844b0abf1", uri="/rets/login", response="db214dcb999219968d829b5513e476dd", opaque="20050024497281", qop="auth", nc=00000001, cnonce="1d545807784766d0"
HTTP/1.x 200 OK
Connection: close
Date: Sun, 20 May 2007 00:24:54 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Expires: 0
Cache-Control: private
RETS-Version: RETS/1.5
Set-Cookie: RETS-Session-ID=2aaa0db6ed2bb21e8b913e1844b0abf1; path=/
Content-Type: text/xml
Now even with me exactly copying these headers. I still get 401 (Unauthorized) errors. Does anyone see where I went wrong with this?
Here is a link to my current test:
And here is my code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " dtd">
<html xmlns="<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>RETS 1.5 Auth Test</title>
</head>
<body>
<cfscript>
// set global vars
userAgent = 'FDR/1.8';
retsVersion = 'RETS/1.5';
hostname = 'rets.armls.mlsrets.com';
port = '';
username = 'cril01';
password = 'Jn!23@';
loginArea = 'GET /rets/login/login.aspx%3d HTTP/1.1';
loginUri = '/rets/login/login.aspx';
realm = 'rets@marketlink.com';
A1 = Lcase(Hash(username & ':' & realm & ':' & password,"MD5"));
A2 = Lcase(Hash(loginArea,"MD5"));
nc = '00000001';
// create initial auth header
function initial_Auth(){
qop = 'auth';
nonce = '';
opaque = '';
response = '';
rawDigest = 'Digest username=' & chr(34) & username & chr(34) & ',' &
'realm=' & chr(34) & realm & chr(34) & ',' &
'nonce=' & nonce & ',' &
'uri=' & chr(34) & '/rets/login' & chr(34) & ',' &
'response=' & Lcase(Hash(A1,"MD5")) & ':' & nonce & ':' & Lcase(Hash(A2,"MD5"));
return rawDigest;
}
function create_Auth(){
tempList = Replace(cfhttp.responseHeader["WWW-Authenticate"],"Digest ",'','All');
headerArr = ListToArray(Trim(tempList));
auth_Temp = ListToArray(Trim(cfhttp.responseHeader["WWW-Authenticate"]),' ');
auth_Type = auth_Temp[1];
// create basic auth header
if (auth_Type eq 'Basic'){
auth = username & ':' & password;
encodedAuth = 'Authorization: Basic ' & toBase64(auth);
return encodedAuth;
}
if(auth_Type eq 'Digest'){
authStc = structNew();
for(i=1;i lte ArrayLen(headerArr);i=i+1){
key = Replace(Left(headerArr,Find('=',headerArr)),'=','','ALL');
value = Replace(RemoveChars(headerArr,1,Find('=',headerArr,"1")),'"','','ALL');
authStc[key] = value;
}
auth_Nonce = authStc['nonce'];
auth_Opaque = authStc['opaque'];
is2069 = false;
if(structKeyExists(authStc,'qop') and NOT structKeyExists(authStc,'auth_qop')){
is2069 = true;
}
if(is2069){
rawDigest = Lcase(Hash(A1,"MD5")) & ':' & auth_Nonce & ':' & Lcase(Hash(A2,"MD5"));
encodedAuth = 'Digest username=' & chr(34) & username & chr(34) & ',' &
'qop=' & chr(34) & qop & chr(34) & ',' &
'realm=' & chr(34) & realm & chr(34) & ',' &
'nonce=' & chr(34) & auth_Nonce & chr(34) & ',' &
'uri=' & chr(34) & loginUri & chr(34) & ',' &
'response=' & chr(34) & Lcase(Hash(rawDigest,"MD5")) & chr(34) & ',' &
'opaque=' & chr(34) & auth_Opaque & chr(34) & ',' &
'nc=' & nc;
}else{
return 'Does not meet 2029 standards';
}
return encodedAuth;
}
}
</cfscript>
<cfoutput>
<h3>Generated Header</h3>
<p>Authorization: #initial_Auth()#</p>
</cfoutput>
<!--- First request to get Authenticate Information --->
<cfhttp url=" method="get" >
<cfhttpparam name="User-Agent" type="header" value="#userAgent#">
<cfhttpparam name="Accept" type="header" value="text/xml,application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam name="Accept-Language" type="header" value="en-us,en;q=0.5">
<cfhttpparam name="Accept-Encoding" type="header" value="gzip,deflate">
<cfhttpparam name="Accept-Charset" type="header" value="ISO-8859-1,utf-8;q=0.7,*;q=0. 7">
<cfhttpparam name="Keep-Alive" type="header" value="300">
<cfhttpparam name="Connection" type="header" value="keep-alive">
<cfhttpparam name="RETS-Version" type="header" value="#retsVersion#">
</cfhttp>
<h3>Initial Response</h3>
<cfdump var="#cfhttp#" /><br><br>
<cfoutput>
<h3>Generated Header</h3>
<p>Authorization: #create_Auth()#</p>
</cfoutput>
<!--- Second request to get Authenticated --->
<cfhttp url=" method="POST">
<cfhttpparam name="User-Agent" type="header" value="#userAgent#">
<cfhttpparam name="Accept" type="header" value="text/xml,application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam name="Accept-Language" type="header" value="en-us,en;q=0.5">
<cfhttpparam name="Accept-Encoding" type="header" value="gzip,deflate">
<cfhttpparam name="Accept-Charset" type="header" value="ISO-8859-1,utf-8;q=0.7,*;q=0. 7">
<cfhttpparam name="Keep-Alive" type="header" value="300">
<cfhttpparam name="Connection" type="header" value="keep-alive">
<cfhttpparam name="RETS-Version" type="header" value="#retsVersion#">
<cfhttpparam name="Authorization" type="header" value="#create_Auth()#">
</cfhttp>
<h3>Response</h3> <cfdump var="#cfhttp#" /> </body> </html>