Digest Authentication

Yennie at aol.com Yennie at aol.com
Wed Nov 20 00:56:01 EST 2002


I can assure you it's possible... cause I've done it!

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.

Hope this helps!

function checkPassword theSocket,requestHeader, at replyHeader, at userName
   global server_opaque,server_nonce,nonce_time, loggedInIDs, loggedInNames, 
xfactor

   put "WebCF Registered Users" into realm -- default
   
   put lineOffset("Authorization:", requestHeader) into theLine
   
   if (theLine > 0) then
     -- check the authorization
     put word 1 of requestHeader into method
     put line theLine of requestHeader into authLine
     
     replace "Authorization: Digest" with empty in authLine
     set the itemDelimiter to comma
     repeat for each item theItem in authLine
       set the itemDelimiter to "="
       put item 1 of theItem into theName
       repeat until (char 1 of theName <> " ")
         delete char 1 of theName
       end repeat
       replace (theName&"=") with (theName&"◊") in theItem
       set the itemDelimiter to "◊"
       put item 2 of theItem into theValue
       replace quote with empty in theValue
       set the itemDelimiter to comma
       switch(theName)
       case "userName"
         put theValue into userName
         exit switch
       case "realm"
         put theValue into realm
         exit switch
       case "nonce"
         put theValue into nonce
         exit switch
       case "uri"
         put theValue into theURL
         exit switch
       case "qop"
         put theValue into qop
         exit switch
       case "nc"
         put theValue into nc
         exit switch
       case "cnonce"
         put theValue into cnonce
         exit switch
       case "response"
         put theValue into digestValue
         exit switch
       case "opaque"
         put theValue into opaque
         exit switch
       end switch
     end repeat
   else
     put authenticateHeader(realm,"auth",empty,"default") into replyHeader
     return FALSE
   end if

   ## edit this to lookup the correct password
   put empty into userID
   put lookupPassword(userName, userID) into password
   if (password is empty) then
     put authenticateHeader(realm,"auth",empty,"default") into replyHeader
     return FALSE
   end if
   
   put makeDigest(userName,password,realm,method,theURL,nonce,nc,cnonce,qop) 
into actualValue
   
   put char 1 to length(actualValue) of digestValue into digestValue
   if ((digestValue = actualValue) AND (opaque = server_opaque)) then
       put 
authenticateInfoHeader(userName,password,realm,method,theURL,server_nonce[user

Name]) into replyHeader
       put userID into loggedInIDs[theSocket]
       put userName into loggedInNames[theSocket]
       
       put base64Encode(userName&tab&thePassword) into loginValue
       SetCookie theSocket,"webcf_entry",loginValue
       return TRUE
   else
     -- failed
     put authenticateHeader(realm,"auth",empty) into replyHeader
     return FALSE
   end if
end checkPassword


function authenticateInfoHeader userName,_password,realm,method,theURL,nonce
   put makeDigest(userName,_password,realm,empty,theURL,nonce) into response
   return "Authentication-Info: next-nonce="&quote&nonce&quote&comma&"qop="&
quote&auth&quote&comma&"rspauth="&quote&response&quote
end authenticateInfoHeader

function authenticateHeader theRealm,authMethods,isStale,userName,forceNonce
   global server_opaque,server_nonce,cfLF
   if (userName is empty) then put "default" into userName
   if (server_opaque is empty) then put base64Encode(random(4*(the ticks))&
md5Digest(the ticks)) into server_opaque
   if (server_nonce is empty) OR (forceNonce) then
     put base64Encode("Dummy") into server_nonce
   end if
   if (isStale is empty) then return "HTTP/1.1 401 Unauthorized"&crLF&
"WWW-Authenticate: Digest"&&"realm="&quote&theRealm&quote&comma&"qop="&quote&
authMethods&quote&comma&"nonce="&quote&server_nonce&quote&comma&"opaque="&
quote&server_opaque&quote&comma&"algorithm="&quote&"MD5"&quote&crLF
   else
     return "HTTP/1.1 401 Unauthorized"&crLF&"Connection: close"&crLF&
"WWW-Authenticate: Digest"&&"realm="&quote&theRealm&quote&comma&"qop="&quote&
authMethods&quote&comma&"nonce="&quote&server_nonce&quote&comma&"opaque="&
quote&server_opaque&quote&comma&"stale="&isStale&",algorithm="&quote&"MD5"&
quote&crLF
   end if
end authenticateHeader

function makeDigest 
userName,_password,realm,method,theURL,nonce,nc,cnonce,qop
   put md5Digest(userName&colon&realm&colon&_password) into A1
   get binaryDecode("H*",A1,A1)
   put md5Digest(method&colon&theURL) into A2
   get binaryDecode("H*",A2,A2)
   if (qop is empty) then
     put md5Digest(A1&colon&nonce&colon&A2) into actualValue
   else
     put md5Digest(A1&colon&nonce&colon&nc&colon&cnonce&colon&qop&colon&A2) 
into actualValue
   end if
   get binaryDecode("H*",actualValue,actualValue)
   return actualvalue
end makeDigest


> 
> I'm sure it'll be a piece of cake, Rob. :)  But please let us know 
> what you come up with. The truth is I just want someone else to 
> interpret section 3.2.2 of the rfc on digest authorization. I'm 
> trying to preserve what few brain cells I have remaining.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.runrev.com/pipermail/use-livecode/attachments/20021120/4e4a9ab0/attachment.html>


More information about the use-livecode mailing list