<HTML><FONT FACE=arial,helvetica><FONT COLOR="#000000" FACE="Geneva" FAMILY="SANSSERIF" SIZE="2" STYLE="BACKGROUND-COLOR: #FFFFFF">I can assure you it's possible... cause I've done it!<BR>
<BR>
I'd have to do some serious editing to post a complete implementation, but here are a few of the important handlers I came up with. The checkPassword() handler has been edited heavily from my original code, so it may need some fixing. Also note that the nonce / opaque values are not implemented ideally in authenticateHeader(). You'll need a basic understanding of the RFC to make good use of these.<BR>
<BR>
Hope this helps!<BR>
<BR>
function checkPassword theSocket,requestHeader,@replyHeader,@userName<BR>
global server_opaque,server_nonce,nonce_time, loggedInIDs, loggedInNames, xfactor<BR>
<BR>
put "WebCF Registered Users" into realm -- default<BR>
<BR>
put lineOffset("Authorization:", requestHeader) into theLine<BR>
<BR>
if (theLine > 0) then<BR>
-- check the authorization<BR>
put word 1 of requestHeader into method<BR>
put line theLine of requestHeader into authLine<BR>
<BR>
replace "Authorization: Digest" with empty in authLine<BR>
set the itemDelimiter to comma<BR>
repeat for each item theItem in authLine<BR>
set the itemDelimiter to "="<BR>
put item 1 of theItem into theName<BR>
repeat until (char 1 of theName <> " ")<BR>
delete char 1 of theName<BR>
end repeat<BR>
replace (theName&"=") with (theName&"◊") in theItem<BR>
set the itemDelimiter to "◊"<BR>
put item 2 of theItem into theValue<BR>
replace quote with empty in theValue<BR>
set the itemDelimiter to comma<BR>
switch(theName)<BR>
case "userName"<BR>
put theValue into userName<BR>
exit switch<BR>
case "realm"<BR>
put theValue into realm<BR>
exit switch<BR>
case "nonce"<BR>
put theValue into nonce<BR>
exit switch<BR>
case "uri"<BR>
put theValue into theURL<BR>
exit switch<BR>
case "qop"<BR>
put theValue into qop<BR>
exit switch<BR>
case "nc"<BR>
put theValue into nc<BR>
exit switch<BR>
case "cnonce"<BR>
put theValue into cnonce<BR>
exit switch<BR>
case "response"<BR>
put theValue into digestValue<BR>
exit switch<BR>
case "opaque"<BR>
put theValue into opaque<BR>
exit switch<BR>
end switch<BR>
end repeat<BR>
else<BR>
put authenticateHeader(realm,"auth",empty,"default") into replyHeader<BR>
return FALSE<BR>
end if<BR>
<BR>
## edit this to lookup the correct password<BR>
put empty into userID<BR>
put lookupPassword(userName, userID) into password<BR>
if (password is empty) then<BR>
put authenticateHeader(realm,"auth",empty,"default") into replyHeader<BR>
return FALSE<BR>
end if<BR>
<BR>
put makeDigest(userName,password,realm,method,theURL,nonce,nc,cnonce,qop) into actualValue<BR>
<BR>
put char 1 to length(actualValue) of digestValue into digestValue<BR>
if ((digestValue = actualValue) AND (opaque = server_opaque)) then<BR>
put authenticateInfoHeader(userName,password,realm,method,theURL,server_nonce[userName]) into replyHeader<BR>
put userID into loggedInIDs[theSocket]<BR>
put userName into loggedInNames[theSocket]<BR>
<BR>
put base64Encode(userName&tab&thePassword) into loginValue<BR>
SetCookie theSocket,"webcf_entry",loginValue<BR>
return TRUE<BR>
else<BR>
-- failed<BR>
put authenticateHeader(realm,"auth",empty) into replyHeader<BR>
return FALSE<BR>
end if<BR>
end checkPassword<BR>
<BR>
<BR>
function authenticateInfoHeader userName,_password,realm,method,theURL,nonce<BR>
put makeDigest(userName,_password,realm,empty,theURL,nonce) into response<BR>
return "Authentication-Info: next-nonce=""e&nonce"e&comma&"qop=""e&auth"e&comma&"rspauth=""e&response"e<BR>
end authenticateInfoHeader<BR>
<BR>
function authenticateHeader theRealm,authMethods,isStale,userName,forceNonce<BR>
global server_opaque,server_nonce,cfLF<BR>
if (userName is empty) then put "default" into userName<BR>
if (server_opaque is empty) then put base64Encode(random(4*(the ticks))&md5Digest(the ticks)) into server_opaque<BR>
if (server_nonce is empty) OR (forceNonce) then<BR>
put base64Encode("Dummy") into server_nonce<BR>
end if<BR>
if (isStale is empty) then return "HTTP/1.1 401 Unauthorized"&crLF&"WWW-Authenticate: Digest"&&"realm=""e&theRealm"e&comma&"qop=""e&authMethods"e&comma&"nonce=""e&server_nonce"e&comma&"opaque=""e&server_opaque"e&comma&"algorithm=""e&"MD5""e&crLF<BR>
else<BR>
return "HTTP/1.1 401 Unauthorized"&crLF&"Connection: close"&crLF&"WWW-Authenticate: Digest"&&"realm=""e&theRealm"e&comma&"qop=""e&authMethods"e&comma&"nonce=""e&server_nonce"e&comma&"opaque=""e&server_opaque"e&comma&"stale="&isStale&",algorithm=""e&"MD5""e&crLF<BR>
end if<BR>
end authenticateHeader<BR>
<BR>
function makeDigest userName,_password,realm,method,theURL,nonce,nc,cnonce,qop<BR>
put md5Digest(userName&colon&realm&colon&_password) into A1<BR>
get binaryDecode("H*",A1,A1)<BR>
put md5Digest(method&colon&theURL) into A2<BR>
get binaryDecode("H*",A2,A2)<BR>
if (qop is empty) then<BR>
put md5Digest(A1&colon&nonce&colon&A2) into actualValue<BR>
else<BR>
put md5Digest(A1&colon&nonce&colon&nc&colon&cnonce&colon&qop&colon&A2) into actualValue<BR>
end if<BR>
get binaryDecode("H*",actualValue,actualValue)<BR>
return actualvalue<BR>
end makeDigest<BR>
<BR>
<BR>
<BLOCKQUOTE CITE STYLE="BORDER-LEFT: #0000ff 2px solid; MARGIN-LEFT: 5px; MARGIN-RIGHT: 0px; PADDING-LEFT: 5px" TYPE="CITE"></FONT><FONT COLOR="#000000" FACE="Geneva" FAMILY="SANSSERIF" SIZE="2" STYLE="BACKGROUND-COLOR: #FFFFFF"><BR>
I'm sure it'll be a piece of cake, Rob. :) But please let us know <BR>
what you come up with. The truth is I just want someone else to <BR>
interpret section 3.2.2 of the rfc on digest authorization. I'm <BR>
trying to preserve what few brain cells I have remaining.<BR>
</BLOCKQUOTE></FONT><FONT COLOR="#000000" FACE="Geneva" FAMILY="SANSSERIF" SIZE="2" STYLE="BACKGROUND-COLOR: #FFFFFF"><BR>
<BR>
</FONT><FONT COLOR="#000000" FACE="Geneva" FAMILY="SANSSERIF" SIZE="2" STYLE="BACKGROUND-COLOR: #FFFFFF"></FONT></HTML>