[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    PATCH: Fix elusive HTTP digest authentication problem (BR# 42604)
From:       "Dawit A." <adawit () kde ! org>
Date:       2002-12-07 6:13:48
[Download RAW message or body]

Hi,

Attached are patches for both HEAD and 3_1_BRANCH that fixes an elusive HTTP 
digest authentication bug that was first reported by BR# 42604.  As luck 
would have it, I run into this bug myself when attempting to log into a  
digest authentication protected website at work.

The problem stemmed from incorrect setting of the uri= parameter in the 
Authentication line. While I was fixing that I also opted to complete the 
proper credential verification for preemptively sending the 
authentication-digest line to the server based on the "domain=" attribute 
extracted from a 401/407 response.  

Anyways, this fixes the problem as verified against my own test apache server.

Regards,
Dawit A.

["http_digest_31.patch" (text/x-diff)]

? .http.cc.swp
Index: http.cc
===================================================================
RCS file: /home/kde/kdelibs/kioslave/http/http.cc,v
retrieving revision 1.470.2.19
diff -u -p -b -B -w -r1.470.2.19 http.cc
--- http.cc	3 Dec 2002 05:45:20 -0000	1.470.2.19
+++ http.cc	7 Dec 2002 05:50:19 -0000
@@ -1903,6 +1903,9 @@ bool HTTPProtocol::httpOpen()
       davHeader = "Lock-token: " + metaData("davLockToken") + "\r\n";
       m_bCachedWrite = false; // Do not put any result in the cache
       break;
+  default:
+      error (ERR_UNSUPPORTED_ACTION, QString::null);
+      return false;      
   }
 
   if ( isSSLTunnelEnabled() )
@@ -2097,11 +2100,9 @@ bool HTTPProtocol::httpOpen()
     {
       case AUTH_Basic:
           header += createBasicAuth();
-          header += "\r\n";
           break;
       case AUTH_Digest:
           header += createDigestAuth();
-          header += "\r\n";
           break;
       case AUTH_None:
       default:
@@ -4702,6 +4703,8 @@ QString HTTPProtocol::createBasicAuth( b
   user += ':';
   user += passwd;
   auth += KCodecs::base64Encode( user );
+  auth += "\r\n";
+  
   return auth;
 }
 
@@ -4731,12 +4734,12 @@ void HTTPProtocol::calculateResponse( Di
   }
   HA1 = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") A1 => " << HA1 << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A1 => " << HA1 << endl;
 
   // Calcualte H(A2)
   authStr = info.method;
   authStr += ':';
-  authStr += info.digestURI.at( 0 );
+  authStr += m_request.url.encodedPathAndQuery(0, true).latin1();
   if ( info.qop == "auth-int" )
   {
     authStr += ':';
@@ -4746,7 +4749,8 @@ void HTTPProtocol::calculateResponse( Di
   md.update( authStr );
   HA2 = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") A2 => " << HA2 << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A2 => " 
+                << HA2 << endl;
 
   // Calcualte the response.
   authStr = HA1;
@@ -4767,7 +4771,8 @@ void HTTPProtocol::calculateResponse( Di
   md.update( authStr );
   Response = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") Response => " << Response << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): Response => " 
+                << Response << endl;
 }
 
 QString HTTPProtocol::createDigestAuth ( bool isForProxy )
@@ -4871,9 +4876,17 @@ QString HTTPProtocol::createDigestAuth (
       {
         pos = uri.find( ',', pos );
         if ( pos != -1 )
-          info.digestURI.append( uri.mid(idx, pos-idx) );
+        {
+          KURL u (m_request.url, uri.mid(idx, pos-idx));
+          if (!u.isMalformed ())
+            info.digestURI.append( u.url().latin1() );
+        }
         else
-          info.digestURI.append( uri.mid(idx, uri.length()-idx) );
+        {
+          KURL u (m_request.url, uri.mid(idx, uri.length()-idx));
+          if (!u.isMalformed ())
+            info.digestURI.append( u.url().latin1() );
+        }
         idx = pos+1;
       } while ( pos != -1 );
     }
@@ -4901,8 +4914,50 @@ QString HTTPProtocol::createDigestAuth (
     p+=(i+1);
   }
 
-  if ( info.digestURI.isEmpty() )
-    info.digestURI.append( m_request.path.latin1() );
+  // If the "domain" attribute was not specified and the current response code
+  // is authentication needed, add the current request url to the list over which
+  // this credential can be automatically applied.
+  if (info.digestURI.isEmpty() && (m_responseCode == 401 || m_responseCode == 407))
+    info.digestURI.append (m_request.url.url().latin1());
+  else
+  {
+    // Verify whether or not we should send a cached credential to the
+    // server based on the stored "domain" attribute...
+    bool send = true;
+    
+    // Determine the path of the request url...
+    QString requestPath = m_request.url.directory(false, false);
+    if (requestPath.isEmpty())
+      requestPath = "/";
+    
+    int count = info.digestURI.count();
+        
+    for (int i = 0; i < count; i++ )
+    {
+      KURL u = info.digestURI.at(i);
+      
+      send &= (m_request.url.protocol().lower() == u.protocol().lower());
+      send &= (m_request.hostname.lower() == u.host().lower());
+      
+      if (m_request.port > 0 && u.port() > 0)
+        send &= (m_request.port == u.port());      
+
+      QString digestPath = u.directory (false, false);        
+      if (digestPath.isEmpty())
+        digestPath = "/";
+      
+      send &= (requestPath.startsWith(digestPath));
+      
+      if (send)
+        break;
+    }
+    
+    kdDebug(7113) << "(" << m_pid << ") createDigestAuth(): passed digest "
+                     "authentication credential test: " << send << endl;
+        
+    if (!send)
+      return QString::null;
+  }
 
   kdDebug(7113) << "(" << m_pid << ") RESULT OF PARSING:" << endl;
   kdDebug(7113) << "(" << m_pid << ")   algorithm: " << info.algorithm << endl;
@@ -4911,11 +4966,6 @@ QString HTTPProtocol::createDigestAuth (
   kdDebug(7113) << "(" << m_pid << ")   opaque:    " << opaque << endl;
   kdDebug(7113) << "(" << m_pid << ")   qop:       " << info.qop << endl;
 
-  int count = info.digestURI.count();
-  for( int i = 0; i < count; i++ )
-    kdDebug(7113) << "(" << m_pid << ")   domain[" << i << "]:    "
-                  << info.digestURI.at(i) << endl;
-
   // Calculate the response...
   calculateResponse( info, Response );
 
@@ -4930,7 +4980,7 @@ QString HTTPProtocol::createDigestAuth (
   auth += info.nonce;
 
   auth += "\", uri=\"";
-  auth += info.digestURI.at(0);
+  auth += m_request.url.encodedPathAndQuery(0, true);
 
   auth += "\", algorithm=\"";
   auth += info.algorithm;
@@ -4953,9 +5003,8 @@ QString HTTPProtocol::createDigestAuth (
     auth += "\", opaque=\"";
     auth += opaque;
   }
-  auth += "\"";
+  auth += "\"\r\n";
 
-  kdDebug(7113) << "(" << m_pid << ") Digest header: " << auth << endl;
   return auth;
 }
 
@@ -5021,11 +5070,9 @@ QString HTTPProtocol::proxyAuthenticatio
   {
     case AUTH_Basic:
       header += createBasicAuth( true );
-      header += "\r\n";
       break;
     case AUTH_Digest:
       header += createDigestAuth( true );
-      header += "\r\n";
       break;
     case AUTH_None:
     default:

["http_digest_head.patch" (text/x-diff)]

Index: http.cc
===================================================================
RCS file: /home/kde/kdelibs/kioslave/http/http.cc,v
retrieving revision 1.555
diff -u -p -b -B -w -r1.555 http.cc
--- http.cc	2 Dec 2002 12:59:47 -0000	1.555
+++ http.cc	7 Dec 2002 05:51:13 -0000
@@ -1967,10 +1967,12 @@ bool HTTPProtocol::httpOpen()
       header = "PROPFIND ";
       davData = true;
       davHeader = "Depth: ";
-      if ( hasMetaData( "davDepth" ) ) {
+      if ( hasMetaData( "davDepth" ) ) 
+      {
         kdDebug(7113) << "Reading DAV depth from metadata: " << metaData( "davDepth" ) << endl;
         davHeader += metaData( "davDepth" );
-      } else
+      } 
+      else
       {
         if ( m_request.davData.depth == 2 )
           davHeader += "infinity";
@@ -2038,7 +2040,7 @@ bool HTTPProtocol::httpOpen()
       header = "POLL ";
       m_request.bCachedWrite = false;
       break;
-  case HTTP_UNKNOWN:
+  default:
       error (ERR_UNSUPPORTED_ACTION, QString::null);
       return false;
   }
@@ -2256,11 +2258,9 @@ bool HTTPProtocol::httpOpen()
     {
       case AUTH_Basic:
           header += createBasicAuth();
-          header += "\r\n";
           break;
       case AUTH_Digest:
           header += createDigestAuth();
-          header += "\r\n";
           break;
       case AUTH_None:
       default:
@@ -4940,6 +4940,8 @@ QString HTTPProtocol::createBasicAuth( b
   user += ':';
   user += passwd;
   auth += KCodecs::base64Encode( user );
+  auth += "\r\n";
+  
   return auth;
 }
 
@@ -4969,12 +4971,12 @@ void HTTPProtocol::calculateResponse( Di
   }
   HA1 = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") A1 => " << HA1 << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A1 => " << HA1 << endl;
 
   // Calcualte H(A2)
   authStr = info.method;
   authStr += ':';
-  authStr += info.digestURI.at( 0 );
+  authStr += m_request.url.encodedPathAndQuery(0, true).latin1();
   if ( info.qop == "auth-int" )
   {
     authStr += ':';
@@ -4984,7 +4986,8 @@ void HTTPProtocol::calculateResponse( Di
   md.update( authStr );
   HA2 = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") A2 => " << HA2 << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): A2 => " 
+                << HA2 << endl;
 
   // Calcualte the response.
   authStr = HA1;
@@ -5005,7 +5008,8 @@ void HTTPProtocol::calculateResponse( Di
   md.update( authStr );
   Response = md.hexDigest();
 
-  kdDebug(7113) << "(" << m_pid << ") Response => " << Response << endl;
+  kdDebug(7113) << "(" << m_pid << ") calculateResponse(): Response => " 
+                << Response << endl;
 }
 
 QString HTTPProtocol::createDigestAuth ( bool isForProxy )
@@ -5110,9 +5114,17 @@ QString HTTPProtocol::createDigestAuth (
       {
         pos = uri.find( ',', pos );
         if ( pos != -1 )
-          info.digestURI.append( uri.mid(idx, pos-idx) );
+        {
+          KURL u (m_request.url, uri.mid(idx, pos-idx));
+          if (!u.isMalformed ())
+            info.digestURI.append( u.url().latin1() );
+        }
         else
-          info.digestURI.append( uri.mid(idx, uri.length()-idx) );
+        {
+          KURL u (m_request.url, uri.mid(idx, uri.length()-idx));
+          if (!u.isMalformed ())
+            info.digestURI.append( u.url().latin1() );
+        }
         idx = pos+1;
       } while ( pos != -1 );
     }
@@ -5140,8 +5152,50 @@ QString HTTPProtocol::createDigestAuth (
     p+=(i+1);
   }
 
-  if ( info.digestURI.isEmpty() )
-    info.digestURI.append( m_request.path.latin1() );
+  // If the "domain" attribute was not specified and the current response code
+  // is authentication needed, add the current request url to the list over which
+  // this credential can be automatically applied.
+  if (info.digestURI.isEmpty() && (m_responseCode == 401 || m_responseCode == 407))
+    info.digestURI.append (m_request.url.url().latin1());
+  else
+  {
+    // Verify whether or not we should send a cached credential to the
+    // server based on the stored "domain" attribute...
+    bool send = true;
+    
+    // Determine the path of the request url...
+    QString requestPath = m_request.url.directory(false, false);
+    if (requestPath.isEmpty())
+      requestPath = "/";
+    
+    int count = info.digestURI.count();
+        
+    for (int i = 0; i < count; i++ )
+    {
+      KURL u = info.digestURI.at(i);
+      
+      send &= (m_request.url.protocol().lower() == u.protocol().lower());
+      send &= (m_request.hostname.lower() == u.host().lower());
+      
+      if (m_request.port > 0 && u.port() > 0)
+        send &= (m_request.port == u.port());      
+
+      QString digestPath = u.directory (false, false);        
+      if (digestPath.isEmpty())
+        digestPath = "/";
+      
+      send &= (requestPath.startsWith(digestPath));
+      
+      if (send)
+        break;
+    }
+    
+    kdDebug(7113) << "(" << m_pid << ") createDigestAuth(): passed digest "
+                     "authentication credential test: " << send << endl;
+        
+    if (!send)
+      return QString::null;
+  }
 
   kdDebug(7113) << "(" << m_pid << ") RESULT OF PARSING:" << endl;
   kdDebug(7113) << "(" << m_pid << ")   algorithm: " << info.algorithm << endl;
@@ -5150,11 +5204,6 @@ QString HTTPProtocol::createDigestAuth (
   kdDebug(7113) << "(" << m_pid << ")   opaque:    " << opaque << endl;
   kdDebug(7113) << "(" << m_pid << ")   qop:       " << info.qop << endl;
 
-  int count = info.digestURI.count();
-  for( int i = 0; i < count; i++ )
-    kdDebug(7113) << "(" << m_pid << ")   domain[" << i << "]:    "
-                  << info.digestURI.at(i) << endl;
-
   // Calculate the response...
   calculateResponse( info, Response );
 
@@ -5169,7 +5218,7 @@ QString HTTPProtocol::createDigestAuth (
   auth += info.nonce;
 
   auth += "\", uri=\"";
-  auth += info.digestURI.at(0);
+  auth += m_request.url.encodedPathAndQuery(0, true);
 
   auth += "\", algorithm=\"";
   auth += info.algorithm;
@@ -5192,9 +5241,8 @@ QString HTTPProtocol::createDigestAuth (
     auth += "\", opaque=\"";
     auth += opaque;
   }
-  auth += "\"";
+  auth += "\"\r\n";
 
-  kdDebug(7113) << "(" << m_pid << ") Digest header: " << auth << endl;
   return auth;
 }
 
@@ -5259,11 +5307,9 @@ QString HTTPProtocol::proxyAuthenticatio
   {
     case AUTH_Basic:
       header += createBasicAuth( true );
-      header += "\r\n";
       break;
     case AUTH_Digest:
       header += createDigestAuth( true );
-      header += "\r\n";
       break;
     case AUTH_None:
     default:


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic