From kfm-devel Sat Dec 07 06:13:48 2002 From: "Dawit A." Date: Sat, 07 Dec 2002 06:13:48 +0000 To: kfm-devel Subject: PATCH: Fix elusive HTTP digest authentication problem (BR# 42604) X-MARC-Message: https://marc.info/?l=kfm-devel&m=103924176329371 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_cGZ89K1NlsWZ2mc" --Boundary-00=_cGZ89K1NlsWZ2mc Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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. --Boundary-00=_cGZ89K1NlsWZ2mc Content-Type: text/x-diff; charset="us-ascii"; name="http_digest_31.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="http_digest_31.patch" ? .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: --Boundary-00=_cGZ89K1NlsWZ2mc Content-Type: text/x-diff; charset="us-ascii"; name="http_digest_head.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="http_digest_head.patch" 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: --Boundary-00=_cGZ89K1NlsWZ2mc--