<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>
&nbsp;  global server_opaque,server_nonce,nonce_time, loggedInIDs, loggedInNames, xfactor<BR>
<BR>
&nbsp;  put "WebCF Registered Users" into realm -- default<BR>
&nbsp;  <BR>
&nbsp;  put lineOffset("Authorization:", requestHeader) into theLine<BR>
&nbsp;  <BR>
&nbsp;  if (theLine &gt; 0) then<BR>
&nbsp;&nbsp;&nbsp;  -- check the authorization<BR>
&nbsp;&nbsp;&nbsp;  put word 1 of requestHeader into method<BR>
&nbsp;&nbsp;&nbsp;  put line theLine of requestHeader into authLine<BR>
&nbsp;&nbsp;&nbsp;  <BR>
&nbsp;&nbsp;&nbsp;  replace "Authorization: Digest" with empty in authLine<BR>
&nbsp;&nbsp;&nbsp;  set the itemDelimiter to comma<BR>
&nbsp;&nbsp;&nbsp;  repeat for each item theItem in authLine<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  set the itemDelimiter to "="<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put item 1 of theItem into theName<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  repeat until (char 1 of theName &lt;&gt; " ")<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete char 1 of theName<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  end repeat<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  replace (theName&amp;"=") with (theName&amp;"\u25ca") in theItem<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  set the itemDelimiter to "\u25ca"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put item 2 of theItem into theValue<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  replace quote with empty in theValue<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  set the itemDelimiter to comma<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  switch(theName)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "userName"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into userName<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "realm"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into realm<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "nonce"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into nonce<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "uri"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into theURL<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "qop"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into qop<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "nc"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into nc<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "cnonce"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into cnonce<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "response"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into digestValue<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  case "opaque"<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put theValue into opaque<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  exit switch<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  end switch<BR>
&nbsp;&nbsp;&nbsp;  end repeat<BR>
&nbsp;  else<BR>
&nbsp;&nbsp;&nbsp;  put authenticateHeader(realm,"auth",empty,"default") into replyHeader<BR>
&nbsp;&nbsp;&nbsp;  return FALSE<BR>
&nbsp;  end if<BR>
<BR>
&nbsp;  ## edit this to lookup the correct password<BR>
&nbsp;  put empty into userID<BR>
&nbsp;  put lookupPassword(userName, userID) into password<BR>
&nbsp;  if (password is empty) then<BR>
&nbsp;&nbsp;&nbsp;  put authenticateHeader(realm,"auth",empty,"default") into replyHeader<BR>
&nbsp;&nbsp;&nbsp;  return FALSE<BR>
&nbsp;  end if<BR>
&nbsp;  <BR>
&nbsp;  put makeDigest(userName,password,realm,method,theURL,nonce,nc,cnonce,qop) into actualValue<BR>
&nbsp;  <BR>
&nbsp;  put char 1 to length(actualValue) of digestValue into digestValue<BR>
&nbsp;  if ((digestValue = actualValue) AND (opaque = server_opaque)) then<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put authenticateInfoHeader(userName,password,realm,method,theURL,server_nonce[userName]) into replyHeader<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put userID into loggedInIDs[theSocket]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put userName into loggedInNames[theSocket]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  put base64Encode(userName&amp;tab&amp;thePassword) into loginValue<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  SetCookie theSocket,"webcf_entry",loginValue<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return TRUE<BR>
&nbsp;  else<BR>
&nbsp;&nbsp;&nbsp;  -- failed<BR>
&nbsp;&nbsp;&nbsp;  put authenticateHeader(realm,"auth",empty) into replyHeader<BR>
&nbsp;&nbsp;&nbsp;  return FALSE<BR>
&nbsp;  end if<BR>
end checkPassword<BR>
<BR>
<BR>
function authenticateInfoHeader userName,_password,realm,method,theURL,nonce<BR>
&nbsp;  put makeDigest(userName,_password,realm,empty,theURL,nonce) into response<BR>
&nbsp;  return "Authentication-Info: next-nonce="&amp;quote&amp;nonce&amp;quote&amp;comma&amp;"qop="&amp;quote&amp;auth&amp;quote&amp;comma&amp;"rspauth="&amp;quote&amp;response&amp;quote<BR>
end authenticateInfoHeader<BR>
<BR>
function authenticateHeader theRealm,authMethods,isStale,userName,forceNonce<BR>
&nbsp;  global server_opaque,server_nonce,cfLF<BR>
&nbsp;  if (userName is empty) then put "default" into userName<BR>
&nbsp;  if (server_opaque is empty) then put base64Encode(random(4*(the ticks))&amp;md5Digest(the ticks)) into server_opaque<BR>
&nbsp;  if (server_nonce is empty) OR (forceNonce) then<BR>
&nbsp;&nbsp;&nbsp;  put base64Encode("Dummy") into server_nonce<BR>
&nbsp;  end if<BR>
&nbsp;  if (isStale is empty) then return "HTTP/1.1 401 Unauthorized"&amp;crLF&amp;"WWW-Authenticate: Digest"&amp;&amp;"realm="&amp;quote&amp;theRealm&amp;quote&amp;comma&amp;"qop="&amp;quote&amp;authMethods&amp;quote&amp;comma&amp;"nonce="&amp;quote&amp;server_nonce&amp;quote&amp;comma&amp;"opaque="&amp;quote&amp;server_opaque&amp;quote&amp;comma&amp;"algorithm="&amp;quote&amp;"MD5"&amp;quote&amp;crLF<BR>
&nbsp;  else<BR>
&nbsp;&nbsp;&nbsp;  return "HTTP/1.1 401 Unauthorized"&amp;crLF&amp;"Connection: close"&amp;crLF&amp;"WWW-Authenticate: Digest"&amp;&amp;"realm="&amp;quote&amp;theRealm&amp;quote&amp;comma&amp;"qop="&amp;quote&amp;authMethods&amp;quote&amp;comma&amp;"nonce="&amp;quote&amp;server_nonce&amp;quote&amp;comma&amp;"opaque="&amp;quote&amp;server_opaque&amp;quote&amp;comma&amp;"stale="&amp;isStale&amp;",algorithm="&amp;quote&amp;"MD5"&amp;quote&amp;crLF<BR>
&nbsp;  end if<BR>
end authenticateHeader<BR>
<BR>
function makeDigest userName,_password,realm,method,theURL,nonce,nc,cnonce,qop<BR>
&nbsp;  put md5Digest(userName&amp;colon&amp;realm&amp;colon&amp;_password) into A1<BR>
&nbsp;  get binaryDecode("H*",A1,A1)<BR>
&nbsp;  put md5Digest(method&amp;colon&amp;theURL) into A2<BR>
&nbsp;  get binaryDecode("H*",A2,A2)<BR>
&nbsp;  if (qop is empty) then<BR>
&nbsp;&nbsp;&nbsp;  put md5Digest(A1&amp;colon&amp;nonce&amp;colon&amp;A2) into actualValue<BR>
&nbsp;  else<BR>
&nbsp;&nbsp;&nbsp;  put md5Digest(A1&amp;colon&amp;nonce&amp;colon&amp;nc&amp;colon&amp;cnonce&amp;colon&amp;qop&amp;colon&amp;A2) into actualValue<BR>
&nbsp;  end if<BR>
&nbsp;  get binaryDecode("H*",actualValue,actualValue)<BR>
&nbsp;  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>